mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
base: entrypoint 'wait_and_dispatch_one_signal'
There existed a race when 'wait_and_dispatch_one_signal' is called form a RPC context, because the 'signal_proxy' or 'main' will block and the signal semaphore, when the EP then calls 'wait_and_dispatch_one_signal', the signal proxy is woken up ands sends an RPC to the EP, leading to a dead lock if no further signal arrive, because the EP will then remain blocked in the signal semaphore. Therefore, for this case, the signal proxy will now perform a semaphore up operation and does not perform an RPC if the EP is within 'wait_and_dispatch_one_signal'.
This commit is contained in:
parent
652f92c9c9
commit
b66716d278
@ -114,7 +114,7 @@ void Signal_receiver::block_for_signal()
|
|||||||
{
|
{
|
||||||
/* wait for a signal */
|
/* wait for a signal */
|
||||||
if (Kernel::await_signal(Capability_space::capid(_cap))) {
|
if (Kernel::await_signal(Capability_space::capid(_cap))) {
|
||||||
Genode::error("failed to receive signal");
|
/* canceled */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* read signal data */
|
/* read signal data */
|
||||||
@ -133,4 +133,11 @@ void Signal_receiver::block_for_signal()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_receiver::unblock_signal_waiter(Rpc_entrypoint &rpc_ep)
|
||||||
|
{
|
||||||
|
/* force ep out of 'await_signal' in 'block_for_signal' */
|
||||||
|
rpc_ep.cancel_blocking();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::local_submit(Signal::Data) { Genode::error("not implemented"); }
|
void Signal_receiver::local_submit(Signal::Data) { Genode::error("not implemented"); }
|
||||||
|
@ -89,6 +89,11 @@ class Genode::Entrypoint : Genode::Noncopyable
|
|||||||
void (*_suspended_callback) () = nullptr;
|
void (*_suspended_callback) () = nullptr;
|
||||||
void (*_resumed_callback) () = nullptr;
|
void (*_resumed_callback) () = nullptr;
|
||||||
|
|
||||||
|
enum Signal_recipient {
|
||||||
|
NONE = 0, ENTRYPOINT = 1, SIGNAL_PROXY = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
int _signal_recipient { NONE };
|
||||||
Post_signal_hook *_post_signal_hook = nullptr;
|
Post_signal_hook *_post_signal_hook = nullptr;
|
||||||
|
|
||||||
void _execute_post_signal_hook()
|
void _execute_post_signal_hook()
|
||||||
@ -164,14 +169,7 @@ class Genode::Entrypoint : Genode::Noncopyable
|
|||||||
* receiver belongs to the calling entrypoint. Alternatively,
|
* receiver belongs to the calling entrypoint. Alternatively,
|
||||||
* remove it.
|
* remove it.
|
||||||
*/
|
*/
|
||||||
void wait_and_dispatch_one_signal()
|
void wait_and_dispatch_one_signal();
|
||||||
{
|
|
||||||
{
|
|
||||||
Signal sig = _sig_rec->wait_for_signal();
|
|
||||||
_dispatch_signal(sig);
|
|
||||||
}
|
|
||||||
_execute_post_signal_hook();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return RPC entrypoint
|
* Return RPC entrypoint
|
||||||
|
@ -28,6 +28,7 @@ namespace Kernel { struct Signal_receiver; }
|
|||||||
namespace Genode {
|
namespace Genode {
|
||||||
|
|
||||||
class Entrypoint;
|
class Entrypoint;
|
||||||
|
class Rpc_entrypoint;
|
||||||
class Signal_source;
|
class Signal_source;
|
||||||
|
|
||||||
class Signal_receiver;
|
class Signal_receiver;
|
||||||
@ -264,6 +265,11 @@ class Genode::Signal_receiver : Noncopyable
|
|||||||
*/
|
*/
|
||||||
void block_for_signal();
|
void block_for_signal();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unblock signal waiter
|
||||||
|
*/
|
||||||
|
void unblock_signal_waiter(Rpc_entrypoint &rpc_ep);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve pending signal
|
* Retrieve pending signal
|
||||||
*
|
*
|
||||||
|
@ -49,6 +49,7 @@ _Z22__ldso_raise_exceptionv T
|
|||||||
_ZN6Genode10Entrypoint16_dispatch_signalERNS_6SignalE T
|
_ZN6Genode10Entrypoint16_dispatch_signalERNS_6SignalE T
|
||||||
_ZN6Genode10Entrypoint16schedule_suspendEPFvvES2_ T
|
_ZN6Genode10Entrypoint16schedule_suspendEPFvvES2_ T
|
||||||
_ZN6Genode10Entrypoint25_process_incoming_signalsEv T
|
_ZN6Genode10Entrypoint25_process_incoming_signalsEv T
|
||||||
|
_ZN6Genode10Entrypoint28wait_and_dispatch_one_signalEv T
|
||||||
_ZN6Genode10Entrypoint6manageERNS_22Signal_dispatcher_baseE T
|
_ZN6Genode10Entrypoint6manageERNS_22Signal_dispatcher_baseE T
|
||||||
_ZN6Genode10Entrypoint8dissolveERNS_22Signal_dispatcher_baseE T
|
_ZN6Genode10Entrypoint8dissolveERNS_22Signal_dispatcher_baseE T
|
||||||
_ZN6Genode10EntrypointC1ERNS_3EnvE T
|
_ZN6Genode10EntrypointC1ERNS_3EnvE T
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#include <base/entrypoint.h>
|
#include <base/entrypoint.h>
|
||||||
#include <base/component.h>
|
#include <base/component.h>
|
||||||
|
|
||||||
|
#include <cpu/atomic.h>
|
||||||
|
|
||||||
#define INCLUDED_BY_ENTRYPOINT_CC /* prevent "deprecated" warning */
|
#define INCLUDED_BY_ENTRYPOINT_CC /* prevent "deprecated" warning */
|
||||||
#include <cap_session/connection.h>
|
#include <cap_session/connection.h>
|
||||||
#undef INCLUDED_BY_ENTRYPOINT_CC
|
#undef INCLUDED_BY_ENTRYPOINT_CC
|
||||||
@ -63,17 +65,28 @@ void Entrypoint::_process_incoming_signals()
|
|||||||
do {
|
do {
|
||||||
_sig_rec->block_for_signal();
|
_sig_rec->block_for_signal();
|
||||||
|
|
||||||
/*
|
int success = cmpxchg(&_signal_recipient, NONE, SIGNAL_PROXY);
|
||||||
* It might happen that we try to forward a signal to the
|
|
||||||
* entrypoint, while the context of that signal is already
|
|
||||||
* destroyed. In that case we will get an ipc error exception
|
|
||||||
* as result, which has to be caught.
|
|
||||||
*/
|
|
||||||
retry<Genode::Blocking_canceled>(
|
|
||||||
[&] () { _signal_proxy_cap.call<Signal_proxy::Rpc_signal>(); },
|
|
||||||
[] () { warning("blocking canceled during signal processing"); }
|
|
||||||
);
|
|
||||||
|
|
||||||
|
/* common case, entrypoint is not in 'wait_and_dispatch_one_signal' */
|
||||||
|
if (success) {
|
||||||
|
/*
|
||||||
|
* It might happen that we try to forward a signal to the
|
||||||
|
* entrypoint, while the context of that signal is already
|
||||||
|
* destroyed. In that case we will get an ipc error exception
|
||||||
|
* as result, which has to be caught.
|
||||||
|
*/
|
||||||
|
retry<Blocking_canceled>(
|
||||||
|
[&] () { _signal_proxy_cap.call<Signal_proxy::Rpc_signal>(); },
|
||||||
|
[] () { warning("blocking canceled during signal processing"); });
|
||||||
|
|
||||||
|
cmpxchg(&_signal_recipient, SIGNAL_PROXY, NONE);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Entrypoint is in 'wait_and_dispatch_one_signal', wakup it up and
|
||||||
|
* block for next signal
|
||||||
|
*/
|
||||||
|
_sig_rec->unblock_signal_waiter(*_rpc_ep);
|
||||||
|
}
|
||||||
} while (!_suspended);
|
} while (!_suspended);
|
||||||
|
|
||||||
_suspend_dispatcher.destruct();
|
_suspend_dispatcher.destruct();
|
||||||
@ -107,6 +120,33 @@ void Entrypoint::_process_incoming_signals()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Entrypoint::wait_and_dispatch_one_signal()
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
{
|
||||||
|
cmpxchg(&_signal_recipient, NONE, ENTRYPOINT);
|
||||||
|
|
||||||
|
Signal sig =_sig_rec->pending_signal();
|
||||||
|
|
||||||
|
cmpxchg(&_signal_recipient, ENTRYPOINT, NONE);
|
||||||
|
|
||||||
|
_dispatch_signal(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
_execute_post_signal_hook();
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (Signal_receiver::Signal_not_pending) {
|
||||||
|
_sig_rec->block_for_signal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Entrypoint::schedule_suspend(void (*suspended)(), void (*resumed)())
|
void Entrypoint::schedule_suspend(void (*suspended)(), void (*resumed)())
|
||||||
{
|
{
|
||||||
_suspended_callback = suspended;
|
_suspended_callback = suspended;
|
||||||
@ -119,7 +159,7 @@ void Entrypoint::schedule_suspend(void (*suspended)(), void (*resumed)())
|
|||||||
_suspend_dispatcher.construct(*this, *this, &Entrypoint::_handle_suspend);
|
_suspend_dispatcher.construct(*this, *this, &Entrypoint::_handle_suspend);
|
||||||
|
|
||||||
/* trigger wakeup of the signal-dispatch loop for suspend */
|
/* trigger wakeup of the signal-dispatch loop for suspend */
|
||||||
Genode::Signal_transmitter(*_suspend_dispatcher).submit();
|
Signal_transmitter(*_suspend_dispatcher).submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -186,7 +226,7 @@ Entrypoint::Entrypoint(Env &env)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
constructor_cap.call<Constructor::Rpc_construct>();
|
constructor_cap.call<Constructor::Rpc_construct>();
|
||||||
} catch (Genode::Blocking_canceled) {
|
} catch (Blocking_canceled) {
|
||||||
warning("blocking canceled in entrypoint constructor");
|
warning("blocking canceled in entrypoint constructor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +255,12 @@ void Signal_receiver::block_for_signal()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Signal_receiver::unblock_signal_waiter(Rpc_entrypoint &)
|
||||||
|
{
|
||||||
|
_signal_available.up();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Signal_receiver::local_submit(Signal::Data ns)
|
void Signal_receiver::local_submit(Signal::Data ns)
|
||||||
{
|
{
|
||||||
Signal_context *context = ns.context;
|
Signal_context *context = ns.context;
|
||||||
|
Loading…
Reference in New Issue
Block a user