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:
Martin Stein
2017-02-24 14:29:29 +01:00
committed by Christian Helmuth
parent 2000b7c0e6
commit 56cafb3b57
7 changed files with 123 additions and 49 deletions

View File

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