parent
07b36573ea
commit
8e80c05be7
|
@ -99,7 +99,7 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
||||||
/* use signal context as imprint */
|
/* use signal context as imprint */
|
||||||
c->_cap = pd().alloc_context(_cap, (unsigned long)c);
|
c->_cap = pd().alloc_context(_cap, (unsigned long)c);
|
||||||
c->_receiver = this;
|
c->_receiver = this;
|
||||||
_contexts.insert(c);
|
_contexts.insert_as_tail(c);
|
||||||
return c->_cap;
|
return c->_cap;
|
||||||
}
|
}
|
||||||
catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; }
|
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
|
* 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
|
* Abstract interface to be implemented by signal dispatchers
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -221,10 +221,10 @@ Signal_context_capability Signal_receiver::manage(Signal_context *context)
|
||||||
|
|
||||||
context->_receiver = this;
|
context->_receiver = this;
|
||||||
|
|
||||||
Lock::Guard list_lock_guard(_contexts_lock);
|
Lock::Guard contexts_lock_guard(_contexts_lock);
|
||||||
|
|
||||||
/* insert context into context list */
|
/* insert context into context list */
|
||||||
_contexts.insert(context);
|
_contexts.insert_as_tail(context);
|
||||||
|
|
||||||
/* register context at process-wide registry */
|
/* register context at process-wide registry */
|
||||||
signal_context_registry()->insert(&context->_registry_le);
|
signal_context_registry()->insert(&context->_registry_le);
|
||||||
|
|
|
@ -160,30 +160,24 @@ Signal Signal_receiver::wait_for_signal()
|
||||||
|
|
||||||
Signal Signal_receiver::pending_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 */
|
if (!context._pending) return;
|
||||||
for (Signal_context *context = _contexts.head(); context; context = context->_next) {
|
|
||||||
|
|
||||||
Lock::Guard lock_guard(context->_lock);
|
_contexts.head(context._next);
|
||||||
|
context._pending = false;
|
||||||
/* check if context has a pending signal */
|
result = context._curr_signal;
|
||||||
if (!context->_pending)
|
context._curr_signal = Signal::Data(0, 0);
|
||||||
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);
|
|
||||||
|
|
||||||
|
Trace::Signal_received trace_event(context, result.num);
|
||||||
|
throw Context_ring::Break_for_each();
|
||||||
|
});
|
||||||
|
if (result.context) {
|
||||||
if (result.num == 0)
|
if (result.num == 0)
|
||||||
warning("returning signal with num == 0");
|
warning("returning signal with num == 0");
|
||||||
|
|
||||||
Trace::Signal_received trace_event(*context, result.num);
|
|
||||||
|
|
||||||
/* return last received signal */
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +196,7 @@ Signal Signal_receiver::pending_signal()
|
||||||
|
|
||||||
Signal_receiver::~Signal_receiver()
|
Signal_receiver::~Signal_receiver()
|
||||||
{
|
{
|
||||||
Lock::Guard list_lock_guard(_contexts_lock);
|
Lock::Guard contexts_lock_guard(_contexts_lock);
|
||||||
|
|
||||||
/* disassociate contexts from the receiver */
|
/* disassociate contexts from the receiver */
|
||||||
while (_contexts.head())
|
while (_contexts.head())
|
||||||
|
@ -235,7 +229,7 @@ void Signal_receiver::dissolve(Signal_context *context)
|
||||||
if (context->_receiver != this)
|
if (context->_receiver != this)
|
||||||
throw Context_not_associated();
|
throw Context_not_associated();
|
||||||
|
|
||||||
Lock::Guard list_lock_guard(_contexts_lock);
|
Lock::Guard contexts_lock_guard(_contexts_lock);
|
||||||
|
|
||||||
_unsynchronized_dissolve(context);
|
_unsynchronized_dissolve(context);
|
||||||
|
|
||||||
|
@ -243,59 +237,38 @@ void Signal_receiver::dissolve(Signal_context *context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Signal_receiver::pending()
|
bool Signal_receiver::pending()
|
||||||
{
|
{
|
||||||
Lock::Guard list_lock_guard(_contexts_lock);
|
Lock::Guard contexts_lock_guard(_contexts_lock);
|
||||||
|
bool result = false;
|
||||||
/* look up the contexts for the pending signal */
|
_contexts.for_each_locked([&] (Signal_context &context) {
|
||||||
for (Signal_context *context = _contexts.head(); context; context = context->_next) {
|
if (context._pending) {
|
||||||
|
result = true;
|
||||||
Lock::Guard lock_guard(context->_lock);
|
throw Context_ring::Break_for_each();
|
||||||
|
}
|
||||||
if (context->_pending)
|
});
|
||||||
return true;
|
return result;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::Context_list::insert(Signal_context *re)
|
void Signal_receiver::Context_ring::insert_as_tail(Signal_context *re)
|
||||||
{
|
{
|
||||||
if (_head) {
|
if (_head) {
|
||||||
re->_prev = _head->_prev;
|
re->_prev = _head->_prev;
|
||||||
re->_next = nullptr;
|
re->_next = _head;
|
||||||
_head->_prev->_next = re;
|
_head->_prev = _head->_prev->_next = re;
|
||||||
_head->_prev = re;
|
|
||||||
} else {
|
} else {
|
||||||
re->_prev = re;
|
_head = re->_prev = re->_next = re;
|
||||||
re->_next = nullptr;
|
|
||||||
_head = 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) {
|
if (re->_next != re) {
|
||||||
_head = nullptr;
|
if (re == _head) { _head = re->_next; }
|
||||||
} else {
|
|
||||||
if (_head == re) {
|
|
||||||
_head = re->_next;
|
|
||||||
}
|
|
||||||
re->_prev->_next = re->_next;
|
re->_prev->_next = re->_next;
|
||||||
if (re->_next) {
|
re->_next->_prev = re->_prev;
|
||||||
re->_next->_prev = re->_prev;
|
|
||||||
} else {
|
|
||||||
_head->_prev = re->_prev;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else { _head = nullptr; }
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::Context_list::head(Signal_context *re)
|
|
||||||
{
|
|
||||||
_head->_prev->_next = _head;
|
|
||||||
_head = re;
|
|
||||||
_head->_prev->_next = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user