2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Test for signalling framework
|
|
|
|
* \author Norman Feske
|
2017-01-17 12:58:00 +01:00
|
|
|
* \author Martin Stein
|
2011-12-22 16:19:25 +01:00
|
|
|
* \date 2008-09-06
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-01-17 12:58:00 +01:00
|
|
|
* Copyright (C) 2008-2017 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
/* Genode includes */
|
2016-11-06 14:27:26 +01:00
|
|
|
#include <base/component.h>
|
|
|
|
#include <base/heap.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <base/thread.h>
|
2017-01-17 12:58:00 +01:00
|
|
|
#include <base/registry.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <timer_session/connection.h>
|
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
/**
|
2017-01-17 12:58:00 +01:00
|
|
|
* A thread that submits a signal context in a periodic fashion
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2016-11-06 14:27:26 +01:00
|
|
|
class Sender : Thread
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Timer::Connection _timer;
|
2016-11-06 14:27:26 +01:00
|
|
|
Signal_transmitter _transmitter;
|
2019-04-09 15:46:36 +02:00
|
|
|
uint64_t const _interval_ms;
|
2017-01-17 12:58:00 +01:00
|
|
|
bool const _verbose;
|
2017-12-07 00:02:39 +01:00
|
|
|
bool volatile _stop { false };
|
2017-01-17 12:58:00 +01:00
|
|
|
unsigned _submit_cnt { 0 };
|
2017-12-07 00:02:39 +01:00
|
|
|
bool volatile _idle { false };
|
2017-01-17 12:58:00 +01:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
void entry() override
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
while (!_stop) {
|
|
|
|
if (!_idle) {
|
|
|
|
_submit_cnt++;
|
2017-01-17 12:58:00 +01:00
|
|
|
if (_verbose) {
|
|
|
|
log("submit signal ", _submit_cnt); }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
_transmitter.submit();
|
2017-01-17 12:58:00 +01:00
|
|
|
if (_interval_ms) {
|
|
|
|
_timer.msleep(_interval_ms); }
|
|
|
|
} else {
|
|
|
|
_timer.msleep(100); }
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Sender(Env &env,
|
|
|
|
Signal_context_capability context,
|
2019-04-09 15:46:36 +02:00
|
|
|
uint64_t interval_ms,
|
2017-01-17 12:58:00 +01:00
|
|
|
bool verbose)
|
2011-12-22 16:19:25 +01:00
|
|
|
:
|
2017-11-21 16:34:37 +01:00
|
|
|
Thread(env, "sender", 16*1024), _timer(env),
|
2017-01-17 12:58:00 +01:00
|
|
|
_transmitter(context), _interval_ms(interval_ms), _verbose(verbose)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
Thread::start();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
2017-12-07 00:02:39 +01:00
|
|
|
~Sender()
|
|
|
|
{
|
|
|
|
if (!_stop && Thread::myself() != this) {
|
|
|
|
_stop = true;
|
|
|
|
join();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
/***************
|
|
|
|
** Accessors **
|
|
|
|
***************/
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
void idle(bool idle) { _idle = idle; }
|
|
|
|
unsigned submit_cnt() const { return _submit_cnt; }
|
2011-12-22 16:19:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2017-01-17 12:58:00 +01:00
|
|
|
* A thread that receives signals and takes some time to handle each
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2016-11-06 14:27:26 +01:00
|
|
|
class Handler : Thread
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Timer::Connection _timer;
|
2019-04-09 15:46:36 +02:00
|
|
|
uint64_t const _dispatch_ms;
|
2017-01-17 12:58:00 +01:00
|
|
|
unsigned const _id;
|
|
|
|
bool const _verbose;
|
|
|
|
Signal_receiver &_receiver;
|
|
|
|
bool _stop { false };
|
|
|
|
unsigned _receive_cnt { 0 };
|
|
|
|
unsigned _activation_cnt { 0 };
|
|
|
|
bool _idle { false };
|
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
void entry() override
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
|
|
|
while (!_stop) {
|
|
|
|
if (!_idle) {
|
2016-11-06 14:27:26 +01:00
|
|
|
Signal signal = _receiver.wait_for_signal();
|
2011-12-22 16:19:25 +01:00
|
|
|
if (_verbose)
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
log("handler ", _id, " got ", signal.num(), " "
|
|
|
|
"signal", (signal.num() == 1 ? "" : "s"), " "
|
|
|
|
"with context ", signal.context());
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
_receive_cnt += signal.num();
|
|
|
|
_activation_cnt++;
|
|
|
|
}
|
|
|
|
if (_dispatch_ms)
|
|
|
|
_timer.msleep(_dispatch_ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Handler(Env &env,
|
|
|
|
Signal_receiver &receiver,
|
2019-04-09 15:46:36 +02:00
|
|
|
uint64_t dispatch_ms,
|
2017-01-17 12:58:00 +01:00
|
|
|
bool verbose,
|
|
|
|
unsigned id)
|
2011-12-22 16:19:25 +01:00
|
|
|
:
|
2017-11-21 16:34:37 +01:00
|
|
|
Thread(env, "handler", 16*1024), _timer(env),
|
2017-01-17 12:58:00 +01:00
|
|
|
_dispatch_ms(dispatch_ms), _id(id), _verbose(verbose),
|
|
|
|
_receiver(receiver)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
Thread::start();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-15 14:38:51 +01:00
|
|
|
~Handler()
|
|
|
|
{
|
|
|
|
Signal_context context;
|
|
|
|
Signal_context_capability context_cap { _receiver.manage(&context) };
|
|
|
|
|
|
|
|
_stop = true;
|
|
|
|
Signal_transmitter(context_cap).submit();
|
|
|
|
Thread::join();
|
|
|
|
_receiver.dissolve(&context);
|
|
|
|
}
|
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
void print(Output &output) const { Genode::print(output, "handler ", _id); }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
/***************
|
|
|
|
** Accessors **
|
|
|
|
***************/
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
void idle(bool idle) { _idle = idle; }
|
|
|
|
unsigned receive_cnt() const { return _receive_cnt; }
|
2013-01-10 20:56:48 +01:00
|
|
|
unsigned activation_cnt() const { return _activation_cnt; }
|
2011-12-22 16:19:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2017-01-17 12:58:00 +01:00
|
|
|
* Base of all signalling tests
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Signal_test
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
enum { SPEED = 10 };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
int id;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Signal_test(int id, char const *brief) : id(id) {
|
|
|
|
log("\nTEST ", id, ": ", brief, "\n"); }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
~Signal_test() { log("\nTEST ", id, " finished\n"); }
|
2011-12-22 16:19:25 +01:00
|
|
|
};
|
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Fast_sender_test : Signal_test
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
static constexpr char const *brief =
|
|
|
|
"reliable delivery if the sender is faster than the handlers";
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
enum { HANDLER_INTERVAL_MS = 10 * SPEED,
|
|
|
|
SENDER_INTERVAL_MS = 2 * SPEED,
|
|
|
|
DURATION_MS = 50 * SPEED,
|
|
|
|
FINISH_IDLE_MS = 2 * HANDLER_INTERVAL_MS };
|
2013-11-25 09:30:51 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Unequal_sent_and_received_signals : Exception { };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Env &env;
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
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 };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Fast_sender_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
|
|
|
{
|
|
|
|
timer.msleep(DURATION_MS);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
/* 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");
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
if (sender.submit_cnt() != handler.receive_cnt()) {
|
|
|
|
throw Unequal_sent_and_received_signals(); }
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2017-01-17 12:58:00 +01:00
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Stress_test : Signal_test
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
static constexpr char const *brief =
|
|
|
|
"throughput when submitting/handling as fast as possible";
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
enum { DURATION_SEC = 5 };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Unequal_sent_and_received_signals : Exception { };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Env &env;
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
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 };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Stress_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
2013-01-14 18:24:32 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
for (unsigned i = 1; i <= DURATION_SEC; i++) {
|
|
|
|
log(i, "/", (unsigned)DURATION_SEC);
|
|
|
|
timer.msleep(1000);
|
|
|
|
}
|
|
|
|
log("deactivate sender");
|
|
|
|
sender.idle(true);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
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();
|
2013-01-14 18:24:32 +01:00
|
|
|
}
|
2017-01-17 12:58:00 +01:00
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Lazy_receivers_test : Signal_test
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
static constexpr char const *brief = "lazy and out-of-order signal reception";
|
2011-12-22 16:19:25 +01:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Signal_context context_1 { }, context_2 { };
|
|
|
|
Signal_receiver receiver_1 { }, receiver_2 { };
|
2017-01-17 12:58:00 +01:00
|
|
|
Signal_transmitter transmitter_1 { receiver_1.manage(&context_1) };
|
|
|
|
Signal_transmitter transmitter_2 { receiver_2.manage(&context_2) };
|
2016-11-06 14:27:26 +01:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Lazy_receivers_test(Env &, int id) : Signal_test(id, brief)
|
2013-01-14 18:24:32 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
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");
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
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");
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
signal = receiver_1.wait_for_signal();
|
|
|
|
log("returned from wait_for_signal for receiver 1");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Context_management_test : Signal_test
|
2013-01-14 18:24:32 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
static constexpr char const *brief =
|
|
|
|
"correct initialization and cleanup of receiver and context";
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Env &env;
|
|
|
|
Timer::Connection timer { env };
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Signal_context context { };
|
|
|
|
Signal_receiver receiver { };
|
2017-01-17 12:58:00 +01:00
|
|
|
Signal_context_capability context_cap { receiver.manage(&context) };
|
|
|
|
Sender sender { env, context_cap, 500, true };
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
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);
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
/* collect pending signals and dissolve context from receiver */
|
2013-01-14 18:24:32 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
Signal signal = receiver.wait_for_signal();
|
|
|
|
log("got ", signal.num(), " signal(s) from ", signal.context());
|
2013-01-14 18:24:32 +01:00
|
|
|
}
|
2017-01-17 12:58:00 +01:00
|
|
|
receiver.dissolve(&context);
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
/* let sender spin for some time */
|
|
|
|
log("resume sender");
|
|
|
|
sender.idle(false);
|
|
|
|
timer.msleep(1000);
|
|
|
|
log("suspend sender");
|
|
|
|
sender.idle(true);
|
|
|
|
log("destroy sender");
|
|
|
|
}
|
|
|
|
};
|
2014-10-02 19:47:36 +02:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
struct Synchronized_destruction_test : private Signal_test, Thread
|
2013-01-14 18:24:32 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
static constexpr char const *brief =
|
|
|
|
"does 'dissolve' block as long as the signal context is referenced?";
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Failed : Exception { };
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Env &env;
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
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 };
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
void entry() override
|
2013-01-14 18:24:32 +01:00
|
|
|
{
|
2017-01-17 12:58:00 +01:00
|
|
|
receiver.dissolve(&context);
|
|
|
|
log("dissolve finished");
|
|
|
|
destroyed = true;
|
|
|
|
destroy(heap, &context);
|
|
|
|
}
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Synchronized_destruction_test(Env &env, int id)
|
2017-11-21 16:34:37 +01:00
|
|
|
: Signal_test(id, brief), Thread(env, "destroyer", 8*1024), env(env)
|
2017-01-17 12:58:00 +01:00
|
|
|
{
|
|
|
|
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");
|
2013-01-14 18:24:32 +01:00
|
|
|
}
|
2017-01-17 12:58:00 +01:00
|
|
|
Thread::join();
|
2013-01-14 18:24:32 +01:00
|
|
|
}
|
2017-01-17 12:58:00 +01:00
|
|
|
};
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Many_contexts_test : Signal_test
|
|
|
|
{
|
|
|
|
static constexpr char const *brief = "create and manage many contexts";
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Manage_failed : Exception { };
|
2013-01-14 18:24:32 +01:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Env &env;
|
|
|
|
Heap heap { env.ram(), env.rm() };
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Registry<Registered<Signal_context> > contexts { };
|
2014-10-02 19:47:36 +02:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
Many_contexts_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
|
|
|
{
|
|
|
|
for (unsigned round = 0; round < 10; round++) {
|
2014-10-02 19:47:36 +02:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
unsigned const nr_of_contexts = 200 + 5 * round;
|
|
|
|
log("round ", round, ": manage ", nr_of_contexts, " contexts");
|
2014-10-02 19:47:36 +02:00
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
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(); }
|
2015-03-05 13:00:08 +01:00
|
|
|
}
|
2017-01-17 12:58:00 +01:00
|
|
|
contexts.for_each([&] (Registered<Signal_context> &context) {
|
|
|
|
receiver.dissolve(&context);
|
|
|
|
destroy(heap, &context);
|
|
|
|
});
|
2014-10-02 19:47:36 +02:00
|
|
|
}
|
|
|
|
}
|
2017-01-17 12:58:00 +01:00
|
|
|
};
|
2014-10-02 19:47:36 +02:00
|
|
|
|
2017-02-16 19:46:11 +01:00
|
|
|
/**
|
2017-04-03 10:45:51 +02:00
|
|
|
* Test 'wait_and_dispatch_one_io_signal' implementation for entrypoints
|
2017-02-16 19:46:11 +01:00
|
|
|
*
|
|
|
|
* 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.
|
2017-04-03 10:45:51 +02:00
|
|
|
* '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'.
|
2017-02-16 19:46:11 +01:00
|
|
|
*/
|
2017-02-27 07:38:33 +01:00
|
|
|
struct Nested_test : Signal_test
|
2017-02-16 19:46:11 +01:00
|
|
|
{
|
|
|
|
static constexpr char const *brief = "wait and dispatch signals at entrypoint";
|
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
struct Test_interface : Interface
|
2017-02-16 19:46:11 +01:00
|
|
|
{
|
2017-04-03 10:45:51 +02:00
|
|
|
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);
|
2017-02-16 19:46:11 +01:00
|
|
|
};
|
|
|
|
|
2017-04-03 10:45:51 +02:00
|
|
|
struct Test_component : Rpc_object<Test_interface, Test_component>
|
2017-02-16 19:46:11 +01:00
|
|
|
{
|
2017-04-03 10:45:51 +02:00
|
|
|
Nested_test &test;
|
2017-02-16 19:46:11 +01:00
|
|
|
|
2017-04-03 10:45:51 +02:00
|
|
|
Test_component(Nested_test &test) : test(test) { }
|
2017-02-16 19:46:11 +01:00
|
|
|
|
2017-04-03 10:45:51 +02:00
|
|
|
void test_io_dispatch()
|
2017-02-16 19:46:11 +01:00
|
|
|
{
|
2017-04-03 10:45:51 +02:00
|
|
|
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");
|
2017-02-16 19:46:11 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Sender_thread : Thread
|
|
|
|
{
|
2017-04-03 10:45:51 +02:00
|
|
|
Nested_test &test;
|
|
|
|
Timer::Connection timer;
|
2017-02-16 19:46:11 +01:00
|
|
|
|
2017-04-03 10:45:51 +02:00
|
|
|
Sender_thread(Env &env, Nested_test &test)
|
|
|
|
:
|
2017-11-21 16:34:37 +01:00
|
|
|
Thread(env, "sender_thread", 8*1024),
|
2017-04-03 10:45:51 +02:00
|
|
|
test(test), timer(env)
|
2017-02-16 19:46:11 +01:00
|
|
|
{ }
|
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
void entry() override
|
2017-04-03 10:45:51 +02:00
|
|
|
{
|
|
|
|
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();
|
2017-02-16 19:46:11 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-04-03 10:45:51 +02:00
|
|
|
Env &env;
|
2018-10-02 16:27:35 +02:00
|
|
|
Entrypoint ep { env, 2048 * sizeof(long), "wait_dispatch_ep", Affinity::Location() };
|
2017-04-03 10:45:51 +02:00
|
|
|
|
|
|
|
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 };
|
2017-02-16 19:46:11 +01:00
|
|
|
|
2017-02-27 07:38:33 +01:00
|
|
|
Nested_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
2017-02-16 19:46:11 +01:00
|
|
|
{
|
|
|
|
thread.start();
|
2017-04-03 10:45:51 +02:00
|
|
|
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>();
|
2017-02-16 19:46:11 +01:00
|
|
|
}
|
|
|
|
|
2017-02-27 07:38:33 +01:00
|
|
|
~Nested_test()
|
2017-02-16 19:46:11 +01:00
|
|
|
{
|
|
|
|
ep.dissolve(wait);
|
|
|
|
}
|
|
|
|
|
2017-04-03 10:45:51 +02:00
|
|
|
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()
|
2017-02-16 19:46:11 +01:00
|
|
|
{
|
|
|
|
if (nested) {
|
2017-04-03 10:45:51 +02:00
|
|
|
log("5/8: [ep] nested I/O-level signal received");
|
|
|
|
io_done = true;
|
2017-02-16 19:46:11 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-04-03 10:45:51 +02:00
|
|
|
log("4/8: [ep] I/O-level signal received - sending nested signal");
|
2017-02-16 19:46:11 +01:00
|
|
|
nested = true;
|
2017-04-03 10:45:51 +02:00
|
|
|
Signal_transmitter(io_handler).submit();
|
|
|
|
ep.wait_and_dispatch_one_io_signal();
|
2017-02-16 19:46:11 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-02-27 07:38:33 +01:00
|
|
|
/**
|
2017-04-03 10:45:51 +02:00
|
|
|
* Stress-test 'wait_and_dispatch_one_io_signal' implementation for entrypoints
|
2017-02-27 07:38:33 +01:00
|
|
|
*
|
|
|
|
* 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;
|
2017-12-07 00:02:39 +01:00
|
|
|
bool volatile destruct { false };
|
2017-02-27 07:38:33 +01:00
|
|
|
|
|
|
|
Sender(Env &env, char const *name, Signal_context_capability cap)
|
2017-11-21 16:34:37 +01:00
|
|
|
: Thread(env, name, 8*1024), transmitter(cap) { }
|
2017-02-27 07:38:33 +01:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
void entry() override
|
2017-02-27 07:38:33 +01:00
|
|
|
{
|
|
|
|
/* send signals as fast as possible */
|
|
|
|
while (!destruct) { transmitter.submit(); }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Receiver
|
|
|
|
{
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Entrypoint ep;
|
|
|
|
|
|
|
|
String<64> const name;
|
|
|
|
|
|
|
|
unsigned count { 0 };
|
|
|
|
unsigned level { 0 };
|
|
|
|
|
|
|
|
bool volatile destruct { false };
|
2017-12-07 00:02:39 +01:00
|
|
|
bool volatile ready_for_destruction { false };
|
2017-04-03 10:45:51 +02:00
|
|
|
|
|
|
|
Io_signal_handler<Receiver> handler { ep, *this, &Receiver::handle };
|
2017-02-27 07:38:33 +01:00
|
|
|
|
|
|
|
Receiver(Env &env, char const *name)
|
2018-10-02 16:27:35 +02:00
|
|
|
: ep(env, 3 * 1024 * sizeof(long), name, Affinity::Location()),
|
|
|
|
name(name) { }
|
2017-02-27 07:38:33 +01:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2017-12-07 00:02:39 +01:00
|
|
|
if (destruct) {
|
|
|
|
if (level == 0)
|
|
|
|
ready_for_destruction = true;
|
|
|
|
return;
|
|
|
|
}
|
2017-02-27 07:38:33 +01:00
|
|
|
|
|
|
|
/* 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) {
|
2017-12-07 00:02:39 +01:00
|
|
|
level ++;
|
|
|
|
ep.wait_and_dispatch_one_io_signal();
|
|
|
|
level --;
|
|
|
|
}
|
2017-02-27 07:38:33 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2017-04-03 10:45:51 +02:00
|
|
|
Io_signal_handler<Nested_stress_test> poll {
|
|
|
|
env.ep(), *this, &Nested_stress_test::handle_poll };
|
2017-02-27 07:38:33 +01:00
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
2017-03-08 08:48:20 +01:00
|
|
|
/* tell timer not to send any signals anymore. */
|
|
|
|
timer.sigh(Timer::Session::Signal_context_capability());
|
|
|
|
|
2017-02-27 07:38:33 +01:00
|
|
|
/* let receivers unwind their nesting and stop with the next signal */
|
|
|
|
receiver_1.destruct = true;
|
|
|
|
receiver_2.destruct = true;
|
|
|
|
receiver_3.destruct = true;
|
|
|
|
|
|
|
|
/*
|
2017-12-07 00:02:39 +01:00
|
|
|
* 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.
|
2017-02-27 07:38:33 +01:00
|
|
|
*/
|
2017-12-07 00:02:39 +01:00
|
|
|
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");
|
2017-03-08 08:48:20 +01:00
|
|
|
|
|
|
|
/* wait until threads joined */
|
|
|
|
sender_1.join(); sender_2.join(), sender_3.join();
|
2017-12-07 00:02:39 +01:00
|
|
|
|
|
|
|
log("destructing ...");
|
2017-02-27 07:38:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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(); }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-17 12:58:00 +01:00
|
|
|
struct Main
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2017-02-27 07:38:33 +01:00
|
|
|
Env &env;
|
2017-06-13 13:06:01 +02:00
|
|
|
Signal_handler<Main> test_8_done { env.ep(), *this, &Main::handle_test_8_done };
|
2017-02-27 07:38:33 +01:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
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 { };
|
2017-06-13 13:06:01 +02:00
|
|
|
|
|
|
|
void handle_test_8_done()
|
2017-02-27 07:38:33 +01:00
|
|
|
{
|
2017-06-13 13:06:01 +02:00
|
|
|
test_8.destruct();
|
2017-02-27 07:38:33 +01:00
|
|
|
log("--- Signalling test finished ---");
|
2020-01-14 11:02:55 +01:00
|
|
|
env.parent().exit(0);
|
2017-02-27 07:38:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Main(Env &env) : env(env)
|
2017-01-17 12:58:00 +01:00
|
|
|
{
|
|
|
|
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();
|
2017-06-13 13:06:01 +02:00
|
|
|
test_8.construct(env, 8, test_8_done);
|
2017-02-16 19:46:11 +01:00
|
|
|
}
|
2017-01-17 12:58:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
void Component::construct(Genode::Env &env) { static Main main(env); }
|