From 76cb06794abf1410a4d9dba6b071b266b3503c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Mon, 20 Feb 2017 14:23:34 +0100 Subject: [PATCH] libports: Libc::with_libc nested Fixes #2286. --- repos/libports/run/libc_with_libc.run | 60 ++++++++ repos/libports/src/lib/libc/task.cc | 46 +++++- .../libports/src/test/libc_with_libc/main.cc | 143 ++++++++++++++++++ .../src/test/libc_with_libc/target.mk | 3 + 4 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 repos/libports/run/libc_with_libc.run create mode 100644 repos/libports/src/test/libc_with_libc/main.cc create mode 100644 repos/libports/src/test/libc_with_libc/target.mk diff --git a/repos/libports/run/libc_with_libc.run b/repos/libports/run/libc_with_libc.run new file mode 100644 index 0000000000..60cf536213 --- /dev/null +++ b/repos/libports/run/libc_with_libc.run @@ -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 { + + + + + + + + + + + + + + + + + + + + } + +append_platform_drv_config + +append 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 diff --git a/repos/libports/src/lib/libc/task.cc b/repos/libports/src/lib/libc/task.cc index 855ea3640c..3de57f1441 100644 --- a/repos/libports/src/lib/libc/task.cc +++ b/repos/libports/src/lib/libc/task.cc @@ -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; } diff --git a/repos/libports/src/test/libc_with_libc/main.cc b/repos/libports/src/test/libc_with_libc/main.cc new file mode 100644 index 0000000000..9c45ad92b0 --- /dev/null +++ b/repos/libports/src/test/libc_with_libc/main.cc @@ -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 +#include + +/* libc includes */ +#include +#include + + +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 _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 test_1; + Constructible test_2; + Constructible 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); } diff --git a/repos/libports/src/test/libc_with_libc/target.mk b/repos/libports/src/test/libc_with_libc/target.mk new file mode 100644 index 0000000000..e4f6e3fdc3 --- /dev/null +++ b/repos/libports/src/test/libc_with_libc/target.mk @@ -0,0 +1,3 @@ +TARGET = test-libc_with_libc +SRC_CC = main.cc +LIBS = libc