mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 06:57:51 +00:00
hw: introduce non-blocking signal checking
* Introduces pending_signal syscall to check for new signals for the calling thread without blocking * Implements pending_signal in the base-library specific for hw to use the new syscall Fix #3217
This commit is contained in:
parent
3e70b53165
commit
330692350e
@ -32,14 +32,15 @@ namespace Kernel
|
|||||||
constexpr Call_arg call_id_kill_signal_context() { return 6; }
|
constexpr Call_arg call_id_kill_signal_context() { return 6; }
|
||||||
constexpr Call_arg call_id_submit_signal() { return 7; }
|
constexpr Call_arg call_id_submit_signal() { return 7; }
|
||||||
constexpr Call_arg call_id_await_signal() { return 8; }
|
constexpr Call_arg call_id_await_signal() { return 8; }
|
||||||
constexpr Call_arg call_id_cancel_next_await_signal() { return 9; }
|
constexpr Call_arg call_id_pending_signal() { return 9; }
|
||||||
constexpr Call_arg call_id_ack_signal() { return 10; }
|
constexpr Call_arg call_id_cancel_next_await_signal() { return 10; }
|
||||||
constexpr Call_arg call_id_print_char() { return 11; }
|
constexpr Call_arg call_id_ack_signal() { return 11; }
|
||||||
constexpr Call_arg call_id_update_data_region() { return 12; }
|
constexpr Call_arg call_id_print_char() { return 12; }
|
||||||
constexpr Call_arg call_id_update_instr_region() { return 13; }
|
constexpr Call_arg call_id_update_data_region() { return 13; }
|
||||||
constexpr Call_arg call_id_ack_cap() { return 14; }
|
constexpr Call_arg call_id_update_instr_region() { return 14; }
|
||||||
constexpr Call_arg call_id_delete_cap() { return 15; }
|
constexpr Call_arg call_id_ack_cap() { return 15; }
|
||||||
constexpr Call_arg call_id_timeout() { return 16; }
|
constexpr Call_arg call_id_delete_cap() { return 16; }
|
||||||
|
constexpr Call_arg call_id_timeout() { return 17; }
|
||||||
constexpr Call_arg call_id_timeout_max_us() { return 18; }
|
constexpr Call_arg call_id_timeout_max_us() { return 18; }
|
||||||
constexpr Call_arg call_id_time() { return 19; }
|
constexpr Call_arg call_id_time() { return 19; }
|
||||||
|
|
||||||
@ -285,6 +286,25 @@ namespace Kernel
|
|||||||
return call(call_id_await_signal(), receiver_id);
|
return call(call_id_await_signal(), receiver_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for any pending signal of a context of a receiver the calling
|
||||||
|
* thread relates to
|
||||||
|
*
|
||||||
|
* \param receiver_id capability id of the targeted signal receiver
|
||||||
|
*
|
||||||
|
* \retval 0 suceeded
|
||||||
|
* \retval -1 failed
|
||||||
|
*
|
||||||
|
* If this call returns 0, an instance of 'Signal::Data' is located at the
|
||||||
|
* base of the callers UTCB.
|
||||||
|
*/
|
||||||
|
inline int pending_signal(capid_t const receiver_id)
|
||||||
|
{
|
||||||
|
return call(call_id_pending_signal(), receiver_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request to cancel the next signal blocking of a local thread
|
* Request to cancel the next signal blocking of a local thread
|
||||||
*
|
*
|
||||||
|
@ -464,6 +464,33 @@ void Thread::_call_await_signal()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::_call_pending_signal()
|
||||||
|
{
|
||||||
|
/* lookup receiver */
|
||||||
|
Signal_receiver * const r = pd().cap_tree().find<Signal_receiver>(user_arg_1());
|
||||||
|
if (!r) {
|
||||||
|
Genode::warning(*this, ": cannot await, unknown signal receiver ",
|
||||||
|
(unsigned)user_arg_1());
|
||||||
|
user_arg_0(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* register handler at the receiver */
|
||||||
|
if (r->add_handler(this)) {
|
||||||
|
user_arg_0(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_state == AWAITS_SIGNAL) {
|
||||||
|
_cancel_blocking();
|
||||||
|
user_arg_0(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
user_arg_0(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::_call_cancel_next_await_signal()
|
void Thread::_call_cancel_next_await_signal()
|
||||||
{
|
{
|
||||||
/* kill the caller if the capability of the target thread is invalid */
|
/* kill the caller if the capability of the target thread is invalid */
|
||||||
@ -631,6 +658,7 @@ void Thread::_call()
|
|||||||
case call_id_kill_signal_context(): _call_kill_signal_context(); return;
|
case call_id_kill_signal_context(): _call_kill_signal_context(); return;
|
||||||
case call_id_submit_signal(): _call_submit_signal(); return;
|
case call_id_submit_signal(): _call_submit_signal(); return;
|
||||||
case call_id_await_signal(): _call_await_signal(); return;
|
case call_id_await_signal(): _call_await_signal(); return;
|
||||||
|
case call_id_pending_signal(): _call_pending_signal(); return;
|
||||||
case call_id_cancel_next_await_signal(): _call_cancel_next_await_signal(); return;
|
case call_id_cancel_next_await_signal(): _call_cancel_next_await_signal(); return;
|
||||||
case call_id_ack_signal(): _call_ack_signal(); return;
|
case call_id_ack_signal(): _call_ack_signal(); return;
|
||||||
case call_id_print_char(): _call_print_char(); return;
|
case call_id_print_char(): _call_print_char(); return;
|
||||||
|
@ -216,6 +216,7 @@ class Kernel::Thread
|
|||||||
void _call_update_instr_region();
|
void _call_update_instr_region();
|
||||||
void _call_print_char();
|
void _call_print_char();
|
||||||
void _call_await_signal();
|
void _call_await_signal();
|
||||||
|
void _call_pending_signal();
|
||||||
void _call_cancel_next_await_signal();
|
void _call_cancel_next_await_signal();
|
||||||
void _call_submit_signal();
|
void _call_submit_signal();
|
||||||
void _call_ack_signal();
|
void _call_ack_signal();
|
||||||
|
@ -129,9 +129,10 @@ void Signal_receiver::block_for_signal()
|
|||||||
/* canceled */
|
/* canceled */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read signal data */
|
/* read signal data */
|
||||||
const void * const utcb = Thread::myself()->utcb()->data();
|
Signal::Data * const data =
|
||||||
Signal::Data * const data = (Signal::Data *)utcb;
|
(Signal::Data *)Thread::myself()->utcb()->data();
|
||||||
Signal_context * const context = data->context;
|
Signal_context * const context = data->context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,11 +146,60 @@ void Signal_receiver::block_for_signal()
|
|||||||
context->_pending = true;
|
context->_pending = true;
|
||||||
context->_curr_signal = Signal::Data(context, num);
|
context->_curr_signal = Signal::Data(context, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end kernel-aided life-time management */
|
/* end kernel-aided life-time management */
|
||||||
Kernel::ack_signal(Capability_space::capid(data->context->_cap));
|
Kernel::ack_signal(Capability_space::capid(data->context->_cap));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Signal Signal_receiver::pending_signal()
|
||||||
|
{
|
||||||
|
Lock::Guard contexts_lock_guard(_contexts_lock);
|
||||||
|
Signal::Data result;
|
||||||
|
_contexts.for_each_locked([&] (Signal_context &context) {
|
||||||
|
|
||||||
|
if (!context._pending) return;
|
||||||
|
|
||||||
|
_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) {
|
||||||
|
Lock::Guard lock_guard(result.context->_lock);
|
||||||
|
if (result.num == 0)
|
||||||
|
warning("returning signal with num == 0");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look for pending signals */
|
||||||
|
if (Kernel::pending_signal(Capability_space::capid(_cap)) != 0) {
|
||||||
|
throw Signal_not_pending();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read signal data */
|
||||||
|
Signal::Data * const data =
|
||||||
|
(Signal::Data *)Thread::myself()->utcb()->data();
|
||||||
|
Signal_context * const context = data->context;
|
||||||
|
|
||||||
|
{
|
||||||
|
/* update signal context */
|
||||||
|
Lock::Guard lock_guard(context->_lock);
|
||||||
|
context->_pending = false;
|
||||||
|
context->_curr_signal = Signal::Data(context, data->num);
|
||||||
|
result = context->_curr_signal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end kernel-aided life-time management */
|
||||||
|
Kernel::ack_signal(Capability_space::capid(data->context->_cap));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::unblock_signal_waiter(Rpc_entrypoint &rpc_ep)
|
void Signal_receiver::unblock_signal_waiter(Rpc_entrypoint &rpc_ep)
|
||||||
{
|
{
|
||||||
Kernel::cancel_next_await_signal(native_thread_id(&rpc_ep));
|
Kernel::cancel_next_await_signal(native_thread_id(&rpc_ep));
|
||||||
|
@ -49,4 +49,7 @@ void Signal_receiver::block_for_signal()
|
|||||||
sleep_forever();
|
sleep_forever();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Signal Signal_receiver::pending_signal() {
|
||||||
|
throw Signal_not_pending(); }
|
||||||
|
|
||||||
void Signal_receiver::local_submit(Signal::Data) { ASSERT_NEVER_CALLED; }
|
void Signal_receiver::local_submit(Signal::Data) { ASSERT_NEVER_CALLED; }
|
||||||
|
@ -235,6 +235,42 @@ void Signal_receiver::block_for_signal()
|
|||||||
_signal_available.down();
|
_signal_available.down();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Signal Signal_receiver::pending_signal()
|
||||||
|
{
|
||||||
|
Lock::Guard contexts_lock_guard(_contexts_lock);
|
||||||
|
Signal::Data result;
|
||||||
|
_contexts.for_each_locked([&] (Signal_context &context) {
|
||||||
|
|
||||||
|
if (!context._pending) return;
|
||||||
|
|
||||||
|
_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) {
|
||||||
|
Lock::Guard lock_guard(result.context->_lock);
|
||||||
|
if (result.num == 0)
|
||||||
|
warning("returning signal with num == 0");
|
||||||
|
|
||||||
|
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::unblock_signal_waiter(Rpc_entrypoint &)
|
void Signal_receiver::unblock_signal_waiter(Rpc_entrypoint &)
|
||||||
{
|
{
|
||||||
|
@ -159,43 +159,6 @@ Signal Signal_receiver::wait_for_signal()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Signal Signal_receiver::pending_signal()
|
|
||||||
{
|
|
||||||
Lock::Guard contexts_lock_guard(_contexts_lock);
|
|
||||||
Signal::Data result;
|
|
||||||
_contexts.for_each_locked([&] (Signal_context &context) {
|
|
||||||
|
|
||||||
if (!context._pending) return;
|
|
||||||
|
|
||||||
_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) {
|
|
||||||
Lock::Guard lock_guard(result.context->_lock);
|
|
||||||
if (result.num == 0)
|
|
||||||
warning("returning signal with num == 0");
|
|
||||||
|
|
||||||
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()
|
Signal_receiver::~Signal_receiver()
|
||||||
{
|
{
|
||||||
Lock::Guard contexts_lock_guard(_contexts_lock);
|
Lock::Guard contexts_lock_guard(_contexts_lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user