libports: Libc::with_libc nested

Fixes #2286.
This commit is contained in:
Josef Söntgen 2017-02-20 14:23:34 +01:00 committed by Christian Helmuth
parent c20bfd4414
commit 76cb06794a
4 changed files with 251 additions and 1 deletions

View File

@ -0,0 +1,60 @@
set build_components {
core init drivers/timer test/libc_with_libc
}
source ${genode_dir}/repos/base/run/platform_drv.inc
append_platform_drv_build_components
build $build_components
create_boot_directory
set config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<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>}
append_platform_drv_config
append config {
<start name="test-libc_with_libc">
<resource name="RAM" quantum="4M"/>
<config>
<vfs> <dir name="dev"> <log/> </dir> </vfs>
<libc stdout="/dev/log"/>
</config>
</start>
</config>}
install_config $config
set boot_modules {
core init timer
ld.lib.so libc.lib.so
test-libc_with_libc
}
append_platform_drv_boot_modules
build_boot_image $boot_modules
append qemu_args " -nographic -m 64 "
run_genode_until ".*finished with_libc tests.*\n" 10

View File

@ -370,6 +370,8 @@ struct Libc::Kernel
State _state = KERNEL;
Application_code *_nested_app_code = nullptr;
Application_code *_app_code = nullptr;
bool _app_returned = false;
@ -507,6 +509,25 @@ struct Libc::Kernel
_valid_user_context = false;
}
/*
* During the supension of the application code a nested
* Libc::with_libc() call took place, which will be executed
* before returning to the first Libc::with_libc() call.
*/
if (_nested_app_code) {
/*
* We have to explicitly set the user context back to true
* because we are borrowing it to execute our nested application
* code.
*/
_valid_user_context = true;
_nested_app_code->execute();
_nested_app_code = nullptr;
_longjmp(_kernel_context, 1);
}
return timeout_ms > 0 ? _main_timeout.duration_left() : 0;
}
@ -547,6 +568,7 @@ struct Libc::Kernel
while (!_app_returned) {
_env.ep().wait_and_dispatch_one_signal();
if (_resume_main_once && !_setjmp(_kernel_context))
_switch_to_user();
}
@ -643,6 +665,23 @@ struct Libc::Kernel
_resume_main();
}
/**
* Return if main is currently suspended
*/
bool main_suspended() { return _state == KERNEL; }
/**
* Execute application code while already executing in run()
*/
void nested_execution(Libc::Application_code &app_code)
{
_nested_app_code = &app_code;
if (!_setjmp(_kernel_context)) {
_switch_to_user();
}
}
};
@ -722,7 +761,12 @@ void Libc::execute_in_application_context(Libc::Application_code &app_code)
static bool nested = false;
if (nested) {
error("nested call of with_libc() detected");
if (kernel->main_suspended()) {
kernel->nested_execution(app_code);
} else {
app_code.execute();
}
return;
}

View File

@ -0,0 +1,143 @@
/*
* \brief Test Libc::with_libc nesting
* \author Josef Soentgen
* \date 2017-02-20
*/
/*
* 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/env.h>
#include <libc/component.h>
/* libc includes */
#include <sys/select.h>
#include <stdio.h>
using namespace Genode;
struct Test
{
int _id;
Test(Env &env, int id) : _id(id) { log("Start test ", _id); }
virtual ~Test() { log("Finished test ", _id); }
};
/*
* Explicitly_nested test
*
* Call with_libc from within with_libc.
*/
struct Explicitly_nested : Test
{
Explicitly_nested(Env &env, int id) : Test(env, id)
{
log("calling with_libc");
Libc::with_libc([&] () {
log("calling with_libc nested");
Libc::with_libc([&] () {
printf("Hello from with_libc nested\n");
});
});
}
};
/*
* Implicitly_nested test
*
* Call with_libc from within a signal handler while being
* suspended in a select() call.
*/
struct Implicitly_nested : Test
{
Env &_env;
void _handle()
{
log("calling with_libc from signal handler");
Libc::with_libc([&] () {
printf("Hello from with_libc in signal handler\n");
});
}
Signal_handler<Implicitly_nested> _dispatcher {
_env.ep(), *this, &Implicitly_nested::_handle };
Implicitly_nested(Env &env, int id)
: Test(env, id), _env(env)
{
log("calling with_libc");
Libc::with_libc([&] () {
Signal_transmitter(_dispatcher).submit();
unsigned const secs = 3;
log("calling select with ", secs, " secs timeout from with_libc");
timeval to { secs, 0 };
select(0, nullptr, nullptr, nullptr, &to);
});
}
};
/*
* Explicitly_triple_nested test
*
* Call with_libc from within with_libc from within with_libc.
*/
struct Explicitly_triple_nested : Test
{
Explicitly_triple_nested(Env &env, int id) : Test(env, id)
{
log("calling with_libc");
Libc::with_libc([&] () {
log("calling with_libc nested");
Libc::with_libc([&] () {
log("calling with_libc nested again");
Libc::with_libc([&] () {
printf("Hello from with_libc nested again\n");
});
});
});
}
};
struct Main
{
Constructible<Explicitly_nested> test_1;
Constructible<Implicitly_nested> test_2;
Constructible<Explicitly_triple_nested> test_3;
Main(Env &env)
{
log("--- start with_libc tests ---");
test_1.construct(env, 1); test_1.destruct();
test_2.construct(env, 2); test_2.destruct();
test_3.construct(env, 3); test_3.destruct();
log("--- finished with_libc tests ---");
}
};
void Libc::Component::construct(Libc::Env &env) { static Main main(env); }

View File

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