diff --git a/repos/base-hw/src/base/signal/signal.cc b/repos/base-hw/src/base/signal/signal.cc index fcaf3621a..848e2ecef 100644 --- a/repos/base-hw/src/base/signal/signal.cc +++ b/repos/base-hw/src/base/signal/signal.cc @@ -195,6 +195,41 @@ void Signal_receiver::dissolve(Signal_context * const context) bool Signal_receiver::pending() { return Kernel::signal_pending(_cap.dst()); } +/* + * Last signal received by 'block_for_signal' + */ +void Signal_receiver::block_for_signal() +{ + /* await a signal */ + if (Kernel::await_signal(_cap.dst())) { + PERR("failed to receive signal"); + return; + } + + /* get signal */ + Signal::Data *data = (Signal::Data *)Thread_base::myself()->utcb()->base(); + Signal s(*data); + + /* save signal data in context list */ + s.context()->_curr_signal = *data; + _contexts.insert(&s.context()->_receiver_le); +} + + +Signal Signal_receiver::pending_signal() +{ + List_element *le = _contexts.first(); + if (!le) + throw Signal_not_pending(); + + /* remove from context list */ + Signal_context *context = le->object(); + _contexts.remove(le); + + return Signal(context->_curr_signal); +} + + Signal Signal_receiver::wait_for_signal() { /* await a signal */ diff --git a/repos/base/include/base/signal.h b/repos/base/include/base/signal.h index a3ac70cef..fc54496d4 100644 --- a/repos/base/include/base/signal.h +++ b/repos/base/include/base/signal.h @@ -207,6 +207,7 @@ class Genode::Signal_receiver : Noncopyable */ class Context_already_in_use { }; class Context_not_associated { }; + class Signal_not_pending { }; /** * Constructor @@ -243,12 +244,25 @@ class Genode::Signal_receiver : Noncopyable bool pending(); /** - * Block until a signal is received + * 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(); + + /** + * Retrieve pending signal + * + * \throw 'Signal_not_pending' no pending signal found + * \return received signal + */ + Signal pending_signal(); + /** * Locally submit signal to the receiver * diff --git a/repos/base/src/base/signal/signal.cc b/repos/base/src/base/signal/signal.cc index 31ba96fef..c2c1f0bf1 100644 --- a/repos/base/src/base/signal/signal.cc +++ b/repos/base/src/base/signal/signal.cc @@ -332,52 +332,66 @@ bool Signal_receiver::pending() } +Signal Signal_receiver::pending_signal() +{ + Lock::Guard list_lock_guard(_contexts_lock); + + /* look up the contexts for the pending signal */ + for (List_element *le = _contexts.first(); le; le = le->next()) { + + Signal_context *context = le->object(); + + Lock::Guard lock_guard(context->_lock); + + /* check if context has a pending signal */ + if (!context->_pending) + continue; + + context->_pending = false; + Signal::Data result = context->_curr_signal; + + /* invalidate current signal in context */ + context->_curr_signal = Signal::Data(0, 0); + + if (result.num == 0) + PWRN("returning signal with num == 0"); + + Trace::Signal_received trace_event(*context, result.num); + + /* return last received signal */ + return result; + } + + /* + * Normally, we should never arrive at this point because that would + * mean, the '_signal_available' semaphore was increased without + * registering the signal in any context associated to the receiver. + * + * However, if a context gets dissolved right after submitting a + * signal, we may have increased the semaphore already. In this case + * the signal-causing context is absent from the list. + */ + throw Signal_not_pending(); +} + + +void Signal_receiver::block_for_signal() +{ + _signal_available.down(); +} + + Signal Signal_receiver::wait_for_signal() { for (;;) { /* block until the receiver has received a signal */ - _signal_available.down(); + block_for_signal(); - Lock::Guard list_lock_guard(_contexts_lock); - - /* look up the contexts for the pending signal */ - for (List_element *le = _contexts.first(); le; le = le->next()) { - - Signal_context *context = le->object(); - - Lock::Guard lock_guard(context->_lock); - - /* check if context has a pending signal */ - if (!context->_pending) - continue; - - context->_pending = false; - Signal::Data result = context->_curr_signal; - - /* invalidate current signal in context */ - context->_curr_signal = Signal::Data(0, 0); - - if (result.num == 0) - PWRN("returning signal with num == 0"); - - Trace::Signal_received trace_event(*context, result.num); - - /* return last received signal */ - return result; - } - - /* - * Normally, we should never arrive at this point because that would - * mean, the '_signal_available' semaphore was increased without - * registering the signal in any context associated to the receiver. - * - * However, if a context gets dissolved right after submitting a - * signal, we may have increased the semaphore already. In this case - * the signal-causing context is absent from the list. - */ + try { + return pending_signal(); + } catch (Signal_not_pending) { } } - return Signal::Data(0, 0); /* unreachable */ } diff --git a/repos/os/include/os/server.h b/repos/os/include/os/server.h index 68f5fddf5..d412c60ca 100644 --- a/repos/os/include/os/server.h +++ b/repos/os/include/os/server.h @@ -69,12 +69,12 @@ class Server::Entrypoint /** * Associate signal dispatcher with entry point */ - Signal_context_capability manage(Signal_rpc_dispatcher_base &); + Signal_context_capability manage(Signal_dispatcher_base &); /** * Disassociate signal dispatcher from entry point */ - void dissolve(Signal_rpc_dispatcher_base &); + void dissolve(Signal_dispatcher_base &); /** * Return RPC entrypoint diff --git a/repos/os/include/os/signal_rpc_dispatcher.h b/repos/os/include/os/signal_rpc_dispatcher.h index 5dac72563..2aa133b84 100644 --- a/repos/os/include/os/signal_rpc_dispatcher.h +++ b/repos/os/include/os/signal_rpc_dispatcher.h @@ -18,120 +18,13 @@ #include namespace Genode { - - class Signal_rpc_dispatcher_base; - template class Signal_rpc_functor; template class Signal_rpc_member; - - template - Signal_rpc_functor signal_rpc_functor(FUNCTOR &); } - -struct Genode::Signal_rpc_dispatcher_base : Genode::Signal_dispatcher_base -{ - private: - - struct Proxy - { - GENODE_RPC(Rpc_handle_signal, void, handle_signal, unsigned); - GENODE_RPC_INTERFACE(Rpc_handle_signal); - }; - - struct Proxy_component : Genode::Rpc_object - { - Genode::Signal_rpc_dispatcher_base &_dispatcher; - - Proxy_component(Signal_rpc_dispatcher_base &dispatcher) - : _dispatcher(dispatcher) { } - - void handle_signal(unsigned num) - { - _dispatcher.dispatch_at_entrypoint(num); - } - }; - - Proxy_component _proxy; - Capability _proxy_cap; - - protected: - - Signal_rpc_dispatcher_base() : _proxy(*this) { } - - Capability proxy_cap() { return _proxy_cap; } - - public: - - /** - * Associate signal dispatcher with entrypoint - */ - Signal_context_capability manage(Signal_receiver &sig_rec, Rpc_entrypoint &ep) - { - _proxy_cap = ep.manage(&_proxy); - return sig_rec.manage(this); - } - - /** - * Disassociate signal dispatcher from entrypoint - */ - void dissolve(Signal_receiver &sig_rec, Rpc_entrypoint &ep) - { - ep.dissolve(&_proxy); - _proxy_cap = Capability(); - sig_rec.dissolve(this); - } - - public: - - /** - * Interface of Signal_dispatcher_base - */ - void dispatch(unsigned num) { - proxy_cap().call(num); } - - /** - * To be implemented by the derived class - */ - virtual void dispatch_at_entrypoint(unsigned num) = 0; -}; - - -/** - * Signal dispatcher that executes the signal handling code in the context - * of an RPC entrypoint - * - * The 'Signal_rpc_dispatcher' provides an easy way for a server to serialize - * the handling of signals with incoming RPC requests. Incoming signals are - * delegated to the RPC entrypoint via a local RPC call. The signal handling - * code is then executed in the context of the RPC entrypoint. - */ -template -struct Genode::Signal_rpc_functor : Genode::Signal_rpc_dispatcher_base -{ - FUNCTOR &functor; - - /** - * Constructor - * - * \param func functor taking containing the signal-handling code - * - * The functor 'func' has the signature 'void func(unsigned num)' - * whereas 'num' is the number of signals received at once. - */ - Signal_rpc_functor(FUNCTOR &functor) : functor(functor) { } - - /** - * Interface of Signal_rpc_dispatcher_base - */ - void dispatch_at_entrypoint(unsigned num) { functor(num); } -}; - - namespace Server{ class Entrypoint; } - /** * Signal dispatcher for directing signals via RPC to object methods * @@ -146,7 +39,7 @@ namespace Server{ * \param EP type of entrypoint handling signal RPC */ template -struct Genode::Signal_rpc_member : Genode::Signal_rpc_dispatcher_base, +struct Genode::Signal_rpc_member : Genode::Signal_dispatcher_base, Genode::Signal_context_capability { EP &ep; @@ -167,19 +60,9 @@ struct Genode::Signal_rpc_member : Genode::Signal_rpc_dispatcher_base, ~Signal_rpc_member() { ep.dissolve(*this); } /** - * Interface of Signal_rpc_dispatcher_base + * Interface of Signal_dispatcher_base */ - void dispatch_at_entrypoint(unsigned num) { (obj.*member)(num); } + void dispatch(unsigned num) { (obj.*member)(num); } }; - -/** - * Convenience utility for creating 'Signal_rpc_dispatcher' objects - */ -template -Genode::Signal_rpc_functor Genode::signal_rpc_functor(FUNCTOR &func) -{ - return Signal_rpc_functor(func); -} - #endif /* _INCLUDE__OS__SIGNAL_RPC_DISPATCHER_H_ */ diff --git a/repos/os/src/lib/server/server.cc b/repos/os/src/lib/server/server.cc index faa6abed3..1b9061e27 100644 --- a/repos/os/src/lib/server/server.cc +++ b/repos/os/src/lib/server/server.cc @@ -47,55 +47,43 @@ static Genode::Signal_receiver &global_sig_rec() } -static void wait_and_dispatch_one_signal(bool entrypoint) +static void dispatch(Signal &sig) { - /* - * We call the signal dispatcher outside of the scope of 'Signal' - * object because we block the RPC interface in the input handler - * when the kill mode gets actived. While kill mode is active, we - * do not serve incoming RPC requests but we need to stay responsive - * to user input. Hence, we wait for signals in the input dispatcher - * in this case. An already existing 'Signal' object would lock the - * signal receiver and thereby prevent this nested way of signal - * handling. - */ - Signal_rpc_dispatcher_base *dispatcher = 0; - unsigned num = 0; - - { - Signal sig = global_sig_rec().wait_for_signal(); - dispatcher = dynamic_cast(sig.context()); - num = sig.num(); - } + Signal_dispatcher_base *dispatcher = 0; + dispatcher = dynamic_cast(sig.context()); if (!dispatcher) return; - if (entrypoint) - dispatcher->dispatch_at_entrypoint(num); - else - dispatcher->dispatch(num); -} - -Signal_context_capability Entrypoint::manage(Signal_rpc_dispatcher_base &dispatcher) -{ - return dispatcher.manage(global_sig_rec(), global_rpc_ep()); + dispatcher->dispatch(sig.num()); } -void Server::Entrypoint::dissolve(Signal_rpc_dispatcher_base &dispatcher) +/** + * Dispatch a signal at entry point + */ +void Server::wait_and_dispatch_one_signal() { - dispatcher.dissolve(global_sig_rec(), global_rpc_ep()); + Signal sig = global_sig_rec().wait_for_signal(); + dispatch(sig); +} + + +Signal_context_capability Entrypoint::manage(Signal_dispatcher_base &dispatcher) +{ + return global_sig_rec().manage(&dispatcher); +} + + +void Server::Entrypoint::dissolve(Signal_dispatcher_base &dispatcher) +{ + global_sig_rec().dissolve(&dispatcher); } Server::Entrypoint::Entrypoint() : _rpc_ep(global_rpc_ep()) { } -void Server::wait_and_dispatch_one_signal() { - ::wait_and_dispatch_one_signal(true); } - - namespace Server { struct Constructor; struct Constructor_component; @@ -105,7 +93,8 @@ namespace Server { struct Server::Constructor { GENODE_RPC(Rpc_construct, void, construct); - GENODE_RPC_INTERFACE(Rpc_construct); + GENODE_RPC(Rpc_signal, void, signal); + GENODE_RPC_INTERFACE(Rpc_construct, Rpc_signal); }; @@ -113,6 +102,14 @@ struct Server::Constructor_component : Rpc_object { void construct() { Server::construct(global_ep()); } + + void signal() + { + try { + Signal sig = global_sig_rec().pending_signal(); + ::dispatch(sig); + } catch (Signal_receiver::Signal_not_pending) { } + } }; @@ -130,13 +127,15 @@ int main(int argc, char **argv) /* process incoming signals */ for (;;) { + global_sig_rec().block_for_signal(); + /* * It might happen that we try to forward a signal to the entrypoint, * while the context of that signal is already destroyed. In that case * we will get an ipc error exception as result, which has to be caught. */ try { - wait_and_dispatch_one_signal(false); + constructor_cap.call(); } catch(Genode::Ipc_error) { } } }