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,13 +69,8 @@ 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
@ -83,5 +78,4 @@ 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);
env.rm().detach(config_ds_addr);
loader.commit_rom_module("config"); 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
{ {
Env &env;
Attached_rom_dataspace config { env, "config" };
Signal_handler<Main> config_handler { env.ep(), *this, &Main::handle_config };
void handle_config()
{
config.update();
try { try {
long counter = 1; long counter = 1;
Genode::config()->xml_node().sub_node("counter").value(&counter); config.xml().sub_node("counter").value(&counter);
Genode::log("obtained counter value ", counter, " from config"); log("obtained counter value ", counter, " from config");
} catch (...) {
Genode::error("could not parse configuration");
} }
} catch (...) { error("could not parse configuration"); }
int main(int, char **)
{
parse_config();
/* register signal handler for config changes */
Genode::Signal_receiver sig_rec;
Genode::Signal_context sig_ctx;
Genode::config()->sigh(sig_rec.manage(&sig_ctx));
for (;;) {
/* wait for config change */
sig_rec.wait_for_signal();
Genode::config()->reload();
parse_config();
} }
return 0;
} Main(Env &env) : env(env)
{
handle_config();
config.sigh(config_handler);
}
};
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();
return static_cap_cast<Rom_dataspace>(ds_cap);
} }
Genode::Dataspace_capability ds_cap = _fg.cap(); void sigh(Signal_context_capability sigh_cap) override { _sigh = sigh_cap; }
return Genode::static_cap_cast<Genode::Rom_dataspace>(ds_cap);
}
void sigh(Genode::Signal_context_capability 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();
/* line width in bytes */
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel(); unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
unsigned const h = fb_mode.height(); unsigned const h = fb_mode.height();
for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) {
for (unsigned i = 0; now_ms() - start_ms < duration_ms; i++) { blit(buf[i % 2], w, fb_ds.local_addr<char>(), w, w, h);
blit(src_buf[i % 2], w, fb_ds.local_addr<char>(), w, w, h); kib += (w * h) / 1024;
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();
/* line width in bytes */
unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel(); unsigned const w = fb_mode.width() * fb_mode.bytes_per_pixel();
unsigned const h = fb_mode.height(); unsigned const h = fb_mode.height();
for (unsigned i = 0; timer.elapsed_ms() - start_ms < DURATION_MS; i++) {
for (unsigned i = 0; now_ms() - start_ms < duration_ms; i++) { blit(buf[i % 2] + 2, w, fb_ds.local_addr<char>() + 2, w, w - 2, h);
blit(src_buf[i % 2] + 2, w, fb_ds.local_addr<char>() + 2, w, w - 2, h); kib += (w * h) / 1024;
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,48 +45,33 @@ 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;
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 ---"); log("--- Input test ---");
input.sigh(input_sigh);
_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"
@ -99,10 +82,5 @@ void Test_environment::_handle_input()
}); });
} }
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,26 +1,55 @@
/* /*
* \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
{ {
static char read_buf[Chunk_level_0::SIZE];
if (used_size() > Chunk_level_0::SIZE) {
throw Index_out_of_range(); }
read(read_buf, used_size(), 0);
Genode::print(out, "content (size=", used_size(), "): ");
Genode::print(out, "\"");
for (unsigned i = 0; i < used_size(); i++) {
char const c = read_buf[i];
if (c) {
Genode::print(out, Char(c)); }
else {
Genode::print(out, "."); }
}
Genode::print(out, "\"");
}
};
struct Allocator_tracer : Allocator
{
struct Alloc struct Alloc
{ {
using Id = Id_space<Alloc>::Id; using Id = Id_space<Alloc>::Id;
@ -32,105 +61,49 @@ namespace Genode {
: id_space_elem(*this, space, id), size(size) { } : id_space_elem(*this, space, id), size(size) { }
}; };
Id_space<Alloc> _allocs; Id_space<Alloc> allocs;
size_t _sum; size_t sum { 0 };
Allocator &_wrapped; Allocator &wrapped;
Allocator_tracer(Allocator &wrapped) : _sum(0), _wrapped(wrapped) { } Allocator_tracer(Allocator &wrapped) : wrapped(wrapped) { }
size_t sum() const { return _sum; } bool alloc(size_t size, void **out_addr) override
bool alloc(size_t size, void **out_addr)
{ {
_sum += size; sum += size;
bool result = _wrapped.alloc(size, out_addr); bool result = wrapped.alloc(size, out_addr);
new (_wrapped) Alloc(_allocs, Alloc::Id { (addr_t)*out_addr }, size); new (wrapped) Alloc(allocs, Alloc::Id { (addr_t)*out_addr }, size);
return result; return result;
} }
void free(void *addr, size_t size) void free(void *addr, size_t size) override
{ {
_allocs.apply<Alloc>(Alloc::Id { (addr_t)addr }, [&] (Alloc &alloc) { allocs.apply<Alloc>(Alloc::Id { (addr_t)addr }, [&] (Alloc &alloc) {
_sum -= alloc.size; sum -= alloc.size;
destroy(_wrapped, &alloc); destroy(wrapped, &alloc);
_wrapped.free(addr, size); wrapped.free(addr, size);
}); });
} }
size_t overhead(size_t size) const override { return _wrapped.overhead(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(); } 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 };
namespace Genode { Main(Env &env) : env(env)
/**
* 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; log("--- RAM filesystem chunk test ---");
static char read_buf[Chunk_level_0::SIZE];
size_t used_size = chunk.used_size();
struct File_size_out_of_bounds { };
if (used_size > Chunk_level_0::SIZE)
throw File_size_out_of_bounds();
chunk.read(read_buf, used_size, 0);
Genode::print(out, "content (size=", used_size, "): ");
Genode::print(out, "\"");
for (unsigned i = 0; i < used_size; i++) {
char const c = read_buf[i];
if (c)
Genode::print(out, Genode::Char(c));
else
Genode::print(out, ".");
}
Genode::print(out, "\"");
}
}
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("chunk sizes");
log(" level 0: payload=", (int)Chunk_level_0::SIZE, " sizeof=", sizeof(Chunk_level_0)); 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 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 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)); log(" level 3: payload=", (int)Chunk_level_3::SIZE, " sizeof=", sizeof(Chunk_level_3));
static Allocator_tracer alloc(*env()->heap());
{ {
Chunk_level_0 chunk(alloc, 0); Chunk_level_0 chunk(alloc, 0);
write(chunk, "five-o-one", 0); write(chunk, "five-o-one", 0);
/* overwrite part of the file */ /* overwrite part of the file */
@ -141,12 +114,24 @@ int main(int, char **)
write(chunk, "YM-2149", 35); write(chunk, "YM-2149", 35);
truncate(chunk, 30); truncate(chunk, 30);
for (unsigned i = 29; i > 0; i--) for (unsigned i = 29; i > 0; i--)
truncate(chunk, i); truncate(chunk, i);
} }
log("allocator: sum=", alloc.sum);
log("--- RAM filesystem chunk test finished ---");
}
log("allocator: sum=", alloc.sum()); void write(Chunk_level_0 &chunk, char const *str, off_t seek_offset)
{
chunk.write(str, strlen(str), seek_offset);
log("write \"", str, "\" at offset ", seek_offset, " -> ", chunk);
}
return 0; void truncate(Chunk_level_0 &chunk, file_size_t size)
} {
chunk.truncate(size);
log("trunc(", size, ") -> ", chunk);
}
};
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); }
@ -42,18 +32,12 @@ 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");
}
}; };
@ -62,17 +46,10 @@ 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,34 +71,26 @@ 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)
{
log("--- Reconstructible utility test ---");
{ {
Object object_1(1); Object object_1(1);
Object object_2(2); 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 ",
@ -129,44 +98,41 @@ int main(int, char **)
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 { try { call_const_method(compound); }
call_const_method(compound); }
catch (typename Reconstructible<Member_with_reference>::Deref_unconstructed_object) { catch (typename Reconstructible<Member_with_reference>::Deref_unconstructed_object) {
log("got exception, as expected"); } log("got exception, as expected"); }
log("-- destruct Compound and Objects 1 and 2 --"); log("destruct Compound and Objects 1 and 2");
} }
try { try {
log("-- construct Throwing object"); log("construct Throwing object");
Bool const b_false(false), b_true(true); Bool const b_false(false), b_true(true);
Reconstructible<Throwing> inst(b_false); Reconstructible<Throwing> inst(b_false);
inst.construct(b_true); inst.construct(b_true);
Genode::error("expected contructor to throw"); Genode::error("expected contructor to throw");
} catch (int i) { } catch (int i) {
log("-- catched exception as expected"); log("got exception, as expected"); }
log("--- Reconstructible utility test finished ---");
} }
};
log("--- test-reconstructible finished ---"); void Component::construct(Env &env) { static Main main(env); }
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)
enum {
BLOCK_REQ_PARALLEL = 10 /* number of blocks to handle per block-request */
};
Comparer(Genode::Allocator_avl *block_alloc,
const char* filename)
: Thread_deprecated("comparer"), _blk_con(block_alloc), _rom(filename),
_addr(Genode::env()->rm_session()->attach(_rom.dataspace())) { }
void entry()
{ {
using namespace Genode; log("--- ROM Block test ---");
Block::Session::Tx::Source *source = _blk_con.tx(); Block::Session::Tx::Source &src = *block.tx();
size_t blk_size = 0; size_t blk_sz;
Block::sector_t blk_cnt = 0; Block::sector_t blk_cnt;
Genode::addr_t end =
_addr + Dataspace_client(_rom.dataspace()).size();
Block::Session::Operations ops; Block::Session::Operations ops;
_blk_con.info(&blk_cnt, &blk_size, &ops);
if (!ops.supported(Block::Packet_descriptor::READ)) { block.info(&blk_cnt, &blk_sz, &ops);
error("Block device not readable!"); if (!ops.supported(Packet_descriptor::READ)) {
} throw Device_not_readable(); }
log("We have ", blk_cnt, " blocks with a " log("We have ", blk_cnt, " blocks with a size of ", blk_sz, " bytes");
"size of ", Hex(blk_size), " bytes"); for (size_t i = 0; i < blk_cnt; i += REQ_PARALLEL) {
size_t cnt = (blk_cnt - i > REQ_PARALLEL) ? REQ_PARALLEL : blk_cnt - i;
Packet_descriptor pkt(src.alloc_packet(cnt * blk_sz),
Packet_descriptor::READ, i, cnt);
for (size_t i = 0; i < blk_cnt; i += BLOCK_REQ_PARALLEL) { log("Check blocks ", i, "..", i + cnt - 1);
try { src.submit_packet(pkt);
size_t cnt = (blk_cnt - i > BLOCK_REQ_PARALLEL) pkt = src.get_acked_packet();
? BLOCK_REQ_PARALLEL : blk_cnt - i; if (!pkt.succeeded()) {
Block::Packet_descriptor p(source->alloc_packet(cnt * blk_size), throw Read_request_failed(); }
Block::Packet_descriptor::READ, i, cnt);
source->submit_packet(p); char const *rom_src = rom.local_addr<char>() + i * blk_sz;
p = source->get_acked_packet(); if (strcmp(rom_src, src.packet_content(pkt), rom.size())) {
throw Files_differ(); }
if (!p.succeeded()) { src.release_packet(pkt);
error("could not read block ", Hex(i), "-", Hex(i + cnt));
return;
} }
log("--- ROM Block test finished ---");
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!");
} }
}; };
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,13 +51,13 @@ 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 };

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
*/
void idle(bool idle = true) { _idle = idle; }
/**
* Return total number of received notifications
*/
unsigned receive_cnt() const { return _receive_cnt; } 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 };
struct Unequal_sent_and_received_signals : Exception { };
Env &env;
Timer::Connection timer { env };
Signal_context context;
Signal_receiver receiver; Signal_receiver receiver;
Id_signal_context context_123(123); Handler handler { env, receiver, HANDLER_INTERVAL_MS, false, 1 };
Sender sender { env, receiver.manage(&context),
SENDER_INTERVAL_MS, false };
Heap heap(env.ram(), env.rm()); Fast_sender_test(Env &env, int id) : Signal_test(id, brief), env(env)
Timer::Connection timer(env); {
timer.msleep(DURATION_MS);
Handler *handler = new (heap) Handler(env, receiver, HANDLER_INTERVAL, false);
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123),
SENDER_INTERVAL, false);
timer.msleep(TEST_DURATION);
/* stop emitting signals */ /* stop emitting signals */
log("deactivate sender"); log("deactivate sender");
sender->idle(); sender.idle(true);
timer.msleep(FINISH_IDLE_TIME); 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");
log(""); if (sender.submit_cnt() != handler.receive_cnt()) {
log("sender submitted a total of ", sender->submit_cnt(), " signals"); throw Unequal_sent_and_received_signals(); }
log("handler received a total of ", handler->receive_cnt(), " signals"); }
log(""); };
if (sender->submit_cnt() != handler->receive_cnt()) struct Multiple_handlers_test : Signal_test
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 }; static constexpr char const *brief =
enum { TEST_DURATION = 50*SPEED }; "get multiple handlers at one sender activated in a fair manner";
enum { HANDLER_INTERVAL = 8*SPEED };
enum { SENDER_INTERVAL = 1*SPEED };
enum { FINISH_IDLE_TIME = 2*HANDLER_INTERVAL };
enum { NUM_HANDLERS = 4 };
log(""); enum { HANDLER_INTERVAL_MS = 8 * SPEED,
log("TEST ", ++test_cnt, ": one busy sender, ", (int)NUM_HANDLERS, " handlers"); SENDER_INTERVAL_MS = 1 * SPEED,
log(""); FINISH_IDLE_MS = 2 * HANDLER_INTERVAL_MS,
DURATION_MS = 50 * SPEED,
NR_OF_HANDLERS = 4 };
Heap heap(env.ram(), env.rm()); struct Unequal_sent_and_received_signals : Exception { };
Timer::Connection timer(env); struct Unequal_activation_of_handlers : Exception { };
Env &env;
Heap heap { env.ram(), env.rm() };
Timer::Connection timer { env };
Signal_context context;
Signal_receiver receiver; Signal_receiver receiver;
Registry<Registered<Handler> > handlers;
Sender sender { env, receiver.manage(&context),
SENDER_INTERVAL_MS, true};
Handler *handler[NUM_HANDLERS]; Multiple_handlers_test(Env &env, int id) : Signal_test(id, brief), env(env)
for (int i = 0; i < NUM_HANDLERS; i++) {
handler[i] = new (heap) Handler(env, receiver, HANDLER_INTERVAL); for (unsigned i = 0; i < NR_OF_HANDLERS; i++)
new (heap) Registered<Handler>(handlers, env, receiver,
Id_signal_context context_123(123); HANDLER_INTERVAL_MS, true, i);
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123), SENDER_INTERVAL); timer.msleep(DURATION_MS);
timer.msleep(TEST_DURATION);
/* stop emitting signals */ /* stop emitting signals */
log("stop generating new notifications"); log("stop generating new signals");
sender->idle(); sender.idle(true);
timer.msleep(FINISH_IDLE_TIME); timer.msleep(FINISH_IDLE_MS);
/* let handlers settle down */ /* let handlers settle down */
for (int i = 0; i < NUM_HANDLERS; i++) handlers.for_each([&] (Handler &handler) { handler.idle(true); });
handler[i]->idle(); timer.msleep(FINISH_IDLE_MS);
timer.msleep(FINISH_IDLE_TIME);
/* print signal delivery statistics */ /* print statistics and clean up */
log(""); unsigned total_rcv = 0, max_act = 0, min_act = ~0;;
log("sender submitted a total of ", sender->submit_cnt(), " signals"); handlers.for_each([&] (Handler &handler) {
unsigned total_receive_cnt = 0; unsigned const rcv = handler.receive_cnt();
for (int i = 0; i < NUM_HANDLERS; i++) { unsigned const act = handler.activation_cnt();
log("handler ", i, " " log(handler, " received ", rcv, " signals, was activated ", act, " times");
"received a total of ", handler[i]->receive_cnt(), " signals"); total_rcv += rcv;
total_receive_cnt += handler[i]->receive_cnt(); 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(); }
} }
log("all handlers received a total of ", total_receive_cnt, " signals"); };
/* check if number of sent notifications match the received ones */ struct Stress_test : Signal_test
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 }; static constexpr char const *brief =
enum { DURATION_SECONDS = 5 }; "throughput when submitting/handling as fast as possible";
enum { FINISH_IDLE_TIME = 100*SPEED };
log(""); enum { DURATION_SEC = 5 };
log("TEST ", ++test_cnt, ": stress test, busy signal transmission and handling");
log("");
Timer::Connection timer(env); struct Unequal_sent_and_received_signals : Exception { };
Heap heap(env.ram(), env.rm());
Env &env;
Timer::Connection timer { env };
Signal_context context;
Signal_receiver receiver; Signal_receiver receiver;
Id_signal_context context_123(123); Handler handler { env, receiver, 0, false, 1 };
Sender sender { env, receiver.manage(&context), 0, false };
Handler *handler = new (heap) Handler(env, receiver, 0, false); Stress_test(Env &env, int id) : Signal_test(id, brief), env(env)
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123), {
0, false); for (unsigned i = 1; i <= DURATION_SEC; i++) {
log(i, "/", (unsigned)DURATION_SEC);
for (int i = 1; i <= DURATION_SECONDS; i++) {
log(i, "/", (int)DURATION_SECONDS);
timer.msleep(1000); timer.msleep(1000);
} }
/* stop emitting signals */
log("deactivate sender"); log("deactivate sender");
sender->idle(); sender.idle(true);
while (handler->receive_cnt() < sender->submit_cnt()) { while (handler.receive_cnt() < sender.submit_cnt()) {
log("waiting for signals still in flight..."); log("waiting for signals still in flight...");
timer.msleep(FINISH_IDLE_TIME); timer.msleep(1000);
} }
log(""); log("");
log("sender submitted a total of ", sender->submit_cnt(), " signals"); log("sender submitted a total of ", sender.submit_cnt(), " signals");
log("handler received a total of ", handler->receive_cnt(), " signals"); log("handler received a total of ", handler.receive_cnt(), " signals");
log(""); log("");
log("processed ", (handler->receive_cnt()/DURATION_SECONDS), " notifications per second"); log("handler received ", handler.receive_cnt() / DURATION_SEC, " signals per second");
log("handler was activated ", (handler->activation_cnt()/DURATION_SECONDS), " times per second"); log("handler was activated ", handler.activation_cnt() / DURATION_SEC, " times per second");
log(""); log("");
if (sender->submit_cnt() != handler->receive_cnt()) if (sender.submit_cnt() != handler.receive_cnt())
throw Test_failed_with_unequal_sent_and_received_signals(); throw Unequal_sent_and_received_signals();
}
};
receiver.dissolve(&context_123); struct Lazy_receivers_test : Signal_test
destroy(heap, sender);
destroy(heap, handler);
log("TEST ", test_cnt, " FINISHED");
}
static void lazy_receivers_test(Env &env)
{ {
log(""); static constexpr char const *brief = "lazy and out-of-order signal reception";
log("TEST ", ++test_cnt, ": lazy and out-of-order signal reception test");
log("");
Signal_receiver rec_1, rec_2; Signal_context context_1, context_2;
Signal_context rec_context_1, rec_context_2; Signal_receiver receiver_1, receiver_2;
Signal_transmitter transmitter_1 { receiver_1.manage(&context_1) };
Signal_transmitter transmitter_1(rec_1.manage(&rec_context_1)); Signal_transmitter transmitter_2 { receiver_2.manage(&context_2) };
Signal_transmitter transmitter_2(rec_2.manage(&rec_context_2));
Lazy_receivers_test(Env &env, int id) : Signal_test(id, brief)
{
log("submit and receive signals with multiple receivers in order"); log("submit and receive signals with multiple receivers in order");
transmitter_1.submit(); transmitter_1.submit();
transmitter_2.submit(); transmitter_2.submit();
{ {
Signal signal = rec_1.wait_for_signal(); Signal signal = receiver_1.wait_for_signal();
log("returned from wait_for_signal for receiver 1"); log("returned from wait_for_signal for receiver 1");
signal = rec_2.wait_for_signal(); signal = receiver_2.wait_for_signal();
log("returned from wait_for_signal for receiver 2"); log("returned from wait_for_signal for receiver 2");
} }
log("submit and receive signals with multiple receivers out of order"); log("submit and receive signals with multiple receivers out of order");
transmitter_1.submit(); transmitter_1.submit();
transmitter_2.submit(); transmitter_2.submit();
{ {
Signal signal = rec_2.wait_for_signal(); Signal signal = receiver_2.wait_for_signal();
log("returned from wait_for_signal for receiver 2"); log("returned from wait_for_signal for receiver 2");
signal = rec_1.wait_for_signal(); signal = receiver_1.wait_for_signal();
log("returned from wait_for_signal for receiver 1"); 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;
Signal_receiver *rec;
Signal_context_capability cap;
Timer::Connection timer(env);
Heap heap(env.ram(), env.rm());
/* setup receiver side */
context = new (heap) Id_signal_context(321);
rec = new (heap) Signal_receiver;
cap = rec->manage(context);
/* spawn sender */
Sender *sender = new (heap) Sender(env, cap, 500);
/* stop sender after timeout */
timer.msleep(1000);
log("suspend sender");
sender->idle();
/* collect pending signals and dissolve context from receiver */
{
Signal signal = rec->wait_for_signal();
log("got ", signal.num(), " signal(s) from ", signal.context());
}
rec->dissolve(context);
/* let sender spin for some time */
log("resume sender");
sender->idle(false);
timer.msleep(1000);
log("suspend sender");
sender->idle();
log("destroy sender");
destroy(heap, sender);
destroy(heap, context);
destroy(heap, rec);
}
/**
* Test if 'Signal_receiver::dissolve()' blocks as long as the signal context
* is still referenced by one or more 'Signal' objects
*/
static Lock signal_context_destroyer_lock(Lock::LOCKED);
static bool signal_context_destroyed = false;
class Signal_context_destroyer : public Thread_deprecated<4096>
{
private:
Signal_receiver *_receiver;
Signal_context *_context;
public:
Signal_context_destroyer(Signal_receiver *receiver, Signal_context *context)
: Thread_deprecated("signal_context_destroyer"),
_receiver(receiver), _context(context) { }
void entry()
{
signal_context_destroyer_lock.lock();
_receiver->dissolve(_context);
signal_context_destroyed = true;
destroy(env()->heap(), _context);
} }
}; };
struct Context_management_test : Signal_test
static void synchronized_context_destruction_test(Env &env)
{ {
static constexpr char const *brief =
"correct initialization and cleanup of receiver and context";
Env &env;
Timer::Connection timer { env };
Signal_context context;
Signal_receiver receiver; Signal_receiver receiver;
Timer::Connection timer(env); Signal_context_capability context_cap { receiver.manage(&context) };
static Heap heap(env.ram(), env.rm()); Sender sender { env, context_cap, 500, true };
Signal_context *context = new (heap) Signal_context; Context_management_test(Env &env, int id) : Signal_test(id, brief), env(env)
{
/* stop sender after timeout */
timer.msleep(1000);
log("suspend sender");
sender.idle(true);
Signal_transmitter transmitter(receiver.manage(context)); /* collect pending signals and dissolve context from receiver */
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(); Signal signal = receiver.wait_for_signal();
log("got ", signal.num(), " signal(s) from ", signal.context());
}
receiver.dissolve(&context);
/* let the signal context destroyer thread try to destroy the signal context */ /* let sender spin for some time */
signal_context_destroyer_lock.unlock(); log("resume sender");
sender.idle(false);
timer.msleep(1000); timer.msleep(1000);
log("suspend sender");
Signal signal_copy = signal; sender.idle(true);
Signal signal_copy2 = signal; log("destroy sender");
signal_copy = signal_copy2;
if (signal_context_destroyed) {
error("signal context destroyed too early");
sleep_forever();
}
} }
};
signal_context_destroyer.join(); struct Synchronized_destruction_test : Signal_test, Thread
signal_context_destroyed = false;
}
static void many_managed_contexts(Env &env)
{ {
static Heap heap(env.ram(), env.rm()); static constexpr char const *brief =
for (unsigned round = 0; round < 10; ++round) { "does 'dissolve' block as long as the signal context is referenced?";
unsigned const num_contexts = 200 + 5*round; struct Failed : Exception { };
log("round ", round, ": create and manage ", num_contexts, " contexts");
Signal_receiver rec; 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 };
for (unsigned i = 0; i < num_contexts; ++i) { void entry()
Id_signal_context *context = new (heap) Id_signal_context(i); {
if (!rec.manage(context).valid()) { receiver.dissolve(&context);
error("failed to manage signal context"); log("dissolve finished");
sleep_forever(); destroyed = true;
} destroy(heap, &context);
}
} }
log("many contexts finished"); Synchronized_destruction_test(Env &env, int id)
} : Signal_test(id, brief), Thread(env, "destroyer", 1024 * sizeof(addr_t)), env(env)
{
transmitter.submit();
{
Signal signal = receiver.wait_for_signal();
log("start dissolving");
Thread::start();
timer.msleep(2000);
Signal signal_copy_1 = signal;
Signal signal_copy_2 = signal;
signal_copy_1 = signal_copy_2;
if (destroyed) {
throw Failed(); }
log("destruct signal");
}
Thread::join();
}
};
struct Many_contexts_test : Signal_test
void Component::construct(Genode::Env &env)
{ {
log("--- signalling test ---"); static constexpr char const *brief = "create and manage many contexts";
fast_sender_test(env); struct Manage_failed : Exception { };
multiple_handlers_test(env);
stress_test(env);
lazy_receivers_test(env);
check_context_management(env);
synchronized_context_destruction_test(env);
many_managed_contexts(env);
log("--- signalling test finished ---"); Env &env;
env.parent().exit(0); Heap heap { env.ram(), env.rm() };
Registry<Registered<Signal_context> > contexts;
Many_contexts_test(Env &env, int id) : Signal_test(id, brief), env(env)
{
for (unsigned round = 0; round < 10; round++) {
unsigned const nr_of_contexts = 200 + 5 * round;
log("round ", round, ": manage ", nr_of_contexts, " contexts");
Signal_receiver receiver;
for (unsigned i = 0; i < nr_of_contexts; i++) {
if (!receiver.manage(new (heap) Registered<Signal_context>(contexts)).valid()) {
throw Manage_failed(); }
}
contexts.for_each([&] (Registered<Signal_context> &context) {
receiver.dissolve(&context);
destroy(heap, &context);
});
}
}
};
struct Main
{
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;
Main(Env &env)
{
log("--- Signalling test ---");
test_1.construct(env, 1); test_1.destruct();
test_2.construct(env, 2); test_2.destruct();
test_3.construct(env, 3); test_3.destruct();
test_4.construct(env, 4); test_4.destruct();
test_5.construct(env, 5); test_5.destruct();
test_6.construct(env, 6); test_6.destruct();
test_7.construct(env, 7); test_7.destruct();
log("--- Signalling test finished ---");
} }
};
void Component::construct(Genode::Env &env) { static Main main(env); }

View File

@ -13,14 +13,16 @@
/* Genode includes */ /* 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; Pseudo_lock lock;
Adder adder; Adder adder;
Synced_interface<Adder, Pseudo_lock> synced_adder { lock, &adder };
Synced_interface<Adder, Pseudo_lock> synced_adder(lock, &adder); Main(Env &env)
{
log("--- Synced interface test ---");
int const res = synced_adder()->add(13, 14); int const res = synced_adder()->add(13, 14);
log("result is ", res); log("result is ", res);
return 0; log("--- Synced interface test finished ---");
} }
};
void Component::construct(Env &env) { static Main main(env); }

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,14 +11,15 @@
* 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;
@ -26,33 +27,31 @@ struct Worker : Genode::Thread_deprecated<4096>
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;
Main(Env &env) : timer(env)
{
log("--- Thread join test ---");
for (unsigned i = 0; i < 10; i++) { for (unsigned i = 0; i < 10; i++) {
/* /*
@ -61,15 +60,14 @@ int main(int, char **)
* 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) {
error("work remains unfinished after 'join()' returned"); throw Worker_unfinished_after_join(); }
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 };
public: bool got_timeouts { false };
Wakeup_thread(Timed_semaphore *sem,
Timer::Session *timer,
Alarm::Time timeout)
: Thread_deprecated("wakeup"), _sem(sem), _timer(timer), _timeout(timeout),
_lock(Lock::LOCKED), _stop(false) { }
void entry() void entry()
{ {
while(true) { do {
_timer->msleep(_timeout); wakeup_timer.msleep(wakeup_period);
_sem->up(); sem.up();
} while (!stop_wakeup);
if (_stop) { wakeup_stopped.unlock();
_lock.unlock();
return;
}
}
} }
void stop() { _stop = true; _lock.lock(); } Test(Env &env, bool timeouts, unsigned id, char const *brief)
: Thread(env, "wakeup", 1024 * sizeof(addr_t)), id(id), wakeup_timer(env),
wakeup_period(timeouts ? 1000 : 100)
{
log("\nTEST ", id, ": ", brief, "\n");
Thread::start();
try { for (int i = 0; i < 10; i++) { sem.down(timeouts ? 100 : 1000); } }
catch (Timeout_exception) { got_timeouts = true; }
if (timeouts != got_timeouts) {
throw Failed(); }
stop_wakeup = true;
wakeup_stopped.lock();
}
~Test() { log("\nTEST ", id, " finished\n"); }
}; };
bool test_loop(Timer::Session *timer, Alarm::Time timeout1, Alarm::Time timeout2, int loops) struct Main
{ {
Timed_semaphore sem; 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,56 +16,42 @@
/* 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;
@ -74,16 +61,16 @@ class Trace_buffer_monitor
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,15 +97,18 @@ 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
{ {
Env &env;
Test_out_of_metadata(Env &env) : env(env)
{
log("test Out_of_metadata exception of Trace::Session::subjects call"); log("test Out_of_metadata exception of Trace::Session::subjects call");
/* /*
@ -132,20 +121,21 @@ static void test_out_of_metadata()
*/ */
enum { MAX_SUBJECT_IDS = 16 }; enum { MAX_SUBJECT_IDS = 16 };
Genode::Trace::Subject_id subject_ids[MAX_SUBJECT_IDS]; Trace::Subject_id subject_ids[MAX_SUBJECT_IDS];
try { try {
Genode::Trace::Connection trace(sizeof(subject_ids) + 4096, sizeof(subject_ids), 0); Trace::Connection trace(env, sizeof(subject_ids) + 4096,
sizeof(subject_ids), 0);
/* we should never arrive here */ /* we should never arrive here */
struct Unexpectedly_got_no_exception{}; struct Unexpectedly_got_no_exception{};
throw Unexpectedly_got_no_exception(); throw Unexpectedly_got_no_exception();
} catch (Genode::Parent::Service_denied) { } catch (Parent::Service_denied) {
log("got Genode::Parent::Service_denied exception as expected"); log("got Parent::Service_denied exception as expected"); }
}
try { try {
Genode::Trace::Connection trace(sizeof(subject_ids) + 5*4096, sizeof(subject_ids), 0); Trace::Connection trace(env, sizeof(subject_ids) + 5*4096,
sizeof(subject_ids), 0);
trace.subjects(subject_ids, MAX_SUBJECT_IDS); trace.subjects(subject_ids, MAX_SUBJECT_IDS);
/* we should never arrive here */ /* we should never arrive here */
@ -153,44 +143,52 @@ static void test_out_of_metadata()
throw Unexpectedly_got_no_exception(); throw Unexpectedly_got_no_exception();
} catch (Trace::Out_of_metadata) { } catch (Trace::Out_of_metadata) {
log("got Trace::Out_of_metadata exception as expected"); log("got Trace::Out_of_metadata exception as expected"); }
}
log("passed Out_of_metadata test"); 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" };
log("--- test-trace started ---"); Heap heap { env.ram(), env.rm() };
Trace::Connection trace { env, 1024*1024, 64*1024, 0 };
test_out_of_metadata(); Timer::Connection timer { env };
Test_thread::Name thread_name { "test-thread" };
static Genode::Trace::Connection trace(1024*1024, 64*1024, 0); Test_thread thread { env, thread_name };
Trace_buffer_monitor *test_monitor { nullptr };
static Timer::Connection timer; bool policy_set { false };
Trace::Policy_id policy_id;
static Test_thread test("test-thread");
static Trace_buffer_monitor *test_monitor = 0;
Genode::Trace::Policy_id policy_id;
bool policy_set = false;
char policy_label[64]; char policy_label[64];
char policy_module[64]; char policy_module[64];
Rom_dataspace_capability policy_module_rom_ds; Rom_dataspace_capability policy_module_rom_ds;
char const *state_name(Trace::Subject_info::State state)
{
switch (state) {
case Trace::Subject_info::INVALID: return "INVALID";
case Trace::Subject_info::UNTRACED: return "UNTRACED";
case Trace::Subject_info::TRACED: return "TRACED";
case Trace::Subject_info::FOREIGN: return "FOREIGN";
case Trace::Subject_info::ERROR: return "ERROR";
case Trace::Subject_info::DEAD: return "DEAD";
}
return "undefined";
}
Test_tracing(Env &env) : env(env)
{
try { try {
Xml_node policy = config()->xml_node().sub_node("trace_policy"); Xml_node policy = config.xml().sub_node("trace_policy");
for (;; policy = policy.next("trace_policy")) { for (;; policy = policy.next("trace_policy")) {
try { try {
policy.attribute("label").value(policy_label, sizeof (policy_label)); policy.attribute("label").value(policy_label, sizeof (policy_label));
policy.attribute("module").value(policy_module, sizeof (policy_module)); policy.attribute("module").value(policy_module, sizeof (policy_module));
static Rom_connection policy_rom(policy_module); Rom_connection policy_rom(env, policy_module);
policy_module_rom_ds = policy_rom.dataspace(); policy_module_rom_ds = policy_rom.dataspace();
size_t rom_size = Dataspace_client(policy_module_rom_ds).size(); size_t rom_size = Dataspace_client(policy_module_rom_ds).size();
@ -199,12 +197,12 @@ int main(int argc, char **argv)
Dataspace_capability ds_cap = trace.policy(policy_id); Dataspace_capability ds_cap = trace.policy(policy_id);
if (ds_cap.valid()) { if (ds_cap.valid()) {
void *ram = env()->rm_session()->attach(ds_cap); void *ram = env.rm().attach(ds_cap);
void *rom = env()->rm_session()->attach(policy_module_rom_ds); void *rom = env.rm().attach(policy_module_rom_ds);
memcpy(ram, rom, rom_size); memcpy(ram, rom, rom_size);
env()->rm_session()->detach(ram); env.rm().detach(ram);
env()->rm_session()->detach(rom); env.rm().detach(rom);
} }
} catch (...) { } catch (...) {
error("could not load module '", Cstring(policy_module), "' for " error("could not load module '", Cstring(policy_module), "' for "
@ -250,7 +248,8 @@ int main(int argc, char **argv)
trace.trace(subjects[i].id, policy_id, 16384U); trace.trace(subjects[i].id, policy_id, 16384U);
Dataspace_capability ds_cap = trace.buffer(subjects[i].id); Dataspace_capability ds_cap = trace.buffer(subjects[i].id);
test_monitor = new (env()->heap()) Trace_buffer_monitor(subjects[i].id, ds_cap); test_monitor = new (heap)
Trace_buffer_monitor(env.rm(), subjects[i].id, ds_cap);
} catch (Trace::Source_is_dead) { error("source is dead"); } } catch (Trace::Source_is_dead) { error("source is dead"); }
@ -266,8 +265,25 @@ int main(int argc, char **argv)
} }
if (test_monitor) if (test_monitor)
destroy(env()->heap(), test_monitor); destroy(heap, test_monitor);
}
};
struct Main
{
Constructible<Test_out_of_metadata> test_1;
Constructible<Test_tracing> test_2;
Main(Env &env)
{
log("--- test-trace started ---");
test_1.construct(env);
test_1.destruct();
test_2.construct(env);
test_2.destruct();
log("--- test-trace finished ---"); log("--- test-trace finished ---");
return 0; }
} };
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
{ {
Timer::Connection timer;
Uart::Connection uart;
char buf[100];
Main(Env &env)
{
log("--- UART test started ---"); log("--- UART test started ---");
static Timer::Connection timer;
static Uart::Connection uart;
for (unsigned i = 0; ; ++i) { for (unsigned i = 0; ; ++i) {
static char buf[100];
int n = snprintf(buf, sizeof(buf), "UART test message %d\n", i); int n = snprintf(buf, sizeof(buf), "UART test message %d\n", i);
uart.write(buf, n); uart.write(buf, n);
timer.msleep(2000); 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("/");