mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
parent
07b36573ea
commit
8e80c05be7
@ -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) }; }
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user