libc: tests for components using RPC and select()

This commit is contained in:
Christian Helmuth 2017-02-12 12:39:18 +01:00
parent 0aac473229
commit f7f18710de
5 changed files with 399 additions and 7 deletions

View File

@ -0,0 +1,103 @@
#
# Build
#
set build_components {
core init drivers/timer server/terminal_crosslink
test/libc_counter test/libc_component
}
build $build_components
create_boot_directory
#
# Generate config
#
append config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="terminal_crosslink">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Terminal"/> </provides>
</start>
<start name="test-libc_component">
<resource name="RAM" quantum="8M"/>
<provides> <service name="LOG"/> </provides>
<config ld_verbose="yes">
<vfs>
<dir name="dev"> <log/> <terminal/> </dir>
<dir name="tmp"> <ram/> </dir>
</vfs>
<libc stdin="/dev/log" stdout="/dev/log" stderr="/dev/log"/>
</config>
</start>
<start name="counter-terminal">
<binary name="test-libc_counter-source"/>
<resource name="RAM" quantum="8M"/>
<config>
<vfs>
<dir name="dev"> <terminal/> <log/> </dir>
</vfs>
<libc stdin="/dev/terminal" stdout="/dev/terminal" stderr="/dev/log"/>
</config>
</start>
<start name="counter-log">
<binary name="test-libc_counter-source"/>
<resource name="RAM" quantum="8M"/>
<config>
<vfs>
<dir name="dev"> <log/> <log name="log2" label="2"/> </dir>
</vfs>
<libc stdin="/dev/log2" stdout="/dev/log2" stderr="/dev/log"/>
</config>
<route>
<service name="LOG" label="2"> <child name="test-libc_component"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
</config>
}
install_config $config
#
# Boot modules
#
set boot_modules {
core init timer terminal_crosslink
test-libc_counter-source test-libc_component
ld.lib.so libc.lib.so libm.lib.so
}
build_boot_image $boot_modules
append qemu_args "-nographic -m 128"
#
# Execute test case
#
run_genode_until forever
run_genode_until "child \"test-libc_counter-sink\" exited with exit value 0.*\n" 30
# vi: set ft=tcl :

View File

@ -0,0 +1,114 @@
#
# Build
#
set build_components {
core init drivers/timer server/terminal_crosslink server/vfs
test/libc_counter test/libc_component
}
build $build_components
create_boot_directory
#
# Generate config
#
append config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="terminal_crosslink">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Terminal"/> </provides>
</start>
<start name="vfs">
<resource name="RAM" quantum="12M"/>
<provides> <service name="File_system"/> </provides>
<config>
<vfs>
<dir name="dev"> <terminal/> </dir>
<dir name="tmp"> <ram/> </dir>
</vfs>
<default-policy root="/" writeable="yes"/>
</config>
</start>
<start name="test-libc_component">
<resource name="RAM" quantum="8M"/>
<provides> <service name="LOG"/> </provides>
<config ld_verbose="yes">
<vfs>
<dir name="dev"> <log/> </dir>
<fs/>
</vfs>
<libc stdin="/dev/log" stdout="/dev/log" stderr="/dev/log"/>
</config>
</start>
<start name="counter-terminal">
<binary name="test-libc_counter-source"/>
<resource name="RAM" quantum="8M"/>
<config>
<vfs>
<dir name="dev"> <terminal/> <log/> </dir>
</vfs>
<libc stdin="/dev/terminal" stdout="/dev/terminal" stderr="/dev/log"/>
</config>
</start>
<start name="counter-log">
<binary name="test-libc_counter-source"/>
<resource name="RAM" quantum="8M"/>
<config>
<vfs>
<dir name="dev"> <log/> <log name="log2" label="2"/> </dir>
</vfs>
<libc stdin="/dev/log2" stdout="/dev/log2" stderr="/dev/log"/>
</config>
<route>
<service name="LOG" label="2"> <child name="test-libc_component"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
</config>
}
install_config $config
#
# Boot modules
#
set boot_modules {
core init timer terminal_crosslink vfs
test-libc_counter-source test-libc_component
ld.lib.so libc.lib.so libm.lib.so
}
build_boot_image $boot_modules
append qemu_args "-nographic -m 128"
#
# Execute test case
#
run_genode_until forever
run_genode_until "child \"test-libc_counter-sink\" exited with exit value 0.*\n" 30
# vi: set ft=tcl :

View File

@ -510,8 +510,9 @@ struct Libc::Kernel
return;
}
_app_returned = false;
_app_code = &app_code;
_resume_main_once = false;
_app_returned = false;
_app_code = &app_code;
/* save continuation of libc kernel (incl. current stack) */
if (!_setjmp(_kernel_context)) {
@ -526,7 +527,7 @@ struct Libc::Kernel
while (!_app_returned) {
_env.ep().wait_and_dispatch_one_signal();
if (_resume_main_once)
if (_resume_main_once && !_setjmp(_kernel_context))
_switch_to_user();
}
}
@ -665,8 +666,6 @@ void Libc::schedule_suspend(void (*suspended) ())
void Libc::execute_in_application_context(Libc::Application_code &app_code)
{
warning("executing code in application context, not implemented");
/*
* XXX We don't support a second entrypoint - pthreads should work as they
* don't use this code.
@ -687,8 +686,6 @@ void Libc::execute_in_application_context(Libc::Application_code &app_code)
nested = true;
kernel->run(app_code);
nested = false;
warning("leaving application context");
}

View File

@ -0,0 +1,175 @@
/*
* \brief Libc-component using select test
* \author Christian Helmuth
* \date 2017-02-09
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/log.h>
#include <base/rpc_server.h>
#include <os/static_root.h>
#include <libc/component.h>
#include <libc/select.h>
#include <log_session/log_session.h>
/* libc includes */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/fcntl.h>
namespace Log {
using Genode::Static_root;
using Genode::Log_session;
struct Session_component;
struct Main;
}
static void die(char const *token) __attribute__((noreturn));
static void die(char const *token)
{
Genode::error("[", Genode::Cstring(token), "] ", Genode::Cstring(strerror(errno)));
exit(1);
}
static void use_file_system()
{
int result = 0;
int const fd = open("/tmp/blub", O_RDWR | O_NONBLOCK | O_CREAT | O_APPEND);
if (fd == -1) die("open");
printf("open returned fd %d\n", fd);
static char buf[1024];
result = read(fd, buf, sizeof(buf));
if (result == -1) die("read");
printf("read %d bytes\n", result);
result = write(fd, "X", 1);
if (result == -1) die("write");
printf("wrote %d bytes\n", result);
result = close(fd);
if (result == -1) die("close");
}
struct Log::Session_component : Genode::Rpc_object<Log_session>
{
char _buf[Log_session::MAX_STRING_LEN];
int _fd = -1;
fd_set _readfds;
fd_set _writefds;
fd_set _exceptfds;
void _select()
{
int nready = 0;
do {
fd_set readfds = _readfds;
fd_set writefds = _writefds;
fd_set exceptfds = _exceptfds;
nready = _select_handler.select(_fd + 1, readfds, writefds, exceptfds);
if (nready)
_select_ready(nready, readfds, writefds, exceptfds);
} while (nready);
}
Libc::Select_handler<Session_component> _select_handler {
*this, &Session_component::_select_ready };
void _select_ready(int nready, fd_set const &readfds, fd_set const &writefds, fd_set const &exceptfds)
{
Libc::with_libc([&] () {
if (nready <= 0) {
Genode::warning("select handler reported nready=", nready);
return;
}
if (!FD_ISSET(_fd, &readfds)) {
Genode::warning("select handler reported unexpected fd, nready=", nready);
for (unsigned i = 0; i < FD_SETSIZE; ++i)
if (FD_ISSET(i, &readfds)) Genode::log("fd ", i, " readable");
for (unsigned i = 0; i < FD_SETSIZE; ++i)
if (FD_ISSET(i, &writefds)) Genode::log("fd ", i, " writeable");
for (unsigned i = 0; i < FD_SETSIZE; ++i)
if (FD_ISSET(i, &exceptfds)) Genode::log("fd ", i, " exceptable?");
return;
}
int const result = read(_fd, _buf, sizeof(_buf)-1);
if (result <= 0) {
Genode::warning("read returned ", result, " in select handler");
return;
}
_buf[result] = 0;
Genode::log("read from file \"", Genode::Cstring(_buf), "\"");
});
}
Session_component()
{
Libc::with_libc([&] () {
_fd = open("/dev/terminal", O_RDWR);
if (_fd == -1) die("open");
FD_ZERO(&_readfds);
FD_ZERO(&_writefds);
FD_ZERO(&_exceptfds);
FD_SET(_fd, &_readfds);
});
}
Genode::size_t write(String const &string_buf)
{
if (!(string_buf.valid_string())) { return 0; }
strncpy(_buf, string_buf.string(), sizeof(_buf));
size_t len = strlen(_buf);
if (_buf[len-1] == '\n') _buf[len-1] = 0;
Genode::log("RPC with \"", Genode::Cstring(_buf), "\"");
_select();
return len;
}
};
struct Log::Main
{
Libc::Env &_env;
Session_component _session { };
Static_root<Log_session> _root { _env.ep().manage(_session) };
Main(Libc::Env &env) : _env(env)
{
Libc::with_libc([] () { use_file_system(); });
_env.parent().announce(_env.ep().manage(_root));
}
};
void Libc::Component::construct(Libc::Env &env) { static Log::Main inst(env); }

View File

@ -0,0 +1,3 @@
TARGET = test-libc_component
SRC_CC = main.cc
LIBS = libc