os/test: transition to new base API

For all tests
* use Component::construct instead of main
* use new connection constructors with env argument
* use log instead of printf

For some tests
* replace signal receivers with signal handlers
* replace global static variables with Main class members
* remove unnecessary multithreading
* model test steps as classes that are independent from each other and managed
  by Main as constructibles
* use references instead of pointers and exceptions instead of error codes
* use Attached_* helpers intead of doing attach/detach manually
* use helpers like String, Id_space, Registry instead of arrays and lists
* make the run script suitable for automated execution and conclusion

Ref #1987
This commit is contained in:
Martin Stein 2017-01-17 12:58:00 +01:00 committed by Norman Feske
parent e0fef69cb3
commit ad2d1fe586
31 changed files with 1159 additions and 1499 deletions

View File

@ -54,7 +54,6 @@ set config {
<resource name="RAM" quantum="10M"/>
</start>
</config>
</config>
}
install_config $config
@ -74,5 +73,11 @@ set boot_modules {
}
build_boot_image $boot_modules
run_genode_until forever
run_genode_until {.*Round 04: A A.*\n.*Setting CPU frequency low.*\n.*Setting CPU frequency high.*\n.*Round 05: A A} 60
grep_output {^\[init -> test-cpufreq\] }
compare_output_to {
[init -> test-cpufreq] Setting CPU frequency low
[init -> test-cpufreq] Setting CPU frequency high
}

View File

@ -24,6 +24,12 @@ install_config {
<start name="loader">
<resource name="RAM" quantum="1M"/>
<provides><service name="Loader"/></provides>
<config>
<policy label_prefix="test-dynamic_config_loader">
<parent-rom name="test-dynamic_config"/>
<parent-rom name="ld.lib.so"/>
</policy>
</config>
</start>
<start name="test-dynamic_config_loader">
<resource name="RAM" quantum="10M"/>

View File

@ -69,19 +69,13 @@ install_config $config
# Boot modules
#
# generic modules
set boot_modules {
core ld.lib.so init timer
test-fb_bench
}
set boot_modules { core ld.lib.so init timer test-fb_bench }
# platform-specific modules
append_platform_drv_boot_modules
lappend_if [have_spec sdl] boot_modules fb_sdl
lappend_if [have_spec framebuffer] boot_modules fb_drv
lappend_if [have_spec sdl] boot_modules fb_sdl
lappend_if [have_spec framebuffer] boot_modules fb_drv
build_boot_image $boot_modules
run_genode_until forever
run_genode_until {.*--- Framebuffer benchmark finished ---.*\n} 30

View File

@ -30,13 +30,13 @@ build_boot_image "core ld.lib.so init test-ram_fs_chunk"
append qemu_args "-nographic -m 64"
run_genode_until {child "test-ram_fs_chunk" exited with exit value 0.*\n} 10
run_genode_until {.*--- RAM filesystem chunk test finished ---.*\n} 10
grep_output {^\[init -> test-ram_fs_chunk\]}
unify_output { sizeof=[0-9]+} {}
compare_output_to {
[init -> test-ram_fs_chunk] --- ram_fs_chunk test ---
[init -> test-ram_fs_chunk] --- RAM filesystem chunk test ---
[init -> test-ram_fs_chunk] chunk sizes
[init -> test-ram_fs_chunk] level 0: payload=120
[init -> test-ram_fs_chunk] level 1: payload=24
@ -77,6 +77,7 @@ compare_output_to {
[init -> test-ram_fs_chunk] trunc(2) -> content (size=2): "fi"
[init -> test-ram_fs_chunk] trunc(1) -> content (size=1): "f"
[init -> test-ram_fs_chunk] allocator: sum=0
[init -> test-ram_fs_chunk] --- RAM filesystem chunk test finished ---
}

View File

@ -25,43 +25,43 @@ build_boot_image "core ld.lib.so init test-reconstructible"
append qemu_args "-nographic -m 64"
run_genode_until {child "test-reconstructible" exited with exit value 0.*\n} 10
run_genode_until {.*--- Reconstructible utility test finished ---.*\n} 10
grep_output {-> test-reconstructible}
compare_output_to {
[init -> test-reconstructible] --- test-reconstructible started ---
[init -> test-reconstructible] --- Reconstructible utility test ---
[init -> test-reconstructible] construct Object 1
[init -> test-reconstructible] construct Object 2
[init -> test-reconstructible] -- create Compound object --
[init -> test-reconstructible] create Compound object
[init -> test-reconstructible] construct Member_with_reference
[init -> test-reconstructible] construct Compound
[init -> test-reconstructible] compound.member.constructed returns 1
[init -> test-reconstructible] compound.lazy_member.constructed returns 0
[init -> test-reconstructible] -- construct lazy member --
[init -> test-reconstructible] construct lazy member
[init -> test-reconstructible] construct Member_with_reference
[init -> test-reconstructible] compound.lazy_member.constructed returns 1
[init -> test-reconstructible] -- call method on member (with reference to Object 1) --
[init -> test-reconstructible] call method on member (with reference to Object 1)
[init -> test-reconstructible] const method called on Object 1
[init -> test-reconstructible] -- reconstruct member with Object 2 as reference --
[init -> test-reconstructible] reconstruct member with Object 2 as reference
[init -> test-reconstructible] destruct Member_with_reference
[init -> test-reconstructible] construct Member_with_reference
[init -> test-reconstructible] -- call method on member --
[init -> test-reconstructible] call method on member
[init -> test-reconstructible] const method called on Object 2
[init -> test-reconstructible] -- destruct member --
[init -> test-reconstructible] destruct member
[init -> test-reconstructible] destruct Member_with_reference
[init -> test-reconstructible] -- try to call method on member, catch exception --
[init -> test-reconstructible] try to call method on member, catch exception
[init -> test-reconstructible] got exception, as expected
[init -> test-reconstructible] -- destruct Compound and Objects 1 and 2 --
[init -> test-reconstructible] destruct Compound and Objects 1 and 2
[init -> test-reconstructible] destruct Compound
[init -> test-reconstructible] destruct Member_with_reference
[init -> test-reconstructible] destruct Object 2
[init -> test-reconstructible] destruct Object 1
[init -> test-reconstructible] -- construct Throwing object
[init -> test-reconstructible] construct Throwing object
[init -> test-reconstructible] construct Throwing -> don't throw
[init -> test-reconstructible] destruct Throwing
[init -> test-reconstructible] construct Throwing -> throw exception
[init -> test-reconstructible] -- catched exception as expected
[init -> test-reconstructible] --- test-reconstructible finished ---
[init -> test-reconstructible] got exception, as expected
[init -> test-reconstructible] --- Reconstructible utility test finished ---
}

View File

@ -1,9 +1,3 @@
#
# \brief Test for 'rom_blk' service
# \author Stefan Kalkowski
# \date 2011-05-10
#
build "core init server/rom_blk test/rom_blk"
create_boot_directory
@ -37,4 +31,4 @@ build_boot_image "core ld.lib.so init rom_blk test-rom_blk"
append qemu_args "-m 64 -nographic "
run_genode_until "all done, finished!" 10
run_genode_until {.*--- ROM Block test finished ---.*\n} 10

View File

@ -32,4 +32,4 @@ build_boot_image "core ld.lib.so init timer test-signal"
append qemu_args "-nographic -m 64"
run_genode_until {.*child "test-signal" exited with exit value 0.*} 200
run_genode_until {.*--- Signalling test finished ---.*\n} 200

View File

@ -25,14 +25,15 @@ build_boot_image "core ld.lib.so init test-synced_interface"
append qemu_args "-nographic -m 64"
run_genode_until {child "test-synced_interface" exited with exit value 0} 10
run_genode_until {.*--- Synced interface test finished ---.*\n} 10
grep_output {-> test-synced_interface}
compare_output_to {
[init -> test-synced_interface] --- Synced interface test ---
[init -> test-synced_interface] lock
[init -> test-synced_interface] adding 13 + 14
[init -> test-synced_interface] unlock
[init -> test-synced_interface] result is 27
[init -> test-synced_interface] --- Synced interface test finished ---
}

View File

@ -32,4 +32,4 @@ build_boot_image "core ld.lib.so init timer test-thread_join"
append qemu_args "-nographic -m 64"
run_genode_until {child "test-thread_join" exited with exit value 0.*\n} 10
run_genode_until {.*--- Thread join test finished ---.*\n} 10

View File

@ -54,4 +54,4 @@ build_boot_image $boot_modules
append qemu_args " -m 64 -nographic "
run_genode_until "end of timed-semaphore test" 10
run_genode_until {.*--- Timed semaphore test finished ---.*\n} 10

View File

@ -64,5 +64,4 @@ build_boot_image $boot_modules
append qemu_args " -nographic -serial mon:stdio -m 256 "
run_genode_until forever
#{.*child exited with exit value 0.* } 60
run_genode_until "--- test-trace finished ---" 30

View File

@ -1,42 +1,49 @@
/*
* \brief Test for changing the CPU frequency
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2013-06-14
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/log.h>
#include <base/env.h>
#include <base/sleep.h>
#include <base/component.h>
#include <regulator/consts.h>
#include <regulator_session/connection.h>
#include <timer_session/connection.h>
int main(int argc, char **argv)
using namespace Genode;
struct Main
{
using namespace Genode;
enum { PERIOD_US = 8 * 1000 * 1000 };
log("--- test-cpufreq started ---");
Env &env;
Timer::Connection timer { env };
Regulator::Connection cpu_regulator { env, Regulator::CLK_CPU };
Signal_handler<Main> timer_handler { env.ep(), *this, &Main::handle_timer };
bool high { true };
static Timer::Connection timer;
static Regulator::Connection cpu_regulator(Regulator::CLK_CPU);
bool high = true;
while (true) {
timer.msleep(10000);
void handle_timer()
{
log("Setting CPU frequency ", high ? "low" : "high");
cpu_regulator.level(high ? Regulator::CPU_FREQ_200
: Regulator::CPU_FREQ_1600);
cpu_regulator.level(high ? Regulator::CPU_FREQ_200 :
Regulator::CPU_FREQ_1600);
high = !high;
timer.trigger_once(PERIOD_US);
}
return 1;
}
Main(Env &env) : env(env)
{
timer.sigh(timer_handler);
timer.trigger_once(PERIOD_US);
}
};
void Component::construct(Env &env) { static Main main(env); }

View File

@ -12,53 +12,40 @@
*/
/* Genode includes */
#include <base/snprintf.h>
#include <base/sleep.h>
#include <timer_session/connection.h>
#include <loader_session/connection.h>
#include <base/component.h>
using namespace Genode;
enum { CONFIG_SIZE = 100 };
static Loader::Connection loader(8*1024*1024);
static void update_config(int counter)
struct Main
{
Dataspace_capability config_ds =
loader.alloc_rom_module("config", CONFIG_SIZE);
enum { CONFIG_SIZE = 100 };
char *config_ds_addr = env()->rm_session()->attach(config_ds);
Env &env;
int counter { -1 };
Loader::Connection loader { env, 8 * 1024 * 1024 };
Timer::Connection timer { env };
Signal_handler<Main> timer_handler { env.ep(), *this, &Main::handle_timer };
snprintf(config_ds_addr, CONFIG_SIZE,
"<config><counter>%d</counter></config>",
counter);
void handle_timer()
{
char *config_ds_addr =
env.rm().attach(loader.alloc_rom_module("config", CONFIG_SIZE));
env()->rm_session()->detach(config_ds_addr);
loader.commit_rom_module("config");
}
int main(int, char **)
{
update_config(-1);
loader.start("test-dynamic_config", "test-label");
/* update slave config at regular intervals */
int counter = 0;
for (;;) {
static Timer::Connection timer;
timer.msleep(250);
update_config(counter++);
String<100> config("<config><counter>", counter++, "</counter></config>");
strncpy(config_ds_addr, config.string(), CONFIG_SIZE);
env.rm().detach(config_ds_addr);
loader.commit_rom_module("config");
timer.trigger_once(250 * 1000);
}
sleep_forever();
Main(Env &env) : env(env)
{
timer.sigh(timer_handler);
handle_timer();
loader.start("test-dynamic_config", "test-label");
}
};
return 0;
}
void Component::construct(Env &env) { static Main main(env); }

View File

@ -1,49 +1,45 @@
/*
* \brief Test for changing configuration at runtime
* \author Norman Feske
* \author Martin Stein
* \date 2012-04-04
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <os/config.h>
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
using namespace Genode;
void parse_config()
struct Main
{
try {
long counter = 1;
Genode::config()->xml_node().sub_node("counter").value(&counter);
Genode::log("obtained counter value ", counter, " from config");
Env &env;
Attached_rom_dataspace config { env, "config" };
Signal_handler<Main> config_handler { env.ep(), *this, &Main::handle_config };
} catch (...) {
Genode::error("could not parse configuration");
void handle_config()
{
config.update();
try {
long counter = 1;
config.xml().sub_node("counter").value(&counter);
log("obtained counter value ", counter, " from config");
}
catch (...) { error("could not parse configuration"); }
}
}
int main(int, char **)
{
parse_config();
/* register signal handler for config changes */
Genode::Signal_receiver sig_rec;
Genode::Signal_context sig_ctx;
Genode::config()->sigh(sig_rec.manage(&sig_ctx));
for (;;) {
/* wait for config change */
sig_rec.wait_for_signal();
Genode::config()->reload();
parse_config();
Main(Env &env) : env(env)
{
handle_config();
config.sigh(config_handler);
}
return 0;
}
};
void Component::construct(Env &env) { static Main main(env); }

View File

@ -1,6 +1,7 @@
/*
* \brief Test for changing configuration at runtime (server-side)
* \author Norman Feske
* \author Martin Stein
* \date 2012-04-04
*
* This program provides a generated config file as ROM service. After
@ -8,65 +9,56 @@
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/signal.h>
#include <os/attached_ram_dataspace.h>
#include <os/static_root.h>
#include <timer_session/connection.h>
#include <rom_session/rom_session.h>
#include <cap_session/connection.h>
#include <base/component.h>
using namespace Genode;
/*
* The implementation of this class follows the lines of
* 'os/include/os/child_policy_dynamic_rom.h'.
*/
class Rom_session_component : public Genode::Rpc_object<Genode::Rom_session>
class Rom_session_component : public Rpc_object<Rom_session>
{
private:
Genode::Attached_ram_dataspace _fg;
Genode::Attached_ram_dataspace _bg;
bool _bg_has_pending_data;
Genode::Lock _lock;
Genode::Signal_context_capability _sigh;
Env &_env;
Attached_ram_dataspace _fg { _env.ram(), _env.rm(), 0 };
Attached_ram_dataspace _bg { _env.ram(), _env.rm(), 0 };
bool _bg_pending_data { false };
Signal_context_capability _sigh;
public:
/**
* Constructor
*/
Rom_session_component()
: _fg(0, 0), _bg(0, 0), _bg_has_pending_data(false) { }
Rom_session_component(Env &env) : _env(env) { }
/**
* Update the config file
*/
void configure(char const *data)
{
Genode::Lock::Guard guard(_lock);
Genode::size_t const data_len = Genode::strlen(data) + 1;
size_t const data_len = strlen(data) + 1;
/* let background buffer grow if needed */
if (_bg.size() < data_len)
_bg.realloc(Genode::env()->ram_session(), data_len);
_bg.realloc(&_env.ram(), data_len);
Genode::strncpy(_bg.local_addr<char>(), data, data_len);
_bg_has_pending_data = true;
strncpy(_bg.local_addr<char>(), data, data_len);
_bg_pending_data = true;
/* inform client about the changed data */
if (_sigh.valid())
Genode::Signal_transmitter(_sigh).submit();
Signal_transmitter(_sigh).submit();
}
@ -74,67 +66,51 @@ class Rom_session_component : public Genode::Rpc_object<Genode::Rom_session>
** ROM session interface **
***************************/
Genode::Rom_dataspace_capability dataspace()
Rom_dataspace_capability dataspace() override
{
Genode::Lock::Guard guard(_lock);
if (!_fg.size() && !_bg_has_pending_data) {
Genode::error("no data loaded");
return Genode::Rom_dataspace_capability();
if (!_fg.size() && !_bg_pending_data) {
error("no data loaded");
return Rom_dataspace_capability();
}
/*
* Keep foreground if no background exists. Otherwise, use old
* background as new foreground.
*/
if (_bg_has_pending_data) {
if (_bg_pending_data) {
_fg.swap(_bg);
_bg_has_pending_data = false;
_bg_pending_data = false;
}
Genode::Dataspace_capability ds_cap = _fg.cap();
return Genode::static_cap_cast<Genode::Rom_dataspace>(ds_cap);
Dataspace_capability ds_cap = _fg.cap();
return static_cap_cast<Rom_dataspace>(ds_cap);
}
void sigh(Genode::Signal_context_capability sigh_cap)
{
Genode::Lock::Guard guard(_lock);
_sigh = sigh_cap;
}
void sigh(Signal_context_capability sigh_cap) override { _sigh = sigh_cap; }
};
int main(int argc, char **argv)
struct Main
{
using namespace Genode;
enum { STACK_SIZE = 2 * 1024 * sizeof(addr_t) };
/* connection to capability service needed to create capabilities */
static Cap_connection cap;
Env &env;
Rom_session_component rom_session { env };
Static_root<Rom_session> rom_root { env.ep().manage(rom_session) };
int counter { -1 };
Timer::Connection timer { env };
Signal_handler<Main> timer_handler { env.ep(), *this, &Main::handle_timer };
enum { STACK_SIZE = 8*1024 };
static Rpc_entrypoint ep(&cap, STACK_SIZE, "rom_ep");
static Rom_session_component rom_session;
static Static_root<Rom_session> rom_root(ep.manage(&rom_session));
rom_session.configure("<config><counter>-1</counter></config>");
/* announce server */
env()->parent()->announce(ep.manage(&rom_root));
int counter = 0;
for (;;) {
static Timer::Connection timer;
timer.msleep(250);
/* re-generate configuration */
char buf[100];
Genode::snprintf(buf, sizeof(buf),
"<config><counter>%d</counter></config>",
counter++);
rom_session.configure(buf);
void handle_timer()
{
String<100> config("<config><counter>", counter++, "</counter></config>");
rom_session.configure(config.string());
timer.trigger_once(250 * 1000);
}
Main(Env &env) : env(env)
{
timer.sigh(timer_handler);
handle_timer();
env.parent().announce(env.ep().manage(rom_root));
}
return 0;
};
void Component::construct(Env &env) { static Main main(env); }

View File

@ -1,138 +1,141 @@
/*
* \brief Framebuffer throughput test
* \author Norman Feske
* \author Martin Stein
* \date 2015-06-05
*/
/*
* Copyright (C) 2012-2014 Genode Labs GmbH
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/env.h>
#include <base/printf.h>
#include <base/component.h>
#include <base/heap.h>
#include <os/attached_dataspace.h>
#include <blit/blit.h>
#include <framebuffer_session/connection.h>
#include <timer_session/connection.h>
using namespace Genode;
static unsigned long now_ms()
struct Test
{
static Timer::Connection timer;
return timer.elapsed_ms();
}
enum { DURATION_MS = 2000 };
Env &env;
int id;
Timer::Connection timer { env };
Heap heap { env.ram(), env.rm() };
Framebuffer::Connection fb { env, Framebuffer::Mode() };
Attached_dataspace fb_ds { env.rm(), fb.dataspace() };
Framebuffer::Mode const fb_mode { fb.mode() };
char *buf[2];
int main(int argc, char **argv)
Test(Env &env, int id, char const *brief) : env(env), id(id)
{
log("\nTEST ", id, ": ", brief, "\n");
for (unsigned i = 0; i < 2; i++) {
if (!heap.alloc(fb_ds.size(), (void **)&buf[i])) {
env.parent().exit(-1); }
}
/* fill one memory buffer with white pixels */
memset(buf[1], ~0, fb_ds.size());
}
void conclusion(unsigned kib, unsigned start_ms, unsigned end_ms) {
log("throughput: ", kib / (end_ms - start_ms), " MiB/sec"); }
~Test() { log("\nTEST ", id, " finished\n"); }
};
struct Bytewise_ram_test : Test
{
using namespace Genode;
static constexpr char const *brief = "byte-wise memcpy from RAM to RAM";
printf("--- test-fb_bench started ---\n");
static Framebuffer::Connection fb;
static Attached_dataspace fb_ds(fb.dataspace());
static Framebuffer::Mode const fb_mode = fb.mode();
/*
* Allocate two memory buffers as big as the framebuffer.
*/
char *src_buf[2];
for (unsigned i = 0; i < 2; i++)
src_buf[i] = (char *)env()->heap()->alloc(fb_ds.size());
/* duration of individual test, in milliseconds */
unsigned long duration_ms = 2000;
printf("byte-wise memcpy from RAM to RAM...\n");
Bytewise_ram_test(Env &env, int id) : Test(env, id, brief)
{
unsigned long transferred_kib = 0;
unsigned long const start_ms = now_ms();
for (; now_ms() - start_ms < duration_ms;) {
memcpy(src_buf[0], src_buf[1], fb_ds.size());
transferred_kib += fb_ds.size() / 1024;
unsigned kib = 0;
unsigned const start_ms = timer.elapsed_ms();
for (; timer.elapsed_ms() - start_ms < DURATION_MS;) {
memcpy(buf[0], buf[1], fb_ds.size());
kib += fb_ds.size() / 1024;
}
unsigned long const end_ms = now_ms();
printf("-> %ld MiB/sec\n",
(transferred_kib)/(end_ms - start_ms));
conclusion(kib, start_ms, timer.elapsed_ms());
}
};
/*
* Fill one memory buffer with white pixels.
*/
memset(src_buf[1], ~0, fb_ds.size());
struct Bytewise_fb_test : Test
{
static constexpr char const *brief = "byte-wise memcpy from RAM to FB";
printf("byte-wise memcpy from RAM to framebuffer...\n");
Bytewise_fb_test(Env &env, int id) : Test(env, id, brief)
{
unsigned long transferred_kib = 0;
unsigned long const start_ms = now_ms();
for (unsigned i = 0; now_ms() - start_ms < duration_ms; i++) {
memcpy(fb_ds.local_addr<char>(), src_buf[i % 2], fb_ds.size());
transferred_kib += fb_ds.size() / 1024;
unsigned kib = 0;
unsigned const start_ms = timer.elapsed_ms();
for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) {
memcpy(fb_ds.local_addr<char>(), buf[i % 2], fb_ds.size());
kib += fb_ds.size() / 1024;
}
unsigned long const end_ms = now_ms();
printf("-> %ld MiB/sec\n",
(transferred_kib)/(end_ms - start_ms));
conclusion(kib, start_ms, timer.elapsed_ms());
}
};
/*
* Blitting via the blit library from RAM to framebuffer
*/
printf("copy via blit library from RAM to framebuffer...\n");
struct Blit_test : Test
{
static constexpr char const *brief = "copy via blit library from RAM to FB";
Blit_test(Env &env, int id) : Test(env, id, brief)
{
unsigned long transferred_kib = 0;
unsigned long const start_ms = now_ms();
/* line width in bytes */
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
unsigned const h = fb_mode.height();
for (unsigned i = 0; now_ms() - start_ms < duration_ms; i++) {
blit(src_buf[i % 2], w, fb_ds.local_addr<char>(), w, w, h);
transferred_kib += (w*h) / 1024;
unsigned kib = 0;
unsigned const start_ms = timer.elapsed_ms();
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
unsigned const h = fb_mode.height();
for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) {
blit(buf[i % 2], w, fb_ds.local_addr<char>(), w, w, h);
kib += (w * h) / 1024;
}
unsigned long const end_ms = now_ms();
printf("-> %ld MiB/sec\n",
(transferred_kib)/(end_ms - start_ms));
conclusion(kib, start_ms, timer.elapsed_ms());
}
};
/*
* Unaligned blitting via the blit library from RAM to framebuffer
*/
printf("unaligned copy via blit library from RAM to framebuffer...\n");
struct Unaligned_blit_test : Test
{
static constexpr char const *brief = "unaligned copy via blit library from RAM to FB";
Unaligned_blit_test(Env &env, int id) : Test(env, id, brief)
{
unsigned long transferred_kib = 0;
unsigned long const start_ms = now_ms();
/* line width in bytes */
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
unsigned const h = fb_mode.height();
for (unsigned i = 0; now_ms() - start_ms < duration_ms; i++) {
blit(src_buf[i % 2] + 2, w, fb_ds.local_addr<char>() + 2, w, w - 2, h);
transferred_kib += (w*h) / 1024;
unsigned kib = 0;
unsigned const start_ms = timer.elapsed_ms();
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
unsigned const h = fb_mode.height();
for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) {
blit(buf[i % 2] + 2, w, fb_ds.local_addr<char>() + 2, w, w - 2, h);
kib += (w * h) / 1024;
}
unsigned long const end_ms = now_ms();
printf("-> %ld MiB/sec\n",
(transferred_kib)/(end_ms - start_ms));
conclusion(kib, start_ms, timer.elapsed_ms());
}
};
printf("--- test-fb_bench finished ---\n");
return 0;
}
struct Main
{
Constructible<Bytewise_ram_test> test_1;
Constructible<Bytewise_fb_test> test_2;
Constructible<Blit_test> test_3;
Constructible<Unaligned_blit_test> test_4;
Main(Env &env)
{
log("--- Framebuffer benchmark ---");
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();
log("--- Framebuffer benchmark finished ---");
}
};
void Component::construct(Env &env) { static Main main(env); }

View File

@ -5,22 +5,20 @@
*/
/*
* Copyright (C) 2010-2016 Genode Labs GmbH
* Copyright (C) 2010-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/component.h>
#include <base/env.h>
#include <base/log.h>
#include <timer_session/connection.h>
#include <input_session/connection.h>
#include <input/event.h>
using namespace Genode;
static char const * ev_type(Input::Event::Type type)
{
switch (type) {
@ -47,62 +45,42 @@ static char const * key_name(Input::Event const &ev)
}
class Test_environment
struct Main
{
private:
Env &env;
Input::Connection input { env };
Signal_handler<Main> input_sigh { env.ep(), *this, &Main::handle_input };
unsigned event_cnt { 0 };
Genode::Env &_env;
void handle_input();
Input::Connection _input;
Genode::Signal_handler<Test_environment> _input_sigh;
unsigned int event_count = 0;
void _handle_input();
public:
Test_environment(Genode::Env &env)
: _env(env),
_input_sigh(env.ep(), *this, &Test_environment::_handle_input)
{
log("--- Input test is up ---");
_input.sigh(_input_sigh);
}
Main(Env &env) : env(env)
{
log("--- Input test ---");
input.sigh(input_sigh);
}
};
void Test_environment::_handle_input()
void Main::handle_input()
{
/*
* Handle input events
*/
int key_cnt = 0;
_input.for_each_event([&] (Input::Event const &ev) {
event_count++;
input.for_each_event([&] (Input::Event const &ev) {
event_cnt++;
if (ev.type() == Input::Event::PRESS) key_cnt++;
if (ev.type() == Input::Event::RELEASE) key_cnt--;
/* log event */
log("Input event #", event_count, "\t"
log("Input event #", event_cnt, "\t"
"type=", ev_type(ev.type()), "\t"
"code=", ev.code(), "\t"
"rx=", ev.rx(), "\t"
"ry=", ev.ry(), "\t"
"ax=", ev.ax(), "\t"
"ay=", ev.ay(), "\t"
"key_cnt=", key_cnt, "\t", key_name(ev));
"key_cnt=", key_cnt, "\t", key_name(ev));
});
}
void Component::construct(Genode::Env &env)
{
using namespace Genode;
log("--- Test input ---\n");
static Test_environment te(env);
}
void Component::construct(Env &env) { static Main main(env); }

View File

@ -61,7 +61,7 @@ struct Test::Base
enum { BUF_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE * 128 };
Nic::Connection _nic { &_tx_block_alloc, BUF_SIZE, BUF_SIZE };
Nic::Connection _nic { _env, &_tx_block_alloc, BUF_SIZE, BUF_SIZE };
void _handle_nic() { if (!_done) handle_nic(); }

View File

@ -1,152 +1,137 @@
/*
* \brief Unit test for RAM fs chunk data structure
* \author Norman Feske
* \author Martin Stein
* \date 2012-04-19
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/env.h>
#include <base/log.h>
#include <base/heap.h>
#include <base/component.h>
#include <ram_fs/chunk.h>
namespace File_system {
typedef Chunk<2> Chunk_level_3;
typedef Chunk_index<3, Chunk_level_3> Chunk_level_2;
typedef Chunk_index<4, Chunk_level_2> Chunk_level_1;
typedef Chunk_index<5, Chunk_level_1> Chunk_level_0;
}
using namespace File_system;
using namespace Genode;
using Chunk_level_3 = Chunk<2>;
using Chunk_level_2 = Chunk_index<3, Chunk_level_3>;
using Chunk_level_1 = Chunk_index<4, Chunk_level_2>;
namespace Genode {
struct Chunk_level_0 : Chunk_index<5, Chunk_level_1>
{
Chunk_level_0(Allocator &alloc, seek_off_t off) : Chunk_index(alloc, off) { }
struct Allocator_tracer : Allocator
void print(Output &out) const
{
struct Alloc
{
using Id = Id_space<Alloc>::Id;
static char read_buf[Chunk_level_0::SIZE];
if (used_size() > Chunk_level_0::SIZE) {
throw Index_out_of_range(); }
Id_space<Alloc>::Element id_space_elem;
size_t size;
Alloc(Id_space<Alloc> &space, Id id, size_t size)
: id_space_elem(*this, space, id), size(size) { }
};
Id_space<Alloc> _allocs;
size_t _sum;
Allocator &_wrapped;
Allocator_tracer(Allocator &wrapped) : _sum(0), _wrapped(wrapped) { }
size_t sum() const { return _sum; }
bool alloc(size_t size, void **out_addr)
{
_sum += size;
bool result = _wrapped.alloc(size, out_addr);
new (_wrapped) Alloc(_allocs, Alloc::Id { (addr_t)*out_addr }, size);
return result;
read(read_buf, used_size(), 0);
Genode::print(out, "content (size=", used_size(), "): ");
Genode::print(out, "\"");
for (unsigned i = 0; i < used_size(); i++) {
char const c = read_buf[i];
if (c) {
Genode::print(out, Char(c)); }
else {
Genode::print(out, "."); }
}
void free(void *addr, size_t size)
{
_allocs.apply<Alloc>(Alloc::Id { (addr_t)addr }, [&] (Alloc &alloc) {
_sum -= alloc.size;
destroy(_wrapped, &alloc);
_wrapped.free(addr, size);
});
}
size_t overhead(size_t size) const override { return _wrapped.overhead(size); }
bool need_size_for_free() const override { return _wrapped.need_size_for_free(); }
};
Genode::print(out, "\"");
}
};
namespace Genode {
/**
* Helper for the formatted output of a chunk state
*/
static inline void print(Output &out, File_system::Chunk_level_0 const &chunk)
struct Allocator_tracer : Allocator
{
struct Alloc
{
using namespace File_system;
static char read_buf[Chunk_level_0::SIZE];
size_t used_size = chunk.used_size();
struct File_size_out_of_bounds { };
if (used_size > Chunk_level_0::SIZE)
throw File_size_out_of_bounds();
chunk.read(read_buf, used_size, 0);
Genode::print(out, "content (size=", used_size, "): ");
using Id = Id_space<Alloc>::Id;
Genode::print(out, "\"");
for (unsigned i = 0; i < used_size; i++) {
char const c = read_buf[i];
if (c)
Genode::print(out, Genode::Char(c));
else
Genode::print(out, ".");
Id_space<Alloc>::Element id_space_elem;
size_t size;
Alloc(Id_space<Alloc> &space, Id id, size_t size)
: id_space_elem(*this, space, id), size(size) { }
};
Id_space<Alloc> allocs;
size_t sum { 0 };
Allocator &wrapped;
Allocator_tracer(Allocator &wrapped) : wrapped(wrapped) { }
bool alloc(size_t size, void **out_addr) override
{
sum += size;
bool result = wrapped.alloc(size, out_addr);
new (wrapped) Alloc(allocs, Alloc::Id { (addr_t)*out_addr }, size);
return result;
}
void free(void *addr, size_t size) override
{
allocs.apply<Alloc>(Alloc::Id { (addr_t)addr }, [&] (Alloc &alloc) {
sum -= alloc.size;
destroy(wrapped, &alloc);
wrapped.free(addr, size);
});
}
size_t overhead(size_t size) const override { return wrapped.overhead(size); }
bool need_size_for_free() const override { return wrapped.need_size_for_free(); }
};
struct Main
{
Env &env;
Heap heap { env.ram(), env.rm() };
Allocator_tracer alloc { heap };
Main(Env &env) : env(env)
{
log("--- RAM filesystem chunk test ---");
log("chunk sizes");
log(" level 0: payload=", (int)Chunk_level_0::SIZE, " sizeof=", sizeof(Chunk_level_0));
log(" level 1: payload=", (int)Chunk_level_1::SIZE, " sizeof=", sizeof(Chunk_level_1));
log(" level 2: payload=", (int)Chunk_level_2::SIZE, " sizeof=", sizeof(Chunk_level_2));
log(" level 3: payload=", (int)Chunk_level_3::SIZE, " sizeof=", sizeof(Chunk_level_3));
{
Chunk_level_0 chunk(alloc, 0);
write(chunk, "five-o-one", 0);
/* overwrite part of the file */
write(chunk, "five", 7);
/* write to position beyond current file length */
write(chunk, "Nuance", 17);
write(chunk, "YM-2149", 35);
truncate(chunk, 30);
for (unsigned i = 29; i > 0; i--)
truncate(chunk, i);
}
Genode::print(out, "\"");
log("allocator: sum=", alloc.sum);
log("--- RAM filesystem chunk test finished ---");
}
}
static void write(File_system::Chunk_level_0 &chunk,
char const *str, Genode::off_t seek_offset)
{
chunk.write(str, Genode::strlen(str), seek_offset);
Genode::log("write \"", str, "\" at offset ", seek_offset, " -> ", chunk);
}
static void truncate(File_system::Chunk_level_0 &chunk,
File_system::file_size_t size)
{
chunk.truncate(size);
Genode::log("trunc(", size, ") -> ", chunk);
}
int main(int, char **)
{
using namespace File_system;
using namespace Genode;
log("--- ram_fs_chunk test ---");
log("chunk sizes");
log(" level 0: payload=", (int)Chunk_level_0::SIZE, " sizeof=", sizeof(Chunk_level_0));
log(" level 1: payload=", (int)Chunk_level_1::SIZE, " sizeof=", sizeof(Chunk_level_1));
log(" level 2: payload=", (int)Chunk_level_2::SIZE, " sizeof=", sizeof(Chunk_level_2));
log(" level 3: payload=", (int)Chunk_level_3::SIZE, " sizeof=", sizeof(Chunk_level_3));
static Allocator_tracer alloc(*env()->heap());
void write(Chunk_level_0 &chunk, char const *str, off_t seek_offset)
{
Chunk_level_0 chunk(alloc, 0);
write(chunk, "five-o-one", 0);
/* overwrite part of the file */
write(chunk, "five", 7);
/* write to position beyond current file length */
write(chunk, "Nuance", 17);
write(chunk, "YM-2149", 35);
truncate(chunk, 30);
for (unsigned i = 29; i > 0; i--)
truncate(chunk, i);
chunk.write(str, strlen(str), seek_offset);
log("write \"", str, "\" at offset ", seek_offset, " -> ", chunk);
}
log("allocator: sum=", alloc.sum());
void truncate(Chunk_level_0 &chunk, file_size_t size)
{
chunk.truncate(size);
log("trunc(", size, ") -> ", chunk);
}
};
return 0;
}
void Component::construct(Env &env) { struct Main main(env); }

View File

@ -13,26 +13,16 @@
/* Genode includes */
#include <util/reconstructible.h>
#include <base/log.h>
using Genode::Reconstructible;
using Genode::Constructible;
using Genode::log;
#include <base/component.h>
using namespace Genode;
struct Object
{
unsigned const id;
Object(unsigned id) : id(id)
{
log("construct Object ", id);
}
~Object()
{
log("destruct Object ", id);
}
Object(unsigned id) : id(id) { log("construct Object ", id); }
~Object() { log("destruct Object ", id); }
void method() { log("method called on Object ", id); }
void const_method() const { log("const method called on Object ", id); }
@ -41,38 +31,25 @@ struct Object
struct Member_with_reference
{
Object &reference;
Object &reference;
int const c = 13;
const int c = 13;
Member_with_reference(Object &reference) : reference(reference) {
log("construct Member_with_reference"); }
Member_with_reference(Object &reference) : reference(reference)
{
log("construct Member_with_reference");
}
~Member_with_reference()
{
log("destruct Member_with_reference");
}
~Member_with_reference() { log("destruct Member_with_reference"); }
};
struct Compound
{
Reconstructible<Member_with_reference> member;
Constructible<Member_with_reference> lazy_member;
Reconstructible<Member_with_reference> member;
Constructible<Member_with_reference> lazy_member;
Compound(Object &object)
:
member(object)
{
log("construct Compound");
}
Compound(Object &object) : member(object) {
log("construct Compound"); }
~Compound()
{
log("destruct Compound");
}
~Compound() { log("destruct Compound"); }
};
@ -94,79 +71,68 @@ struct Throwing
log("construct Throwing -> throw exception");
throw -1;
} else {
log("construct Throwing -> don't throw");
}
log("construct Throwing -> don't throw"); }
}
virtual ~Throwing()
{
log("destruct Throwing");
}
virtual ~Throwing() { log("destruct Throwing"); }
};
static void call_const_method(Compound const &compound)
struct Main
{
compound.member->reference.const_method();
}
int main(int, char **)
{
using namespace Genode;
log("--- test-reconstructible started ---");
void call_const_method(Compound const &compound) {
compound.member->reference.const_method(); }
Main(Env &env)
{
Object object_1(1);
Object object_2(2);
log("--- Reconstructible utility test ---");
{
Object object_1(1);
Object object_2(2);
log("-- create Compound object --");
Compound compound(object_1);
log("create Compound object");
Compound compound(object_1);
log("compound.member.constructed returns ",
compound.member.constructed());
log("compound.lazy_member.constructed returns ",
compound.lazy_member.constructed());
log("compound.member.constructed returns ",
compound.member.constructed());
log("compound.lazy_member.constructed returns ",
compound.lazy_member.constructed());
log("-- construct lazy member --");
compound.lazy_member.construct(object_2);
log("compound.lazy_member.constructed returns ",
compound.lazy_member.constructed());
log("construct lazy member");
compound.lazy_member.construct(object_2);
log("compound.lazy_member.constructed returns ",
compound.lazy_member.constructed());
log("-- call method on member (with reference to Object 1) --");
call_const_method(compound);
log("call method on member (with reference to Object 1)");
call_const_method(compound);
log("-- reconstruct member with Object 2 as reference --");
compound.member.construct(object_2);
log("reconstruct member with Object 2 as reference");
compound.member.construct(object_2);
log("-- call method on member --");
call_const_method(compound);
log("call method on member");
call_const_method(compound);
log("-- destruct member --");
compound.member.destruct();
log("destruct member");
compound.member.destruct();
log("-- try to call method on member, catch exception --");
log("try to call method on member, catch exception");
try { call_const_method(compound); }
catch (typename Reconstructible<Member_with_reference>::Deref_unconstructed_object) {
log("got exception, as expected"); }
log("destruct Compound and Objects 1 and 2");
}
try {
call_const_method(compound); }
catch (typename Reconstructible<Member_with_reference>::Deref_unconstructed_object) {
log("construct Throwing object");
Bool const b_false(false), b_true(true);
Reconstructible<Throwing> inst(b_false);
inst.construct(b_true);
Genode::error("expected contructor to throw");
} catch (int i) {
log("got exception, as expected"); }
log("-- destruct Compound and Objects 1 and 2 --");
log("--- Reconstructible utility test finished ---");
}
};
try {
log("-- construct Throwing object");
Bool const b_false(false), b_true(true);
Reconstructible<Throwing> inst(b_false);
inst.construct(b_true);
Genode::error("expected contructor to throw");
} catch (int i) {
log("-- catched exception as expected");
}
log("--- test-reconstructible finished ---");
return 0;
}
void Component::construct(Env &env) { static Main main(env); }

View File

@ -1,6 +1,7 @@
/*
* \brief Rom-file to block-session client test implementation
* \brief ROM-file to block-session client test implementation
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2010-07-07
*
* The test program compares the values delivered by the block-service,
@ -8,120 +9,72 @@
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
* Copyright (C) 2010-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/allocator_avl.h>
#include <base/log.h>
#include <base/sleep.h>
#include <base/exception.h>
#include <base/thread.h>
#include <os/config.h>
#include <base/heap.h>
#include <base/component.h>
#include <block_session/connection.h>
#include <rom_session/connection.h>
#include <base/attached_rom_dataspace.h>
using namespace Genode;
class Comparer : public Genode::Thread_deprecated<8192>
struct Main
{
private:
enum { REQ_PARALLEL = 10 };
Block::Connection _blk_con;
Genode::Rom_connection _rom;
Genode::addr_t _addr;
using File_name = String<64>;
using Packet_descriptor = Block::Packet_descriptor;
struct Files_differ : Exception { };
struct Device_not_readable : Exception { };
struct Read_request_failed : Exception { };
class Block_file_differ : Genode::Exception {};
Env &env;
Attached_rom_dataspace config { env, "config" };
File_name file_name { config.xml().attribute_value("file", File_name()) };
Heap heap { env.ram(), env.rm() };
Allocator_avl block_alloc { &heap };
Block::Connection block { env, &block_alloc };
Attached_rom_dataspace rom { env, file_name.string() };
public:
Main(Env &env) : env(env)
{
log("--- ROM Block test ---");
enum {
BLOCK_REQ_PARALLEL = 10 /* number of blocks to handle per block-request */
};
Block::Session::Tx::Source &src = *block.tx();
size_t blk_sz;
Block::sector_t blk_cnt;
Block::Session::Operations ops;
Comparer(Genode::Allocator_avl *block_alloc,
const char* filename)
: Thread_deprecated("comparer"), _blk_con(block_alloc), _rom(filename),
_addr(Genode::env()->rm_session()->attach(_rom.dataspace())) { }
block.info(&blk_cnt, &blk_sz, &ops);
if (!ops.supported(Packet_descriptor::READ)) {
throw Device_not_readable(); }
void entry()
{
using namespace Genode;
log("We have ", blk_cnt, " blocks with a size of ", blk_sz, " bytes");
for (size_t i = 0; i < blk_cnt; i += REQ_PARALLEL) {
size_t cnt = (blk_cnt - i > REQ_PARALLEL) ? REQ_PARALLEL : blk_cnt - i;
Packet_descriptor pkt(src.alloc_packet(cnt * blk_sz),
Packet_descriptor::READ, i, cnt);
Block::Session::Tx::Source *source = _blk_con.tx();
size_t blk_size = 0;
Block::sector_t blk_cnt = 0;
Genode::addr_t end =
_addr + Dataspace_client(_rom.dataspace()).size();
Block::Session::Operations ops;
_blk_con.info(&blk_cnt, &blk_size, &ops);
log("Check blocks ", i, "..", i + cnt - 1);
src.submit_packet(pkt);
pkt = src.get_acked_packet();
if (!pkt.succeeded()) {
throw Read_request_failed(); }
if (!ops.supported(Block::Packet_descriptor::READ)) {
error("Block device not readable!");
}
char const *rom_src = rom.local_addr<char>() + i * blk_sz;
if (strcmp(rom_src, src.packet_content(pkt), rom.size())) {
throw Files_differ(); }
log("We have ", blk_cnt, " blocks with a "
"size of ", Hex(blk_size), " bytes");
for (size_t i = 0; i < blk_cnt; i += BLOCK_REQ_PARALLEL) {
try {
size_t cnt = (blk_cnt - i > BLOCK_REQ_PARALLEL)
? BLOCK_REQ_PARALLEL : blk_cnt - i;
Block::Packet_descriptor p(source->alloc_packet(cnt * blk_size),
Block::Packet_descriptor::READ, i, cnt);
source->submit_packet(p);
p = source->get_acked_packet();
if (!p.succeeded()) {
error("could not read block ", Hex(i), "-", Hex(i + cnt));
return;
}
char* blk_src = source->packet_content(p);
char* rom_src = (char*) _addr + i * blk_size;
bool differ = false;
for (size_t j = 0; j < cnt; j++)
for (size_t k = 0; k < blk_size; k++) {
if (&rom_src[j*blk_size+k] >= (char*)end) {
error("end of image file reached!");
return;
}
if (blk_src[j*blk_size+k] != rom_src[j*blk_size+k])
differ = true;
}
if (differ) {
warning("block ", i, " differs!");
throw Block_file_differ();
}
source->release_packet(p);
} catch (Block::Session::Tx::Source::Packet_alloc_failed) {
error("Mmh, strange we run out of packets");
return;
}
}
log("all done, finished!");
src.release_packet(pkt);
}
log("--- ROM Block test finished ---");
}
};
int main(int argc, char **argv)
{
using namespace Genode;
log("--- Block session test ---");
try {
static char filename[64];
config()->xml_node().attribute("file").value(filename, sizeof(filename));
Allocator_avl block_alloc(env()->heap());
Comparer th(&block_alloc, filename);
th.start();
sleep_forever();
} catch (Rom_connection::Rom_connection_failed) {
error("config file or file given by <filename> tag is missing.");
}
log("An error occured, exit now ...");
return -1;
}
void Component::construct(Env &env) { static Main main(env); }

View File

@ -13,11 +13,11 @@
#include <base/component.h>
#include <base/env.h>
#include <base/log.h>
#include <base/printf.h>
#include <rtc_session/connection.h>
#include <timer_session/connection.h>
using namespace Genode;
struct Main
{
Main(Genode::Env &env)
@ -31,9 +31,8 @@ struct Main
for (unsigned i = 0; i < 4; ++i) {
Rtc::Timestamp now = rtc.current_time();
Genode::printf("RTC: %u-%02u-%02u %02u:%02u:%02u\n",
now.year, now.month, now.day,
now.hour, now.minute, now.second);
log("RTC: ", now.year, "-", now.month, "-", now.day, " ",
now.hour, ":", now.minute, ":", now.second);
timer.msleep(1000);
}

View File

@ -16,7 +16,7 @@
#include <base/component.h>
#include <timer_session/connection.h>
#include <os/attached_ram_dataspace.h>
#include <os/config.h>
#include <base/attached_rom_dataspace.h>
/* local includes */
#include <driver.h>
@ -51,14 +51,14 @@ struct Main
Env &env;
Packet_descriptor pkt;
unsigned long time_before_ms;
Timer::Connection timer;
Timer::Connection timer { env };
Operation operation { READ };
Signal_handler<Main> ack_handler { env.ep(), *this, &Main::update_state };
Driver_session drv_session { ack_handler };
Sd_card::Driver drv { env };
size_t const buf_size_kib { config()->xml_node()
.attribute_value("buffer_size_kib",
(size_t)0) };
size_t const buf_size_kib { Attached_rom_dataspace(env, "config")
.xml().attribute_value("buffer_size_kib",
(size_t)0) };
size_t const buf_size { buf_size_kib * 1024 };
Attached_ram_dataspace buf { &env.ram(), buf_size, UNCACHED };
char *buf_virt { buf.local_addr<char>() };

View File

@ -1,142 +1,100 @@
/*
* \brief Test for signalling framework
* \author Norman Feske
* \author Martin Stein
* \date 2008-09-06
*/
/*
* Copyright (C) 2008-2013 Genode Labs GmbH
* 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 General Public License version 2.
*/
/* Genode includes */
#include <base/component.h>
#include <base/heap.h>
#include <base/log.h>
#include <base/signal.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <base/registry.h>
#include <timer_session/connection.h>
#include <util/misc_math.h>
using namespace Genode;
/**
* Transmit signals in a periodic fashion
* A thread that submits a signal context in a periodic fashion
*/
class Sender : Thread
{
private:
Timer::Connection _timer; /* timer connection for local use */
Timer::Connection _timer;
Signal_transmitter _transmitter;
unsigned const _interval_ms; /* interval between signals in milliseconds */
bool _stop; /* state for destruction protocol */
unsigned _submit_cnt; /* statistics */
bool _idle; /* suppress the submission of signals */
bool const _verbose; /* print activities */
unsigned const _interval_ms;
bool const _verbose;
bool _stop { false };
unsigned _submit_cnt { 0 };
bool _idle { false };
/**
* Sender thread submits signals every '_interval_ms' milliseconds
*/
void entry()
{
while (!_stop) {
if (!_idle) {
_submit_cnt++;
if (_verbose)
log("submit signal ", _submit_cnt);
if (_verbose) {
log("submit signal ", _submit_cnt); }
_transmitter.submit();
if (_interval_ms)
_timer.msleep(_interval_ms);
} else
_timer.msleep(100);
if (_interval_ms) {
_timer.msleep(_interval_ms); }
} else {
_timer.msleep(100); }
}
}
public:
/**
* Constructor
*
* \param context signal destination
* \param interval_ms interval between signals
* \param verbose print status information
*/
Sender(Env &env, Signal_context_capability context,
unsigned interval_ms, bool verbose = true)
Sender(Env &env,
Signal_context_capability context,
unsigned interval_ms,
bool verbose)
:
Thread(env, "sender", 4096*sizeof(long)),
_timer(env),
_transmitter(context),
_interval_ms(interval_ms),
_stop(false),
_submit_cnt(0),
_idle(0),
_verbose(verbose)
Thread(env, "sender", 4096 * sizeof(addr_t)), _timer(env),
_transmitter(context), _interval_ms(interval_ms), _verbose(verbose)
{
/* start thread at 'entry' function */
start();
Thread::start();
}
/**
* Destructor
*/
~Sender()
{
/* tell thread to stop iterating */
_stop = true;
/***************
** Accessors **
***************/
/* wait for current 'msleep' call of the thread to finish */
_timer.msleep(0);
}
/**
* Suppress the transmission of further signals
*/
void idle(bool idle = true) { _idle = idle; }
/**
* Return total number of submitted notifications
*/
unsigned submit_cnt() { return _submit_cnt; }
void idle(bool idle) { _idle = idle; }
unsigned submit_cnt() const { return _submit_cnt; }
};
/**
* Signal handler receives signals and takes some time to handle each
* A thread that receives signals and takes some time to handle each
*/
class Handler : Thread
{
private:
Timer::Connection _timer; /* timer connection for local use */
unsigned const _dispatch_ms; /* time needed for dispatching a signal */
unsigned const _id; /* unique ID of signal handler for debug output */
static unsigned _id_cnt; /* counter for producing unique IDs */
Signal_receiver &_receiver; /* signal endpoint */
bool _stop; /* state for destruction protocol */
unsigned _receive_cnt; /* number of received notifications */
unsigned _activation_cnt; /* number of invocations of the signal handler */
bool _idle; /* suppress the further handling of signals */
bool const _verbose; /* print status information */
Timer::Connection _timer;
unsigned 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 };
/**
* Signal handler needs '_dispatch_ms' milliseconds for each signal
*/
void entry()
{
while (!_stop) {
if (!_idle) {
Signal signal = _receiver.wait_for_signal();
if (_verbose)
log("handler ", _id, " got ", signal.num(), " "
"signal", (signal.num() == 1 ? "" : "s"), " "
@ -145,7 +103,6 @@ class Handler : Thread
_receive_cnt += signal.num();
_activation_cnt++;
}
if (_dispatch_ms)
_timer.msleep(_dispatch_ms);
}
@ -153,486 +110,351 @@ class Handler : Thread
public:
/**
* Constructor
*
* \param receiver receiver to request signals from
* \param dispatch_ms duration of signal-handler activity
* \param verbose print status information
*/
Handler(Env &env, Signal_receiver &receiver, unsigned dispatch_ms, bool verbose = true)
Handler(Env &env,
Signal_receiver &receiver,
unsigned dispatch_ms,
bool verbose,
unsigned id)
:
Thread(env, "handler", 4096*sizeof(long)),
_timer(env),
_dispatch_ms(dispatch_ms),
_id(++_id_cnt),
_receiver(receiver),
_stop(false),
_receive_cnt(0),
_activation_cnt(0),
_idle(0),
_verbose(verbose)
Thread(env, "handler", 4096 * sizeof(addr_t)), _timer(env),
_dispatch_ms(dispatch_ms), _id(id), _verbose(verbose),
_receiver(receiver)
{
start();
Thread::start();
}
/**
* Destructor
*/
~Handler()
{
/* tell thread to stop iterating */
_stop = true;
void print(Output &output) const { Genode::print(output, "handler ", _id); }
/* wait for current 'msleep' call of the thread to finish */
_timer.msleep(0);
}
/***************
** Accessors **
***************/
/**
* Suppress the handling of further signals
*/
void idle(bool idle = true) { _idle = idle; }
/**
* Return total number of received notifications
*/
unsigned receive_cnt() const { return _receive_cnt; }
/**
* Return total number of signal-handler activations
*/
void idle(bool idle) { _idle = idle; }
unsigned receive_cnt() const { return _receive_cnt; }
unsigned activation_cnt() const { return _activation_cnt; }
};
/**
* Counter for generating unique signal-handler IDs
* Base of all signalling tests
*/
unsigned Handler::_id_cnt = 0;
/**
* Counter for enumerating the tests
*/
static unsigned test_cnt = 0;
/**
* Symbolic error codes
*/
class Test_failed { };
class Test_failed_with_unequal_sent_and_received_signals : public Test_failed { };
class Test_failed_with_unequal_activation_of_handlers : public Test_failed { };
class Id_signal_context : public Signal_context
struct Signal_test
{
private:
enum { SPEED = 10 };
int _id;
int id;
public:
Signal_test(int id, char const *brief) : id(id) {
log("\nTEST ", id, ": ", brief, "\n"); }
Id_signal_context(int id) : _id(id) { }
int id() const { return _id; }
~Signal_test() { log("\nTEST ", id, " finished\n"); }
};
/**
* Test for reliable notification delivery
*
* For this test, the produce more notification than that can be handled.
* Still, the total number of notifications gets transmitted because of the
* batching of notifications in one signal. This test fails if the number of
* submitted notifications on the sender side does not match the number of
* notifications received at the signal handler.
*/
static void fast_sender_test(Env &env)
struct Fast_sender_test : Signal_test
{
enum { SPEED = 10 };
enum { TEST_DURATION = 50*SPEED };
enum { HANDLER_INTERVAL = 10*SPEED };
enum { SENDER_INTERVAL = 2*SPEED };
enum { FINISH_IDLE_TIME = 2*HANDLER_INTERVAL };
static constexpr char const *brief =
"reliable delivery if the sender is faster than the handlers";
log("");
log("TEST ", ++test_cnt, ": one sender, one handler, sender is faster than handler");
log("");
enum { HANDLER_INTERVAL_MS = 10 * SPEED,
SENDER_INTERVAL_MS = 2 * SPEED,
DURATION_MS = 50 * SPEED,
FINISH_IDLE_MS = 2 * HANDLER_INTERVAL_MS };
Signal_receiver receiver;
Id_signal_context context_123(123);
struct Unequal_sent_and_received_signals : Exception { };
Heap heap(env.ram(), env.rm());
Timer::Connection timer(env);
Handler *handler = new (heap) Handler(env, receiver, HANDLER_INTERVAL, false);
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123),
SENDER_INTERVAL, false);
timer.msleep(TEST_DURATION);
/* stop emitting signals */
log("deactivate sender");
sender->idle();
timer.msleep(FINISH_IDLE_TIME);
log("");
log("sender submitted a total of ", sender->submit_cnt(), " signals");
log("handler received a total of ", handler->receive_cnt(), " signals");
log("");
if (sender->submit_cnt() != handler->receive_cnt())
throw Test_failed();
receiver.dissolve(&context_123);
destroy(heap, sender);
destroy(heap, handler);
log("TEST ", test_cnt, " FINISHED");
}
/**
* Fairness test if multiple signal-handler threads are present at one receiver
*
* We expect that all handler threads get activated in a fair manner. The test
* fails if the number of activations per handler differs by more than one.
* Furthermore, if operating in non-descrete mode, the total number of sent and
* handled notifications is checked.
*/
static void multiple_handlers_test(Env &env)
{
enum { SPEED = 10 };
enum { TEST_DURATION = 50*SPEED };
enum { HANDLER_INTERVAL = 8*SPEED };
enum { SENDER_INTERVAL = 1*SPEED };
enum { FINISH_IDLE_TIME = 2*HANDLER_INTERVAL };
enum { NUM_HANDLERS = 4 };
log("");
log("TEST ", ++test_cnt, ": one busy sender, ", (int)NUM_HANDLERS, " handlers");
log("");
Heap heap(env.ram(), env.rm());
Timer::Connection timer(env);
Signal_receiver receiver;
Handler *handler[NUM_HANDLERS];
for (int i = 0; i < NUM_HANDLERS; i++)
handler[i] = new (heap) Handler(env, receiver, HANDLER_INTERVAL);
Id_signal_context context_123(123);
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123), SENDER_INTERVAL);
timer.msleep(TEST_DURATION);
/* stop emitting signals */
log("stop generating new notifications");
sender->idle();
timer.msleep(FINISH_IDLE_TIME);
/* let handlers settle down */
for (int i = 0; i < NUM_HANDLERS; i++)
handler[i]->idle();
timer.msleep(FINISH_IDLE_TIME);
/* print signal delivery statistics */
log("");
log("sender submitted a total of ", sender->submit_cnt(), " signals");
unsigned total_receive_cnt = 0;
for (int i = 0; i < NUM_HANDLERS; i++) {
log("handler ", i, " "
"received a total of ", handler[i]->receive_cnt(), " signals");
total_receive_cnt += handler[i]->receive_cnt();
}
log("all handlers received a total of ", total_receive_cnt, " signals");
/* check if number of sent notifications match the received ones */
if (sender->submit_cnt() != total_receive_cnt)
throw Test_failed_with_unequal_sent_and_received_signals();
/* print activation statistics */
log("");
for (int i = 0; i < NUM_HANDLERS; i++)
log("handler ", i, " was activated ", handler[i]->activation_cnt(), " times");
log("");
/* check if handlers had been activated equally (tolerating a difference of one) */
for (int i = 0; i < NUM_HANDLERS; i++) {
int diff = handler[0]->activation_cnt()
- handler[(i + 1)/NUM_HANDLERS]->activation_cnt();
if (abs(diff) > 1)
throw Test_failed_with_unequal_activation_of_handlers();
}
/* cleanup */
receiver.dissolve(&context_123);
destroy(heap, sender);
for (int i = 0; i < NUM_HANDLERS; i++)
destroy(heap, handler[i]);
log("TEST ", test_cnt, " FINISHED");
}
/**
* Stress test to estimate signal throughput
*
* For this test, we disable status output and any simulated wait times.
* We produce and handle notifications as fast as possible via spinning
* loops at the sender and handler side.
*/
static void stress_test(Env &env)
{
enum { SPEED = 10 };
enum { DURATION_SECONDS = 5 };
enum { FINISH_IDLE_TIME = 100*SPEED };
log("");
log("TEST ", ++test_cnt, ": stress test, busy signal transmission and handling");
log("");
Timer::Connection timer(env);
Heap heap(env.ram(), env.rm());
Signal_receiver receiver;
Id_signal_context context_123(123);
Handler *handler = new (heap) Handler(env, receiver, 0, false);
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123),
0, false);
for (int i = 1; i <= DURATION_SECONDS; i++) {
log(i, "/", (int)DURATION_SECONDS);
timer.msleep(1000);
}
/* stop emitting signals */
log("deactivate sender");
sender->idle();
while (handler->receive_cnt() < sender->submit_cnt()) {
log("waiting for signals still in flight...");
timer.msleep(FINISH_IDLE_TIME);
}
log("");
log("sender submitted a total of ", sender->submit_cnt(), " signals");
log("handler received a total of ", handler->receive_cnt(), " signals");
log("");
log("processed ", (handler->receive_cnt()/DURATION_SECONDS), " notifications per second");
log("handler was activated ", (handler->activation_cnt()/DURATION_SECONDS), " times per second");
log("");
if (sender->submit_cnt() != handler->receive_cnt())
throw Test_failed_with_unequal_sent_and_received_signals();
receiver.dissolve(&context_123);
destroy(heap, sender);
destroy(heap, handler);
log("TEST ", test_cnt, " FINISHED");
}
static void lazy_receivers_test(Env &env)
{
log("");
log("TEST ", ++test_cnt, ": lazy and out-of-order signal reception test");
log("");
Signal_receiver rec_1, rec_2;
Signal_context rec_context_1, rec_context_2;
Signal_transmitter transmitter_1(rec_1.manage(&rec_context_1));
Signal_transmitter transmitter_2(rec_2.manage(&rec_context_2));
log("submit and receive signals with multiple receivers in order");
transmitter_1.submit();
transmitter_2.submit();
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)
{
Signal signal = rec_1.wait_for_signal();
log("returned from wait_for_signal for receiver 1");
timer.msleep(DURATION_MS);
signal = rec_2.wait_for_signal();
log("returned from wait_for_signal for receiver 2");
/* 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(); }
}
};
log("submit and receive signals with multiple receivers out of order");
transmitter_1.submit();
transmitter_2.submit();
{
Signal signal = rec_2.wait_for_signal();
log("returned from wait_for_signal for receiver 2");
signal = rec_1.wait_for_signal();
log("returned from wait_for_signal for receiver 1");
}
rec_1.dissolve(&rec_context_1);
rec_2.dissolve(&rec_context_2);
log("TEST ", test_cnt, " FINISHED");
}
/**
* Try correct initialization and cleanup of receiver/context
*/
static void check_context_management(Env &env)
struct Multiple_handlers_test : Signal_test
{
Id_signal_context *context;
Signal_receiver *rec;
Signal_context_capability cap;
static constexpr char const *brief =
"get multiple handlers at one sender activated in a fair manner";
Timer::Connection timer(env);
Heap heap(env.ram(), env.rm());
enum { HANDLER_INTERVAL_MS = 8 * SPEED,
SENDER_INTERVAL_MS = 1 * SPEED,
FINISH_IDLE_MS = 2 * HANDLER_INTERVAL_MS,
DURATION_MS = 50 * SPEED,
NR_OF_HANDLERS = 4 };
/* setup receiver side */
context = new (heap) Id_signal_context(321);
rec = new (heap) Signal_receiver;
cap = rec->manage(context);
struct Unequal_sent_and_received_signals : Exception { };
struct Unequal_activation_of_handlers : Exception { };
/* spawn sender */
Sender *sender = new (heap) Sender(env, cap, 500);
Env &env;
Heap heap { env.ram(), env.rm() };
Timer::Connection timer { env };
Signal_context context;
Signal_receiver receiver;
Registry<Registered<Handler> > handlers;
Sender sender { env, receiver.manage(&context),
SENDER_INTERVAL_MS, true};
/* stop sender after timeout */
timer.msleep(1000);
log("suspend sender");
sender->idle();
/* collect pending signals and dissolve context from receiver */
Multiple_handlers_test(Env &env, int id) : Signal_test(id, brief), env(env)
{
Signal signal = rec->wait_for_signal();
log("got ", signal.num(), " signal(s) from ", signal.context());
for (unsigned i = 0; i < NR_OF_HANDLERS; i++)
new (heap) Registered<Handler>(handlers, env, receiver,
HANDLER_INTERVAL_MS, true, i);
timer.msleep(DURATION_MS);
/* stop emitting signals */
log("stop generating new signals");
sender.idle(true);
timer.msleep(FINISH_IDLE_MS);
/* let handlers settle down */
handlers.for_each([&] (Handler &handler) { handler.idle(true); });
timer.msleep(FINISH_IDLE_MS);
/* print statistics and clean up */
unsigned total_rcv = 0, max_act = 0, min_act = ~0;;
handlers.for_each([&] (Handler &handler) {
unsigned const rcv = handler.receive_cnt();
unsigned const act = handler.activation_cnt();
log(handler, " received ", rcv, " signals, was activated ", act, " times");
total_rcv += rcv;
if (act > max_act) { max_act = act; }
if (act < min_act) { min_act = act; }
destroy(heap, &handler);
});
log("sender submitted a total of ", sender.submit_cnt(), " signals");
log("handlers received a total of ", total_rcv, " signals");
/* check if number of sent signals match the received ones */
if (sender.submit_cnt() != total_rcv) {
throw Unequal_sent_and_received_signals(); }
/* check if handlers had been activated equally (tolerance of one) */
if (max_act - min_act > 1) {
throw Unequal_activation_of_handlers(); }
}
rec->dissolve(context);
};
/* let sender spin for some time */
log("resume sender");
sender->idle(false);
timer.msleep(1000);
log("suspend sender");
sender->idle();
log("destroy sender");
destroy(heap, sender);
destroy(heap, context);
destroy(heap, rec);
}
/**
* Test if 'Signal_receiver::dissolve()' blocks as long as the signal context
* is still referenced by one or more 'Signal' objects
*/
static Lock signal_context_destroyer_lock(Lock::LOCKED);
static bool signal_context_destroyed = false;
class Signal_context_destroyer : public Thread_deprecated<4096>
struct Stress_test : Signal_test
{
private:
static constexpr char const *brief =
"throughput when submitting/handling as fast as possible";
Signal_receiver *_receiver;
Signal_context *_context;
enum { DURATION_SEC = 5 };
public:
struct Unequal_sent_and_received_signals : Exception { };
Signal_context_destroyer(Signal_receiver *receiver, Signal_context *context)
: Thread_deprecated("signal_context_destroyer"),
_receiver(receiver), _context(context) { }
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 };
void entry()
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 &env, int id) : Signal_test(id, brief)
{
log("submit and receive signals with multiple receivers in order");
transmitter_1.submit();
transmitter_2.submit();
{
signal_context_destroyer_lock.lock();
_receiver->dissolve(_context);
signal_context_destroyed = true;
destroy(env()->heap(), _context);
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");
}
}
};
static void synchronized_context_destruction_test(Env &env)
struct Context_management_test : Signal_test
{
Signal_receiver receiver;
Timer::Connection timer(env);
static Heap heap(env.ram(), env.rm());
static constexpr char const *brief =
"correct initialization and cleanup of receiver and context";
Signal_context *context = new (heap) Signal_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 };
Signal_transmitter transmitter(receiver.manage(context));
transmitter.submit();
Signal_context_destroyer signal_context_destroyer(&receiver, context);
signal_context_destroyer.start();
/* The signal context destroyer thread should not be able to destroy the
* signal context during the 'Signal' objects life time. */
Context_management_test(Env &env, int id) : Signal_test(id, brief), env(env)
{
Signal signal = receiver.wait_for_signal();
/* let the signal context destroyer thread try to destroy the signal context */
signal_context_destroyer_lock.unlock();
/* stop sender after timeout */
timer.msleep(1000);
log("suspend sender");
sender.idle(true);
Signal signal_copy = signal;
Signal signal_copy2 = signal;
signal_copy = signal_copy2;
if (signal_context_destroyed) {
error("signal context destroyed too early");
sleep_forever();
/* 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 : 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()
{
receiver.dissolve(&context);
log("dissolve finished");
destroyed = true;
destroy(heap, &context);
}
signal_context_destroyer.join();
signal_context_destroyed = false;
}
Synchronized_destruction_test(Env &env, int id)
: Signal_test(id, brief), Thread(env, "destroyer", 1024 * sizeof(addr_t)), 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();
}
};
static void many_managed_contexts(Env &env)
struct Many_contexts_test : Signal_test
{
static Heap heap(env.ram(), env.rm());
for (unsigned round = 0; round < 10; ++round) {
static constexpr char const *brief = "create and manage many contexts";
unsigned const num_contexts = 200 + 5*round;
log("round ", round, ": create and manage ", num_contexts, " contexts");
struct Manage_failed : Exception { };
Signal_receiver rec;
Env &env;
Heap heap { env.ram(), env.rm() };
Registry<Registered<Signal_context> > contexts;
for (unsigned i = 0; i < num_contexts; ++i) {
Id_signal_context *context = new (heap) Id_signal_context(i);
if (!rec.manage(context).valid()) {
error("failed to manage signal context");
sleep_forever();
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);
});
}
}
};
log("many contexts finished");
}
void Component::construct(Genode::Env &env)
struct Main
{
log("--- signalling test ---");
Constructible<Fast_sender_test> test_1;
Constructible<Multiple_handlers_test> test_2;
Constructible<Stress_test> test_3;
Constructible<Lazy_receivers_test> test_4;
Constructible<Context_management_test> test_5;
Constructible<Synchronized_destruction_test> test_6;
Constructible<Many_contexts_test> test_7;
fast_sender_test(env);
multiple_handlers_test(env);
stress_test(env);
lazy_receivers_test(env);
check_context_management(env);
synchronized_context_destruction_test(env);
many_managed_contexts(env);
log("--- signalling test finished ---");
env.parent().exit(0);
Main(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();
log("--- Signalling test finished ---");
}
};
void Component::construct(Genode::Env &env) { static Main main(env); }

View File

@ -13,14 +13,16 @@
/* Genode includes */
#include <base/synced_interface.h>
#include <base/log.h>
#include <base/component.h>
using namespace Genode;
struct Adder
{
int add(int a, int b)
{
Genode::log("adding ", a, " + ", b);
log("adding ", a, " + ", b);
return a + b;
}
};
@ -28,22 +30,25 @@ struct Adder
struct Pseudo_lock
{
void lock() { Genode::log("lock"); }
void unlock() { Genode::log("unlock"); }
void lock() { log("lock"); }
void unlock() { log("unlock"); }
};
int main(int, char **)
struct Main
{
using namespace Genode;
Pseudo_lock lock;
Adder adder;
Synced_interface<Adder, Pseudo_lock> synced_adder { lock, &adder };
Pseudo_lock lock;
Adder adder;
Main(Env &env)
{
log("--- Synced interface test ---");
int const res = synced_adder()->add(13, 14);
log("result is ", res);
log("--- Synced interface test finished ---");
}
};
Synced_interface<Adder, Pseudo_lock> synced_adder(lock, &adder);
int const res = synced_adder()->add(13, 14);
log("result is ", res);
return 0;
}
void Component::construct(Env &env) { static Main main(env); }

View File

@ -1,57 +1,49 @@
/*
* \brief Terminal echo program
* \author Norman Feske
* \author Martin Stein
* \date 2009-10-16
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
* Copyright (C) 2009-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/log.h>
#include <base/signal.h>
/* Genode includes */
#include <base/component.h>
#include <terminal_session/connection.h>
using namespace Genode;
static const bool verbose = false;
int main(int, char **)
struct Main
{
static Terminal::Connection terminal;
Terminal::Connection terminal;
Signal_handler<Main> read_avail;
char read_buffer[100];
enum { READ_BUFFER_SIZE = 100 };
static char read_buffer[READ_BUFFER_SIZE];
String<128> intro {
"--- Terminal echo test started - now you can type characters to be echoed. ---\r\n" };
Signal_receiver sig_rec;
Signal_context sig_ctx;
terminal.read_avail_sigh(sig_rec.manage(&sig_ctx));
static const char *intro_text =
"--- Terminal echo test started - now you can type characters to be echoed. ---\r\n";
terminal.write(intro_text, strlen(intro_text) + 1);
for (;;) {
sig_rec.wait_for_signal();
int num_bytes = terminal.read(read_buffer, sizeof(read_buffer));
if (verbose && (num_bytes > 0))
log("got ", num_bytes, " bytes");
for (int i = 0; i < num_bytes; i++) {
void handle_read_avail()
{
unsigned num_bytes = terminal.read(read_buffer, sizeof(read_buffer));
log("got ", num_bytes, " byte(s)");
for (unsigned i = 0; i < num_bytes; i++) {
if (read_buffer[i] == '\r') {
terminal.write("\n", 1);
}
terminal.write("\n", 1); }
terminal.write(&read_buffer[i], 1);
}
}
return 0;
}
Main(Env &env) : terminal(env),
read_avail(env.ep(), *this, &Main::handle_read_avail)
{
terminal.read_avail_sigh(read_avail);
terminal.write(intro.string(), intro.length() + 1);
}
};
void Component::construct(Env &env) { static Main main(env); }

View File

@ -11,65 +11,63 @@
* under the terms of the GNU General Public License version 2.
*/
#include <base/log.h>
/* Genode includes */
#include <base/component.h>
#include <base/thread.h>
#include <timer_session/connection.h>
using namespace Genode;
struct Worker : Genode::Thread_deprecated<4096>
struct Worker : Thread
{
Timer::Session &timer;
unsigned const result_value;
unsigned volatile result;
Timer::Session &timer;
unsigned const result_value;
unsigned volatile result;
void entry()
{
log("worker thread is up");
log("Worker thread is up");
timer.msleep(250);
log("worker is leaving the entry function with "
"result=", result_value, "...");
log("Worker is leaving the entry function with result=", result_value);
result = result_value;
}
Worker(Timer::Session &timer, int result_value)
:
Thread_deprecated("worker"),
timer(timer), result_value(result_value), result(~0)
Worker(Env &env, Timer::Session &timer, unsigned result_value)
: Thread(env, "worker", 1024 * sizeof(addr_t)), timer(timer),
result_value(result_value), result(~0)
{
start();
Thread::start();
}
};
/**
* Main program
*/
int main(int, char **)
struct Main
{
log("--- thread join test ---");
struct Worker_unfinished_after_join : Exception { };
Timer::Connection timer;
for (unsigned i = 0; i < 10; i++) {
Main(Env &env) : timer(env)
{
log("--- Thread join test ---");
for (unsigned i = 0; i < 10; i++) {
/*
* A worker thread is created in each iteration. Just before
* leaving the entry function, the worker assigns the result
* to 'Worker::result' variable. By validating this value,
* we determine whether the worker has finished or not.
*/
Worker worker(timer, i);
worker.join();
if (worker.result != i) {
error("work remains unfinished after 'join()' returned");
return -1;
/*
* A worker thread is created in each iteration. Just before
* leaving the entry function, the worker assigns the result
* to 'Worker::result' variable. By validating this value,
* we determine whether the worker has finished or not.
*/
Worker worker(env, timer, i);
worker.join();
if (worker.result != i) {
throw Worker_unfinished_after_join(); }
}
log("--- Thread join test finished ---");
}
};
log("--- signalling test finished ---");
return 0;
}
void Component::construct(Genode::Env &env) { static Main main(env); }

View File

@ -1,6 +1,7 @@
/*
* \brief Test for the timed-semaphore
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2010-03-05
*/
@ -11,93 +12,67 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <timer_session/connection.h>
#include <os/timed_semaphore.h>
#include <base/thread.h>
#include <base/component.h>
using namespace Genode;
class Wakeup_thread : public Thread_deprecated<4096>
struct Test : Thread
{
private:
struct Failed : Exception { };
Timed_semaphore *_sem;
Timer::Session *_timer;
int _timeout;
Lock _lock;
bool _stop;
unsigned id;
Timer::Connection wakeup_timer;
unsigned const wakeup_period;
Timed_semaphore sem;
bool stop_wakeup { false };
Lock wakeup_stopped { Lock::LOCKED };
bool got_timeouts { false };
public:
void entry()
{
do {
wakeup_timer.msleep(wakeup_period);
sem.up();
} while (!stop_wakeup);
wakeup_stopped.unlock();
}
Wakeup_thread(Timed_semaphore *sem,
Timer::Session *timer,
Alarm::Time timeout)
: Thread_deprecated("wakeup"), _sem(sem), _timer(timer), _timeout(timeout),
_lock(Lock::LOCKED), _stop(false) { }
Test(Env &env, bool timeouts, unsigned id, char const *brief)
: Thread(env, "wakeup", 1024 * sizeof(addr_t)), id(id), wakeup_timer(env),
wakeup_period(timeouts ? 1000 : 100)
{
log("\nTEST ", id, ": ", brief, "\n");
Thread::start();
try { for (int i = 0; i < 10; i++) { sem.down(timeouts ? 100 : 1000); } }
catch (Timeout_exception) { got_timeouts = true; }
if (timeouts != got_timeouts) {
throw Failed(); }
void entry()
{
while(true) {
_timer->msleep(_timeout);
_sem->up();
if (_stop) {
_lock.unlock();
return;
}
}
}
void stop() { _stop = true; _lock.lock(); }
stop_wakeup = true;
wakeup_stopped.lock();
}
~Test() { log("\nTEST ", id, " finished\n"); }
};
bool test_loop(Timer::Session *timer, Alarm::Time timeout1, Alarm::Time timeout2, int loops)
struct Main
{
Timed_semaphore sem;
Wakeup_thread thread(&sem, timer, timeout2);
bool ret = true;
Constructible<Test> test;
thread.start();
try{
for (int i = 0; i < loops; i++)
sem.down(timeout1);
} catch (Timeout_exception) {
ret = false;
Main(Env &env)
{
log("--- Timed semaphore test ---");
test.construct(env, false, 1, "without timeouts"); test.destruct();
test.construct(env, true, 2, "with timeouts"); test.destruct();
log("--- Timed semaphore test finished ---");
}
/*
* Explicitly stop the thread, so the destructor does not get called in
* unfavourable situations, e.g. where the semaphore-meta lock is still
* held and the semaphore destructor stalls afterwards
*/
thread.stop();
return ret;
}
};
int main(int, char **)
{
log("--- timed-semaphore test ---");
Timer::Connection timer;
log("--- test 1: good case, no timeout triggers --");
if(!test_loop(&timer, 1000, 100, 10)) {
error("Test 1 failed!");
return -1;
}
log("--- everything went ok --");
log("--- test 2: triggers timeouts --");
if(test_loop(&timer, 100, 1000, 10)) {
error("Test 2 failed!");
return -2;
}
log("--- everything went ok --");
log("--- end of timed-semaphore test ---");
return 0;
}
void Component::construct(Genode::Env &env) { static Main main(env); }

View File

@ -2,11 +2,12 @@
* \brief Low-level test for TRACE service
* \author Norman Feske
* \author Josef Soentgen
* \author Martin Stein
* \date 2013-08-12
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@ -15,75 +16,61 @@
/* Genode includes */
#include <trace_session/connection.h>
#include <timer_session/connection.h>
#include <os/config.h>
#include <base/sleep.h>
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/heap.h>
static char const *state_name(Genode::Trace::Subject_info::State state)
using namespace Genode;
struct Test_thread : Thread
{
switch (state) {
case Genode::Trace::Subject_info::INVALID: return "INVALID";
case Genode::Trace::Subject_info::UNTRACED: return "UNTRACED";
case Genode::Trace::Subject_info::TRACED: return "TRACED";
case Genode::Trace::Subject_info::FOREIGN: return "FOREIGN";
case Genode::Trace::Subject_info::ERROR: return "ERROR";
case Genode::Trace::Subject_info::DEAD: return "DEAD";
}
return "undefined";
}
struct Test_thread : Genode::Thread_deprecated<1024 * sizeof (unsigned long)>
{
Timer::Connection _timer;
Env &env;
Timer::Connection timer { env };
void entry()
{
using namespace Genode;
for (size_t i = 0; ; i++) {
for (unsigned i = 0; ; i++) {
if (i & 0x3) {
Ram_dataspace_capability ds_cap = env()->ram_session()->alloc(1024);
env()->ram_session()->free(ds_cap);
Ram_dataspace_capability ds_cap = env.ram().alloc(1024);
env.ram().free(ds_cap);
}
_timer.msleep(250);
timer.msleep(250);
}
}
Test_thread(const char *name)
: Thread_deprecated(name) { start(); }
Test_thread(Env &env, Name &name)
: Thread(env, name, 1024 * sizeof(addr_t)), env(env) { start(); }
};
using namespace Genode;
class Trace_buffer_monitor
{
private:
enum { MAX_ENTRY_BUF = 256 };
char _buf[MAX_ENTRY_BUF];
char _buf[MAX_ENTRY_BUF];
Region_map &_rm;
Trace::Subject_id _id;
Trace::Buffer *_buffer;
Trace::Buffer::Entry _curr_entry;
Trace::Buffer::Entry _curr_entry;
const char *_terminate_entry(Trace::Buffer::Entry const &entry)
{
size_t len = min(entry.length() + 1, MAX_ENTRY_BUF);
memcpy(_buf, entry.data(), len);
_buf[len-1] = '\0';
return _buf;
}
public:
Trace_buffer_monitor(Trace::Subject_id id, Dataspace_capability ds_cap)
Trace_buffer_monitor(Region_map &rm,
Trace::Subject_id id,
Dataspace_capability ds_cap)
:
_id(id),
_buffer(env()->rm_session()->attach(ds_cap)),
_rm(rm), _id(id), _buffer(rm.attach(ds_cap)),
_curr_entry(_buffer->first())
{
log("monitor subject:", _id.id, " buffer:", Hex((addr_t)_buffer));
@ -92,7 +79,7 @@ class Trace_buffer_monitor
~Trace_buffer_monitor()
{
if (_buffer)
env()->rm_session()->detach(_buffer);
_rm.detach(_buffer);
}
Trace::Subject_id id() { return _id; };
@ -100,7 +87,6 @@ class Trace_buffer_monitor
void dump()
{
log("overflows: ", _buffer->wrapped());
log("read all remaining events");
for (; !_curr_entry.last(); _curr_entry = _buffer->next(_curr_entry)) {
/* omit empty entries */
@ -111,163 +97,193 @@ class Trace_buffer_monitor
if (data)
log(data);
}
/* reset after we read all available entries */
_curr_entry = _buffer->first();
}
};
static void test_out_of_metadata()
struct Test_out_of_metadata
{
log("test Out_of_metadata exception of Trace::Session::subjects call");
Env &env;
/*
* The call of 'subjects' will prompt core's TRACE service to import those
* threads as trace subjects into the TRACE session. This step should fail
* because we dimensioned the TRACE session with a very low amount of
* session quota. The allocation failure is propagated to the TRACE client
* by the 'Out_of_metadata' exception. The test validates this
* error-handling procedure.
*/
Test_out_of_metadata(Env &env) : env(env)
{
log("test Out_of_metadata exception of Trace::Session::subjects call");
enum { MAX_SUBJECT_IDS = 16 };
Genode::Trace::Subject_id subject_ids[MAX_SUBJECT_IDS];
/*
* The call of 'subjects' will prompt core's TRACE service to import those
* threads as trace subjects into the TRACE session. This step should fail
* because we dimensioned the TRACE session with a very low amount of
* session quota. The allocation failure is propagated to the TRACE client
* by the 'Out_of_metadata' exception. The test validates this
* error-handling procedure.
*/
try {
Genode::Trace::Connection trace(sizeof(subject_ids) + 4096, sizeof(subject_ids), 0);
enum { MAX_SUBJECT_IDS = 16 };
Trace::Subject_id subject_ids[MAX_SUBJECT_IDS];
/* we should never arrive here */
struct Unexpectedly_got_no_exception{};
throw Unexpectedly_got_no_exception();
} catch (Genode::Parent::Service_denied) {
log("got Genode::Parent::Service_denied exception as expected");
try {
Trace::Connection trace(env, sizeof(subject_ids) + 4096,
sizeof(subject_ids), 0);
/* we should never arrive here */
struct Unexpectedly_got_no_exception{};
throw Unexpectedly_got_no_exception();
} catch (Parent::Service_denied) {
log("got Parent::Service_denied exception as expected"); }
try {
Trace::Connection trace(env, sizeof(subject_ids) + 5*4096,
sizeof(subject_ids), 0);
trace.subjects(subject_ids, MAX_SUBJECT_IDS);
/* we should never arrive here */
struct Unexpectedly_got_no_exception{};
throw Unexpectedly_got_no_exception();
} catch (Trace::Out_of_metadata) {
log("got Trace::Out_of_metadata exception as expected"); }
log("passed Out_of_metadata test");
}
try {
Genode::Trace::Connection trace(sizeof(subject_ids) + 5*4096, sizeof(subject_ids), 0);
trace.subjects(subject_ids, MAX_SUBJECT_IDS);
/* we should never arrive here */
struct Unexpectedly_got_no_exception{};
throw Unexpectedly_got_no_exception();
} catch (Trace::Out_of_metadata) {
log("got Trace::Out_of_metadata exception as expected");
}
log("passed Out_of_metadata test");
}
};
int main(int argc, char **argv)
struct Test_tracing
{
using namespace Genode;
Env &env;
Attached_rom_dataspace config { env, "config" };
Heap heap { env.ram(), env.rm() };
Trace::Connection trace { env, 1024*1024, 64*1024, 0 };
Timer::Connection timer { env };
Test_thread::Name thread_name { "test-thread" };
Test_thread thread { env, thread_name };
Trace_buffer_monitor *test_monitor { nullptr };
bool policy_set { false };
Trace::Policy_id policy_id;
char policy_label[64];
char policy_module[64];
Rom_dataspace_capability policy_module_rom_ds;
log("--- test-trace started ---");
test_out_of_metadata();
static Genode::Trace::Connection trace(1024*1024, 64*1024, 0);
static Timer::Connection timer;
static Test_thread test("test-thread");
static Trace_buffer_monitor *test_monitor = 0;
Genode::Trace::Policy_id policy_id;
bool policy_set = false;
char policy_label[64];
char policy_module[64];
Rom_dataspace_capability policy_module_rom_ds;
try {
Xml_node policy = config()->xml_node().sub_node("trace_policy");
for (;; policy = policy.next("trace_policy")) {
try {
policy.attribute("label").value(policy_label, sizeof (policy_label));
policy.attribute("module").value(policy_module, sizeof (policy_module));
static Rom_connection policy_rom(policy_module);
policy_module_rom_ds = policy_rom.dataspace();
size_t rom_size = Dataspace_client(policy_module_rom_ds).size();
policy_id = trace.alloc_policy(rom_size);
Dataspace_capability ds_cap = trace.policy(policy_id);
if (ds_cap.valid()) {
void *ram = env()->rm_session()->attach(ds_cap);
void *rom = env()->rm_session()->attach(policy_module_rom_ds);
memcpy(ram, rom, rom_size);
env()->rm_session()->detach(ram);
env()->rm_session()->detach(rom);
}
} catch (...) {
error("could not load module '", Cstring(policy_module), "' for "
"label '", Cstring(policy_label), "'");
}
log("load module: '", Cstring(policy_module), "' for "
"label: '", Cstring(policy_label), "'");
if (policy.last("trace_policy")) break;
char const *state_name(Trace::Subject_info::State state)
{
switch (state) {
case Trace::Subject_info::INVALID: return "INVALID";
case Trace::Subject_info::UNTRACED: return "UNTRACED";
case Trace::Subject_info::TRACED: return "TRACED";
case Trace::Subject_info::FOREIGN: return "FOREIGN";
case Trace::Subject_info::ERROR: return "ERROR";
case Trace::Subject_info::DEAD: return "DEAD";
}
return "undefined";
}
} catch (...) { }
for (size_t cnt = 0; cnt < 5; cnt++) {
timer.msleep(3000);
Trace::Subject_id subjects[32];
size_t num_subjects = trace.subjects(subjects, 32);
log(num_subjects, " tracing subjects present");
for (size_t i = 0; i < num_subjects; i++) {
Trace::Subject_info info = trace.subject_info(subjects[i]);
log("ID:", subjects[i].id, " "
"label:\"", info.session_label(), "\" "
"name:\"", info.thread_name(), "\" "
"state:", state_name(info.state()), " "
"policy:", info.policy_id().id, " "
"time:", info.execution_time().value);
/* enable tracing */
if (!policy_set
&& strcmp(info.session_label().string(), policy_label) == 0
&& strcmp(info.thread_name().string(), "test-thread") == 0) {
Test_tracing(Env &env) : env(env)
{
try {
Xml_node policy = config.xml().sub_node("trace_policy");
for (;; policy = policy.next("trace_policy")) {
try {
log("enable tracing for "
"thread:'", info.thread_name().string(), "' with "
"policy:", policy_id.id);
policy.attribute("label").value(policy_label, sizeof (policy_label));
policy.attribute("module").value(policy_module, sizeof (policy_module));
trace.trace(subjects[i].id, policy_id, 16384U);
Rom_connection policy_rom(env, policy_module);
policy_module_rom_ds = policy_rom.dataspace();
Dataspace_capability ds_cap = trace.buffer(subjects[i].id);
test_monitor = new (env()->heap()) Trace_buffer_monitor(subjects[i].id, ds_cap);
size_t rom_size = Dataspace_client(policy_module_rom_ds).size();
} catch (Trace::Source_is_dead) { error("source is dead"); }
policy_id = trace.alloc_policy(rom_size);
Dataspace_capability ds_cap = trace.policy(policy_id);
policy_set = true;
if (ds_cap.valid()) {
void *ram = env.rm().attach(ds_cap);
void *rom = env.rm().attach(policy_module_rom_ds);
memcpy(ram, rom, rom_size);
env.rm().detach(ram);
env.rm().detach(rom);
}
} catch (...) {
error("could not load module '", Cstring(policy_module), "' for "
"label '", Cstring(policy_label), "'");
}
log("load module: '", Cstring(policy_module), "' for "
"label: '", Cstring(policy_label), "'");
if (policy.last("trace_policy")) break;
}
/* read events from trace buffer */
if (test_monitor) {
if (subjects[i].id == test_monitor->id().id)
test_monitor->dump();
} catch (...) { }
for (size_t cnt = 0; cnt < 5; cnt++) {
timer.msleep(3000);
Trace::Subject_id subjects[32];
size_t num_subjects = trace.subjects(subjects, 32);
log(num_subjects, " tracing subjects present");
for (size_t i = 0; i < num_subjects; i++) {
Trace::Subject_info info = trace.subject_info(subjects[i]);
log("ID:", subjects[i].id, " "
"label:\"", info.session_label(), "\" "
"name:\"", info.thread_name(), "\" "
"state:", state_name(info.state()), " "
"policy:", info.policy_id().id, " "
"time:", info.execution_time().value);
/* enable tracing */
if (!policy_set
&& strcmp(info.session_label().string(), policy_label) == 0
&& strcmp(info.thread_name().string(), "test-thread") == 0) {
try {
log("enable tracing for "
"thread:'", info.thread_name().string(), "' with "
"policy:", policy_id.id);
trace.trace(subjects[i].id, policy_id, 16384U);
Dataspace_capability ds_cap = trace.buffer(subjects[i].id);
test_monitor = new (heap)
Trace_buffer_monitor(env.rm(), subjects[i].id, ds_cap);
} catch (Trace::Source_is_dead) { error("source is dead"); }
policy_set = true;
}
/* read events from trace buffer */
if (test_monitor) {
if (subjects[i].id == test_monitor->id().id)
test_monitor->dump();
}
}
}
if (test_monitor)
destroy(heap, test_monitor);
}
};
if (test_monitor)
destroy(env()->heap(), test_monitor);
struct Main
{
Constructible<Test_out_of_metadata> test_1;
Constructible<Test_tracing> test_2;
log("--- test-trace finished ---");
return 0;
}
Main(Env &env)
{
log("--- test-trace started ---");
test_1.construct(env);
test_1.destruct();
test_2.construct(env);
test_2.destruct();
log("--- test-trace finished ---");
}
};
void Component::construct(Env &env) { static Main main(env); }

View File

@ -5,35 +5,37 @@
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
* Copyright (C) 2011-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/snprintf.h>
#include <base/log.h>
#include <base/component.h>
#include <timer_session/connection.h>
#include <uart_session/connection.h>
using namespace Genode;
int main()
struct Main
{
log("--- UART test started ---");
Timer::Connection timer;
Uart::Connection uart;
char buf[100];
static Timer::Connection timer;
static Uart::Connection uart;
Main(Env &env)
{
log("--- UART test started ---");
for (unsigned i = 0; ; ++i) {
static char buf[100];
int n = snprintf(buf, sizeof(buf), "UART test message %d\n", i);
uart.write(buf, n);
timer.msleep(2000);
for (unsigned i = 0; ; ++i) {
int n = snprintf(buf, sizeof(buf), "UART test message %d\n", i);
uart.write(buf, n);
timer.msleep(2000);
}
}
};
return 0;
}
void Component::construct(Env &env) { static Main main(env); }

View File

@ -477,7 +477,7 @@ void Component::construct(Genode::Env &env)
MAX_DEPTH = config_xml.attribute_value("depth", 16U);
unsigned long elapsed_ms;
Timer::Connection timer;
Timer::Connection timer(env);
/* populate the directory file system at / */
vfs_root.num_dirent("/");