714 lines
20 KiB
C++
714 lines
20 KiB
C++
/*
|
|
* \brief Test for signalling framework
|
|
* \author Norman Feske
|
|
* \author Martin Stein
|
|
* \date 2008-09-06
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2008-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/component.h>
|
|
#include <base/heap.h>
|
|
#include <base/thread.h>
|
|
#include <base/registry.h>
|
|
#include <timer_session/connection.h>
|
|
|
|
using namespace Genode;
|
|
|
|
/**
|
|
* A thread that submits a signal context in a periodic fashion
|
|
*/
|
|
class Sender : Thread
|
|
{
|
|
private:
|
|
|
|
Timer::Connection _timer;
|
|
Signal_transmitter _transmitter;
|
|
uint64_t const _interval_ms;
|
|
bool const _verbose;
|
|
bool volatile _stop { false };
|
|
unsigned _submit_cnt { 0 };
|
|
bool volatile _idle { false };
|
|
|
|
void entry() override
|
|
{
|
|
while (!_stop) {
|
|
if (!_idle) {
|
|
_submit_cnt++;
|
|
if (_verbose) {
|
|
log("submit signal ", _submit_cnt); }
|
|
|
|
_transmitter.submit();
|
|
if (_interval_ms) {
|
|
_timer.msleep(_interval_ms); }
|
|
} else {
|
|
_timer.msleep(100); }
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
Sender(Env &env,
|
|
Signal_context_capability context,
|
|
uint64_t interval_ms,
|
|
bool verbose)
|
|
:
|
|
Thread(env, "sender", 16*1024), _timer(env),
|
|
_transmitter(context), _interval_ms(interval_ms), _verbose(verbose)
|
|
{
|
|
Thread::start();
|
|
}
|
|
|
|
~Sender()
|
|
{
|
|
if (!_stop && Thread::myself() != this) {
|
|
_stop = true;
|
|
join();
|
|
}
|
|
}
|
|
|
|
/***************
|
|
** Accessors **
|
|
***************/
|
|
|
|
void idle(bool idle) { _idle = idle; }
|
|
unsigned submit_cnt() const { return _submit_cnt; }
|
|
};
|
|
|
|
/**
|
|
* A thread that receives signals and takes some time to handle each
|
|
*/
|
|
class Handler : Thread
|
|
{
|
|
private:
|
|
|
|
Timer::Connection _timer;
|
|
uint64_t const _dispatch_ms;
|
|
unsigned const _id;
|
|
bool const _verbose;
|
|
Signal_receiver &_receiver;
|
|
bool _stop { false };
|
|
unsigned _receive_cnt { 0 };
|
|
unsigned _activation_cnt { 0 };
|
|
bool _idle { false };
|
|
|
|
void entry() override
|
|
{
|
|
while (!_stop) {
|
|
if (!_idle) {
|
|
Signal signal = _receiver.wait_for_signal();
|
|
if (_verbose)
|
|
log("handler ", _id, " got ", signal.num(), " "
|
|
"signal", (signal.num() == 1 ? "" : "s"), " "
|
|
"with context ", signal.context());
|
|
|
|
_receive_cnt += signal.num();
|
|
_activation_cnt++;
|
|
}
|
|
if (_dispatch_ms)
|
|
_timer.msleep(_dispatch_ms);
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
Handler(Env &env,
|
|
Signal_receiver &receiver,
|
|
uint64_t dispatch_ms,
|
|
bool verbose,
|
|
unsigned id)
|
|
:
|
|
Thread(env, "handler", 16*1024), _timer(env),
|
|
_dispatch_ms(dispatch_ms), _id(id), _verbose(verbose),
|
|
_receiver(receiver)
|
|
{
|
|
Thread::start();
|
|
}
|
|
|
|
~Handler()
|
|
{
|
|
Signal_context context;
|
|
Signal_context_capability context_cap { _receiver.manage(&context) };
|
|
|
|
_stop = true;
|
|
Signal_transmitter(context_cap).submit();
|
|
Thread::join();
|
|
_receiver.dissolve(&context);
|
|
}
|
|
|
|
void print(Output &output) const { Genode::print(output, "handler ", _id); }
|
|
|
|
/***************
|
|
** Accessors **
|
|
***************/
|
|
|
|
void idle(bool idle) { _idle = idle; }
|
|
unsigned receive_cnt() const { return _receive_cnt; }
|
|
unsigned activation_cnt() const { return _activation_cnt; }
|
|
};
|
|
|
|
/**
|
|
* Base of all signalling tests
|
|
*/
|
|
struct Signal_test
|
|
{
|
|
enum { SPEED = 10 };
|
|
|
|
int id;
|
|
|
|
Signal_test(int id, char const *brief) : id(id) {
|
|
log("\nTEST ", id, ": ", brief, "\n"); }
|
|
|
|
~Signal_test() { log("\nTEST ", id, " finished\n"); }
|
|
};
|
|
|
|
struct Fast_sender_test : Signal_test
|
|
{
|
|
static constexpr char const *brief =
|
|
"reliable delivery if the sender is faster than the handlers";
|
|
|
|
enum { HANDLER_INTERVAL_MS = 10 * SPEED,
|
|
SENDER_INTERVAL_MS = 2 * SPEED,
|
|
DURATION_MS = 50 * SPEED,
|
|
FINISH_IDLE_MS = 2 * HANDLER_INTERVAL_MS };
|
|
|
|
struct Unequal_sent_and_received_signals : Exception { };
|
|
|
|
Env &env;
|
|
Timer::Connection timer { env };
|
|
Signal_context context { };
|
|
Signal_receiver receiver { };
|
|
Handler handler { env, receiver, HANDLER_INTERVAL_MS, false, 1 };
|
|
Sender sender { env, receiver.manage(&context),
|
|
SENDER_INTERVAL_MS, false };
|
|
|
|
Fast_sender_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
|
{
|
|
timer.msleep(DURATION_MS);
|
|
|
|
/* stop emitting signals */
|
|
log("deactivate sender");
|
|
sender.idle(true);
|
|
timer.msleep(FINISH_IDLE_MS);
|
|
log("sender submitted a total of ", sender.submit_cnt(), " signals");
|
|
log("handler received a total of ", handler.receive_cnt(), " signals");
|
|
|
|
if (sender.submit_cnt() != handler.receive_cnt()) {
|
|
throw Unequal_sent_and_received_signals(); }
|
|
}
|
|
};
|
|
|
|
struct Stress_test : Signal_test
|
|
{
|
|
static constexpr char const *brief =
|
|
"throughput when submitting/handling as fast as possible";
|
|
|
|
enum { DURATION_SEC = 5 };
|
|
|
|
struct Unequal_sent_and_received_signals : Exception { };
|
|
|
|
Env &env;
|
|
Timer::Connection timer { env };
|
|
Signal_context context { };
|
|
Signal_receiver receiver { };
|
|
Handler handler { env, receiver, 0, false, 1 };
|
|
Sender sender { env, receiver.manage(&context), 0, false };
|
|
|
|
Stress_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
|
{
|
|
for (unsigned i = 1; i <= DURATION_SEC; i++) {
|
|
log(i, "/", (unsigned)DURATION_SEC);
|
|
timer.msleep(1000);
|
|
}
|
|
log("deactivate sender");
|
|
sender.idle(true);
|
|
|
|
while (handler.receive_cnt() < sender.submit_cnt()) {
|
|
log("waiting for signals still in flight...");
|
|
timer.msleep(1000);
|
|
}
|
|
log("");
|
|
log("sender submitted a total of ", sender.submit_cnt(), " signals");
|
|
log("handler received a total of ", handler.receive_cnt(), " signals");
|
|
log("");
|
|
log("handler received ", handler.receive_cnt() / DURATION_SEC, " signals per second");
|
|
log("handler was activated ", handler.activation_cnt() / DURATION_SEC, " times per second");
|
|
log("");
|
|
|
|
if (sender.submit_cnt() != handler.receive_cnt())
|
|
throw Unequal_sent_and_received_signals();
|
|
}
|
|
};
|
|
|
|
struct Lazy_receivers_test : Signal_test
|
|
{
|
|
static constexpr char const *brief = "lazy and out-of-order signal reception";
|
|
|
|
Signal_context context_1 { }, context_2 { };
|
|
Signal_receiver receiver_1 { }, receiver_2 { };
|
|
Signal_transmitter transmitter_1 { receiver_1.manage(&context_1) };
|
|
Signal_transmitter transmitter_2 { receiver_2.manage(&context_2) };
|
|
|
|
Lazy_receivers_test(Env &, int id) : Signal_test(id, brief)
|
|
{
|
|
log("submit and receive signals with multiple receivers in order");
|
|
transmitter_1.submit();
|
|
transmitter_2.submit();
|
|
{
|
|
Signal signal = receiver_1.wait_for_signal();
|
|
log("returned from wait_for_signal for receiver 1");
|
|
|
|
signal = receiver_2.wait_for_signal();
|
|
log("returned from wait_for_signal for receiver 2");
|
|
}
|
|
log("submit and receive signals with multiple receivers out of order");
|
|
transmitter_1.submit();
|
|
transmitter_2.submit();
|
|
{
|
|
Signal signal = receiver_2.wait_for_signal();
|
|
log("returned from wait_for_signal for receiver 2");
|
|
|
|
signal = receiver_1.wait_for_signal();
|
|
log("returned from wait_for_signal for receiver 1");
|
|
}
|
|
}
|
|
};
|
|
|
|
struct Context_management_test : Signal_test
|
|
{
|
|
static constexpr char const *brief =
|
|
"correct initialization and cleanup of receiver and context";
|
|
|
|
Env &env;
|
|
Timer::Connection timer { env };
|
|
Signal_context context { };
|
|
Signal_receiver receiver { };
|
|
Signal_context_capability context_cap { receiver.manage(&context) };
|
|
Sender sender { env, context_cap, 500, true };
|
|
|
|
Context_management_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
|
{
|
|
/* stop sender after timeout */
|
|
timer.msleep(1000);
|
|
log("suspend sender");
|
|
sender.idle(true);
|
|
|
|
/* collect pending signals and dissolve context from receiver */
|
|
{
|
|
Signal signal = receiver.wait_for_signal();
|
|
log("got ", signal.num(), " signal(s) from ", signal.context());
|
|
}
|
|
receiver.dissolve(&context);
|
|
|
|
/* let sender spin for some time */
|
|
log("resume sender");
|
|
sender.idle(false);
|
|
timer.msleep(1000);
|
|
log("suspend sender");
|
|
sender.idle(true);
|
|
log("destroy sender");
|
|
}
|
|
};
|
|
|
|
struct Synchronized_destruction_test : private Signal_test, Thread
|
|
{
|
|
static constexpr char const *brief =
|
|
"does 'dissolve' block as long as the signal context is referenced?";
|
|
|
|
struct Failed : Exception { };
|
|
|
|
Env &env;
|
|
Timer::Connection timer { env };
|
|
Heap heap { env.ram(), env.rm() };
|
|
Signal_context &context { *new (heap) Signal_context };
|
|
Signal_receiver receiver { };
|
|
Signal_transmitter transmitter { receiver.manage(&context) };
|
|
bool destroyed { false };
|
|
|
|
void entry() override
|
|
{
|
|
receiver.dissolve(&context);
|
|
log("dissolve finished");
|
|
destroyed = true;
|
|
destroy(heap, &context);
|
|
}
|
|
|
|
Synchronized_destruction_test(Env &env, int id)
|
|
: Signal_test(id, brief), Thread(env, "destroyer", 8*1024), env(env)
|
|
{
|
|
transmitter.submit();
|
|
{
|
|
Signal signal = receiver.wait_for_signal();
|
|
log("start dissolving");
|
|
Thread::start();
|
|
timer.msleep(2000);
|
|
Signal signal_copy_1 = signal;
|
|
Signal signal_copy_2 = signal;
|
|
signal_copy_1 = signal_copy_2;
|
|
if (destroyed) {
|
|
throw Failed(); }
|
|
log("destruct signal");
|
|
}
|
|
Thread::join();
|
|
}
|
|
};
|
|
|
|
struct Many_contexts_test : Signal_test
|
|
{
|
|
static constexpr char const *brief = "create and manage many contexts";
|
|
|
|
struct Manage_failed : Exception { };
|
|
|
|
Env &env;
|
|
Heap heap { env.ram(), env.rm() };
|
|
Registry<Registered<Signal_context> > contexts { };
|
|
|
|
Many_contexts_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
|
{
|
|
for (unsigned round = 0; round < 10; round++) {
|
|
|
|
unsigned const nr_of_contexts = 200 + 5 * round;
|
|
log("round ", round, ": manage ", nr_of_contexts, " contexts");
|
|
|
|
Signal_receiver receiver;
|
|
for (unsigned i = 0; i < nr_of_contexts; i++) {
|
|
if (!receiver.manage(new (heap) Registered<Signal_context>(contexts)).valid()) {
|
|
throw Manage_failed(); }
|
|
}
|
|
contexts.for_each([&] (Registered<Signal_context> &context) {
|
|
receiver.dissolve(&context);
|
|
destroy(heap, &context);
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Test 'wait_and_dispatch_one_io_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_io_signal' allows an entrypoint to receive I/O-level
|
|
* 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_io_signal' here, which also caused
|
|
* dead locks in the past. Also, the test verifies application-level signals
|
|
* are deferred during 'wait_and_dispatch_one_io_signal'.
|
|
*/
|
|
struct Nested_test : Signal_test
|
|
{
|
|
static constexpr char const *brief = "wait and dispatch signals at entrypoint";
|
|
|
|
struct Test_interface : Interface
|
|
{
|
|
GENODE_RPC(Rpc_test_io_dispatch, void, test_io_dispatch);
|
|
GENODE_RPC(Rpc_test_app_dispatch, void, test_app_dispatch);
|
|
GENODE_RPC_INTERFACE(Rpc_test_io_dispatch, Rpc_test_app_dispatch);
|
|
};
|
|
|
|
struct Test_component : Rpc_object<Test_interface, Test_component>
|
|
{
|
|
Nested_test &test;
|
|
|
|
Test_component(Nested_test &test) : test(test) { }
|
|
|
|
void test_io_dispatch()
|
|
{
|
|
log("1/8: [ep] wait for I/O-level signal during RPC from [outside]");
|
|
while (!test.io_done) test.ep.wait_and_dispatch_one_io_signal();
|
|
log("6/8: [ep] I/O completed");
|
|
}
|
|
|
|
void test_app_dispatch()
|
|
{
|
|
if (!test.app_done)
|
|
error("8/8: [ep] application-level signal was not dispatched");
|
|
else
|
|
log("8/8: [ep] success");
|
|
}
|
|
};
|
|
|
|
struct Sender_thread : Thread
|
|
{
|
|
Nested_test &test;
|
|
Timer::Connection timer;
|
|
|
|
Sender_thread(Env &env, Nested_test &test)
|
|
:
|
|
Thread(env, "sender_thread", 8*1024),
|
|
test(test), timer(env)
|
|
{ }
|
|
|
|
void entry() override
|
|
{
|
|
timer.msleep(1000);
|
|
|
|
log("2/8: [outside] submit application-level signal (should be deferred)");
|
|
Signal_transmitter(test.nop_handler).submit();
|
|
Signal_transmitter(test.app_handler).submit();
|
|
Signal_transmitter(test.nop_handler).submit();
|
|
|
|
log("3/8: [outside] submit I/O-level signal");
|
|
Signal_transmitter(test.io_handler).submit();
|
|
Signal_transmitter(test.nop_handler).submit();
|
|
}
|
|
};
|
|
|
|
Env &env;
|
|
Entrypoint ep { env, 2048 * sizeof(long), "wait_dispatch_ep", Affinity::Location() };
|
|
|
|
Signal_handler<Nested_test> app_handler { ep, *this, &Nested_test::handle_app };
|
|
Signal_handler<Nested_test> nop_handler { ep, *this, &Nested_test::handle_nop };
|
|
Io_signal_handler<Nested_test> io_handler { ep, *this, &Nested_test::handle_io };
|
|
|
|
Test_component wait { *this };
|
|
Capability<Test_interface> wait_cap { ep.manage(wait) };
|
|
Sender_thread thread { env, *this };
|
|
bool nested { false };
|
|
bool volatile app_done { false };
|
|
bool volatile io_done { false };
|
|
|
|
Timer::Connection timer { env };
|
|
|
|
Nested_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
|
{
|
|
thread.start();
|
|
wait_cap.call<Test_interface::Rpc_test_io_dispatch>();
|
|
|
|
/* grant the ep some time for application-signal handling */
|
|
timer.msleep(1000);
|
|
wait_cap.call<Test_interface::Rpc_test_app_dispatch>();
|
|
}
|
|
|
|
~Nested_test()
|
|
{
|
|
ep.dissolve(wait);
|
|
}
|
|
|
|
void handle_app()
|
|
{
|
|
if (!io_done)
|
|
error("7/8: [ep] application-level signal was not deferred");
|
|
else
|
|
log("7/8: [ep] application-level signal received");
|
|
|
|
app_done = true;
|
|
}
|
|
|
|
void handle_nop() { }
|
|
|
|
void handle_io()
|
|
{
|
|
if (nested) {
|
|
log("5/8: [ep] nested I/O-level signal received");
|
|
io_done = true;
|
|
return;
|
|
}
|
|
|
|
log("4/8: [ep] I/O-level signal received - sending nested signal");
|
|
nested = true;
|
|
Signal_transmitter(io_handler).submit();
|
|
ep.wait_and_dispatch_one_io_signal();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Stress-test 'wait_and_dispatch_one_io_signal' implementation for entrypoints
|
|
*
|
|
* Let multiple entrypoints directly wait and dispatch signals in a
|
|
* highly nested manner and with multiple stressful senders.
|
|
*/
|
|
struct Nested_stress_test : Signal_test
|
|
{
|
|
static constexpr char const *brief = "stressful wait and dispatch signals at entrypoint";
|
|
|
|
enum {
|
|
COUNTER_GOAL = 300,
|
|
UNWIND_COUNT_MOD_LOG2 = 5,
|
|
POLLING_PERIOD_US = 1000000,
|
|
};
|
|
|
|
struct Sender : Thread
|
|
{
|
|
Signal_transmitter transmitter;
|
|
bool volatile destruct { false };
|
|
|
|
Sender(Env &env, char const *name, Signal_context_capability cap)
|
|
: Thread(env, name, 8*1024), transmitter(cap) { }
|
|
|
|
void entry() override
|
|
{
|
|
/* send signals as fast as possible */
|
|
while (!destruct) { transmitter.submit(); }
|
|
}
|
|
};
|
|
|
|
struct Receiver
|
|
{
|
|
Entrypoint ep;
|
|
|
|
String<64> const name;
|
|
|
|
unsigned count { 0 };
|
|
unsigned level { 0 };
|
|
|
|
bool volatile destruct { false };
|
|
bool volatile ready_for_destruction { false };
|
|
|
|
Io_signal_handler<Receiver> handler { ep, *this, &Receiver::handle };
|
|
|
|
Receiver(Env &env, char const *name)
|
|
: ep(env, 3 * 1024 * sizeof(long), name, Affinity::Location()),
|
|
name(name) { }
|
|
|
|
void handle()
|
|
{
|
|
/*
|
|
* We have to get out of the nesting if the host wants to destroy
|
|
* us to avoid a deadlock at the lock in the signal handler.
|
|
*/
|
|
if (destruct) {
|
|
if (level == 0)
|
|
ready_for_destruction = true;
|
|
return;
|
|
}
|
|
|
|
/* raise call counter */
|
|
count++;
|
|
|
|
/*
|
|
* Open a new nesting level with each signal until count module X
|
|
* gives zero, then unwind the whole nesting and start afresh.
|
|
*/
|
|
if ((count & ((1 << UNWIND_COUNT_MOD_LOG2) - 1)) != 0) {
|
|
level ++;
|
|
ep.wait_and_dispatch_one_io_signal();
|
|
level --;
|
|
}
|
|
}
|
|
};
|
|
|
|
Env &env;
|
|
Timer::Connection timer { env };
|
|
Receiver receiver_1 { env, "receiver-1" };
|
|
Receiver receiver_2 { env, "receiver-2" };
|
|
Receiver receiver_3 { env, "receiver-3" };
|
|
Sender sender_1 { env, "sender-1", receiver_1.handler };
|
|
Sender sender_2 { env, "sender-2", receiver_2.handler };
|
|
Sender sender_3 { env, "sender-3", receiver_3.handler };
|
|
Signal_transmitter done;
|
|
|
|
Io_signal_handler<Nested_stress_test> poll {
|
|
env.ep(), *this, &Nested_stress_test::handle_poll };
|
|
|
|
Nested_stress_test(Env &env, int id, Signal_context_capability done)
|
|
: Signal_test(id, brief), env(env), done(done)
|
|
{
|
|
/* let senders start sending signals like crazy */
|
|
sender_1.start();
|
|
sender_2.start();
|
|
sender_3.start();
|
|
|
|
/* initialize polling for the receiver counts */
|
|
timer.sigh(poll);
|
|
timer.trigger_periodic(POLLING_PERIOD_US);
|
|
}
|
|
|
|
~Nested_stress_test()
|
|
{
|
|
/* tell timer not to send any signals anymore. */
|
|
timer.sigh(Timer::Session::Signal_context_capability());
|
|
|
|
/* let receivers unwind their nesting and stop with the next signal */
|
|
receiver_1.destruct = true;
|
|
receiver_2.destruct = true;
|
|
receiver_3.destruct = true;
|
|
|
|
/*
|
|
* Wait until receiver threads get out of
|
|
* wait_and_dispatch_one_io_signal, otherwise we may (dead)lock forever
|
|
* during destruction of the Io_signal_handler.
|
|
*/
|
|
log("waiting for receivers");
|
|
|
|
while (!receiver_1.ready_for_destruction) { }
|
|
while (!receiver_2.ready_for_destruction) { }
|
|
while (!receiver_3.ready_for_destruction) { }
|
|
|
|
/* let senders stop burning our CPU time */
|
|
sender_1.destruct = true;
|
|
sender_2.destruct = true;
|
|
sender_3.destruct = true;
|
|
|
|
log ("waiting for senders");
|
|
|
|
/* wait until threads joined */
|
|
sender_1.join(); sender_2.join(), sender_3.join();
|
|
|
|
log("destructing ...");
|
|
}
|
|
|
|
void handle_poll()
|
|
{
|
|
/* print counter status */
|
|
log(receiver_1.name, " received ", receiver_1.count, " times");
|
|
log(receiver_2.name, " received ", receiver_2.count, " times");
|
|
log(receiver_3.name, " received ", receiver_3.count, " times");
|
|
|
|
/* request to end the test if receiver counts are all high enough */
|
|
if (receiver_1.count > COUNTER_GOAL &&
|
|
receiver_2.count > COUNTER_GOAL &&
|
|
receiver_3.count > COUNTER_GOAL)
|
|
{ done.submit(); }
|
|
}
|
|
};
|
|
|
|
struct Main
|
|
{
|
|
Env &env;
|
|
Signal_handler<Main> test_8_done { env.ep(), *this, &Main::handle_test_8_done };
|
|
|
|
Constructible<Fast_sender_test> test_1 { };
|
|
Constructible<Stress_test> test_2 { };
|
|
Constructible<Lazy_receivers_test> test_3 { };
|
|
Constructible<Context_management_test> test_4 { };
|
|
Constructible<Synchronized_destruction_test> test_5 { };
|
|
Constructible<Many_contexts_test> test_6 { };
|
|
Constructible<Nested_test> test_7 { };
|
|
Constructible<Nested_stress_test> test_8 { };
|
|
|
|
void handle_test_8_done()
|
|
{
|
|
test_8.destruct();
|
|
log("--- Signalling test finished ---");
|
|
env.parent().exit(0);
|
|
}
|
|
|
|
Main(Env &env) : env(env)
|
|
{
|
|
log("--- Signalling test ---");
|
|
test_1.construct(env, 1); test_1.destruct();
|
|
test_2.construct(env, 2); test_2.destruct();
|
|
test_3.construct(env, 3); test_3.destruct();
|
|
test_4.construct(env, 4); test_4.destruct();
|
|
test_5.construct(env, 5); test_5.destruct();
|
|
test_6.construct(env, 6); test_6.destruct();
|
|
test_7.construct(env, 7); test_7.destruct();
|
|
test_8.construct(env, 8, test_8_done);
|
|
}
|
|
};
|
|
|
|
void Component::construct(Genode::Env &env) { static Main main(env); }
|