mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-18 23:28:29 +00:00
hw: fix race in signal dispatching
There was a race when the component entrypoint wanted to do 'wait_and_dispatch_one_signal'. In this function it raises a flag for the signal proxy thread to notice that the entrypoint also wants to block for signals. When the flag is set and the signal proxy wakes up with a new signal, it tried to cancel the blocking of the entrypoint. However, if the entrypoint had not reached the signal blocking at this point, the cancel blocking failed without a solution. Now, the new Kernel::cancel_next_signal_blocking call solves the problem by storing a request to cancel the next signal blocking of a thread immediately without blocking itself. Ref #2284
This commit is contained in:
committed by
Christian Helmuth
parent
2000b7c0e6
commit
56cafb3b57
@ -65,7 +65,11 @@ void Entrypoint::_process_incoming_signals()
|
||||
do {
|
||||
_sig_rec->block_for_signal();
|
||||
|
||||
int success = cmpxchg(&_signal_recipient, NONE, SIGNAL_PROXY);
|
||||
int success;
|
||||
{
|
||||
Lock::Guard guard(_signal_pending_lock);
|
||||
success = cmpxchg(&_signal_recipient, NONE, SIGNAL_PROXY);
|
||||
}
|
||||
|
||||
/* common case, entrypoint is not in 'wait_and_dispatch_one_signal' */
|
||||
if (success) {
|
||||
@ -86,6 +90,11 @@ void Entrypoint::_process_incoming_signals()
|
||||
* block for next signal
|
||||
*/
|
||||
_sig_rec->unblock_signal_waiter(*_rpc_ep);
|
||||
|
||||
/*
|
||||
* wait for the acknowledgment by the entrypoint
|
||||
*/
|
||||
_signal_pending_ack_lock.lock();
|
||||
}
|
||||
} while (!_suspended);
|
||||
|
||||
@ -125,25 +134,26 @@ void Entrypoint::wait_and_dispatch_one_signal()
|
||||
for (;;) {
|
||||
|
||||
try {
|
||||
_signal_pending_lock.lock();
|
||||
|
||||
{
|
||||
cmpxchg(&_signal_recipient, NONE, ENTRYPOINT);
|
||||
cmpxchg(&_signal_recipient, NONE, ENTRYPOINT);
|
||||
Signal sig =_sig_rec->pending_signal();
|
||||
cmpxchg(&_signal_recipient, ENTRYPOINT, NONE);
|
||||
|
||||
Signal sig =_sig_rec->pending_signal();
|
||||
_signal_pending_lock.unlock();
|
||||
|
||||
cmpxchg(&_signal_recipient, ENTRYPOINT, NONE);
|
||||
_signal_pending_ack_lock.unlock();
|
||||
|
||||
_dispatch_signal(sig);
|
||||
}
|
||||
|
||||
_execute_post_signal_hook();
|
||||
|
||||
return;
|
||||
_dispatch_signal(sig);
|
||||
break;
|
||||
|
||||
} catch (Signal_receiver::Signal_not_pending) {
|
||||
_signal_pending_lock.unlock();
|
||||
_sig_rec->block_for_signal();
|
||||
}
|
||||
}
|
||||
|
||||
_execute_post_signal_hook();
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user