mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 22:47:50 +00:00
os: add 'wait_and_dispatch_one_signal' test
This commit is contained in:
parent
06e605defa
commit
2d199982eb
@ -433,6 +433,99 @@ struct Many_contexts_test : Signal_test
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test 'wait_and_dispatch_one_signal' implementation for entrypoints
|
||||||
|
*
|
||||||
|
* Normally Genode signals are delivered by a signal thread, which blocks for
|
||||||
|
* incoming signals and is woken up when a signals arrives, the thread then
|
||||||
|
* sends an RPC to an entrypoint that, in turn, processes the signal.
|
||||||
|
* 'wait_and_dispatch_one_signal' allows an entrypoint to receive signals
|
||||||
|
* directly, by taking advantage of the same code as the signal thread. This
|
||||||
|
* leaves the problem that at this point two entities (the signal thread and the
|
||||||
|
* entrypoint) may wait for signals to arrive. It is not decidable which entity
|
||||||
|
* is woken up on signal arrival. If the signal thread is woken up and tries to
|
||||||
|
* deliver the signal RPC, system may dead lock when no additional signal
|
||||||
|
* arrives to pull the entrypoint out of the signal waiting code. This test
|
||||||
|
* triggers this exact situation. We also test nesting with the same signal
|
||||||
|
* context of 'wait_and_dispatch_one_signal' here, which also caused dead locks
|
||||||
|
* in the past.
|
||||||
|
*/
|
||||||
|
struct Wait_and_dispatch_test : Signal_test
|
||||||
|
{
|
||||||
|
static constexpr char const *brief = "wait and dispatch signals at entrypoint";
|
||||||
|
|
||||||
|
struct Wait_interface
|
||||||
|
{
|
||||||
|
GENODE_RPC(Rpc_dispatch_test, void, dispatch_test);
|
||||||
|
GENODE_RPC_INTERFACE(Rpc_dispatch_test);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Wait_component :
|
||||||
|
Rpc_object<Wait_interface, Wait_component>
|
||||||
|
{
|
||||||
|
Entrypoint &ep;
|
||||||
|
|
||||||
|
Wait_component(Entrypoint &ep) : ep(ep) { }
|
||||||
|
|
||||||
|
void dispatch_test()
|
||||||
|
{
|
||||||
|
log("1/5: [ep] wait for signal during RPC from [outside]");
|
||||||
|
ep.wait_and_dispatch_one_signal();
|
||||||
|
log("5/5: [ep] success");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sender_thread : Thread
|
||||||
|
{
|
||||||
|
Signal_context_capability cap;
|
||||||
|
Timer::Connection timer;
|
||||||
|
|
||||||
|
Sender_thread(Env &env, Signal_context_capability cap)
|
||||||
|
: Thread(env, "sender_thread", 1024 * sizeof(long)), cap(cap), timer(env)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void entry() {
|
||||||
|
timer.msleep(500);
|
||||||
|
log("2/5: [outside] submit initial signal");
|
||||||
|
Signal_transmitter(cap).submit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Env &env;
|
||||||
|
Entrypoint ep { env, 2048 * sizeof(long),
|
||||||
|
"wait_dispatch_ep" };
|
||||||
|
Signal_handler<Wait_and_dispatch_test> dispatcher { ep, *this,
|
||||||
|
&Wait_and_dispatch_test::handle };
|
||||||
|
Wait_component wait { ep };
|
||||||
|
Capability<Wait_interface> wait_cap = ep.manage(wait);
|
||||||
|
Sender_thread thread { env, dispatcher };
|
||||||
|
bool nested { false };
|
||||||
|
|
||||||
|
Wait_and_dispatch_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
||||||
|
{
|
||||||
|
thread.start();
|
||||||
|
wait_cap.call<Wait_interface::Rpc_dispatch_test>();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Wait_and_dispatch_test()
|
||||||
|
{
|
||||||
|
ep.dissolve(wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle()
|
||||||
|
{
|
||||||
|
if (nested) {
|
||||||
|
log("4/5: [ep] nested signal received");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log("3/5: [ep] signal received - sending nested signal");
|
||||||
|
nested = true;
|
||||||
|
Signal_transmitter(dispatcher).submit();
|
||||||
|
ep.wait_and_dispatch_one_signal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct Main
|
struct Main
|
||||||
{
|
{
|
||||||
Constructible<Fast_sender_test> test_1;
|
Constructible<Fast_sender_test> test_1;
|
||||||
@ -442,6 +535,7 @@ struct Main
|
|||||||
Constructible<Context_management_test> test_5;
|
Constructible<Context_management_test> test_5;
|
||||||
Constructible<Synchronized_destruction_test> test_6;
|
Constructible<Synchronized_destruction_test> test_6;
|
||||||
Constructible<Many_contexts_test> test_7;
|
Constructible<Many_contexts_test> test_7;
|
||||||
|
Constructible<Wait_and_dispatch_test> test_8;
|
||||||
|
|
||||||
Main(Env &env)
|
Main(Env &env)
|
||||||
{
|
{
|
||||||
@ -453,8 +547,9 @@ struct Main
|
|||||||
test_5.construct(env, 5); test_5.destruct();
|
test_5.construct(env, 5); test_5.destruct();
|
||||||
test_6.construct(env, 6); test_6.destruct();
|
test_6.construct(env, 6); test_6.destruct();
|
||||||
test_7.construct(env, 7); test_7.destruct();
|
test_7.construct(env, 7); test_7.destruct();
|
||||||
log("--- Signalling test finished ---");
|
test_8.construct(env, 8); test_8.destruct();
|
||||||
}
|
log("--- Signalling test finished ---");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void Component::construct(Genode::Env &env) { static Main main(env); }
|
void Component::construct(Genode::Env &env) { static Main main(env); }
|
||||||
|
Loading…
Reference in New Issue
Block a user