diff --git a/repos/base/include/timer/timeout.h b/repos/base/include/timer/timeout.h index 832543b84f..8d87c91252 100644 --- a/repos/base/include/timer/timeout.h +++ b/repos/base/include/timer/timeout.h @@ -171,7 +171,8 @@ class Genode::Timeout : private Noncopyable Mutex _dispatch_mutex { }; Raw _raw { }; - int _active { 0 }; + short _active { 0 }; + bool _delete { false }; Alarm *_next { nullptr }; Alarm_timeout_scheduler *_scheduler { nullptr }; diff --git a/repos/base/include/timer_session/connection.h b/repos/base/include/timer_session/connection.h index 00c66ef652..39b9586653 100644 --- a/repos/base/include/timer_session/connection.h +++ b/repos/base/include/timer_session/connection.h @@ -76,6 +76,8 @@ struct Timer::Periodic_timeout : private Genode::Noncopyable { _timeout.schedule_periodic(duration, _handler); } + + ~Periodic_timeout() { _timeout.discard(); } }; @@ -121,6 +123,8 @@ class Timer::One_shot_timeout : private Genode::Noncopyable Handler_method method) : _timeout(timeout_scheduler), _handler(object, method) { } + ~One_shot_timeout() { _timeout.discard(); } + void schedule(Microseconds duration) { _timeout.schedule_one_shot(duration, _handler); } diff --git a/repos/base/src/lib/timeout/timeout.cc b/repos/base/src/lib/timeout/timeout.cc index 22e8e3136d..97c832f245 100644 --- a/repos/base/src/lib/timeout/timeout.cc +++ b/repos/base/src/lib/timeout/timeout.cc @@ -236,24 +236,30 @@ Timeout::Alarm *Alarm_timeout_scheduler::_alarm_get_pending_alarm() { Mutex::Guard mutex_guard(_mutex); - if (!_active_head || !_active_head->_raw.is_pending_at(_now, _now_period)) { - return nullptr; } + do { + if (!_active_head || !_active_head->_raw.is_pending_at(_now, _now_period)) { + return nullptr; } - /* remove alarm from head of the list */ - Alarm *pending_alarm = _active_head; - _active_head = _active_head->_next; + /* remove alarm from head of the list */ + Alarm *pending_alarm = _active_head; + _active_head = _active_head->_next; - /* - * Acquire dispatch mutex to defer destruction until the call of '_on_alarm' - * is finished - */ - pending_alarm->_dispatch_mutex.acquire(); + /* + * Acquire dispatch mutex to defer destruction until the call of '_on_alarm' + * is finished + */ + pending_alarm->_dispatch_mutex.acquire(); - /* reset alarm object */ - pending_alarm->_next = nullptr; - pending_alarm->_active--; + /* reset alarm object */ + pending_alarm->_next = nullptr; + pending_alarm->_active--; - return pending_alarm; + if (pending_alarm->_delete) { + pending_alarm->_dispatch_mutex.release(); + continue; + } + return pending_alarm; + } while (true); } @@ -399,11 +405,19 @@ void Alarm_timeout_scheduler::_alarm_discard(Alarm *alarm) * is finished, '_alarm_get_pending_alarm' would proceed with operating on * a dangling pointer. */ - Mutex::Guard alarm_list_guard(_mutex); - if (alarm) { + { + /* inform that this object is going to be deleted */ + Mutex::Guard alarm_guard(alarm->_dispatch_mutex); + alarm->_delete = true; + } + { + Mutex::Guard alarm_list_guard(_mutex); + _alarm_unsynchronized_dequeue(alarm); + } + + /* get anyone using this out of '_alarm_get_pending_alarm'() finally */ Mutex::Guard alarm_guard(alarm->_dispatch_mutex); - _alarm_unsynchronized_dequeue(alarm); } }