diff --git a/repos/base-hw/src/lib/base/signal_receiver.cc b/repos/base-hw/src/lib/base/signal_receiver.cc index 28a5301f6..b2359612f 100644 --- a/repos/base-hw/src/lib/base/signal_receiver.cc +++ b/repos/base-hw/src/lib/base/signal_receiver.cc @@ -99,7 +99,7 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c) /* use signal context as imprint */ c->_cap = pd().alloc_context(_cap, (unsigned long)c); c->_receiver = this; - _contexts.insert(c); + _contexts.insert_as_tail(c); return c->_cap; } catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; } diff --git a/repos/base/include/base/signal.h b/repos/base/include/base/signal.h index 89419e8b5..9710f219c 100644 --- a/repos/base/include/base/signal.h +++ b/repos/base/include/base/signal.h @@ -167,159 +167,6 @@ class Genode::Signal_transmitter }; -/** - * Signal receiver - */ -class Genode::Signal_receiver : Noncopyable -{ - private: - - /** - * A list where the head can be moved - */ - class Context_list - { - private: - - Signal_context *_head { nullptr }; - - public: - - Signal_context *head() const { return _head; } - - void head(Signal_context *re); - - void insert(Signal_context *re); - - void remove(Signal_context const *re); - }; - - /** - * Semaphore used to indicate that signal(s) are ready to be picked - * up. This is needed for platforms other than 'base-hw' only. - */ - Semaphore _signal_available; - - /** - * Provides the kernel-object name via the 'dst' method. This is - * needed for 'base-hw' only. - */ - Capability _cap; - - /** - * List of associated contexts - */ - Lock _contexts_lock; - Context_list _contexts; - - /** - * Helper to dissolve given context - * - * This method prevents duplicated code in '~Signal_receiver' - * and 'dissolve'. Note that '_contexts_lock' must be held when - * calling this method. - */ - void _unsynchronized_dissolve(Signal_context *context); - - /** - * Hook to platform specific destructor parts - */ - void _platform_destructor(); - - /** - * Hooks to platform specific dissolve parts - */ - void _platform_begin_dissolve(Signal_context * const c); - void _platform_finish_dissolve(Signal_context * const c); - - public: - - /** - * Exception class - */ - class Context_already_in_use { }; - class Context_not_associated { }; - class Signal_not_pending { }; - - /** - * Constructor - */ - Signal_receiver(); - - /** - * Destructor - */ - ~Signal_receiver(); - - /** - * Manage signal context and return new signal-context capability - * - * \param context context associated with signals delivered to the - * receiver - * \throw 'Context_already_in_use' - * \return new signal-context capability that can be - * passed to a signal transmitter - */ - Signal_context_capability manage(Signal_context *context); - - /** - * Dissolve signal context from receiver - * - * \param context context to remove from receiver - * \throw 'Context_not_associated' - */ - void dissolve(Signal_context *context); - - /** - * Return true if signal was received - */ - bool pending(); - - /** - * Block until a signal is received and return the signal - * - * \return received signal - */ - Signal wait_for_signal(); - - /** - * Block until a signal is received - */ - void block_for_signal(); - - /** - * Unblock signal waiter - */ - void unblock_signal_waiter(Rpc_entrypoint &rpc_ep); - - /** - * Retrieve pending signal - * - * \throw 'Signal_not_pending' no pending signal found - * \return received signal - */ - Signal pending_signal(); - - /** - * Locally submit signal to the receiver - * - * \noapi - */ - void local_submit(Signal::Data signal); - - /** - * Framework-internal signal-dispatcher - * - * \noapi - * - * This method is called from the thread that monitors the signal - * source associated with the process. It must not be used for other - * purposes. - */ - static void dispatch_signals(Signal_source *); -}; - - /** * Signal context * @@ -431,6 +278,176 @@ class Genode::Signal_context }; +/** + * Signal receiver + */ +class Genode::Signal_receiver : Noncopyable +{ + private: + + /** + * A list where the head can be moved + */ + class Context_ring + { + private: + + Signal_context *_head { nullptr }; + + public: + + struct Break_for_each : Exception { }; + + Signal_context *head() const { return _head; } + + void head(Signal_context *re) { _head = re; } + + void insert_as_tail(Signal_context *re); + + void remove(Signal_context const *re); + + template + void for_each_locked(FUNC && functor) const + { + Signal_context *context = _head; + if (!context) return; + + do { + Lock::Guard lock_guard(context->_lock); + try { + functor(*context); + } catch (Break_for_each) { return; } + context = context->_next; + } while (context != _head); + } + }; + + /** + * Semaphore used to indicate that signal(s) are ready to be picked + * up. This is needed for platforms other than 'base-hw' only. + */ + Semaphore _signal_available; + + /** + * Provides the kernel-object name via the 'dst' method. This is + * needed for 'base-hw' only. + */ + Capability _cap; + + /** + * List of associated contexts + */ + Lock _contexts_lock; + Context_ring _contexts; + + /** + * Helper to dissolve given context + * + * This method prevents duplicated code in '~Signal_receiver' + * and 'dissolve'. Note that '_contexts_lock' must be held when + * calling this method. + */ + void _unsynchronized_dissolve(Signal_context *context); + + /** + * Hook to platform specific destructor parts + */ + void _platform_destructor(); + + /** + * Hooks to platform specific dissolve parts + */ + void _platform_begin_dissolve(Signal_context * const c); + void _platform_finish_dissolve(Signal_context * const c); + + public: + + /** + * Exception class + */ + class Context_already_in_use { }; + class Context_not_associated { }; + class Signal_not_pending { }; + + /** + * Constructor + */ + Signal_receiver(); + + /** + * Destructor + */ + ~Signal_receiver(); + + /** + * Manage signal context and return new signal-context capability + * + * \param context context associated with signals delivered to the + * receiver + * \throw 'Context_already_in_use' + * \return new signal-context capability that can be + * passed to a signal transmitter + */ + Signal_context_capability manage(Signal_context *context); + + /** + * Dissolve signal context from receiver + * + * \param context context to remove from receiver + * \throw 'Context_not_associated' + */ + void dissolve(Signal_context *context); + + /** + * Return true if signal was received + */ + bool pending(); + + /** + * Block until a signal is received and return the signal + * + * \return received signal + */ + Signal wait_for_signal(); + + /** + * Block until a signal is received + */ + void block_for_signal(); + + /** + * Unblock signal waiter + */ + void unblock_signal_waiter(Rpc_entrypoint &rpc_ep); + + /** + * Retrieve pending signal + * + * \throw 'Signal_not_pending' no pending signal found + * \return received signal + */ + Signal pending_signal(); + + /** + * Locally submit signal to the receiver + * + * \noapi + */ + void local_submit(Signal::Data signal); + + /** + * Framework-internal signal-dispatcher + * + * \noapi + * + * This method is called from the thread that monitors the signal + * source associated with the process. It must not be used for other + * purposes. + */ + static void dispatch_signals(Signal_source *); +}; + + /** * Abstract interface to be implemented by signal dispatchers */ diff --git a/repos/base/src/lib/base/signal.cc b/repos/base/src/lib/base/signal.cc index 4bcb6bc2a..118c84f0e 100644 --- a/repos/base/src/lib/base/signal.cc +++ b/repos/base/src/lib/base/signal.cc @@ -221,10 +221,10 @@ Signal_context_capability Signal_receiver::manage(Signal_context *context) context->_receiver = this; - Lock::Guard list_lock_guard(_contexts_lock); + Lock::Guard contexts_lock_guard(_contexts_lock); /* insert context into context list */ - _contexts.insert(context); + _contexts.insert_as_tail(context); /* register context at process-wide registry */ signal_context_registry()->insert(&context->_registry_le); diff --git a/repos/base/src/lib/base/signal_common.cc b/repos/base/src/lib/base/signal_common.cc index 2804bc8f0..f136e5271 100644 --- a/repos/base/src/lib/base/signal_common.cc +++ b/repos/base/src/lib/base/signal_common.cc @@ -160,30 +160,24 @@ Signal Signal_receiver::wait_for_signal() Signal Signal_receiver::pending_signal() { - Lock::Guard list_lock_guard(_contexts_lock); + Lock::Guard contexts_lock_guard(_contexts_lock); + Signal::Data result; + _contexts.for_each_locked([&] (Signal_context &context) { - /* look up the contexts for the pending signal */ - for (Signal_context *context = _contexts.head(); context; context = context->_next) { + if (!context._pending) return; - Lock::Guard lock_guard(context->_lock); - - /* check if context has a pending signal */ - if (!context->_pending) - continue; - - _contexts.head(context); - context->_pending = false; - Signal::Data result = context->_curr_signal; - - /* invalidate current signal in context */ - context->_curr_signal = Signal::Data(0, 0); + _contexts.head(context._next); + context._pending = false; + result = context._curr_signal; + context._curr_signal = Signal::Data(0, 0); + Trace::Signal_received trace_event(context, result.num); + throw Context_ring::Break_for_each(); + }); + if (result.context) { if (result.num == 0) warning("returning signal with num == 0"); - Trace::Signal_received trace_event(*context, result.num); - - /* return last received signal */ return result; } @@ -202,7 +196,7 @@ Signal Signal_receiver::pending_signal() Signal_receiver::~Signal_receiver() { - Lock::Guard list_lock_guard(_contexts_lock); + Lock::Guard contexts_lock_guard(_contexts_lock); /* disassociate contexts from the receiver */ while (_contexts.head()) @@ -235,7 +229,7 @@ void Signal_receiver::dissolve(Signal_context *context) if (context->_receiver != this) throw Context_not_associated(); - Lock::Guard list_lock_guard(_contexts_lock); + Lock::Guard contexts_lock_guard(_contexts_lock); _unsynchronized_dissolve(context); @@ -243,59 +237,38 @@ void Signal_receiver::dissolve(Signal_context *context) } - bool Signal_receiver::pending() { - Lock::Guard list_lock_guard(_contexts_lock); - - /* look up the contexts for the pending signal */ - for (Signal_context *context = _contexts.head(); context; context = context->_next) { - - Lock::Guard lock_guard(context->_lock); - - if (context->_pending) - return true; - } - return false; + Lock::Guard contexts_lock_guard(_contexts_lock); + bool result = false; + _contexts.for_each_locked([&] (Signal_context &context) { + if (context._pending) { + result = true; + throw Context_ring::Break_for_each(); + } + }); + return result; } -void Signal_receiver::Context_list::insert(Signal_context *re) +void Signal_receiver::Context_ring::insert_as_tail(Signal_context *re) { if (_head) { - re->_prev = _head->_prev; - re->_next = nullptr; - _head->_prev->_next = re; - _head->_prev = re; + re->_prev = _head->_prev; + re->_next = _head; + _head->_prev = _head->_prev->_next = re; } else { - re->_prev = re; - re->_next = nullptr; - _head = re; + _head = re->_prev = re->_next = re; } } -void Signal_receiver::Context_list::remove(Signal_context const *re) +void Signal_receiver::Context_ring::remove(Signal_context const *re) { - if (re->_prev == re) { - _head = nullptr; - } else { - if (_head == re) { - _head = re->_next; - } + if (re->_next != re) { + if (re == _head) { _head = re->_next; } re->_prev->_next = re->_next; - if (re->_next) { - re->_next->_prev = re->_prev; - } else { - _head->_prev = re->_prev; - } + re->_next->_prev = re->_prev; } -} - - -void Signal_receiver::Context_list::head(Signal_context *re) -{ - _head->_prev->_next = _head; - _head = re; - _head->_prev->_next = nullptr; + else { _head = nullptr; } }