diff --git a/repos/base-hw/include/kernel/interface.h b/repos/base-hw/include/kernel/interface.h index 71c9ebbc2..b74f5a08d 100644 --- a/repos/base-hw/include/kernel/interface.h +++ b/repos/base-hw/include/kernel/interface.h @@ -37,12 +37,11 @@ namespace Kernel constexpr Call_arg call_id_kill_signal_context() { return 6; } constexpr Call_arg call_id_submit_signal() { return 7; } constexpr Call_arg call_id_await_signal() { return 8; } - constexpr Call_arg call_id_signal_pending() { return 9; } - constexpr Call_arg call_id_ack_signal() { return 10; } - constexpr Call_arg call_id_print_char() { return 11; } - constexpr Call_arg call_id_update_data_region() { return 12; } - constexpr Call_arg call_id_update_instr_region() { return 13; } - constexpr Call_arg call_id_delete_cap() { return 14; } + constexpr Call_arg call_id_ack_signal() { return 9; } + constexpr Call_arg call_id_print_char() { return 10; } + constexpr Call_arg call_id_update_data_region() { return 11; } + constexpr Call_arg call_id_update_instr_region() { return 12; } + constexpr Call_arg call_id_delete_cap() { return 13; } /***************************************************************** @@ -228,20 +227,6 @@ namespace Kernel } - /** - * Return wether any context of a receiver is pending - * - * \param receiver capability id of the targeted signal receiver - * - * \retval 0 none of the contexts is pending or the receiver doesn't exist - * \retval 1 a context of the signal receiver is pending - */ - inline bool signal_pending(capid_t const receiver) - { - return call(call_id_signal_pending(), receiver); - } - - /** * Trigger a specific signal context * diff --git a/repos/base-hw/src/base/signal/signal.cc b/repos/base-hw/src/base/signal/signal.cc index 848e2ecef..7dcc2bd29 100644 --- a/repos/base-hw/src/base/signal/signal.cc +++ b/repos/base-hw/src/base/signal/signal.cc @@ -21,67 +21,16 @@ using namespace Genode; - -/** - * Provide one signal connection per program - */ -static Signal_connection * signal_connection() -{ - static Signal_connection _object; - return &_object; -} - - -/************ - ** Signal ** - ************/ - -void Signal::_dec_ref_and_unlock() -{ - if (_data.context) { - Lock::Guard lock_guard(_data.context->_lock); - _data.context->_ref_cnt--; - - /* acknowledge as soon as receipt is fully processed */ - if (_data.context->_ref_cnt == 0) { - Kernel::ack_signal(_data.context->_cap.dst()); - } - } -} - - -void Signal::_inc_ref() -{ - if (_data.context) { - Lock::Guard lock_guard(_data.context->_lock); - _data.context->_ref_cnt++; - } -} - - -Signal::Signal(Signal::Data data) : _data(data) -{ - if (_data.context) { _data.context->_ref_cnt = 1; } -} - - /******************** ** Signal context ** ********************/ -void Signal_context::submit(unsigned num) -{ - Kernel::submit_signal(_cap.dst(), num); -} - +void Signal_context::submit(unsigned) { PERR("not implemented"); } /************************ ** Signal transmitter ** ************************/ -Signal_connection * Signal_transmitter::connection() { return signal_connection(); } - - void Signal_transmitter::submit(unsigned cnt) { { @@ -127,22 +76,13 @@ void Signal_receiver::_platform_destructor() } -void Signal_receiver::_unsynchronized_dissolve(Signal_context * const c) +void Signal_receiver::_platform_begin_dissolve(Signal_context * const c) { - /* wait untill all context references disappear and put context to sleep */ Kernel::kill_signal_context(c->_cap.dst()); - - /* release server resources of context */ - signal_connection()->free_context(c->_cap); - - /* reset the context */ - c->_receiver = 0; - c->_cap = Signal_context_capability(); - - /* forget the context */ - _contexts.remove(&c->_receiver_le); } +void Signal_receiver::_platform_finish_dissolve(Signal_context *) { } + Signal_context_capability Signal_receiver::manage(Signal_context * const c) { @@ -175,76 +115,27 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c) } -void Signal_receiver::dissolve(Signal_context * const context) -{ - if (context->_receiver != this) { throw Context_not_associated(); } - Lock::Guard list_lock_guard(_contexts_lock); - _unsynchronized_dissolve(context); - - /* - * We assume that dissolve is always called before the context destructor. - * On other platforms a 'context->_destroy_lock' is locked and unlocked at - * this point to block until all remaining signals of this context get - * destructed and prevent the context from beeing destructed to early. - * However on this platform we don't have to wait because - * 'kill_signal_context' in '_unsynchronized_dissolve' already does it. - */ -} - - -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 */ + /* wait for 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 */ - if (Kernel::await_signal(_cap.dst())) { - PERR("failed to receive signal"); - return Signal(Signal::Data()); + /* read signal data */ + const void * const utcb = Thread_base::myself()->utcb()->base(); + Signal::Data * const data = (Signal::Data *)utcb; + Signal_context * const context = data->context; + { + /* update signal context */ + Lock::Guard lock_guard(context->_lock); + unsigned const num = context->_curr_signal.num + data->num; + context->_pending = true; + context->_curr_signal = Signal::Data(context, num); } - - /* get signal data */ - Signal s(*(Signal::Data *)Thread_base::myself()->utcb()->base()); - return s; + /* end kernel-aided life-time management */ + Kernel::ack_signal(data->context->_cap.dst()); } -void Signal_receiver::local_submit(Signal::Data signal) -{ - PERR("not implemented"); -} +void Signal_receiver::local_submit(Signal::Data) { PERR("not implemented"); } diff --git a/repos/base-hw/src/core/include/kernel/signal_receiver.h b/repos/base-hw/src/core/include/kernel/signal_receiver.h index 57f490caf..45e2576f8 100644 --- a/repos/base-hw/src/core/include/kernel/signal_receiver.h +++ b/repos/base-hw/src/core/include/kernel/signal_receiver.h @@ -339,11 +339,6 @@ class Kernel::Signal_receiver : public Kernel::Object */ int add_handler(Signal_handler * const h); - /** - * Return wether any of the contexts of this receiver is deliverable - */ - bool deliverable(); - /** * Syscall to create a signal receiver * diff --git a/repos/base-hw/src/core/include/kernel/thread.h b/repos/base-hw/src/core/include/kernel/thread.h index 66a51d168..5c180a93f 100644 --- a/repos/base-hw/src/core/include/kernel/thread.h +++ b/repos/base-hw/src/core/include/kernel/thread.h @@ -232,7 +232,6 @@ class Kernel::Thread void _call_update_instr_region(); void _call_print_char(); void _call_await_signal(); - void _call_signal_pending(); void _call_submit_signal(); void _call_ack_signal(); void _call_kill_signal_context(); diff --git a/repos/base-hw/src/core/kernel/signal_receiver.cc b/repos/base-hw/src/core/kernel/signal_receiver.cc index 37059c110..21cb2b0ca 100644 --- a/repos/base-hw/src/core/kernel/signal_receiver.cc +++ b/repos/base-hw/src/core/kernel/signal_receiver.cc @@ -223,9 +223,6 @@ int Signal_receiver::add_handler(Signal_handler * const h) } -bool Signal_receiver::deliverable() { return !_deliver.empty(); } - - Signal_receiver::~Signal_receiver() { /* destruct all attached contexts */ diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index 3bbc51037..fa328e5a5 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -483,21 +483,6 @@ void Thread::_call_await_signal() } -void Thread::_call_signal_pending() -{ - /* lookup signal receiver */ - Signal_receiver * const r = pd()->cap_tree().find(user_arg_1()); - if (!r) { - PWRN("%s -> %s: no pending, unknown signal receiver", - pd_label(), label()); - user_arg_0(0); - return; - } - /* get pending state */ - user_arg_0(r->deliverable()); -} - - void Thread::_call_submit_signal() { /* lookup signal context */ @@ -625,7 +610,6 @@ void Thread::_call() case call_id_kill_signal_context(): _call_kill_signal_context(); return; case call_id_submit_signal(): _call_submit_signal(); return; case call_id_await_signal(): _call_await_signal(); return; - case call_id_signal_pending(): _call_signal_pending(); return; case call_id_ack_signal(): _call_ack_signal(); return; case call_id_print_char(): _call_print_char(); return; case call_id_delete_cap(): _call_delete_cap(); return; diff --git a/repos/base/include/base/signal.h b/repos/base/include/base/signal.h index fc54496d4..9f44d9211 100644 --- a/repos/base/include/base/signal.h +++ b/repos/base/include/base/signal.h @@ -36,6 +36,7 @@ namespace Genode { class Signal_dispatcher_base; class Signal_connection; template class Signal_dispatcher; + Signal_connection * signal_connection(); } @@ -200,6 +201,12 @@ class Genode::Signal_receiver : Noncopyable */ 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: /** diff --git a/repos/base/src/base/signal/common.cc b/repos/base/src/base/signal/common.cc index 7de4ebe65..446cc1910 100644 --- a/repos/base/src/base/signal/common.cc +++ b/repos/base/src/base/signal/common.cc @@ -15,9 +15,19 @@ /* Genode includes */ #include +#include using namespace Genode; +/** + * Return process-wide signal session + */ +Signal_connection * Genode::signal_connection() +{ + static Signal_connection sc; + return ≻ +} + /************ ** Signal ** @@ -52,6 +62,35 @@ Signal & Signal::operator=(Signal const &other) Signal::~Signal() { _dec_ref_and_unlock(); } +void Signal::_dec_ref_and_unlock() +{ + if (_data.context) { + Lock::Guard lock_guard(_data.context->_lock); + _data.context->_ref_cnt--; + if (_data.context->_ref_cnt == 0) + _data.context->_destroy_lock.unlock(); + } +} + + +void Signal::_inc_ref() +{ + if (_data.context) { + Lock::Guard lock_guard(_data.context->_lock); + _data.context->_ref_cnt++; + } +} + + +Signal::Signal(Signal::Data data) : _data(data) +{ + if (_data.context) { + _data.context->_ref_cnt = 1; + _data.context->_destroy_lock.lock(); + } +} + + /******************** ** Signal_context ** ********************/ @@ -71,6 +110,9 @@ Signal_context::~Signal_context() ** Signal_transmitter ** ************************/ +Signal_connection * Signal_transmitter::connection() { return signal_connection(); } + + Signal_transmitter::Signal_transmitter(Signal_context_capability context) : _context(context) { } @@ -85,6 +127,63 @@ Signal_context_capability Signal_transmitter::context() { return _context; } ** Signal_receiver ** *********************/ +Signal Signal_receiver::wait_for_signal() +{ + for (;;) { + + /* block until the receiver has received a signal */ + block_for_signal(); + + try { + return pending_signal(); + } catch (Signal_not_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(); +} + + Signal_receiver::~Signal_receiver() { Lock::Guard list_lock_guard(_contexts_lock); @@ -95,3 +194,53 @@ Signal_receiver::~Signal_receiver() _platform_destructor(); } + + +void Signal_receiver::_unsynchronized_dissolve(Signal_context * const context) +{ + _platform_begin_dissolve(context); + + /* tell core to stop sending signals referring to the context */ + signal_connection()->free_context(context->_cap); + + /* restore default initialization of signal context */ + context->_receiver = 0; + context->_cap = Signal_context_capability(); + + /* remove context from context list */ + _contexts.remove(&context->_receiver_le); + + _platform_finish_dissolve(context); +} + + +void Signal_receiver::dissolve(Signal_context *context) +{ + if (context->_receiver != this) + throw Context_not_associated(); + + Lock::Guard list_lock_guard(_contexts_lock); + + _unsynchronized_dissolve(context); + + Lock::Guard context_destroy_lock_guard(context->_destroy_lock); +} + + + +bool Signal_receiver::pending() +{ + 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); + + if (context->_pending) + return true; + } + return false; +} diff --git a/repos/base/src/base/signal/signal.cc b/repos/base/src/base/signal/signal.cc index c2c1f0bf1..b29c947c7 100644 --- a/repos/base/src/base/signal/signal.cc +++ b/repos/base/src/base/signal/signal.cc @@ -18,21 +18,6 @@ using namespace Genode; - -/** - * Return process-wide signal session used for signal allocation and submission - */ -static Signal_connection *signal_connection() -{ - static Signal_connection sc; - return ≻ -} - - -/****************************************************** - ** Process-wide connection to core's signal service ** - ******************************************************/ - enum { STACK_SIZE = 4*1024*sizeof(addr_t) }; class Signal_handler_thread : Thread, Lock @@ -166,39 +151,6 @@ Genode::Signal_context_registry *signal_context_registry() } -/************ - ** Signal ** - ************/ - -void Signal::_dec_ref_and_unlock() -{ - if (_data.context) { - Lock::Guard lock_guard(_data.context->_lock); - _data.context->_ref_cnt--; - if (_data.context->_ref_cnt == 0) - _data.context->_destroy_lock.unlock(); - } -} - - -void Signal::_inc_ref() -{ - if (_data.context) { - Lock::Guard lock_guard(_data.context->_lock); - _data.context->_ref_cnt++; - } -} - - -Signal::Signal(Signal::Data data) : _data(data) -{ - if (_data.context) { - _data.context->_ref_cnt = 1; - _data.context->_destroy_lock.lock(); - } -} - - /******************** ** Signal context ** ********************/ @@ -224,33 +176,10 @@ void Signal_context::submit(unsigned num) } -/************************ - ** Signal transmitter ** - ************************/ - -Signal_connection * Signal_transmitter::connection() { return signal_connection(); } - - /********************* ** Signal receiver ** *********************/ -void Signal_receiver::_unsynchronized_dissolve(Signal_context *context) -{ - /* tell core to stop sending signals referring to the context */ - signal_connection()->free_context(context->_cap); - - /* restore default initialization of signal context */ - context->_receiver = 0; - context->_cap = Signal_context_capability(); - - /* remove context from context list */ - _contexts.remove(&context->_receiver_le); - - /* unregister context from process-wide registry */ - signal_context_registry()->remove(&context->_registry_le); -} - Signal_receiver::Signal_receiver() { @@ -301,100 +230,12 @@ Signal_context_capability Signal_receiver::manage(Signal_context *context) } -void Signal_receiver::dissolve(Signal_context *context) -{ - if (context->_receiver != this) - throw Context_not_associated(); - - Lock::Guard list_lock_guard(_contexts_lock); - - _unsynchronized_dissolve(context); - - Lock::Guard context_destroy_lock_guard(context->_destroy_lock); -} - - -bool Signal_receiver::pending() -{ - 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); - - if (context->_pending) - return true; - } - return false; -} - - -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 */ - block_for_signal(); - - try { - return pending_signal(); - } catch (Signal_not_pending) { } - } -} - - void Signal_receiver::local_submit(Signal::Data ns) { Signal_context *context = ns.context; @@ -437,5 +278,9 @@ void Signal_receiver::dispatch_signals(Signal_source *signal_source) } } +void Signal_receiver::_platform_begin_dissolve(Signal_context *) { } + +void Signal_receiver::_platform_finish_dissolve(Signal_context * const c) { + signal_context_registry()->remove(&c->_registry_le); } void Signal_receiver::_platform_destructor() { }