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"/> <resource name="RAM" quantum="10M"/>
</start> </start>
</config> </config>
</config>
} }
install_config $config install_config $config
@ -74,5 +73,11 @@ set boot_modules {
} }
build_boot_image $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"> <start name="loader">
<resource name="RAM" quantum="1M"/> <resource name="RAM" quantum="1M"/>
<provides><service name="Loader"/></provides> <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>
<start name="test-dynamic_config_loader"> <start name="test-dynamic_config_loader">
<resource name="RAM" quantum="10M"/> <resource name="RAM" quantum="10M"/>

View File

@ -69,19 +69,13 @@ install_config $config
# Boot modules # 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 append_platform_drv_boot_modules
lappend_if [have_spec sdl] boot_modules fb_sdl lappend_if [have_spec sdl] boot_modules fb_sdl
lappend_if [have_spec framebuffer] boot_modules fb_drv lappend_if [have_spec framebuffer] boot_modules fb_drv
build_boot_image $boot_modules 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" 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\]} grep_output {^\[init -> test-ram_fs_chunk\]}
unify_output { sizeof=[0-9]+} {} unify_output { sizeof=[0-9]+} {}
compare_output_to { 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] chunk sizes
[init -> test-ram_fs_chunk] level 0: payload=120 [init -> test-ram_fs_chunk] level 0: payload=120
[init -> test-ram_fs_chunk] level 1: payload=24 [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(2) -> content (size=2): "fi"
[init -> test-ram_fs_chunk] trunc(1) -> content (size=1): "f" [init -> test-ram_fs_chunk] trunc(1) -> content (size=1): "f"
[init -> test-ram_fs_chunk] allocator: sum=0 [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" 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} grep_output {-> test-reconstructible}
compare_output_to { 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 1
[init -> test-reconstructible] construct Object 2 [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 Member_with_reference
[init -> test-reconstructible] construct Compound [init -> test-reconstructible] construct Compound
[init -> test-reconstructible] compound.member.constructed returns 1 [init -> test-reconstructible] compound.member.constructed returns 1
[init -> test-reconstructible] compound.lazy_member.constructed returns 0 [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] construct Member_with_reference
[init -> test-reconstructible] compound.lazy_member.constructed returns 1 [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] 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] destruct Member_with_reference
[init -> test-reconstructible] construct 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] 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] 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] 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 Compound
[init -> test-reconstructible] destruct Member_with_reference [init -> test-reconstructible] destruct Member_with_reference
[init -> test-reconstructible] destruct Object 2 [init -> test-reconstructible] destruct Object 2
[init -> test-reconstructible] destruct Object 1 [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] construct Throwing -> don't throw
[init -> test-reconstructible] destruct Throwing [init -> test-reconstructible] destruct Throwing
[init -> test-reconstructible] construct Throwing -> throw exception [init -> test-reconstructible] construct Throwing -> throw exception
[init -> test-reconstructible] -- catched exception as expected [init -> test-reconstructible] got exception, as expected
[init -> test-reconstructible] --- test-reconstructible finished --- [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" build "core init server/rom_blk test/rom_blk"
create_boot_directory 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 " 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" 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" 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} grep_output {-> test-synced_interface}
compare_output_to { compare_output_to {
[init -> test-synced_interface] --- Synced interface test ---
[init -> test-synced_interface] lock [init -> test-synced_interface] lock
[init -> test-synced_interface] adding 13 + 14 [init -> test-synced_interface] adding 13 + 14
[init -> test-synced_interface] unlock [init -> test-synced_interface] unlock
[init -> test-synced_interface] result is 27 [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" 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 " 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 " append qemu_args " -nographic -serial mon:stdio -m 256 "
run_genode_until forever run_genode_until "--- test-trace finished ---" 30
#{.*child exited with exit value 0.* } 60

View File

@ -1,42 +1,49 @@
/* /*
* \brief Test for changing the CPU frequency * \brief Test for changing the CPU frequency
* \author Stefan Kalkowski * \author Stefan Kalkowski
* \author Martin Stein
* \date 2013-06-14 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */ /* Genode includes */
#include <base/log.h> #include <base/component.h>
#include <base/env.h>
#include <base/sleep.h>
#include <regulator/consts.h> #include <regulator/consts.h>
#include <regulator_session/connection.h> #include <regulator_session/connection.h>
#include <timer_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; void handle_timer()
static Regulator::Connection cpu_regulator(Regulator::CLK_CPU); {
bool high = true;
while (true) {
timer.msleep(10000);
log("Setting CPU frequency ", high ? "low" : "high"); log("Setting CPU frequency ", high ? "low" : "high");
cpu_regulator.level(high ? Regulator::CPU_FREQ_200 cpu_regulator.level(high ? Regulator::CPU_FREQ_200 :
: Regulator::CPU_FREQ_1600); Regulator::CPU_FREQ_1600);
high = !high; 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 */ /* Genode includes */
#include <base/snprintf.h>
#include <base/sleep.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <loader_session/connection.h> #include <loader_session/connection.h>
#include <base/component.h>
using namespace Genode; using namespace Genode;
struct Main
enum { CONFIG_SIZE = 100 };
static Loader::Connection loader(8*1024*1024);
static void update_config(int counter)
{ {
Dataspace_capability config_ds = enum { CONFIG_SIZE = 100 };
loader.alloc_rom_module("config", CONFIG_SIZE);
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, void handle_timer()
"<config><counter>%d</counter></config>", {
counter); char *config_ds_addr =
env.rm().attach(loader.alloc_rom_module("config", CONFIG_SIZE));
env()->rm_session()->detach(config_ds_addr); String<100> config("<config><counter>", counter++, "</counter></config>");
strncpy(config_ds_addr, config.string(), CONFIG_SIZE);
loader.commit_rom_module("config"); env.rm().detach(config_ds_addr);
} loader.commit_rom_module("config");
timer.trigger_once(250 * 1000);
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++);
} }
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 * \brief Test for changing configuration at runtime
* \author Norman Feske * \author Norman Feske
* \author Martin Stein
* \date 2012-04-04 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */ /* 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 { Env &env;
long counter = 1; Attached_rom_dataspace config { env, "config" };
Genode::config()->xml_node().sub_node("counter").value(&counter); Signal_handler<Main> config_handler { env.ep(), *this, &Main::handle_config };
Genode::log("obtained counter value ", counter, " from config");
} catch (...) { void handle_config()
Genode::error("could not parse configuration"); {
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"); }
} }
}
Main(Env &env) : env(env)
int main(int, char **) {
{ handle_config();
parse_config(); config.sigh(config_handler);
/* 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();
} }
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) * \brief Test for changing configuration at runtime (server-side)
* \author Norman Feske * \author Norman Feske
* \author Martin Stein
* \date 2012-04-04 * \date 2012-04-04
* *
* This program provides a generated config file as ROM service. After * 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */ /* Genode includes */
#include <base/signal.h>
#include <os/attached_ram_dataspace.h> #include <os/attached_ram_dataspace.h>
#include <os/static_root.h> #include <os/static_root.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <rom_session/rom_session.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 * The implementation of this class follows the lines of
* 'os/include/os/child_policy_dynamic_rom.h'. * '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: private:
Genode::Attached_ram_dataspace _fg; Env &_env;
Genode::Attached_ram_dataspace _bg; Attached_ram_dataspace _fg { _env.ram(), _env.rm(), 0 };
Attached_ram_dataspace _bg { _env.ram(), _env.rm(), 0 };
bool _bg_has_pending_data; bool _bg_pending_data { false };
Signal_context_capability _sigh;
Genode::Lock _lock;
Genode::Signal_context_capability _sigh;
public: public:
/** Rom_session_component(Env &env) : _env(env) { }
* Constructor
*/
Rom_session_component()
: _fg(0, 0), _bg(0, 0), _bg_has_pending_data(false) { }
/** /**
* Update the config file * Update the config file
*/ */
void configure(char const *data) void configure(char const *data)
{ {
Genode::Lock::Guard guard(_lock); size_t const data_len = strlen(data) + 1;
Genode::size_t const data_len = Genode::strlen(data) + 1;
/* let background buffer grow if needed */ /* let background buffer grow if needed */
if (_bg.size() < data_len) 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); strncpy(_bg.local_addr<char>(), data, data_len);
_bg_has_pending_data = true; _bg_pending_data = true;
/* inform client about the changed data */ /* inform client about the changed data */
if (_sigh.valid()) 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 ** ** ROM session interface **
***************************/ ***************************/
Genode::Rom_dataspace_capability dataspace() Rom_dataspace_capability dataspace() override
{ {
Genode::Lock::Guard guard(_lock); if (!_fg.size() && !_bg_pending_data) {
error("no data loaded");
if (!_fg.size() && !_bg_has_pending_data) { return Rom_dataspace_capability();
Genode::error("no data loaded");
return Genode::Rom_dataspace_capability();
} }
/* /*
* Keep foreground if no background exists. Otherwise, use old * Keep foreground if no background exists. Otherwise, use old
* background as new foreground. * background as new foreground.
*/ */
if (_bg_has_pending_data) { if (_bg_pending_data) {
_fg.swap(_bg); _fg.swap(_bg);
_bg_has_pending_data = false; _bg_pending_data = false;
} }
Dataspace_capability ds_cap = _fg.cap();
Genode::Dataspace_capability ds_cap = _fg.cap(); return static_cap_cast<Rom_dataspace>(ds_cap);
return Genode::static_cap_cast<Genode::Rom_dataspace>(ds_cap);
} }
void sigh(Genode::Signal_context_capability sigh_cap) void sigh(Signal_context_capability sigh_cap) override { _sigh = sigh_cap; }
{
Genode::Lock::Guard guard(_lock);
_sigh = sigh_cap;
}
}; };
struct Main
int main(int argc, char **argv)
{ {
using namespace Genode; enum { STACK_SIZE = 2 * 1024 * sizeof(addr_t) };
/* connection to capability service needed to create capabilities */ Env &env;
static Cap_connection cap; 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 }; void handle_timer()
static Rpc_entrypoint ep(&cap, STACK_SIZE, "rom_ep"); {
String<100> config("<config><counter>", counter++, "</counter></config>");
static Rom_session_component rom_session; rom_session.configure(config.string());
static Static_root<Rom_session> rom_root(ep.manage(&rom_session)); timer.trigger_once(250 * 1000);
}
rom_session.configure("<config><counter>-1</counter></config>");
Main(Env &env) : env(env)
/* announce server */ {
env()->parent()->announce(ep.manage(&rom_root)); timer.sigh(timer_handler);
handle_timer();
int counter = 0; env.parent().announce(env.ep().manage(rom_root));
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);
} }
return 0;
}; };
void Component::construct(Env &env) { static Main main(env); }

View File

@ -1,138 +1,141 @@
/* /*
* \brief Framebuffer throughput test * \brief Framebuffer throughput test
* \author Norman Feske * \author Norman Feske
* \author Martin Stein
* \date 2015-06-05 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */ /* Genode includes */
#include <base/env.h> #include <base/component.h>
#include <base/printf.h> #include <base/heap.h>
#include <os/attached_dataspace.h> #include <os/attached_dataspace.h>
#include <blit/blit.h> #include <blit/blit.h>
#include <framebuffer_session/connection.h> #include <framebuffer_session/connection.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
using namespace Genode;
static unsigned long now_ms() struct Test
{ {
static Timer::Connection timer; enum { DURATION_MS = 2000 };
return timer.elapsed_ms();
}
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"); Bytewise_ram_test(Env &env, int id) : Test(env, id, brief)
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");
{ {
unsigned long transferred_kib = 0; unsigned kib = 0;
unsigned long const start_ms = now_ms(); unsigned const start_ms = timer.elapsed_ms();
for (; timer.elapsed_ms() - start_ms < DURATION_MS;) {
for (; now_ms() - start_ms < duration_ms;) { memcpy(buf[0], buf[1], fb_ds.size());
memcpy(src_buf[0], src_buf[1], fb_ds.size()); kib += fb_ds.size() / 1024;
transferred_kib += fb_ds.size() / 1024;
} }
conclusion(kib, start_ms, timer.elapsed_ms());
unsigned long const end_ms = now_ms();
printf("-> %ld MiB/sec\n",
(transferred_kib)/(end_ms - start_ms));
} }
};
/* struct Bytewise_fb_test : Test
* Fill one memory buffer with white pixels. {
*/ static constexpr char const *brief = "byte-wise memcpy from RAM to FB";
memset(src_buf[1], ~0, fb_ds.size());
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 kib = 0;
unsigned long const start_ms = now_ms(); unsigned const start_ms = timer.elapsed_ms();
for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) {
for (unsigned i = 0; now_ms() - start_ms < duration_ms; i++) { memcpy(fb_ds.local_addr<char>(), buf[i % 2], fb_ds.size());
memcpy(fb_ds.local_addr<char>(), src_buf[i % 2], fb_ds.size()); kib += fb_ds.size() / 1024;
transferred_kib += fb_ds.size() / 1024;
} }
conclusion(kib, start_ms, timer.elapsed_ms());
unsigned long const end_ms = now_ms();
printf("-> %ld MiB/sec\n",
(transferred_kib)/(end_ms - start_ms));
} }
};
/* struct Blit_test : Test
* Blitting via the blit library from RAM to framebuffer {
*/ static constexpr char const *brief = "copy via blit library from RAM to FB";
printf("copy via blit library from RAM to framebuffer...\n");
Blit_test(Env &env, int id) : Test(env, id, brief)
{ {
unsigned long transferred_kib = 0; unsigned kib = 0;
unsigned long const start_ms = now_ms(); unsigned const start_ms = timer.elapsed_ms();
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
/* line width in bytes */ unsigned const h = fb_mode.height();
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel(); for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) {
unsigned const h = fb_mode.height(); blit(buf[i % 2], w, fb_ds.local_addr<char>(), w, w, h);
kib += (w * h) / 1024;
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;
} }
conclusion(kib, start_ms, timer.elapsed_ms());
unsigned long const end_ms = now_ms();
printf("-> %ld MiB/sec\n",
(transferred_kib)/(end_ms - start_ms));
} }
};
/* struct Unaligned_blit_test : Test
* Unaligned blitting via the blit library from RAM to framebuffer {
*/ static constexpr char const *brief = "unaligned copy via blit library from RAM to FB";
printf("unaligned copy via blit library from RAM to framebuffer...\n");
Unaligned_blit_test(Env &env, int id) : Test(env, id, brief)
{ {
unsigned long transferred_kib = 0; unsigned kib = 0;
unsigned long const start_ms = now_ms(); unsigned const start_ms = timer.elapsed_ms();
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
/* line width in bytes */ unsigned const h = fb_mode.height();
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel(); for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) {
unsigned const h = fb_mode.height(); blit(buf[i % 2] + 2, w, fb_ds.local_addr<char>() + 2, w, w - 2, h);
kib += (w * h) / 1024;
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;
} }
conclusion(kib, start_ms, timer.elapsed_ms());
unsigned long const end_ms = now_ms();
printf("-> %ld MiB/sec\n",
(transferred_kib)/(end_ms - start_ms));
} }
};
printf("--- test-fb_bench finished ---\n"); struct Main
return 0; {
} 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */
#include <base/component.h> #include <base/component.h>
#include <base/env.h>
#include <base/log.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <input_session/connection.h> #include <input_session/connection.h>
#include <input/event.h>
using namespace Genode; using namespace Genode;
static char const * ev_type(Input::Event::Type type) static char const * ev_type(Input::Event::Type type)
{ {
switch (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; Main(Env &env) : env(env)
{
Genode::Signal_handler<Test_environment> _input_sigh; log("--- Input test ---");
input.sigh(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);
}
}; };
void Test_environment::_handle_input() void Main::handle_input()
{ {
/*
* Handle input events
*/
int key_cnt = 0; int key_cnt = 0;
input.for_each_event([&] (Input::Event const &ev) {
_input.for_each_event([&] (Input::Event const &ev) { event_cnt++;
event_count++;
if (ev.type() == Input::Event::PRESS) key_cnt++; if (ev.type() == Input::Event::PRESS) key_cnt++;
if (ev.type() == Input::Event::RELEASE) key_cnt--; if (ev.type() == Input::Event::RELEASE) key_cnt--;
/* log event */ log("Input event #", event_cnt, "\t"
log("Input event #", event_count, "\t"
"type=", ev_type(ev.type()), "\t" "type=", ev_type(ev.type()), "\t"
"code=", ev.code(), "\t" "code=", ev.code(), "\t"
"rx=", ev.rx(), "\t" "rx=", ev.rx(), "\t"
"ry=", ev.ry(), "\t" "ry=", ev.ry(), "\t"
"ax=", ev.ax(), "\t" "ax=", ev.ax(), "\t"
"ay=", ev.ay(), "\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"); void Component::construct(Env &env) { static Main main(env); }
static Test_environment te(env);
}

View File

@ -61,7 +61,7 @@ struct Test::Base
enum { BUF_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE * 128 }; 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(); } void _handle_nic() { if (!_done) handle_nic(); }

View File

@ -1,152 +1,137 @@
/* /*
* \brief Unit test for RAM fs chunk data structure * \brief Unit test for RAM fs chunk data structure
* \author Norman Feske * \author Norman Feske
* \author Martin Stein
* \date 2012-04-19 * \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 */ /* Genode includes */
#include <base/env.h> #include <base/heap.h>
#include <base/log.h> #include <base/component.h>
#include <ram_fs/chunk.h> #include <ram_fs/chunk.h>
namespace File_system { using namespace File_system;
typedef Chunk<2> Chunk_level_3; using namespace Genode;
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 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 static char read_buf[Chunk_level_0::SIZE];
{ if (used_size() > Chunk_level_0::SIZE) {
using Id = Id_space<Alloc>::Id; throw Index_out_of_range(); }
Id_space<Alloc>::Element id_space_elem; read(read_buf, used_size(), 0);
size_t size; Genode::print(out, "content (size=", used_size(), "): ");
Genode::print(out, "\"");
Alloc(Id_space<Alloc> &space, Id id, size_t size) for (unsigned i = 0; i < used_size(); i++) {
: id_space_elem(*this, space, id), size(size) { } char const c = read_buf[i];
}; if (c) {
Genode::print(out, Char(c)); }
Id_space<Alloc> _allocs; else {
size_t _sum; Genode::print(out, "."); }
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;
} }
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(); }
};
}; };
struct Allocator_tracer : Allocator
namespace Genode { {
struct Alloc
/**
* Helper for the formatted output of a chunk state
*/
static inline void print(Output &out, File_system::Chunk_level_0 const &chunk)
{ {
using namespace File_system; using Id = Id_space<Alloc>::Id;
static char read_buf[Chunk_level_0::SIZE]; Id_space<Alloc>::Element id_space_elem;
size_t size;
size_t used_size = chunk.used_size(); Alloc(Id_space<Alloc> &space, Id id, size_t size)
: id_space_elem(*this, space, id), size(size) { }
};
struct File_size_out_of_bounds { }; Id_space<Alloc> allocs;
if (used_size > Chunk_level_0::SIZE) size_t sum { 0 };
throw File_size_out_of_bounds(); Allocator &wrapped;
chunk.read(read_buf, used_size, 0); Allocator_tracer(Allocator &wrapped) : wrapped(wrapped) { }
Genode::print(out, "content (size=", used_size, "): "); 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;
}
Genode::print(out, "\""); void free(void *addr, size_t size) override
for (unsigned i = 0; i < used_size; i++) { {
char const c = read_buf[i]; allocs.apply<Alloc>(Alloc::Id { (addr_t)addr }, [&] (Alloc &alloc) {
if (c) sum -= alloc.size;
Genode::print(out, Genode::Char(c)); destroy(wrapped, &alloc);
else wrapped.free(addr, size);
Genode::print(out, "."); });
}
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); chunk.write(str, strlen(str), seek_offset);
log("write \"", str, "\" at offset ", seek_offset, " -> ", chunk);
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);
} }
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 */ /* Genode includes */
#include <util/reconstructible.h> #include <util/reconstructible.h>
#include <base/log.h> #include <base/component.h>
using Genode::Reconstructible;
using Genode::Constructible;
using Genode::log;
using namespace Genode;
struct Object struct Object
{ {
unsigned const id; unsigned const id;
Object(unsigned id) : id(id) Object(unsigned id) : id(id) { log("construct Object ", id); }
{ ~Object() { log("destruct Object ", id); }
log("construct Object ", id);
}
~Object()
{
log("destruct Object ", id);
}
void method() { log("method called on Object ", id); } void method() { log("method called on Object ", id); }
void const_method() const { log("const 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 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) ~Member_with_reference() { log("destruct Member_with_reference"); }
{
log("construct Member_with_reference");
}
~Member_with_reference()
{
log("destruct Member_with_reference");
}
}; };
struct Compound struct Compound
{ {
Reconstructible<Member_with_reference> member; Reconstructible<Member_with_reference> member;
Constructible<Member_with_reference> lazy_member; Constructible<Member_with_reference> lazy_member;
Compound(Object &object) Compound(Object &object) : member(object) {
: log("construct Compound"); }
member(object)
{
log("construct Compound");
}
~Compound() ~Compound() { log("destruct Compound"); }
{
log("destruct Compound");
}
}; };
@ -94,79 +71,68 @@ struct Throwing
log("construct Throwing -> throw exception"); log("construct Throwing -> throw exception");
throw -1; throw -1;
} else { } else {
log("construct Throwing -> don't throw"); log("construct Throwing -> don't throw"); }
}
} }
virtual ~Throwing() virtual ~Throwing() { log("destruct Throwing"); }
{
log("destruct Throwing");
}
}; };
static void call_const_method(Compound const &compound) struct Main
{ {
compound.member->reference.const_method(); void call_const_method(Compound const &compound) {
} compound.member->reference.const_method(); }
int main(int, char **)
{
using namespace Genode;
log("--- test-reconstructible started ---");
Main(Env &env)
{ {
Object object_1(1); log("--- Reconstructible utility test ---");
Object object_2(2); {
Object object_1(1);
Object object_2(2);
log("-- create Compound object --"); log("create Compound object");
Compound compound(object_1); Compound compound(object_1);
log("compound.member.constructed returns ", log("compound.member.constructed returns ",
compound.member.constructed()); compound.member.constructed());
log("compound.lazy_member.constructed returns ", log("compound.lazy_member.constructed returns ",
compound.lazy_member.constructed()); compound.lazy_member.constructed());
log("-- construct lazy member --"); log("construct lazy member");
compound.lazy_member.construct(object_2); compound.lazy_member.construct(object_2);
log("compound.lazy_member.constructed returns ", log("compound.lazy_member.constructed returns ",
compound.lazy_member.constructed()); compound.lazy_member.constructed());
log("-- call method on member (with reference to Object 1) --"); log("call method on member (with reference to Object 1)");
call_const_method(compound); call_const_method(compound);
log("-- reconstruct member with Object 2 as reference --"); log("reconstruct member with Object 2 as reference");
compound.member.construct(object_2); compound.member.construct(object_2);
log("-- call method on member --"); log("call method on member");
call_const_method(compound); call_const_method(compound);
log("-- destruct member --"); log("destruct member");
compound.member.destruct(); 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 { try {
call_const_method(compound); } log("construct Throwing object");
catch (typename Reconstructible<Member_with_reference>::Deref_unconstructed_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("got exception, as expected"); }
log("-- destruct Compound and Objects 1 and 2 --"); log("--- Reconstructible utility test finished ---");
} }
};
try { void Component::construct(Env &env) { static Main main(env); }
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;
}

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 Stefan Kalkowski
* \author Martin Stein
* \date 2010-07-07 * \date 2010-07-07
* *
* The test program compares the values delivered by the block-service, * 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */
#include <base/allocator_avl.h> #include <base/allocator_avl.h>
#include <base/log.h> #include <base/heap.h>
#include <base/sleep.h> #include <base/component.h>
#include <base/exception.h>
#include <base/thread.h>
#include <os/config.h>
#include <block_session/connection.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; using File_name = String<64>;
Genode::Rom_connection _rom; using Packet_descriptor = Block::Packet_descriptor;
Genode::addr_t _addr; 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::Session::Tx::Source &src = *block.tx();
BLOCK_REQ_PARALLEL = 10 /* number of blocks to handle per block-request */ size_t blk_sz;
}; Block::sector_t blk_cnt;
Block::Session::Operations ops;
Comparer(Genode::Allocator_avl *block_alloc, block.info(&blk_cnt, &blk_sz, &ops);
const char* filename) if (!ops.supported(Packet_descriptor::READ)) {
: Thread_deprecated("comparer"), _blk_con(block_alloc), _rom(filename), throw Device_not_readable(); }
_addr(Genode::env()->rm_session()->attach(_rom.dataspace())) { }
void entry() log("We have ", blk_cnt, " blocks with a size of ", blk_sz, " bytes");
{ for (size_t i = 0; i < blk_cnt; i += REQ_PARALLEL) {
using namespace Genode; 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(); log("Check blocks ", i, "..", i + cnt - 1);
size_t blk_size = 0; src.submit_packet(pkt);
Block::sector_t blk_cnt = 0; pkt = src.get_acked_packet();
Genode::addr_t end = if (!pkt.succeeded()) {
_addr + Dataspace_client(_rom.dataspace()).size(); throw Read_request_failed(); }
Block::Session::Operations ops;
_blk_con.info(&blk_cnt, &blk_size, &ops);
if (!ops.supported(Block::Packet_descriptor::READ)) { char const *rom_src = rom.local_addr<char>() + i * blk_sz;
error("Block device not readable!"); if (strcmp(rom_src, src.packet_content(pkt), rom.size())) {
} throw Files_differ(); }
log("We have ", blk_cnt, " blocks with a " src.release_packet(pkt);
"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!");
} }
log("--- ROM Block test finished ---");
}
}; };
void Component::construct(Env &env) { static Main main(env); }
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;
}

View File

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

View File

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

View File

@ -1,142 +1,100 @@
/* /*
* \brief Test for signalling framework * \brief Test for signalling framework
* \author Norman Feske * \author Norman Feske
* \author Martin Stein
* \date 2008-09-06 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */
#include <base/component.h> #include <base/component.h>
#include <base/heap.h> #include <base/heap.h>
#include <base/log.h>
#include <base/signal.h>
#include <base/sleep.h>
#include <base/thread.h> #include <base/thread.h>
#include <base/registry.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <util/misc_math.h>
using namespace Genode; using namespace Genode;
/** /**
* Transmit signals in a periodic fashion * A thread that submits a signal context in a periodic fashion
*/ */
class Sender : Thread class Sender : Thread
{ {
private: private:
Timer::Connection _timer; /* timer connection for local use */ Timer::Connection _timer;
Signal_transmitter _transmitter; Signal_transmitter _transmitter;
unsigned const _interval_ms; /* interval between signals in milliseconds */ unsigned const _interval_ms;
bool _stop; /* state for destruction protocol */ bool const _verbose;
unsigned _submit_cnt; /* statistics */ bool _stop { false };
bool _idle; /* suppress the submission of signals */ unsigned _submit_cnt { 0 };
bool const _verbose; /* print activities */ bool _idle { false };
/**
* Sender thread submits signals every '_interval_ms' milliseconds
*/
void entry() void entry()
{ {
while (!_stop) { while (!_stop) {
if (!_idle) { if (!_idle) {
_submit_cnt++; _submit_cnt++;
if (_verbose) {
if (_verbose) log("submit signal ", _submit_cnt); }
log("submit signal ", _submit_cnt);
_transmitter.submit(); _transmitter.submit();
if (_interval_ms) {
if (_interval_ms) _timer.msleep(_interval_ms); }
_timer.msleep(_interval_ms); } else {
} else _timer.msleep(100); }
_timer.msleep(100);
} }
} }
public: public:
/** Sender(Env &env,
* Constructor Signal_context_capability context,
* unsigned interval_ms,
* \param context signal destination bool verbose)
* \param interval_ms interval between signals
* \param verbose print status information
*/
Sender(Env &env, Signal_context_capability context,
unsigned interval_ms, bool verbose = true)
: :
Thread(env, "sender", 4096*sizeof(long)), Thread(env, "sender", 4096 * sizeof(addr_t)), _timer(env),
_timer(env), _transmitter(context), _interval_ms(interval_ms), _verbose(verbose)
_transmitter(context),
_interval_ms(interval_ms),
_stop(false),
_submit_cnt(0),
_idle(0),
_verbose(verbose)
{ {
/* start thread at 'entry' function */ Thread::start();
start();
} }
/** /***************
* Destructor ** Accessors **
*/ ***************/
~Sender()
{
/* tell thread to stop iterating */
_stop = true;
/* wait for current 'msleep' call of the thread to finish */ void idle(bool idle) { _idle = idle; }
_timer.msleep(0); unsigned submit_cnt() const { return _submit_cnt; }
}
/**
* 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; }
}; };
/** /**
* 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 class Handler : Thread
{ {
private: private:
Timer::Connection _timer; /* timer connection for local use */ Timer::Connection _timer;
unsigned const _dispatch_ms; /* time needed for dispatching a signal */ unsigned const _dispatch_ms;
unsigned const _id; /* unique ID of signal handler for debug output */ unsigned const _id;
static unsigned _id_cnt; /* counter for producing unique IDs */ bool const _verbose;
Signal_receiver &_receiver; /* signal endpoint */ Signal_receiver &_receiver;
bool _stop; /* state for destruction protocol */ bool _stop { false };
unsigned _receive_cnt; /* number of received notifications */ unsigned _receive_cnt { 0 };
unsigned _activation_cnt; /* number of invocations of the signal handler */ unsigned _activation_cnt { 0 };
bool _idle; /* suppress the further handling of signals */ bool _idle { false };
bool const _verbose; /* print status information */
/**
* Signal handler needs '_dispatch_ms' milliseconds for each signal
*/
void entry() void entry()
{ {
while (!_stop) { while (!_stop) {
if (!_idle) { if (!_idle) {
Signal signal = _receiver.wait_for_signal(); Signal signal = _receiver.wait_for_signal();
if (_verbose) if (_verbose)
log("handler ", _id, " got ", signal.num(), " " log("handler ", _id, " got ", signal.num(), " "
"signal", (signal.num() == 1 ? "" : "s"), " " "signal", (signal.num() == 1 ? "" : "s"), " "
@ -145,7 +103,6 @@ class Handler : Thread
_receive_cnt += signal.num(); _receive_cnt += signal.num();
_activation_cnt++; _activation_cnt++;
} }
if (_dispatch_ms) if (_dispatch_ms)
_timer.msleep(_dispatch_ms); _timer.msleep(_dispatch_ms);
} }
@ -153,486 +110,351 @@ class Handler : Thread
public: public:
/** Handler(Env &env,
* Constructor Signal_receiver &receiver,
* unsigned dispatch_ms,
* \param receiver receiver to request signals from bool verbose,
* \param dispatch_ms duration of signal-handler activity unsigned id)
* \param verbose print status information
*/
Handler(Env &env, Signal_receiver &receiver, unsigned dispatch_ms, bool verbose = true)
: :
Thread(env, "handler", 4096*sizeof(long)), Thread(env, "handler", 4096 * sizeof(addr_t)), _timer(env),
_timer(env), _dispatch_ms(dispatch_ms), _id(id), _verbose(verbose),
_dispatch_ms(dispatch_ms), _receiver(receiver)
_id(++_id_cnt),
_receiver(receiver),
_stop(false),
_receive_cnt(0),
_activation_cnt(0),
_idle(0),
_verbose(verbose)
{ {
start(); Thread::start();
} }
/** void print(Output &output) const { Genode::print(output, "handler ", _id); }
* Destructor
*/
~Handler()
{
/* tell thread to stop iterating */
_stop = true;
/* wait for current 'msleep' call of the thread to finish */ /***************
_timer.msleep(0); ** Accessors **
} ***************/
/** void idle(bool idle) { _idle = idle; }
* Suppress the handling of further signals unsigned receive_cnt() const { return _receive_cnt; }
*/
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
*/
unsigned activation_cnt() const { return _activation_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; struct Signal_test
/**
* 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
{ {
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) { } ~Signal_test() { log("\nTEST ", id, " finished\n"); }
int id() const { return _id; }
}; };
struct Fast_sender_test : Signal_test
/**
* 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)
{ {
enum { SPEED = 10 }; static constexpr char const *brief =
enum { TEST_DURATION = 50*SPEED }; "reliable delivery if the sender is faster than the handlers";
enum { HANDLER_INTERVAL = 10*SPEED };
enum { SENDER_INTERVAL = 2*SPEED };
enum { FINISH_IDLE_TIME = 2*HANDLER_INTERVAL };
log(""); enum { HANDLER_INTERVAL_MS = 10 * SPEED,
log("TEST ", ++test_cnt, ": one sender, one handler, sender is faster than handler"); SENDER_INTERVAL_MS = 2 * SPEED,
log(""); DURATION_MS = 50 * SPEED,
FINISH_IDLE_MS = 2 * HANDLER_INTERVAL_MS };
Signal_receiver receiver; struct Unequal_sent_and_received_signals : Exception { };
Id_signal_context context_123(123);
Heap heap(env.ram(), env.rm()); Env &env;
Timer::Connection timer(env); Timer::Connection timer { env };
Signal_context context;
Handler *handler = new (heap) Handler(env, receiver, HANDLER_INTERVAL, false); Signal_receiver receiver;
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123), Handler handler { env, receiver, HANDLER_INTERVAL_MS, false, 1 };
SENDER_INTERVAL, false); Sender sender { env, receiver.manage(&context),
SENDER_INTERVAL_MS, 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();
Fast_sender_test(Env &env, int id) : Signal_test(id, brief), env(env)
{ {
Signal signal = rec_1.wait_for_signal(); timer.msleep(DURATION_MS);
log("returned from wait_for_signal for receiver 1");
signal = rec_2.wait_for_signal(); /* stop emitting signals */
log("returned from wait_for_signal for receiver 2"); 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"); struct Multiple_handlers_test : Signal_test
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)
{ {
Id_signal_context *context; static constexpr char const *brief =
Signal_receiver *rec; "get multiple handlers at one sender activated in a fair manner";
Signal_context_capability cap;
Timer::Connection timer(env); enum { HANDLER_INTERVAL_MS = 8 * SPEED,
Heap heap(env.ram(), env.rm()); SENDER_INTERVAL_MS = 1 * SPEED,
FINISH_IDLE_MS = 2 * HANDLER_INTERVAL_MS,
DURATION_MS = 50 * SPEED,
NR_OF_HANDLERS = 4 };
/* setup receiver side */ struct Unequal_sent_and_received_signals : Exception { };
context = new (heap) Id_signal_context(321); struct Unequal_activation_of_handlers : Exception { };
rec = new (heap) Signal_receiver;
cap = rec->manage(context);
/* spawn sender */ Env &env;
Sender *sender = new (heap) Sender(env, cap, 500); 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 */ Multiple_handlers_test(Env &env, int id) : Signal_test(id, brief), env(env)
timer.msleep(1000);
log("suspend sender");
sender->idle();
/* collect pending signals and dissolve context from receiver */
{ {
Signal signal = rec->wait_for_signal(); for (unsigned i = 0; i < NR_OF_HANDLERS; i++)
log("got ", signal.num(), " signal(s) from ", signal.context()); 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 */ struct Stress_test : Signal_test
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>
{ {
private: static constexpr char const *brief =
"throughput when submitting/handling as fast as possible";
Signal_receiver *_receiver; enum { DURATION_SEC = 5 };
Signal_context *_context;
public: struct Unequal_sent_and_received_signals : Exception { };
Signal_context_destroyer(Signal_receiver *receiver, Signal_context *context) Env &env;
: Thread_deprecated("signal_context_destroyer"), Timer::Connection timer { env };
_receiver(receiver), _context(context) { } 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(); Signal signal = receiver_1.wait_for_signal();
_receiver->dissolve(_context); log("returned from wait_for_signal for receiver 1");
signal_context_destroyed = true;
destroy(env()->heap(), _context); signal = receiver_2.wait_for_signal();
log("returned from wait_for_signal for receiver 2");
} }
log("submit and receive signals with multiple receivers out of order");
transmitter_1.submit();
transmitter_2.submit();
{
Signal signal = receiver_2.wait_for_signal();
log("returned from wait_for_signal for receiver 2");
signal = receiver_1.wait_for_signal();
log("returned from wait_for_signal for receiver 1");
}
}
}; };
struct Context_management_test : Signal_test
static void synchronized_context_destruction_test(Env &env)
{ {
Signal_receiver receiver; static constexpr char const *brief =
Timer::Connection timer(env); "correct initialization and cleanup of receiver and context";
static Heap heap(env.ram(), env.rm());
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)); Context_management_test(Env &env, int id) : Signal_test(id, brief), env(env)
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. */
{ {
Signal signal = receiver.wait_for_signal(); /* stop sender after timeout */
/* let the signal context destroyer thread try to destroy the signal context */
signal_context_destroyer_lock.unlock();
timer.msleep(1000); timer.msleep(1000);
log("suspend sender");
sender.idle(true);
Signal signal_copy = signal; /* collect pending signals and dissolve context from receiver */
Signal signal_copy2 = signal; {
Signal signal = receiver.wait_for_signal();
signal_copy = signal_copy2; log("got ", signal.num(), " signal(s) from ", signal.context());
if (signal_context_destroyed) {
error("signal context destroyed too early");
sleep_forever();
} }
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(); Synchronized_destruction_test(Env &env, int id)
signal_context_destroyed = false; : 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();
}
};
struct Many_contexts_test : Signal_test
static void many_managed_contexts(Env &env)
{ {
static Heap heap(env.ram(), env.rm()); static constexpr char const *brief = "create and manage many contexts";
for (unsigned round = 0; round < 10; ++round) {
unsigned const num_contexts = 200 + 5*round; struct Manage_failed : Exception { };
log("round ", round, ": create and manage ", num_contexts, " contexts");
Signal_receiver rec; Env &env;
Heap heap { env.ram(), env.rm() };
Registry<Registered<Signal_context> > contexts;
for (unsigned i = 0; i < num_contexts; ++i) { Many_contexts_test(Env &env, int id) : Signal_test(id, brief), env(env)
Id_signal_context *context = new (heap) Id_signal_context(i); {
if (!rec.manage(context).valid()) { for (unsigned round = 0; round < 10; round++) {
error("failed to manage signal context");
sleep_forever(); 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"); struct Main
}
void Component::construct(Genode::Env &env)
{ {
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); Main(Env &env)
multiple_handlers_test(env); {
stress_test(env); log("--- Signalling test ---");
lazy_receivers_test(env); test_1.construct(env, 1); test_1.destruct();
check_context_management(env); test_2.construct(env, 2); test_2.destruct();
synchronized_context_destruction_test(env); test_3.construct(env, 3); test_3.destruct();
many_managed_contexts(env); test_4.construct(env, 4); test_4.destruct();
test_5.construct(env, 5); test_5.destruct();
log("--- signalling test finished ---"); test_6.construct(env, 6); test_6.destruct();
env.parent().exit(0); 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 */ /* Genode includes */
#include <base/synced_interface.h> #include <base/synced_interface.h>
#include <base/log.h> #include <base/component.h>
using namespace Genode;
struct Adder struct Adder
{ {
int add(int a, int b) int add(int a, int b)
{ {
Genode::log("adding ", a, " + ", b); log("adding ", a, " + ", b);
return a + b; return a + b;
} }
}; };
@ -28,22 +30,25 @@ struct Adder
struct Pseudo_lock struct Pseudo_lock
{ {
void lock() { Genode::log("lock"); } void lock() { log("lock"); }
void unlock() { Genode::log("unlock"); } 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; Main(Env &env)
Adder adder; {
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); void Component::construct(Env &env) { static Main main(env); }
log("result is ", res);
return 0;
}

View File

@ -1,57 +1,49 @@
/* /*
* \brief Terminal echo program * \brief Terminal echo program
* \author Norman Feske * \author Norman Feske
* \author Martin Stein
* \date 2009-10-16 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
#include <base/log.h> /* Genode includes */
#include <base/signal.h> #include <base/component.h>
#include <terminal_session/connection.h> #include <terminal_session/connection.h>
using namespace Genode; using namespace Genode;
static const bool verbose = false; struct Main
int main(int, char **)
{ {
static Terminal::Connection terminal; Terminal::Connection terminal;
Signal_handler<Main> read_avail;
char read_buffer[100];
enum { READ_BUFFER_SIZE = 100 }; String<128> intro {
static char read_buffer[READ_BUFFER_SIZE]; "--- Terminal echo test started - now you can type characters to be echoed. ---\r\n" };
Signal_receiver sig_rec; void handle_read_avail()
Signal_context sig_ctx; {
unsigned num_bytes = terminal.read(read_buffer, sizeof(read_buffer));
terminal.read_avail_sigh(sig_rec.manage(&sig_ctx)); log("got ", num_bytes, " byte(s)");
for (unsigned i = 0; i < num_bytes; i++) {
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++) {
if (read_buffer[i] == '\r') { if (read_buffer[i] == '\r') {
terminal.write("\n", 1); terminal.write("\n", 1); }
}
terminal.write(&read_buffer[i], 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. * 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 <base/thread.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
using namespace Genode; using namespace Genode;
struct Worker : Genode::Thread_deprecated<4096> struct Worker : Thread
{ {
Timer::Session &timer; Timer::Session &timer;
unsigned const result_value; unsigned const result_value;
unsigned volatile result; unsigned volatile result;
void entry() void entry()
{ {
log("worker thread is up"); log("Worker thread is up");
timer.msleep(250); timer.msleep(250);
log("worker is leaving the entry function with " log("Worker is leaving the entry function with result=", result_value);
"result=", result_value, "...");
result = result_value; result = result_value;
} }
Worker(Timer::Session &timer, int result_value) Worker(Env &env, Timer::Session &timer, unsigned result_value)
: : Thread(env, "worker", 1024 * sizeof(addr_t)), timer(timer),
Thread_deprecated("worker"), result_value(result_value), result(~0)
timer(timer), result_value(result_value), result(~0)
{ {
start(); Thread::start();
} }
}; };
/** struct Main
* Main program
*/
int main(int, char **)
{ {
log("--- thread join test ---"); struct Worker_unfinished_after_join : Exception { };
Timer::Connection timer; 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 * A worker thread is created in each iteration. Just before
* leaving the entry function, the worker assigns the result * leaving the entry function, the worker assigns the result
* to 'Worker::result' variable. By validating this value, * to 'Worker::result' variable. By validating this value,
* we determine whether the worker has finished or not. * we determine whether the worker has finished or not.
*/ */
Worker worker(timer, i); Worker worker(env, timer, i);
worker.join(); worker.join();
if (worker.result != i) {
if (worker.result != i) { throw Worker_unfinished_after_join(); }
error("work remains unfinished after 'join()' returned");
return -1;
} }
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 * \brief Test for the timed-semaphore
* \author Stefan Kalkowski * \author Stefan Kalkowski
* \author Martin Stein
* \date 2010-03-05 * \date 2010-03-05
*/ */
@ -11,93 +12,67 @@
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <os/timed_semaphore.h> #include <os/timed_semaphore.h>
#include <base/thread.h> #include <base/thread.h>
#include <base/component.h>
using namespace Genode; using namespace Genode;
class Wakeup_thread : public Thread_deprecated<4096>
struct Test : Thread
{ {
private: struct Failed : Exception { };
Timed_semaphore *_sem; unsigned id;
Timer::Session *_timer; Timer::Connection wakeup_timer;
int _timeout; unsigned const wakeup_period;
Lock _lock; Timed_semaphore sem;
bool _stop; 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, Test(Env &env, bool timeouts, unsigned id, char const *brief)
Timer::Session *timer, : Thread(env, "wakeup", 1024 * sizeof(addr_t)), id(id), wakeup_timer(env),
Alarm::Time timeout) wakeup_period(timeouts ? 1000 : 100)
: Thread_deprecated("wakeup"), _sem(sem), _timer(timer), _timeout(timeout), {
_lock(Lock::LOCKED), _stop(false) { } 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() stop_wakeup = true;
{ wakeup_stopped.lock();
while(true) { }
_timer->msleep(_timeout);
_sem->up();
if (_stop) {
_lock.unlock();
return;
}
}
}
void stop() { _stop = true; _lock.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; Constructible<Test> test;
Wakeup_thread thread(&sem, timer, timeout2);
bool ret = true;
thread.start(); Main(Env &env)
try{ {
for (int i = 0; i < loops; i++) log("--- Timed semaphore test ---");
sem.down(timeout1); test.construct(env, false, 1, "without timeouts"); test.destruct();
} catch (Timeout_exception) { test.construct(env, true, 2, "with timeouts"); test.destruct();
ret = false; 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 **) void Component::construct(Genode::Env &env) { static Main main(env); }
{
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;
}

View File

@ -2,11 +2,12 @@
* \brief Low-level test for TRACE service * \brief Low-level test for TRACE service
* \author Norman Feske * \author Norman Feske
* \author Josef Soentgen * \author Josef Soentgen
* \author Martin Stein
* \date 2013-08-12 * \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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
@ -15,75 +16,61 @@
/* Genode includes */ /* Genode includes */
#include <trace_session/connection.h> #include <trace_session/connection.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <os/config.h> #include <base/attached_rom_dataspace.h>
#include <base/sleep.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) { Env &env;
case Genode::Trace::Subject_info::INVALID: return "INVALID"; Timer::Connection timer { env };
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;
void entry() void entry()
{ {
using namespace Genode; for (unsigned i = 0; ; i++) {
for (size_t i = 0; ; i++) {
if (i & 0x3) { if (i & 0x3) {
Ram_dataspace_capability ds_cap = env()->ram_session()->alloc(1024); Ram_dataspace_capability ds_cap = env.ram().alloc(1024);
env()->ram_session()->free(ds_cap); env.ram().free(ds_cap);
} }
timer.msleep(250);
_timer.msleep(250);
} }
} }
Test_thread(const char *name) Test_thread(Env &env, Name &name)
: Thread_deprecated(name) { start(); } : Thread(env, name, 1024 * sizeof(addr_t)), env(env) { start(); }
}; };
using namespace Genode;
class Trace_buffer_monitor class Trace_buffer_monitor
{ {
private: private:
enum { MAX_ENTRY_BUF = 256 }; enum { MAX_ENTRY_BUF = 256 };
char _buf[MAX_ENTRY_BUF];
char _buf[MAX_ENTRY_BUF];
Region_map &_rm;
Trace::Subject_id _id; Trace::Subject_id _id;
Trace::Buffer *_buffer; Trace::Buffer *_buffer;
Trace::Buffer::Entry _curr_entry; Trace::Buffer::Entry _curr_entry;
const char *_terminate_entry(Trace::Buffer::Entry const &entry) const char *_terminate_entry(Trace::Buffer::Entry const &entry)
{ {
size_t len = min(entry.length() + 1, MAX_ENTRY_BUF); size_t len = min(entry.length() + 1, MAX_ENTRY_BUF);
memcpy(_buf, entry.data(), len); memcpy(_buf, entry.data(), len);
_buf[len-1] = '\0'; _buf[len-1] = '\0';
return _buf; return _buf;
} }
public: 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), _rm(rm), _id(id), _buffer(rm.attach(ds_cap)),
_buffer(env()->rm_session()->attach(ds_cap)),
_curr_entry(_buffer->first()) _curr_entry(_buffer->first())
{ {
log("monitor subject:", _id.id, " buffer:", Hex((addr_t)_buffer)); log("monitor subject:", _id.id, " buffer:", Hex((addr_t)_buffer));
@ -92,7 +79,7 @@ class Trace_buffer_monitor
~Trace_buffer_monitor() ~Trace_buffer_monitor()
{ {
if (_buffer) if (_buffer)
env()->rm_session()->detach(_buffer); _rm.detach(_buffer);
} }
Trace::Subject_id id() { return _id; }; Trace::Subject_id id() { return _id; };
@ -100,7 +87,6 @@ class Trace_buffer_monitor
void dump() void dump()
{ {
log("overflows: ", _buffer->wrapped()); log("overflows: ", _buffer->wrapped());
log("read all remaining events"); log("read all remaining events");
for (; !_curr_entry.last(); _curr_entry = _buffer->next(_curr_entry)) { for (; !_curr_entry.last(); _curr_entry = _buffer->next(_curr_entry)) {
/* omit empty entries */ /* omit empty entries */
@ -111,163 +97,193 @@ class Trace_buffer_monitor
if (data) if (data)
log(data); log(data);
} }
/* reset after we read all available entries */ /* reset after we read all available entries */
_curr_entry = _buffer->first(); _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;
/* Test_out_of_metadata(Env &env) : 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 log("test Out_of_metadata exception of Trace::Session::subjects call");
* 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.
*/
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 { enum { MAX_SUBJECT_IDS = 16 };
Genode::Trace::Connection trace(sizeof(subject_ids) + 4096, sizeof(subject_ids), 0); Trace::Subject_id subject_ids[MAX_SUBJECT_IDS];
/* we should never arrive here */ try {
struct Unexpectedly_got_no_exception{}; Trace::Connection trace(env, sizeof(subject_ids) + 4096,
throw Unexpectedly_got_no_exception(); sizeof(subject_ids), 0);
} catch (Genode::Parent::Service_denied) {
log("got Genode::Parent::Service_denied exception as expected"); /* 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 ---"); char const *state_name(Trace::Subject_info::State state)
{
test_out_of_metadata(); switch (state) {
case Trace::Subject_info::INVALID: return "INVALID";
static Genode::Trace::Connection trace(1024*1024, 64*1024, 0); case Trace::Subject_info::UNTRACED: return "UNTRACED";
case Trace::Subject_info::TRACED: return "TRACED";
static Timer::Connection timer; case Trace::Subject_info::FOREIGN: return "FOREIGN";
case Trace::Subject_info::ERROR: return "ERROR";
static Test_thread test("test-thread"); case Trace::Subject_info::DEAD: return "DEAD";
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;
} }
return "undefined";
}
} catch (...) { } Test_tracing(Env &env) : env(env)
{
for (size_t cnt = 0; cnt < 5; cnt++) { try {
Xml_node policy = config.xml().sub_node("trace_policy");
timer.msleep(3000); for (;; policy = policy.next("trace_policy")) {
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 { try {
log("enable tracing for " policy.attribute("label").value(policy_label, sizeof (policy_label));
"thread:'", info.thread_name().string(), "' with " policy.attribute("module").value(policy_module, sizeof (policy_module));
"policy:", policy_id.id);
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); size_t rom_size = Dataspace_client(policy_module_rom_ds).size();
test_monitor = new (env()->heap()) Trace_buffer_monitor(subjects[i].id, ds_cap);
} 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 */ } catch (...) { }
if (test_monitor) {
if (subjects[i].id == test_monitor->id().id) for (size_t cnt = 0; cnt < 5; cnt++) {
test_monitor->dump();
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) struct Main
destroy(env()->heap(), test_monitor); {
Constructible<Test_out_of_metadata> test_1;
Constructible<Test_tracing> test_2;
log("--- test-trace finished ---"); Main(Env &env)
return 0; {
} 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 * This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
/* Genode includes */
#include <base/snprintf.h> #include <base/snprintf.h>
#include <base/log.h> #include <base/component.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <uart_session/connection.h> #include <uart_session/connection.h>
using namespace Genode; using namespace Genode;
int main()
struct Main
{ {
log("--- UART test started ---"); Timer::Connection timer;
Uart::Connection uart;
char buf[100];
static Timer::Connection timer; Main(Env &env)
static Uart::Connection uart; {
log("--- UART test started ---");
for (unsigned i = 0; ; ++i) { for (unsigned i = 0; ; ++i) {
int n = snprintf(buf, sizeof(buf), "UART test message %d\n", i);
static char buf[100]; uart.write(buf, n);
int n = snprintf(buf, sizeof(buf), "UART test message %d\n", i); timer.msleep(2000);
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); MAX_DEPTH = config_xml.attribute_value("depth", 16U);
unsigned long elapsed_ms; unsigned long elapsed_ms;
Timer::Connection timer; Timer::Connection timer(env);
/* populate the directory file system at / */ /* populate the directory file system at / */
vfs_root.num_dirent("/"); vfs_root.num_dirent("/");