signal: organize signal contexts as ring list

Ref #2532
This commit is contained in:
Martin Stein 2017-11-07 14:04:46 +01:00 committed by Christian Helmuth
parent 07b36573ea
commit 8e80c05be7
4 changed files with 206 additions and 216 deletions

View File

@ -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) }; }

View File

@ -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<Signal_source> _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 <typename FUNC>
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<Signal_source> _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
*/

View File

@ -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);

View File

@ -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; }
}