From bf922326981b5f5ac26f9dc01fd13dbb3497cc41 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 18 Sep 2019 20:19:10 +0200 Subject: [PATCH] libc: split task.cc into multiple files This patch is the first step of re-organizing the internal structure of the libc. The original version involved many direct calls of global functions (often with side effects) across compilation units, which made the control flow (e.g., the initialization sequence) hard to follow. The new version replaces those ad-hoc interactions with dedicated interfaces (like suspend.h, resume.h, select.h, current_time.h). The underlying facilities are provided by the central Libc::Kernel and selectively propagated to the various compilation units. The latter is done by a sequence of 'init_*' calls, which eventually will be replaced by constructor calls. The addition of new headers increases the chance for name clashes with existing (public) headers. To disambiguate libc-internal header files from public headers, this patch moves the former into a new 'internal/' subdirectory. This makes the include directives easier to follow and the libc's source-tree structure more tidy. There are still a few legacies left, which cannot easily be removed right now (e.g., because noux relies on them). However, the patch moves those bad apples to legacy.h and legacy.cc, which highlights the deprecation of those functions. Issue #3497 --- repos/libports/include/libc/select.h | 5 +- repos/libports/lib/mk/libc-mem.mk | 2 + repos/libports/lib/mk/libc.mk | 6 +- repos/libports/lib/mk/spec/arm/libc.mk | 2 +- repos/libports/lib/mk/spec/arm_64/libc.mk | 2 +- repos/libports/lib/mk/spec/x86_32/libc.mk | 2 +- repos/libports/lib/mk/spec/x86_64/libc.mk | 4 +- repos/libports/recipes/api/libc/content.mk | 2 +- .../src/test-timed_semaphore/content.mk | 2 +- repos/libports/src/lib/libc/component.cc | 82 + repos/libports/src/lib/libc/dynamic_linker.cc | 2 +- repos/libports/src/lib/libc/execve.cc | 7 +- repos/libports/src/lib/libc/fd_alloc.cc | 6 +- .../libports/src/lib/libc/file_operations.cc | 8 +- repos/libports/src/lib/libc/fork.cc | 92 +- repos/libports/src/lib/libc/getpwent.cc | 9 +- repos/libports/src/lib/libc/getrandom.cc | 4 +- .../lib/libc/{ => internal}/clone_session.h | 6 +- .../libc/internal/cloned_malloc_heap_range.h | 59 + .../src/lib/libc/internal/current_time.h | 31 + repos/libports/src/lib/libc/internal/env.h | 132 ++ .../libc/{libc_errno.h => internal/errno.h} | 6 +- .../lib/libc/{libc_file.h => internal/file.h} | 6 +- .../lib/libc/{libc_init.h => internal/init.h} | 57 +- repos/libports/src/lib/libc/internal/kernel.h | 561 +++++++ .../src/lib/libc/internal/kernel_routine.h | 46 + .../lib/libc/internal/kernel_timer_accessor.h | 50 + repos/libports/src/lib/libc/internal/legacy.h | 53 + .../lib/libc/internal/malloc_ram_allocator.h | 74 + .../mem_alloc.h} | 13 +- .../mmap_registry.h} | 17 +- .../lib/libc/{thread.h => internal/pthread.h} | 7 +- .../src/lib/libc/internal/pthread_pool.h | 107 ++ repos/libports/src/lib/libc/internal/resume.h | 34 + repos/libports/src/lib/libc/internal/select.h | 35 + .../libc/{ => internal}/socket_fs_plugin.h | 6 +- .../libports/src/lib/libc/internal/suspend.h | 51 + .../lib/libc/{ => internal}/thread_create.h | 11 +- .../lib/libc/{ => internal}/timed_semaphore.h | 6 +- repos/libports/src/lib/libc/internal/timer.h | 117 ++ repos/libports/src/lib/libc/internal/types.h | 21 + .../src/lib/libc/{ => internal}/vfs_plugin.h | 12 +- repos/libports/src/lib/libc/kernel.cc | 333 ++++ repos/libports/src/lib/libc/legacy.cc | 43 + repos/libports/src/lib/libc/libc_mem_alloc.cc | 6 +- repos/libports/src/lib/libc/malloc.cc | 8 +- repos/libports/src/lib/libc/plugin.cc | 18 +- repos/libports/src/lib/libc/poll.cc | 29 +- .../src/lib/libc/{thread.cc => pthread.cc} | 34 +- .../{thread_create.cc => pthread_create.cc} | 8 +- repos/libports/src/lib/libc/select.cc | 49 +- repos/libports/src/lib/libc/semaphore.cc | 3 + repos/libports/src/lib/libc/sleep.cc | 22 +- .../libports/src/lib/libc/socket_fs_plugin.cc | 28 +- .../src/lib/libc/socket_operations.cc | 4 +- .../spec/arm/internal/call_func.h | 0 .../spec/arm_64/internal/call_func.h | 0 .../spec/x86_32/internal/call_func.h | 0 .../spec/x86_64/internal/call_func.h | 0 repos/libports/src/lib/libc/sysctl.cc | 7 +- repos/libports/src/lib/libc/task.cc | 1348 ----------------- repos/libports/src/lib/libc/task.h | 107 -- repos/libports/src/lib/libc/time.cc | 84 +- repos/libports/src/lib/libc/vfs_plugin.cc | 79 +- .../src/test/timed_semaphore/target.mk | 2 +- repos/ports/recipes/src/noux/content.mk | 5 +- repos/ports/recipes/src/vbox5-nova/content.mk | 9 +- repos/ports/recipes/src/vbox5/content.mk | 9 +- repos/ports/src/lib/libc_noux/plugin.cc | 3 +- repos/ports/src/virtualbox5/devxhci.cc | 2 +- .../ports/src/virtualbox5/generic/sup_vmm.cc | 4 +- repos/ports/src/virtualbox5/libc.cc | 2 +- repos/ports/src/virtualbox5/mm.cc | 2 +- repos/ports/src/virtualbox5/network.cpp | 2 +- repos/ports/src/virtualbox5/spec/nova/sup.cc | 2 +- repos/ports/src/virtualbox5/spec/nova/vcpu.h | 2 +- repos/ports/src/virtualbox5/thread.cc | 2 +- repos/ports/src/virtualbox5/vcpu.h | 2 +- 78 files changed, 2324 insertions(+), 1689 deletions(-) create mode 100644 repos/libports/src/lib/libc/component.cc rename repos/libports/src/lib/libc/{ => internal}/clone_session.h (94%) create mode 100644 repos/libports/src/lib/libc/internal/cloned_malloc_heap_range.h create mode 100644 repos/libports/src/lib/libc/internal/current_time.h create mode 100644 repos/libports/src/lib/libc/internal/env.h rename repos/libports/src/lib/libc/{libc_errno.h => internal/errno.h} (82%) rename repos/libports/src/lib/libc/{libc_file.h => internal/file.h} (95%) rename repos/libports/src/lib/libc/{libc_init.h => internal/init.h} (64%) create mode 100644 repos/libports/src/lib/libc/internal/kernel.h create mode 100644 repos/libports/src/lib/libc/internal/kernel_routine.h create mode 100644 repos/libports/src/lib/libc/internal/kernel_timer_accessor.h create mode 100644 repos/libports/src/lib/libc/internal/legacy.h create mode 100644 repos/libports/src/lib/libc/internal/malloc_ram_allocator.h rename repos/libports/src/lib/libc/{libc_mem_alloc.h => internal/mem_alloc.h} (91%) rename repos/libports/src/lib/libc/{libc_mmap_registry.h => internal/mmap_registry.h} (87%) rename repos/libports/src/lib/libc/{thread.h => internal/pthread.h} (97%) create mode 100644 repos/libports/src/lib/libc/internal/pthread_pool.h create mode 100644 repos/libports/src/lib/libc/internal/resume.h create mode 100644 repos/libports/src/lib/libc/internal/select.h rename repos/libports/src/lib/libc/{ => internal}/socket_fs_plugin.h (90%) create mode 100644 repos/libports/src/lib/libc/internal/suspend.h rename repos/libports/src/lib/libc/{ => internal}/thread_create.h (81%) rename repos/libports/src/lib/libc/{ => internal}/timed_semaphore.h (97%) create mode 100644 repos/libports/src/lib/libc/internal/timer.h create mode 100644 repos/libports/src/lib/libc/internal/types.h rename repos/libports/src/lib/libc/{ => internal}/vfs_plugin.h (95%) create mode 100644 repos/libports/src/lib/libc/kernel.cc create mode 100644 repos/libports/src/lib/libc/legacy.cc rename repos/libports/src/lib/libc/{thread.cc => pthread.cc} (96%) rename repos/libports/src/lib/libc/{thread_create.cc => pthread_create.cc} (93%) rename repos/libports/src/lib/libc/{include => }/spec/arm/internal/call_func.h (100%) rename repos/libports/src/lib/libc/{include => }/spec/arm_64/internal/call_func.h (100%) rename repos/libports/src/lib/libc/{include => }/spec/x86_32/internal/call_func.h (100%) rename repos/libports/src/lib/libc/{include => }/spec/x86_64/internal/call_func.h (100%) delete mode 100644 repos/libports/src/lib/libc/task.cc delete mode 100644 repos/libports/src/lib/libc/task.h diff --git a/repos/libports/include/libc/select.h b/repos/libports/include/libc/select.h index c4b7dbb39..b5f87e947 100644 --- a/repos/libports/include/libc/select.h +++ b/repos/libports/include/libc/select.h @@ -14,7 +14,10 @@ #ifndef _INCLUDE__LIBC__SELECT_H_ #define _INCLUDE__LIBC__SELECT_H_ -/* Libc includes */ +/* Genode includes */ +#include + +/* libc includes */ #include /* for fd_set */ diff --git a/repos/libports/lib/mk/libc-mem.mk b/repos/libports/lib/mk/libc-mem.mk index afd682deb..c1f196759 100644 --- a/repos/libports/lib/mk/libc-mem.mk +++ b/repos/libports/lib/mk/libc-mem.mk @@ -2,6 +2,8 @@ SRC_CC = libc_mem_alloc.cc include $(REP_DIR)/lib/mk/libc-common.inc +INC_DIR += $(REP_DIR)/src/lib/libc + vpath libc_mem_alloc.cc $(REP_DIR)/src/lib/libc CC_CXX_WARN_STRICT = diff --git a/repos/libports/lib/mk/libc.mk b/repos/libports/lib/mk/libc.mk index e9596baf6..bd2bbbc33 100644 --- a/repos/libports/lib/mk/libc.mk +++ b/repos/libports/lib/mk/libc.mk @@ -17,14 +17,14 @@ SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc \ plugin.cc plugin_registry.cc select.cc exit.cc environ.cc sleep.cc \ pread_pwrite.cc readv_writev.cc poll.cc \ vfs_plugin.cc dynamic_linker.cc signal.cc \ - socket_operations.cc task.cc socket_fs_plugin.cc syscall.cc \ - getpwent.cc getrandom.cc fork.cc execve.cc + socket_operations.cc socket_fs_plugin.cc syscall.cc legacy.cc \ + getpwent.cc getrandom.cc fork.cc execve.cc kernel.cc component.cc # # Pthreads # SRC_CC += semaphore.cc rwlock.cc \ - thread.cc thread_create.cc + pthread.cc pthread_create.cc # # FreeBSD headers use the C99 restrict keyword diff --git a/repos/libports/lib/mk/spec/arm/libc.mk b/repos/libports/lib/mk/spec/arm/libc.mk index 9dc4d9ca8..56dd9171f 100644 --- a/repos/libports/lib/mk/spec/arm/libc.mk +++ b/repos/libports/lib/mk/spec/arm/libc.mk @@ -1,6 +1,6 @@ include $(REP_DIR)/lib/mk/libc.mk -INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/arm +INC_DIR += $(REP_DIR)/src/lib/libc/spec/arm INC_DIR += $(LIBC_DIR)/include/spec/arm CC_CXX_WARN_STRICT = diff --git a/repos/libports/lib/mk/spec/arm_64/libc.mk b/repos/libports/lib/mk/spec/arm_64/libc.mk index 7fd7c2137..582a70c9c 100644 --- a/repos/libports/lib/mk/spec/arm_64/libc.mk +++ b/repos/libports/lib/mk/spec/arm_64/libc.mk @@ -1,6 +1,6 @@ include $(REP_DIR)/lib/mk/libc.mk -INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/arm_64 +INC_DIR += $(REP_DIR)/src/lib/libc/spec/arm_64 INC_DIR += $(LIBC_DIR)/include/spec/arm_64 CC_CXX_WARN_STRICT = diff --git a/repos/libports/lib/mk/spec/x86_32/libc.mk b/repos/libports/lib/mk/spec/x86_32/libc.mk index 9db361f55..3a4083e65 100644 --- a/repos/libports/lib/mk/spec/x86_32/libc.mk +++ b/repos/libports/lib/mk/spec/x86_32/libc.mk @@ -1,6 +1,6 @@ include $(REP_DIR)/lib/mk/libc.mk -INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/x86_32 +INC_DIR += $(REP_DIR)/src/lib/libc/spec/x86_32 INC_DIR += $(LIBC_DIR)/include/spec/x86_32 SRC_C += msun/i387/fenv.c diff --git a/repos/libports/lib/mk/spec/x86_64/libc.mk b/repos/libports/lib/mk/spec/x86_64/libc.mk index 52889ad93..40e09d41b 100644 --- a/repos/libports/lib/mk/spec/x86_64/libc.mk +++ b/repos/libports/lib/mk/spec/x86_64/libc.mk @@ -1,8 +1,6 @@ include $(REP_DIR)/lib/mk/libc.mk - - -INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/x86_64 +INC_DIR += $(REP_DIR)/src/lib/libc/spec/x86_64 INC_DIR += $(LIBC_DIR)/include/spec/x86_64 CC_CXX_WARN_STRICT = diff --git a/repos/libports/recipes/api/libc/content.mk b/repos/libports/recipes/api/libc/content.mk index e994ff1da..b44625092 100644 --- a/repos/libports/recipes/api/libc/content.mk +++ b/repos/libports/recipes/api/libc/content.mk @@ -16,7 +16,7 @@ include: cp -r $(PORT_DIR)/include/* $@/ cp -r $(REP_DIR)/include/libc $@/ cp -r $(REP_DIR)/include/libc-genode $@/ - cp $(REP_DIR)/src/lib/libc/task.h $@/libc/ + cp $(REP_DIR)/src/lib/libc/internal/legacy.h $@/libc/ content: LICENSE diff --git a/repos/libports/recipes/src/test-timed_semaphore/content.mk b/repos/libports/recipes/src/test-timed_semaphore/content.mk index 5066c0a00..c0c092f2c 100644 --- a/repos/libports/recipes/src/test-timed_semaphore/content.mk +++ b/repos/libports/recipes/src/test-timed_semaphore/content.mk @@ -1,7 +1,7 @@ SRC_DIR = src/test/timed_semaphore include $(GENODE_DIR)/repos/base/recipes/src/content.inc -MIRROR_FROM_REP_DIR := src/lib/libc/timed_semaphore.h +MIRROR_FROM_REP_DIR := src/lib/libc/internal/timed_semaphore.h content: $(MIRROR_FROM_REP_DIR) diff --git a/repos/libports/src/lib/libc/component.cc b/repos/libports/src/lib/libc/component.cc new file mode 100644 index 000000000..1adab4e67 --- /dev/null +++ b/repos/libports/src/lib/libc/component.cc @@ -0,0 +1,82 @@ +/* + * \brief Libc component startup + * \author Christian Helmuth + * \author Norman Feske + * \date 2016-01-22 + */ + +/* + * Copyright (C) 2016-2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include + +/* libc includes */ +#include + +/* base-internal includes */ +#include + +/* libc-internal includes */ +#include + + +extern char **environ; + + +Genode::size_t Component::stack_size() { return Libc::Component::stack_size(); } + + +void Component::construct(Genode::Env &env) +{ + /* initialize the global pointer to environment variables */ + static char *null_env = nullptr; + if (!environ) environ = &null_env; + + Genode::Allocator &heap = + *unmanaged_singleton(env.ram(), env.rm()); + + /* pass Genode::Env to libc subsystems that depend on it */ + Libc::init_fd_alloc(heap); + Libc::init_mem_alloc(env); + Libc::init_dl(env); + Libc::sysctl_init(env); + + Libc::Kernel &kernel = *unmanaged_singleton(env, heap); + + Libc::libc_config_init(kernel.libc_env().libc_config()); + + /* + * XXX The following two steps leave us with the dilemma that we don't know + * which linked library may depend on the successfull initialization of a + * plugin. For example, some high-level library may try to open a network + * connection in its constructor before the network-stack library is + * initialized. But, we can't initialize plugins before calling static + * constructors as those are needed to know about the libc plugin. The only + * solution is to remove all libc plugins beside the VFS implementation, + * which is our final goal anyway. + */ + + /* finish static construction of component and libraries */ + Libc::with_libc([&] () { env.exec_static_constructors(); }); + + /* initialize plugins that require Genode::Env */ + auto init_plugin = [&] (Libc::Plugin &plugin) { + plugin.init(env); + }; + Libc::plugin_registry()->for_each_plugin(init_plugin); + + /* construct libc component on kernel stack */ + Libc::Component::construct(kernel.libc_env()); +} + + +/** + * Default stack size for libc-using components + */ +Genode::size_t Libc::Component::stack_size() __attribute__((weak)); +Genode::size_t Libc::Component::stack_size() { return 32UL*1024*sizeof(long); } diff --git a/repos/libports/src/lib/libc/dynamic_linker.cc b/repos/libports/src/lib/libc/dynamic_linker.cc index 791c4d746..41b2bf9ca 100644 --- a/repos/libports/src/lib/libc/dynamic_linker.cc +++ b/repos/libports/src/lib/libc/dynamic_linker.cc @@ -15,7 +15,7 @@ #include /* libc-internal includes */ -#include +#include /* libc includes */ extern "C" { diff --git a/repos/libports/src/lib/libc/execve.cc b/repos/libports/src/lib/libc/execve.cc index 6ad1a0c84..ee9000e4a 100644 --- a/repos/libports/src/lib/libc/execve.cc +++ b/repos/libports/src/lib/libc/execve.cc @@ -19,13 +19,12 @@ #include #include #include +#include /* libc-internal includes */ -#include #include -#include -#include -#include +#include +#include using namespace Genode; diff --git a/repos/libports/src/lib/libc/fd_alloc.cc b/repos/libports/src/lib/libc/fd_alloc.cc index dffe77904..ec5efa4e9 100644 --- a/repos/libports/src/lib/libc/fd_alloc.cc +++ b/repos/libports/src/lib/libc/fd_alloc.cc @@ -17,6 +17,9 @@ #include #include +/* Genode-internal includes */ +#include + /* libc plugin interface */ #include @@ -25,8 +28,7 @@ #include /* libc-internal includes */ -#include -#include +#include using namespace Libc; using namespace Genode; diff --git a/repos/libports/src/lib/libc/file_operations.cc b/repos/libports/src/lib/libc/file_operations.cc index a45a62e63..4f5a30028 100644 --- a/repos/libports/src/lib/libc/file_operations.cc +++ b/repos/libports/src/lib/libc/file_operations.cc @@ -39,10 +39,10 @@ extern "C" { } /* libc-internal includes */ -#include "libc_file.h" -#include "libc_mem_alloc.h" -#include "libc_mmap_registry.h" -#include "libc_errno.h" +#include +#include +#include +#include using namespace Libc; diff --git a/repos/libports/src/lib/libc/fork.cc b/repos/libports/src/lib/libc/fork.cc index 8eb792111..1dcac5716 100644 --- a/repos/libports/src/lib/libc/fork.cc +++ b/repos/libports/src/lib/libc/fork.cc @@ -32,34 +32,45 @@ #include /* libc-internal includes */ -#include -#include -#include +#include +#include +#include +#include +#include +#include using namespace Genode; static pid_t fork_result; -static Env *_env_ptr; -static Allocator *_alloc_ptr; -static Heap *_malloc_heap_ptr; -static void *_user_stack_base_ptr; -static size_t _user_stack_size; -static int _pid; -static int _pid_cnt; +static Env *_env_ptr; +static Allocator *_alloc_ptr; +static Libc::Suspend *_suspend_ptr; +static Libc::Resume *_resume_ptr; +static Libc::Kernel_routine_scheduler *_kernel_routine_scheduler_ptr; +static Heap *_malloc_heap_ptr; +static void *_user_stack_base_ptr; +static size_t _user_stack_size; +static int _pid; +static int _pid_cnt; static Libc::Config_accessor const *_config_accessor_ptr; void Libc::init_fork(Env &env, Config_accessor const &config_accessor, - Allocator &alloc, Heap &malloc_heap, pid_t pid) + Allocator &alloc, Heap &malloc_heap, pid_t pid, + Suspend &suspend, Resume &resume, + Kernel_routine_scheduler &kernel_routine_scheduler) { - _env_ptr = &env; - _alloc_ptr = &alloc; - _malloc_heap_ptr = &malloc_heap; - _config_accessor_ptr = &config_accessor; - _pid = pid; + _env_ptr = &env; + _alloc_ptr = &alloc; + _suspend_ptr = &suspend; + _resume_ptr = &resume; + _kernel_routine_scheduler_ptr = &kernel_routine_scheduler; + _malloc_heap_ptr = &malloc_heap; + _config_accessor_ptr = &config_accessor; + _pid = pid; } @@ -347,13 +358,15 @@ struct Libc::Local_clone_service : Noncopyable Child_ready &_child_ready; + Resume &_resume; + Io_signal_handler _child_ready_handler; void _handle_child_ready() { _child_ready.child_ready(); - Libc::resume_all(); + _resume.resume_all(); } struct Factory : Local_service::Factory @@ -374,9 +387,10 @@ struct Libc::Local_clone_service : Noncopyable Service service { _factory }; - Local_clone_service(Env &env, Entrypoint &ep, Child_ready &child_ready) + Local_clone_service(Env &env, Entrypoint &ep, Child_ready &child_ready, + Resume &resume) : - _session(env, ep), _child_ready(child_ready), + _session(env, ep), _child_ready(child_ready), _resume(resume), _child_ready_handler(env.ep(), *this, &Local_clone_service::_handle_child_ready), _factory(_session, _child_ready_handler) { } @@ -387,6 +401,8 @@ struct Libc::Forked_child : Child_policy, Child_ready { Env &_env; + Resume &_resume; + pid_t const _pid; enum class State { STARTING_UP, RUNNING, EXITED } _state { State::STARTING_UP }; @@ -402,7 +418,7 @@ struct Libc::Forked_child : Child_policy, Child_ready Io_signal_handler _exit_handler { _env.ep(), *this, &Forked_child::_handle_exit }; - void _handle_exit() { Libc::resume_all(); } + void _handle_exit() { _resume.resume_all(); } Libc::Child_config _child_config; @@ -421,7 +437,7 @@ struct Libc::Forked_child : Child_policy, Child_ready { /* keep executing this kernel routine until child is running */ if (!child.running()) - register_kernel_routine(*this); + _kernel_routine_scheduler_ptr->register_kernel_routine(*this); } } wait_fork_ready { *this }; @@ -513,16 +529,17 @@ struct Libc::Forked_child : Child_policy, Child_ready Forked_child(Env &env, Entrypoint &fork_ep, Allocator &alloc, + Resume &resume, pid_t pid, Config_accessor const &config_accessor, Parent_services &parent_services, Local_rom_services &local_rom_services) : - _env(env), _pid(pid), + _env(env), _resume(resume), _pid(pid), _child_config(env, config_accessor, pid), _parent_services(parent_services), _local_rom_services(local_rom_services), - _local_clone_service(env, fork_ep, *this), + _local_clone_service(env, fork_ep, *this, resume), _config_rom_service(fork_ep, "config", _child_config.ds_cap()), _child(env.rm(), fork_ep.rpc_ep(), *this) { } @@ -545,8 +562,9 @@ static void fork_kernel_routine() abort(); } - Env &env = *_env_ptr; - Allocator &alloc = *_alloc_ptr; + Env &env = *_env_ptr; + Allocator &alloc = *_alloc_ptr; + Libc::Resume &resume = *_resume_ptr; pid_t const child_pid = ++_pid_cnt; @@ -561,19 +579,19 @@ static void fork_kernel_routine() _forked_children_ptr = &forked_children; Registered &child = *new (alloc) - Registered(forked_children, env, fork_ep, alloc, + Registered(forked_children, env, fork_ep, alloc, resume, child_pid, *_config_accessor_ptr, parent_services, local_rom_services); fork_result = child_pid; - register_kernel_routine(child.wait_fork_ready); + _kernel_routine_scheduler_ptr->register_kernel_routine(child.wait_fork_ready); } -/************ - ** getpid ** - ************/ +/********** + ** fork ** + **********/ /* * We provide weak symbols to allow 'libc_noux' to override them. @@ -595,7 +613,11 @@ extern "C" pid_t __sys_fork(void) } kernel_routine { }; - Libc::register_kernel_routine(kernel_routine); + struct Missing_call_of_init_fork : Exception { }; + if (!_kernel_routine_scheduler_ptr || !_suspend_ptr) + throw Missing_call_of_init_fork(); + + _kernel_routine_scheduler_ptr->register_kernel_routine(kernel_routine); struct Suspend_functor_impl : Libc::Suspend_functor { @@ -603,7 +625,7 @@ extern "C" pid_t __sys_fork(void) } suspend_functor { }; - Libc::suspend(suspend_functor, 0); + _suspend_ptr->suspend(suspend_functor, 0); return fork_result; } @@ -681,6 +703,10 @@ extern "C" pid_t __sys_wait4(pid_t pid, int *status, int options, rusage *rusage return -1; } + struct Missing_call_of_init_fork : Genode::Exception { }; + if (!_suspend_ptr) + throw Missing_call_of_init_fork(); + Wait4_suspend_functor suspend_functor { pid, *_forked_children_ptr }; for (;;) { @@ -694,7 +720,7 @@ extern "C" pid_t __sys_wait4(pid_t pid, int *status, int options, rusage *rusage if (result >= 0 || (options & WNOHANG)) break; - Libc::suspend(suspend_functor, 0); + _suspend_ptr->suspend(suspend_functor, 0); } /* diff --git a/repos/libports/src/lib/libc/getpwent.cc b/repos/libports/src/lib/libc/getpwent.cc index 5e7d5459d..ac1becf2b 100644 --- a/repos/libports/src/lib/libc/getpwent.cc +++ b/repos/libports/src/lib/libc/getpwent.cc @@ -14,15 +14,16 @@ /* Genode includes */ #include #include +#include -/* Libc includes */ +/* libc includes */ #include #include #include -/* local includes */ -#include "libc_errno.h" -#include "task.h" +/* libc-local includes */ +#include +#include typedef Genode::String<128> Passwd_string; diff --git a/repos/libports/src/lib/libc/getrandom.cc b/repos/libports/src/lib/libc/getrandom.cc index 88fa63ffe..18bc56768 100644 --- a/repos/libports/src/lib/libc/getrandom.cc +++ b/repos/libports/src/lib/libc/getrandom.cc @@ -20,8 +20,8 @@ extern "C" { #include } -/* local includes */ -#include "libc_errno.h" +/* libc-internal includes */ +#include /* Genode includes */ #include diff --git a/repos/libports/src/lib/libc/clone_session.h b/repos/libports/src/lib/libc/internal/clone_session.h similarity index 94% rename from repos/libports/src/lib/libc/clone_session.h rename to repos/libports/src/lib/libc/internal/clone_session.h index 5b544910d..40e99cd78 100644 --- a/repos/libports/src/lib/libc/clone_session.h +++ b/repos/libports/src/lib/libc/internal/clone_session.h @@ -11,8 +11,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _CLONE_SESSION_H_ -#define _CLONE_SESSION_H_ +#ifndef _LIBC__INTERNAL__CLONE_SESSION_H_ +#define _LIBC__INTERNAL__CLONE_SESSION_H_ /* Genode includes */ #include @@ -92,4 +92,4 @@ struct Libc::Clone_connection : Genode::Connection, void object_content(OBJ &obj) { memory_content(&obj, sizeof(obj)); } }; -#endif /* _CLONE_SESSION_H_ */ +#endif /* _LIBC__INTERNAL__CLONE_SESSION_H_ */ diff --git a/repos/libports/src/lib/libc/internal/cloned_malloc_heap_range.h b/repos/libports/src/lib/libc/internal/cloned_malloc_heap_range.h new file mode 100644 index 000000000..19ca3ca9a --- /dev/null +++ b/repos/libports/src/lib/libc/internal/cloned_malloc_heap_range.h @@ -0,0 +1,59 @@ +/* + * \brief Heap content copied from parent via 'fork' + * \author Norman Feske + * \date 2019-08-14 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__CLONED_MALLOC_HEAP_RANGE_H_ +#define _LIBC__INTERNAL__CLONED_MALLOC_HEAP_RANGE_H_ + +/* Genode includes */ +#include + +/* libc-internal includes */ +#include + +namespace Libc { struct Cloned_malloc_heap_range; } + + +struct Libc::Cloned_malloc_heap_range +{ + Genode::Ram_allocator &ram; + Genode::Region_map &rm; + + Genode::Ram_dataspace_capability ds; + + size_t const size; + addr_t const local_addr; + + Cloned_malloc_heap_range(Genode::Ram_allocator &ram, Genode::Region_map &rm, + void *start, size_t size) + try : + ram(ram), rm(rm), ds(ram.alloc(size)), size(size), + local_addr(rm.attach_at(ds, (addr_t)start)) + { } + catch (Region_map::Region_conflict) { + error("could not clone heap region ", Hex_range(local_addr, size)); + throw; + } + + void import_content(Clone_connection &clone_connection) + { + clone_connection.memory_content((void *)local_addr, size); + } + + virtual ~Cloned_malloc_heap_range() + { + rm.detach(local_addr); + ram.free(ds); + } +}; + +#endif /* _LIBC__INTERNAL__CLONED_MALLOC_HEAP_RANGE_H_ */ diff --git a/repos/libports/src/lib/libc/internal/current_time.h b/repos/libports/src/lib/libc/internal/current_time.h new file mode 100644 index 000000000..518bfc0c9 --- /dev/null +++ b/repos/libports/src/lib/libc/internal/current_time.h @@ -0,0 +1,31 @@ +/* + * \brief Interface for obtaining the current time + * \author Norman Feske + * \date 2019-09-18 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__CURRENT_TIME_H_ +#define _LIBC__INTERNAL__CURRENT_TIME_H_ + +/* Genode includes */ +#include + +/* libc-internal includes */ +#include + +namespace Libc { + + struct Current_time : Interface + { + virtual Duration current_time() = 0; + }; +} + +#endif /* _LIBC__INTERNAL__CURRENT_TIME_H_ */ diff --git a/repos/libports/src/lib/libc/internal/env.h b/repos/libports/src/lib/libc/internal/env.h new file mode 100644 index 000000000..b3a3aa966 --- /dev/null +++ b/repos/libports/src/lib/libc/internal/env.h @@ -0,0 +1,132 @@ +/* + * \brief Libc environment + * \author Christian Helmuth + * \author Emery Hemingway + * \author Norman Feske + * \date 2016-01-22 + */ + +/* + * Copyright (C) 2016-2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__ENV_H_ +#define _LIBC__INTERNAL__ENV_H_ + +/* Genode includes */ +#include +#include + +/* libc includes */ +#include /* 'Libc::Env' */ + +namespace Libc { class Env_implementation; } + + +class Libc::Env_implementation : public Libc::Env, public Config_accessor +{ + private: + + Genode::Env &_env; + + Genode::Attached_rom_dataspace _config { _env, "config" }; + + Genode::Xml_node _vfs_config() + { + try { return _config.xml().sub_node("vfs"); } + catch (Genode::Xml_node::Nonexistent_sub_node) { } + try { + Genode::Xml_node node = + _config.xml().sub_node("libc").sub_node("vfs"); + Genode::warning("' ' is deprecated, " + "please move to ' '"); + return node; + } + catch (Genode::Xml_node::Nonexistent_sub_node) { } + + return Genode::Xml_node(""); + } + + Genode::Xml_node _libc_config() + { + try { return _config.xml().sub_node("libc"); } + catch (Genode::Xml_node::Nonexistent_sub_node) { } + + return Genode::Xml_node(""); + } + + Vfs::Simple_env _vfs_env; + + Genode::Xml_node _config_xml() const override { + return _config.xml(); }; + + public: + + Env_implementation(Genode::Env &env, Genode::Allocator &alloc) + : _env(env), _vfs_env(_env, alloc, _vfs_config()) { } + + + /************************* + ** Libc::Env interface ** + *************************/ + + Vfs::File_system &vfs() override { + return _vfs_env.root_dir(); } + + Genode::Xml_node libc_config() override { + return _libc_config(); } + + + /************************************* + ** Libc::Config_accessor interface ** + *************************************/ + + Xml_node config() const override { return _config.xml(); } + + + /*************************** + ** Genode::Env interface ** + ***************************/ + + Parent &parent() override { return _env.parent(); } + Cpu_session &cpu() override { return _env.cpu(); } + Region_map &rm() override { return _env.rm(); } + Pd_session &pd() override { return _env.pd(); } + Entrypoint &ep() override { return _env.ep(); } + + Cpu_session_capability cpu_session_cap() override { + return _env.cpu_session_cap(); } + + Pd_session_capability pd_session_cap() override { + return _env.pd_session_cap(); } + + Id_space &id_space() override { + return _env.id_space(); } + + Session_capability session(Parent::Service_name const &name, + Parent::Client::Id id, + Parent::Session_args const &args, + Affinity const &aff) override { + return _env.session(name, id, args, aff); } + + void upgrade(Parent::Client::Id id, + Parent::Upgrade_args const &args) override { + return _env.upgrade(id, args); } + + void close(Parent::Client::Id id) override { + return _env.close(id); } + + /* already done by the libc */ + void exec_static_constructors() override { } + + void reinit(Native_capability::Raw raw) override { + _env.reinit(raw); } + + void reinit_main_thread(Capability &stack_area_rm) override { + _env.reinit_main_thread(stack_area_rm); } +}; + +#endif /* _LIBC__INTERNAL__ENV_H_ */ diff --git a/repos/libports/src/lib/libc/libc_errno.h b/repos/libports/src/lib/libc/internal/errno.h similarity index 82% rename from repos/libports/src/lib/libc/libc_errno.h rename to repos/libports/src/lib/libc/internal/errno.h index cab3ee4e1..4e7725a5e 100644 --- a/repos/libports/src/lib/libc/libc_errno.h +++ b/repos/libports/src/lib/libc/internal/errno.h @@ -11,8 +11,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _LIBC_ERRNO_H_ -#define _LIBC_ERRNO_H_ +#ifndef _LIBC__INTERNAL__ERRNO_H_ +#define _LIBC__INTERNAL__ERRNO_H_ /* libc includes */ #include @@ -28,4 +28,4 @@ struct Libc::Errno operator int() const { return -1; } }; -#endif /* _LIBC_ERRNO_H_ */ +#endif /* _LIBC__INTERNAL__ERRNO_H_ */ diff --git a/repos/libports/src/lib/libc/libc_file.h b/repos/libports/src/lib/libc/internal/file.h similarity index 95% rename from repos/libports/src/lib/libc/libc_file.h rename to repos/libports/src/lib/libc/internal/file.h index d92d6e9d8..8ca2980cd 100644 --- a/repos/libports/src/lib/libc/libc_file.h +++ b/repos/libports/src/lib/libc/internal/file.h @@ -12,8 +12,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _LIBC_FILE_H_ -#define _LIBC_FILE_H_ +#ifndef _LIBC__INTERNAL__FILE_H_ +#define _LIBC__INTERNAL__FILE_H_ /* Genode includes */ #include @@ -73,4 +73,4 @@ static inline Libc::File_descriptor *libc_fd_to_fd(int libc_fd, const char *func #define FNAME_FUNC_WRAPPER(func_name, path, ...) \ FNAME_FUNC_WRAPPER_GENERIC(return, func_name, path, ##__VA_ARGS__ ) -#endif /* _LIBC_FILE_H_ */ +#endif /* _LIBC__INTERNAL__FILE_H_ */ diff --git a/repos/libports/src/lib/libc/libc_init.h b/repos/libports/src/lib/libc/internal/init.h similarity index 64% rename from repos/libports/src/lib/libc/libc_init.h rename to repos/libports/src/lib/libc/internal/init.h index 0588fce35..eedd66f7e 100644 --- a/repos/libports/src/lib/libc/libc_init.h +++ b/repos/libports/src/lib/libc/internal/init.h @@ -11,19 +11,30 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _LIBC_INIT_H_ -#define _LIBC_INIT_H_ +#ifndef _LIBC__INTERNAL__INIT_H_ +#define _LIBC__INTERNAL__INIT_H_ /* Genode includes */ #include #include #include +#include /* for 'MAX_PATH_LEN' */ /* libc includes */ #include /* for 'jmp_buf' type */ +/* libc-internal includes */ +#include + namespace Libc { + struct Resume; + struct Suspend; + struct Select; + struct Current_time; + struct Clone_connection; + struct Kernel_routine_scheduler; + /** * Support for shared libraries */ @@ -39,6 +50,26 @@ namespace Libc { */ void init_mem_alloc(Genode::Env &env); + /** + * Plugin interface + */ + void init_plugin(Resume &); + + /** + * Virtual file system + */ + void init_vfs_plugin(Suspend &); + + /** + * Select support + */ + void init_select(Suspend &, Resume &, Select &); + + /** + * Poll support + */ + void init_poll(Suspend &); + /** * Support for querying available RAM quota in sysctl functions */ @@ -49,8 +80,6 @@ namespace Libc { */ void libc_config_init(Genode::Xml_node node); - struct Clone_connection; - /** * Malloc allocator */ @@ -58,11 +87,24 @@ namespace Libc { void init_malloc_cloned(Clone_connection &); void reinit_malloc(Genode::Allocator &); + typedef String Rtc_path; + + /** + * Init timing facilities + */ + void init_sleep(Suspend &); + void init_time(Current_time &, Rtc_path const &); + + /** + * Socket fs + */ + void init_socket_fs(Suspend &); + /** * Allow thread.cc to access the 'Genode::Env' (needed for the * implementation of condition variables with timeout) */ - void init_pthread_support(Genode::Env &env); + void init_pthread_support(Genode::Env &env, Suspend &, Resume &); struct Config_accessor : Genode::Interface { @@ -73,7 +115,8 @@ namespace Libc { * Fork mechanism */ void init_fork(Genode::Env &, Config_accessor const &, - Genode::Allocator &heap, Genode::Heap &malloc_heap, int pid); + Genode::Allocator &heap, Genode::Heap &malloc_heap, int pid, + Suspend &, Resume &, Kernel_routine_scheduler &); struct Reset_malloc_heap : Genode::Interface { @@ -87,4 +130,4 @@ namespace Libc { Reset_malloc_heap &); } -#endif /* _LIBC_INIT_H_ */ +#endif /* _LIBC__INTERNAL__INIT_H_ */ diff --git a/repos/libports/src/lib/libc/internal/kernel.h b/repos/libports/src/lib/libc/internal/kernel.h new file mode 100644 index 000000000..509a58b51 --- /dev/null +++ b/repos/libports/src/lib/libc/internal/kernel.h @@ -0,0 +1,561 @@ +/* + * \brief Libc kernel for main and pthreads user contexts + * \author Christian Helmuth + * \author Emery Hemingway + * \author Norman Feske + * \date 2016-01-22 + */ + +/* + * Copyright (C) 2016-2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__KERNEL_H_ +#define _LIBC__INTERNAL__KERNEL_H_ + +/* base-internal includes */ +#include + +/* libc includes */ +#include + +/* libc-internal includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Libc { class Kernel; } + + +/** + * Libc "kernel" + * + * This class represents the "kernel" of the libc-based application + * Blocking and deblocking happens here on libc functions like read() or + * select(). This combines blocking of the VFS backend and other signal sources + * (e.g., timers). The libc task runs on the component thread and allocates a + * secondary stack for the application task. Context switching uses + * setjmp/longjmp. + */ +struct Libc::Kernel final : Vfs::Io_response_handler, + Entrypoint::Io_progress_handler, + Reset_malloc_heap, + Resume, + Suspend, + Select, + Kernel_routine_scheduler, + Current_time +{ + private: + + /** + * Pointer to singleton instance + */ + static Kernel *_kernel_ptr; + + Genode::Env &_env; + + /** + * Allocator for libc-internal data + * + * Not mirrored to forked processes. Preserved across 'execve' calls. + */ + Allocator &_heap; + + /** + * Allocator for application-owned data + * + * Mirrored to forked processes. Not preserved across 'execve' calls. + */ + Reconstructible _malloc_ram { _heap, _env.ram() }; + + Constructible _malloc_heap { }; + + Registry > _cloned_heap_ranges { }; + + /** + * Reset_malloc_heap interface used by execve + */ + void reset_malloc_heap() override; + + Env_implementation _libc_env { _env, _heap }; + Vfs_plugin _vfs { _libc_env, _heap, *this }; + + bool const _cloned = _libc_env.libc_config().attribute_value("cloned", false); + pid_t const _pid = _libc_env.libc_config().attribute_value("pid", 0U); + + typedef String Config_attr; + + Config_attr const _rtc_path = _libc_env.libc_config().attribute_value("rtc", Config_attr()); + + Reconstructible> _resume_main_handler { + _env.ep(), *this, &Kernel::_resume_main }; + + jmp_buf _kernel_context; + jmp_buf _user_context; + bool _valid_user_context = false; + bool _dispatch_pending_io_signals = false; + + /* io_progress_handler marker */ + bool _io_ready { false }; + + Thread &_myself { *Thread::myself() }; + + addr_t _kernel_stack = Thread::mystack().top; + + size_t _user_stack_size(); + + void *_user_stack = { + _myself.alloc_secondary_stack(_myself.name().string(), + _user_stack_size()) }; + + void (*_original_suspended_callback)() = nullptr; + + enum State { KERNEL, USER }; + + State _state = KERNEL; + + Application_code *_nested_app_code = nullptr; + + Application_code *_app_code = nullptr; + bool _app_returned = false; + + bool _resume_main_once = false; + bool _suspend_scheduled = false; + + Select_handler_base *_scheduled_select_handler = nullptr; + + Kernel_routine *_kernel_routine = nullptr; + + void _resume_main() { _resume_main_once = true; } + + Kernel_timer_accessor _timer_accessor { _env }; + + struct Main_timeout : Timeout_handler + { + Timer_accessor &_timer_accessor; + Constructible _timeout; + Kernel &_kernel; + + void _construct_timeout_once() + { + if (!_timeout.constructed()) + _timeout.construct(_timer_accessor, *this); + } + + Main_timeout(Timer_accessor &timer_accessor, Kernel &kernel) + : _timer_accessor(timer_accessor), _kernel(kernel) + { } + + void timeout(uint64_t timeout_ms) + { + _construct_timeout_once(); + _timeout->start(timeout_ms); + } + + uint64_t duration_left() + { + _construct_timeout_once(); + return _timeout->duration_left(); + } + + void handle_timeout() override + { + _kernel._resume_main(); + } + }; + + Main_timeout _main_timeout { _timer_accessor, *this }; + + Pthread_pool _pthreads { _timer_accessor }; + + struct Resumer + { + GENODE_RPC(Rpc_resume, void, resume); + GENODE_RPC_INTERFACE(Rpc_resume); + }; + + struct Resumer_component : Rpc_object + { + Kernel &_kernel; + + Resumer_component(Kernel &kernel) : _kernel(kernel) { } + + void resume() { _kernel.run_after_resume(); } + }; + + /** + * Trampoline to application (user) code + * + * This function is called by the main thread. + */ + static void _user_entry(Libc::Kernel *kernel) + { + struct Check : Suspend_functor { + bool suspend() override { return true; } + } check; + + kernel->_app_code->execute(); + kernel->_app_returned = true; + kernel->_suspend_main(check, 0); + } + + bool _main_context() const { return &_myself == Thread::myself(); } + + /** + * Utility to switch main context to kernel + * + * User context must be saved explicitly before this function is called + * to enable _switch_to_user() later. + */ + void _switch_to_kernel() + { + _state = KERNEL; + _longjmp(_kernel_context, 1); + } + + /** + * Utility to switch main context to user + * + * Kernel context must be saved explicitly before this function is called + * to enable _switch_to_kernel() later. + */ + void _switch_to_user() + { + if (!_valid_user_context) + error("switching to invalid user context"); + + _resume_main_once = false; + _state = USER; + _longjmp(_user_context, 1); + } + + uint64_t _suspend_main(Suspend_functor &check, uint64_t timeout_ms) + { + /* check that we're not running on libc kernel context */ + if (Thread::mystack().top == _kernel_stack) { + error("libc suspend() called from non-user context (", + __builtin_return_address(0), ") - aborting"); + exit(1); + } + + if (!check.suspend() && !_kernel_routine) + return 0; + + if (timeout_ms > 0) + _main_timeout.timeout(timeout_ms); + + if (!_setjmp(_user_context)) { + _valid_user_context = true; + _switch_to_kernel(); + } else { + _valid_user_context = false; + } + + /* + * During the suspension 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; + } + + void _init_file_descriptors(); + + void _clone_state_from_parent(); + + public: + + Kernel(Genode::Env &env, Allocator &heap); + + ~Kernel() { error(__PRETTY_FUNCTION__, " should not be executed!"); } + + Libc::Env & libc_env() { return _libc_env; } + + /** + * Setup kernel context and run libc application main context + * + * This function is called by the component thread on with_libc(). + */ + void run(Libc::Application_code &app_code) + { + if (!_main_context() || _state != KERNEL) { + error(__PRETTY_FUNCTION__, " called from non-kernel context"); + return; + } + + _resume_main_once = false; + _app_returned = false; + _app_code = &app_code; + + /* save continuation of libc kernel (incl. current stack) */ + if (!_setjmp(_kernel_context)) { + /* _setjmp() returned directly -> switch to user stack and call application code */ + + if (_cloned) { + _switch_to_user(); + } else { + _state = USER; + call_func(_user_stack, (void *)_user_entry, (void *)this); + } + + /* never reached */ + } + + /* _setjmp() returned after _longjmp() - user context suspended */ + + while ((!_app_returned) && (!_suspend_scheduled)) { + + if (_kernel_routine) { + Kernel_routine &routine = *_kernel_routine; + + /* the 'kernel_routine' may install another kernel routine */ + _kernel_routine = nullptr; + routine.execute_in_kernel(); + if (!_kernel_routine) + _switch_to_user(); + } + + if (_dispatch_pending_io_signals) { + /* dispatch pending signals but don't block */ + while (_env.ep().dispatch_pending_io_signal()) ; + } else { + /* block for signals */ + _env.ep().wait_and_dispatch_one_io_signal(); + } + + if (!_kernel_routine && _resume_main_once && !_setjmp(_kernel_context)) + _switch_to_user(); + } + + _suspend_scheduled = false; + } + + /* + * Run libc application main context after suspend and resume + */ + void run_after_resume() + { + if (!_setjmp(_kernel_context)) + _switch_to_user(); + + while ((!_app_returned) && (!_suspend_scheduled)) { + _env.ep().wait_and_dispatch_one_io_signal(); + if (_resume_main_once && !_setjmp(_kernel_context)) + _switch_to_user(); + } + + _suspend_scheduled = false; + } + + /** + * Resume interface + */ + void resume_all() override + { + if (_app_returned) { + if (_scheduled_select_handler) + _scheduled_select_handler->dispatch_select(); + } else { + if (_main_context()) + _resume_main(); + else + Signal_transmitter(*_resume_main_handler).submit(); + } + + _pthreads.resume_all(); + } + + /** + * Suspend interface + */ + uint64_t suspend(Suspend_functor &check, uint64_t timeout_ms) override + { + if (timeout_ms > 0 + && timeout_ms > _timer_accessor.timer().max_timeout()) { + warning("libc: limiting exceeding timeout of ", + timeout_ms, " ms to maximum of ", + _timer_accessor.timer().max_timeout(), " ms"); + + timeout_ms = min(timeout_ms, _timer_accessor.timer().max_timeout()); + } + + return _main_context() ? _suspend_main(check, timeout_ms) + : _pthreads.suspend_myself(check, timeout_ms); + } + + void dispatch_pending_io_signals() + { + if (!_main_context()) return; + + if (!_setjmp(_user_context)) { + _valid_user_context = true; + _dispatch_pending_io_signals = true; + _resume_main_once = true; /* afterwards resume main */ + _switch_to_kernel(); + } else { + _valid_user_context = false; + _dispatch_pending_io_signals = false; + } + } + + /** + * Current_time interface + */ + Duration current_time() override + { + return _timer_accessor.timer().curr_time(); + } + + /** + * Called from the main context (by fork) + */ + void schedule_suspend(void(*original_suspended_callback) ()); + + /** + * Select interface + */ + void schedule_select(Select_handler_base &h) override + { + _scheduled_select_handler = &h; + } + + /** + * Select interface + */ + void deschedule_select() override + { + _scheduled_select_handler = nullptr; + } + + /** + * Called from the context of the initial thread (on fork) + */ + void entrypoint_suspended() + { + _resume_main_handler.destruct(); + + _original_suspended_callback(); + } + + /** + * Called from the context of the initial thread (after fork) + */ + void entrypoint_resumed() + { + _resume_main_handler.construct(_env.ep(), *this, &Kernel::_resume_main); + + Resumer_component resumer { *this }; + + Capability resumer_cap = + _env.ep().rpc_ep().manage(&resumer); + + resumer_cap.call(); + + _env.ep().rpc_ep().dissolve(&resumer); + } + + /** + * Return if main is currently suspended + */ + bool main_suspended() { return _state == KERNEL; } + + /** + * Public alias for _main_context() + */ + bool main_context() const { return _main_context(); } + + /** + * 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(); + } + } + + /** + * Alloc new watch handler for given path + */ + Vfs::Vfs_watch_handle *alloc_watch_handle(char const *path) + { + Vfs::Vfs_watch_handle *watch_handle { nullptr }; + typedef Vfs::Directory_service::Watch_result Result; + return _libc_env.vfs().watch(path, &watch_handle, _heap) == Result::WATCH_OK + ? watch_handle : nullptr; + } + + + /**************************************** + ** Vfs::Io_response_handler interface ** + ****************************************/ + + void read_ready_response() override { + _io_ready = true; } + + void io_progress_response() override { + _io_ready = true; } + + + /********************************************** + * Entrypoint::Io_progress_handler interface ** + **********************************************/ + + void handle_io_progress() override; + + /** + * Kernel_routine_scheduler interface + */ + void register_kernel_routine(Kernel_routine &kernel_routine) override + { + _kernel_routine = &kernel_routine; + } + + + /******************************** + ** Access to kernel singleton ** + ********************************/ + + struct Kernel_called_prior_initialization : Exception { }; + + static Kernel &kernel() + { + if (!_kernel_ptr) + throw Kernel_called_prior_initialization(); + + return *_kernel_ptr; + } +}; + +#endif /* _LIBC__INTERNAL__KERNEL_H_ */ diff --git a/repos/libports/src/lib/libc/internal/kernel_routine.h b/repos/libports/src/lib/libc/internal/kernel_routine.h new file mode 100644 index 000000000..78ad5edba --- /dev/null +++ b/repos/libports/src/lib/libc/internal/kernel_routine.h @@ -0,0 +1,46 @@ +/* + * \brief Interface executing code in the context of the libc kernel + * \author Norman Feske + * \date 2019-09-18 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__KERNEL_ROUTINE_H_ +#define _LIBC__INTERNAL__KERNEL_ROUTINE_H_ + +/* libc-internal includes */ +#include + +namespace Libc { + + /** + * Base class to be implemented by a kernel routine + */ + struct Kernel_routine : Interface + { + virtual void execute_in_kernel() = 0; + }; + + struct Kernel_routine_scheduler : Interface + { + /** + * Register routine to be called once on the next libc-kernel activation + * + * The specified routine is executed only once. For a repeated execution, + * the routine must call 'register_kernel_routine' with itself as + * argument. + * + * This mechanism is used by 'fork' to implement the blocking for the + * startup of a new child and for 'wait4'. + */ + virtual void register_kernel_routine(Kernel_routine &) = 0; + }; +} + +#endif /* _LIBC__INTERNAL__KERNEL_ROUTINE_H_ */ diff --git a/repos/libports/src/lib/libc/internal/kernel_timer_accessor.h b/repos/libports/src/lib/libc/internal/kernel_timer_accessor.h new file mode 100644 index 000000000..fad0cc35f --- /dev/null +++ b/repos/libports/src/lib/libc/internal/kernel_timer_accessor.h @@ -0,0 +1,50 @@ +/* + * \brief Interface for accessing the libc's kernel timer + * \author Norman Feske + * \date 2019-09-19 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__KERNEL_TIMER_ACCESSOR_H_ +#define _LIBC__INTERNAL__KERNEL_TIMER_ACCESSOR_H_ + +/* Genode includes */ +#include +#include +#include + +namespace Libc { struct Kernel_timer_accessor; } + +struct Libc::Kernel_timer_accessor : Timer_accessor +{ + Genode::Env &_env; + + /* + * The '_timer' is constructed by whatever thread (main thread + * of pthread) that uses a time-related function first. Hence, + * the construction must be protected by a lock. + */ + Lock _lock; + + Constructible _timer; + + Kernel_timer_accessor(Genode::Env &env) : _env(env) { } + + Timer &timer() override + { + Lock::Guard guard(_lock); + + if (!_timer.constructed()) + _timer.construct(_env); + + return *_timer; + } +}; + +#endif /* _LIBC__INTERNAL__KERNEL_TIMER_ACCESSOR_H_ */ diff --git a/repos/libports/src/lib/libc/internal/legacy.h b/repos/libports/src/lib/libc/internal/legacy.h new file mode 100644 index 000000000..344de62cd --- /dev/null +++ b/repos/libports/src/lib/libc/internal/legacy.h @@ -0,0 +1,53 @@ +/* + * \brief Globally available accessors to Libc kernel functionality + * \author Norman Feske + * \date 2019-09-18 + */ + +/* + * Copyright (C) 2016-2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__LEGACY_H_ +#define _LIBC__INTERNAL__LEGACY_H_ + +/* Genode includes */ +#include /* needed for 'watch' */ + +/* libc-internal includes */ +#include + +namespace Libc { + + /* + * XXX called only by 'Libc::Vfs_plugin::read' + */ + void dispatch_pending_io_signals(); + + /** + * Get watch handle for given path + * + * \param path path that should be be watched + * + * \return point to the watch handle object or a nullptr + * when the watch operation failed + * + * XXX only needed by time.cc + */ + Vfs::Vfs_watch_handle *watch(char const *path); + + /* + * XXX this function is solely needed to support noux fork mechanism + */ + void schedule_suspend(void (*) ()); + + /** + * Access libc configuration Xml_node. + */ + Genode::Xml_node libc_config(); +} + +#endif /* _LIBC__INTERNAL__LEGACY_H_ */ diff --git a/repos/libports/src/lib/libc/internal/malloc_ram_allocator.h b/repos/libports/src/lib/libc/internal/malloc_ram_allocator.h new file mode 100644 index 000000000..9d897f7cf --- /dev/null +++ b/repos/libports/src/lib/libc/internal/malloc_ram_allocator.h @@ -0,0 +1,74 @@ +/* + * \brief Utility for tracking the allocation of dataspaces by the malloc heap + * \author Norman Feske + * \date 2019-08-20 + */ + +/* + * Copyright (C) 2016-2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__MALLOC_RAM_ALLOCATOR_H_ +#define _LIBC__INTERNAL__MALLOC_RAM_ALLOCATOR_H_ + +/* Genode includes */ +#include +#include +#include + +namespace Libc { struct Malloc_ram_allocator; } + + +struct Libc::Malloc_ram_allocator : Genode::Ram_allocator +{ + Genode::Allocator &_md_alloc; + Genode::Ram_allocator &_ram; + + struct Dataspace + { + Genode::Ram_dataspace_capability cap; + Dataspace(Genode::Ram_dataspace_capability cap) : cap(cap) { } + virtual ~Dataspace() { } + }; + + Genode::Registry > _dataspaces { }; + + void _release(Genode::Registered &ds) + { + _ram.free(ds.cap); + destroy(_md_alloc, &ds); + } + + Malloc_ram_allocator(Allocator &md_alloc, Ram_allocator &ram) + : _md_alloc(md_alloc), _ram(ram) { } + + ~Malloc_ram_allocator() + { + _dataspaces.for_each([&] (Registered &ds) { + _release(ds); }); + } + + Ram_dataspace_capability alloc(size_t size, Cache_attribute cached) override + { + Ram_dataspace_capability cap = _ram.alloc(size, cached); + new (_md_alloc) Registered(_dataspaces, cap); + return cap; + } + + void free(Ram_dataspace_capability ds_cap) override + { + _dataspaces.for_each([&] (Registered &ds) { + if (ds_cap == ds.cap) + _release(ds); }); + } + + size_t dataspace_size(Ram_dataspace_capability ds_cap) const override + { + return _ram.dataspace_size(ds_cap); + } +}; + +#endif /* _LIBC__INTERNAL__MALLOC_RAM_ALLOCATOR_H_ */ diff --git a/repos/libports/src/lib/libc/libc_mem_alloc.h b/repos/libports/src/lib/libc/internal/mem_alloc.h similarity index 91% rename from repos/libports/src/lib/libc/libc_mem_alloc.h rename to repos/libports/src/lib/libc/internal/mem_alloc.h index 981ccaf86..1b1c46c4d 100644 --- a/repos/libports/src/lib/libc/libc_mem_alloc.h +++ b/repos/libports/src/lib/libc/internal/mem_alloc.h @@ -4,8 +4,15 @@ * \date 2012-05-18 */ -#ifndef _LIBC_MEM_ALLOC_H_ -#define _LIBC_MEM_ALLOC_H_ +/* + * Copyright (C) 2012-2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__MEM_ALLOC_H_ +#define _LIBC__INTERNAL__MEM_ALLOC_H_ /* Genode includes */ #include @@ -126,4 +133,4 @@ namespace Libc { }; } -#endif /* _LIBC_MEM_ALLOC_H_ */ +#endif /* _LIBC__INTERNAL__MEM_ALLOC_H_ */ diff --git a/repos/libports/src/lib/libc/libc_mmap_registry.h b/repos/libports/src/lib/libc/internal/mmap_registry.h similarity index 87% rename from repos/libports/src/lib/libc/libc_mmap_registry.h rename to repos/libports/src/lib/libc/internal/mmap_registry.h index 81339e30a..c47f50a47 100644 --- a/repos/libports/src/lib/libc/libc_mmap_registry.h +++ b/repos/libports/src/lib/libc/internal/mmap_registry.h @@ -4,8 +4,15 @@ * \date 2012-08-16 */ -#ifndef _LIBC_MMAP_REGISTRY_H_ -#define _LIBC_MMAP_REGISTRY_H_ +/* + * Copyright (C) 2012-2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__MMAP_REGISTRY_H_ +#define _LIBC__INTERNAL__MMAP_REGISTRY_H_ /* Genode includes */ #include @@ -13,11 +20,9 @@ #include #include -/* libc-internal includes */ -#include - /* libc includes */ #include +#include namespace Libc { @@ -122,4 +127,4 @@ class Libc::Mmap_registry }; -#endif /* _LIBC_MMAP_REGISTRY_H_ */ +#endif /* _LIBC__INTERNAL__MMAP_REGISTRY_H_ */ diff --git a/repos/libports/src/lib/libc/thread.h b/repos/libports/src/lib/libc/internal/pthread.h similarity index 97% rename from repos/libports/src/lib/libc/thread.h rename to repos/libports/src/lib/libc/internal/pthread.h index c4f3af108..97b02b278 100644 --- a/repos/libports/src/lib/libc/thread.h +++ b/repos/libports/src/lib/libc/internal/pthread.h @@ -13,13 +13,14 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_ -#define _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_ +#ifndef _LIBC__INTERNAL__PTHREAD_H_ +#define _LIBC__INTERNAL__PTHREAD_H_ /* Genode includes */ #include #include +/* libc includes */ #include /* @@ -227,4 +228,4 @@ struct pthread : Genode::Noncopyable, Genode::Thread::Tls::Base namespace Libc { void init_pthread_support(Env &env); } -#endif /* _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_ */ +#endif /* _LIBC__INTERNAL__PTHREAD_H_ */ diff --git a/repos/libports/src/lib/libc/internal/pthread_pool.h b/repos/libports/src/lib/libc/internal/pthread_pool.h new file mode 100644 index 000000000..1e7f1697d --- /dev/null +++ b/repos/libports/src/lib/libc/internal/pthread_pool.h @@ -0,0 +1,107 @@ +/* + * \brief Pthread handling + * \author Christian Prochaska + * \author Christian Helmuth + * \date 2016-12-13 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__PTHREAD_POOL_H_ +#define _LIBC__INTERNAL__PTHREAD_POOL_H_ + +/* libc-internal includes */ +#include +#include + +namespace Libc { class Pthread_pool; } + + +struct Libc::Pthread_pool +{ + struct Pthread : Timeout_handler + { + Genode::Lock lock { Genode::Lock::LOCKED }; + Pthread *next { nullptr }; + + Timer_accessor &_timer_accessor; + Constructible _timeout; + + void _construct_timeout_once() + { + if (!_timeout.constructed()) + _timeout.construct(_timer_accessor, *this); + } + + Pthread(Timer_accessor &timer_accessor, Genode::uint64_t timeout_ms) + : _timer_accessor(timer_accessor) + { + if (timeout_ms > 0) { + _construct_timeout_once(); + _timeout->start(timeout_ms); + } + } + + Genode::uint64_t duration_left() + { + _construct_timeout_once(); + return _timeout->duration_left(); + } + + void handle_timeout() override + { + lock.unlock(); + } + }; + + Genode::Lock mutex; + Pthread *pthreads = nullptr; + Timer_accessor &timer_accessor; + + + Pthread_pool(Timer_accessor &timer_accessor) + : timer_accessor(timer_accessor) { } + + void resume_all() + { + Genode::Lock::Guard g(mutex); + + for (Pthread *p = pthreads; p; p = p->next) + p->lock.unlock(); + } + + Genode::uint64_t suspend_myself(Suspend_functor & check, Genode::uint64_t timeout_ms) + { + Pthread myself { timer_accessor, timeout_ms }; + { + Genode::Lock::Guard g(mutex); + + myself.next = pthreads; + pthreads = &myself; + } + + if (check.suspend()) + myself.lock.lock(); + + { + Genode::Lock::Guard g(mutex); + + /* address of pointer to next pthread allows to change the head */ + for (Pthread **next = &pthreads; *next; next = &(*next)->next) { + if (*next == &myself) { + *next = myself.next; + break; + } + } + } + + return timeout_ms > 0 ? myself.duration_left() : 0; + } +}; + +#endif /* _LIBC__INTERNAL__PTHREAD_POOL_H_ */ diff --git a/repos/libports/src/lib/libc/internal/resume.h b/repos/libports/src/lib/libc/internal/resume.h new file mode 100644 index 000000000..6d5bd193c --- /dev/null +++ b/repos/libports/src/lib/libc/internal/resume.h @@ -0,0 +1,34 @@ +/* + * \brief Interface for resuming the execution of user contexts + * \author Norman Feske + * \date 2019-09-18 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__RESUME_H_ +#define _LIBC__INTERNAL__RESUME_H_ + +/* libc-internal includes */ +#include + +namespace Libc { + + /** + * Interface to resume all user contexts + */ + struct Resume : Interface + { + /** + * Resumes the main user context as well as any pthread context + */ + virtual void resume_all() = 0; + }; +} + +#endif /* _LIBC__INTERNAL__RESUME_H_ */ diff --git a/repos/libports/src/lib/libc/internal/select.h b/repos/libports/src/lib/libc/internal/select.h new file mode 100644 index 000000000..e1b65e62d --- /dev/null +++ b/repos/libports/src/lib/libc/internal/select.h @@ -0,0 +1,35 @@ +/* + * \brief Interface for registering select handler + * \author Norman Feske + * \date 2019-09-18 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__SELECT_H_ +#define _LIBC__INTERNAL__SELECT_H_ + +/* libc-internal includes */ +#include + +namespace Libc { + + struct Select_handler_base; + + struct Select : Interface + { + /** + * Schedule select handler that is deblocked by ready fd sets + */ + virtual void schedule_select(Select_handler_base &) = 0; + + virtual void deschedule_select() = 0; + }; +} + +#endif /* _LIBC__INTERNAL__SELECT_H_ */ diff --git a/repos/libports/src/lib/libc/socket_fs_plugin.h b/repos/libports/src/lib/libc/internal/socket_fs_plugin.h similarity index 90% rename from repos/libports/src/lib/libc/socket_fs_plugin.h rename to repos/libports/src/lib/libc/internal/socket_fs_plugin.h index 4a9228a4e..95a3d8e13 100644 --- a/repos/libports/src/lib/libc/socket_fs_plugin.h +++ b/repos/libports/src/lib/libc/internal/socket_fs_plugin.h @@ -12,8 +12,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _LIBC__SOCKET_FS_PLUGIN_H_ -#define _LIBC__SOCKET_FS_PLUGIN_H_ +#ifndef _LIBC__INTERNAL__SOCKET_FS_PLUGIN_H_ +#define _LIBC__INTERNAL__SOCKET_FS_PLUGIN_H_ /* Libc includes */ #include @@ -35,4 +35,4 @@ extern "C" int socket_fs_setsockopt(int, int, int, void const *, socklen_t); extern "C" int socket_fs_shutdown(int, int); extern "C" int socket_fs_socket(int, int, int); -#endif /* _LIBC__SOCKET_FS_PLUGIN_H_ */ +#endif /* _LIBC__INTERNAL__SOCKET_FS_PLUGIN_H_ */ diff --git a/repos/libports/src/lib/libc/internal/suspend.h b/repos/libports/src/lib/libc/internal/suspend.h new file mode 100644 index 000000000..374cbe8d0 --- /dev/null +++ b/repos/libports/src/lib/libc/internal/suspend.h @@ -0,0 +1,51 @@ +/* + * \brief Interface for suspending the execution until I/O activity + * \author Norman Feske + * \date 2019-09-18 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__SUSPEND_H_ +#define _LIBC__INTERNAL__SUSPEND_H_ + +/* libc-internal includes */ +#include + +namespace Libc { + + /** + * Interface for requesting the condition for suspending + */ + struct Suspend_functor : Interface + { + virtual bool suspend() = 0; + }; + + struct Suspend : Interface + { + typedef Genode::uint64_t uint64_t; + + /** + * Suspend the execution of the calling user context + * + * \param timeout_ms maximum time to stay suspended in milliseconds, + * 0 for infinite suspend + * + * \return remaining duration until timeout, + * 0 if the timeout expired + * + * The context could be running on the component entrypoint as main context + * or as separate pthread. This function returns after the libc kernel + * resumed the user context execution. + */ + virtual uint64_t suspend(Suspend_functor &, uint64_t timeout_ms = 0) = 0; + }; +} + +#endif /* _LIBC__INTERNAL__SUSPEND_H_ */ diff --git a/repos/libports/src/lib/libc/thread_create.h b/repos/libports/src/lib/libc/internal/thread_create.h similarity index 81% rename from repos/libports/src/lib/libc/thread_create.h rename to repos/libports/src/lib/libc/internal/thread_create.h index c760cbf31..d11b60c69 100644 --- a/repos/libports/src/lib/libc/thread_create.h +++ b/repos/libports/src/lib/libc/internal/thread_create.h @@ -13,12 +13,15 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _LIBC__THREAD_CREATE_H_ -#define _LIBC__THREAD_CREATE_H_ +#ifndef _LIBC__INTERNAL__THREAD_CREATE_H_ +#define _LIBC__INTERNAL__THREAD_CREATE_H_ -#include +/* Genode includes */ #include +/* libc includes */ +#include + namespace Libc { int pthread_create(pthread_t *thread, void *(*start_routine) (void *), void *arg, @@ -28,4 +31,4 @@ namespace Libc { int pthread_create(pthread_t *, Genode::Thread &); } -#endif /* _LIBC__THREAD_CREATE_H_ */ +#endif /* _LIBC__INTERNAL__THREAD_CREATE_H_ */ diff --git a/repos/libports/src/lib/libc/timed_semaphore.h b/repos/libports/src/lib/libc/internal/timed_semaphore.h similarity index 97% rename from repos/libports/src/lib/libc/timed_semaphore.h rename to repos/libports/src/lib/libc/internal/timed_semaphore.h index 537ce265d..d7853fe9c 100644 --- a/repos/libports/src/lib/libc/timed_semaphore.h +++ b/repos/libports/src/lib/libc/internal/timed_semaphore.h @@ -16,8 +16,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _TIMED_SEMAPHORE_H_ -#define _TIMED_SEMAPHORE_H_ +#ifndef _LIBC__INTERNAL__TIMED_SEMAPHORE_H_ +#define _LIBC__INTERNAL__TIMED_SEMAPHORE_H_ #include #include @@ -259,4 +259,4 @@ class Libc::Timed_semaphore : public Semaphore void up() { Semaphore::up(); } }; -#endif /* _TIMED_SEMAPHORE_H_ */ +#endif /* _LIBC__INTERNAL__TIMED_SEMAPHORE_H_ */ diff --git a/repos/libports/src/lib/libc/internal/timer.h b/repos/libports/src/lib/libc/internal/timer.h new file mode 100644 index 000000000..aa8bee66a --- /dev/null +++ b/repos/libports/src/lib/libc/internal/timer.h @@ -0,0 +1,117 @@ +/* + * \brief Libc-internal timer handling + * \author Norman Feske + * \date 2019-09-16 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__TIMER_H_ +#define _LIBC__INTERNAL__TIMER_H_ + +/* Genode includes */ +#include + +namespace Libc { + class Timer; + class Timer_accessor; + class Timeout; + class Timeout_handler; +} + + +struct Libc::Timer +{ + ::Timer::Connection _timer; + + Timer(Genode::Env &env) : _timer(env) { } + + Genode::Duration curr_time() + { + return _timer.curr_time(); + } + + static Microseconds microseconds(Genode::uint64_t timeout_ms) + { + return Microseconds(1000*timeout_ms); + } + + static Genode::uint64_t max_timeout() + { + return ~0UL/1000; + } +}; + + +/** + * Interface for obtaining the libc-global timer instance + * + * The 'Timer' is instantiated on demand whenever the 'Timer_accessor::timer' + * method is first called. This way, libc-using components do not depend of a + * timer connection unless they actually use time-related functionality. + */ +struct Libc::Timer_accessor +{ + virtual Timer &timer() = 0; +}; + + +struct Libc::Timeout_handler +{ + virtual void handle_timeout() = 0; +}; + + +/* + * TODO curr_time wrapping + */ +struct Libc::Timeout +{ + Libc::Timer_accessor &_timer_accessor; + Timeout_handler &_handler; + ::Timer::One_shot_timeout _timeout; + + bool _expired = true; + Genode::uint64_t _absolute_timeout_ms = 0; + + void _handle(Duration now) + { + _expired = true; + _absolute_timeout_ms = 0; + _handler.handle_timeout(); + } + + Timeout(Timer_accessor &timer_accessor, Timeout_handler &handler) + : + _timer_accessor(timer_accessor), + _handler(handler), + _timeout(_timer_accessor.timer()._timer, *this, &Timeout::_handle) + { } + + void start(Genode::uint64_t timeout_ms) + { + Milliseconds const now = _timer_accessor.timer().curr_time().trunc_to_plain_ms(); + + _expired = false; + _absolute_timeout_ms = now.value + timeout_ms; + + _timeout.schedule(_timer_accessor.timer().microseconds(timeout_ms)); + } + + Genode::uint64_t duration_left() const + { + Milliseconds const now = _timer_accessor.timer().curr_time().trunc_to_plain_ms(); + + if (_expired || _absolute_timeout_ms < now.value) + return 0; + + return _absolute_timeout_ms - now.value; + } +}; + +#endif /* _LIBC__INTERNAL__TIMER_H_ */ diff --git a/repos/libports/src/lib/libc/internal/types.h b/repos/libports/src/lib/libc/internal/types.h new file mode 100644 index 000000000..e8a1253fc --- /dev/null +++ b/repos/libports/src/lib/libc/internal/types.h @@ -0,0 +1,21 @@ +/* + * \brief Common libc-internal types + * \author Norman Feske + * \date 2019-09-16 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _LIBC__INTERNAL__TYPES_H_ +#define _LIBC__INTERNAL__TYPES_H_ + +#include + +namespace Libc { using namespace Genode; } + +#endif /* _LIBC__INTERNAL__TYPES_H_ */ diff --git a/repos/libports/src/lib/libc/vfs_plugin.h b/repos/libports/src/lib/libc/internal/vfs_plugin.h similarity index 95% rename from repos/libports/src/lib/libc/vfs_plugin.h rename to repos/libports/src/lib/libc/internal/vfs_plugin.h index d175b4591..b749d9f96 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.h +++ b/repos/libports/src/lib/libc/internal/vfs_plugin.h @@ -13,11 +13,12 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _LIBC_VFS__PLUGIN_H_ -#define _LIBC_VFS__PLUGIN_H_ +#ifndef _LIBC__INTERNAL__VFS_PLUGIN_H_ +#define _LIBC__INTERNAL__VFS_PLUGIN_H_ /* Genode includes */ #include +#include /* libc includes */ #include @@ -27,9 +28,8 @@ #include #include -/* local includes */ -#include "task.h" -#include "libc_errno.h" +/* libc-internal includes */ +#include namespace Libc { class Vfs_plugin; } @@ -110,4 +110,4 @@ class Libc::Vfs_plugin : public Libc::Plugin int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) override; }; -#endif +#endif /* _LIBC__INTERNAL__VFS_PLUGIN_H_ */ diff --git a/repos/libports/src/lib/libc/kernel.cc b/repos/libports/src/lib/libc/kernel.cc new file mode 100644 index 000000000..d90879553 --- /dev/null +++ b/repos/libports/src/lib/libc/kernel.cc @@ -0,0 +1,333 @@ +/* + * \brief Libc kernel for main and pthreads user contexts + * \author Christian Helmuth + * \author Emery Hemingway + * \author Norman Feske + * \date 2016-01-22 + */ + +/* + * Copyright (C) 2016-2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* libc-internal includes */ +#include + +Libc::Kernel * Libc::Kernel::_kernel_ptr; + + +/** + * Main context execution was suspended (on fork) + * + * This function is executed in the context of the initial thread. + */ +static void suspended_callback() +{ + Libc::Kernel::kernel().entrypoint_suspended(); +} + + +/** + * Resume main context execution (after fork) + * + * This function is executed in the context of the initial thread. + */ +static void resumed_callback() +{ + Libc::Kernel::kernel().entrypoint_resumed(); +} + + +size_t Libc::Kernel::_user_stack_size() +{ + size_t size = Component::stack_size(); + if (!_cloned) + return size; + + _libc_env.libc_config().with_sub_node("stack", [&] (Xml_node stack) { + size = stack.attribute_value("size", 0UL); }); + + return size; +} + + +void Libc::Kernel::schedule_suspend(void(*original_suspended_callback) ()) +{ + if (_state != USER) { + Genode::error(__PRETTY_FUNCTION__, " called from non-user context"); + return; + } + + /* + * We hook into suspend-resume callback chain to destruct and + * reconstruct parts of the kernel from the context of the initial + * thread, i.e., without holding any object locks. + */ + _original_suspended_callback = original_suspended_callback; + _env.ep().schedule_suspend(suspended_callback, resumed_callback); + + if (!_setjmp(_user_context)) { + _valid_user_context = true; + _suspend_scheduled = true; + _switch_to_kernel(); + } else { + _valid_user_context = false; + } +} + + +void Libc::Kernel::reset_malloc_heap() +{ + _malloc_ram.construct(_heap, _env.ram()); + + _cloned_heap_ranges.for_each([&] (Registered &r) { + destroy(_heap, &r); }); + + Heap &raw_malloc_heap = *_malloc_heap; + Genode::construct_at(&raw_malloc_heap, *_malloc_ram, _env.rm()); + + reinit_malloc(raw_malloc_heap); +} + + +void Libc::Kernel::_init_file_descriptors() +{ + auto init_fd = [&] (Genode::Xml_node const &node, char const *attr, + int libc_fd, unsigned flags) + { + if (!node.has_attribute(attr)) + return; + + typedef Genode::String Path; + Path const path = node.attribute_value(attr, Path()); + + struct stat out_stat { }; + if (stat(path.string(), &out_stat) != 0) + return; + + Libc::File_descriptor *fd = _vfs.open(path.string(), flags, libc_fd); + if (fd->libc_fd != libc_fd) { + Genode::error("could not allocate fd ",libc_fd," for ",path,", " + "got fd ",fd->libc_fd); + _vfs.close(fd); + return; + } + + /* + * We need to manually register the path. Normally this is done + * by '_open'. But we call the local 'open' function directly + * because we want to explicitly specify the libc fd ID. + */ + if (fd->fd_path) + Genode::warning("may leak former FD path memory"); + + { + char *dst = (char *)_heap.alloc(path.length()); + Genode::strncpy(dst, path.string(), path.length()); + fd->fd_path = dst; + } + + ::off_t const seek = node.attribute_value("seek", 0ULL); + if (seek) + _vfs.lseek(fd, seek, SEEK_SET); + }; + + if (_vfs.root_dir_has_dirents()) { + + Xml_node const node = _libc_env.libc_config(); + + typedef Genode::String Path; + + if (node.has_attribute("cwd")) + chdir(node.attribute_value("cwd", Path()).string()); + + init_fd(node, "stdin", 0, O_RDONLY); + init_fd(node, "stdout", 1, O_WRONLY); + init_fd(node, "stderr", 2, O_WRONLY); + + node.for_each_sub_node("fd", [&] (Xml_node fd) { + + unsigned const id = fd.attribute_value("id", 0U); + + bool const rd = fd.attribute_value("readable", false); + bool const wr = fd.attribute_value("writeable", false); + + unsigned const flags = rd ? (wr ? O_RDWR : O_RDONLY) + : (wr ? O_WRONLY : 0); + + if (!fd.has_attribute("path")) + warning("Invalid node, 'path' attribute is missing"); + + init_fd(fd, "path", id, flags); + }); + + /* prevent use of IDs of stdin, stdout, and stderr for other files */ + for (unsigned fd = 0; fd <= 2; fd++) + Libc::file_descriptor_allocator()->preserve(fd); + } +} + + +void Libc::Kernel::_clone_state_from_parent() +{ + struct Range { void *at; size_t size; }; + + auto range_attr = [&] (Xml_node node) + { + return Range { + .at = (void *)node.attribute_value("at", 0UL), + .size = node.attribute_value("size", 0UL) + }; + }; + + /* + * Allocate local memory for the backing store of the application heap, + * mirrored from the parent. + * + * This step must precede the creation of the 'Clone_connection' because + * the shared-memory buffer of the clone session may otherwise potentially + * interfere with such a heap region. + */ + _libc_env.libc_config().for_each_sub_node("heap", [&] (Xml_node node) { + Range const range = range_attr(node); + new (_heap) + Registered(_cloned_heap_ranges, + _env.ram(), _env.rm(), + range.at, range.size); }); + + Clone_connection clone_connection(_env); + + /* fetch heap content */ + _cloned_heap_ranges.for_each([&] (Cloned_malloc_heap_range &heap_range) { + heap_range.import_content(clone_connection); }); + + /* fetch user contex of the parent's application */ + clone_connection.memory_content(&_user_context, sizeof(_user_context)); + _valid_user_context = true; + + _libc_env.libc_config().for_each_sub_node([&] (Xml_node node) { + + auto copy_from_parent = [&] (Range range) + { + clone_connection.memory_content(range.at, range.size); + }; + + /* clone application stack */ + if (node.type() == "stack") + copy_from_parent(range_attr(node)); + + /* clone RW segment of a shared library or the binary */ + if (node.type() == "rw") { + typedef String<64> Name; + Name const name = node.attribute_value("name", Name()); + + /* + * The blacklisted segments are initialized via the + * regular startup of the child. + */ + bool const blacklisted = (name == "ld.lib.so") + || (name == "libc.lib.so") + || (name == "libm.lib.so") + || (name == "posix.lib.so") + || (strcmp(name.string(), "vfs", 3) == 0); + if (!blacklisted) + copy_from_parent(range_attr(node)); + } + }); + + /* import application-heap state from parent */ + clone_connection.object_content(_malloc_heap); + init_malloc_cloned(clone_connection); +} + + +extern void (*libc_select_notify)(); + + +void Libc::Kernel::handle_io_progress() +{ + /* + * TODO: make VFS I/O completion checks during + * kernel time to avoid flapping between stacks + */ + + if (_io_ready) { + _io_ready = false; + + /* some contexts may have been deblocked from select() */ + if (libc_select_notify) + libc_select_notify(); + + /* + * resume all as any VFS context may have + * been deblocked from blocking I/O + */ + Kernel::resume_all(); + } +} + + +void Libc::execute_in_application_context(Libc::Application_code &app_code) +{ + /* + * The libc execution model builds on the main entrypoint, which handles + * all relevant signals (e.g., timing and VFS). Additional component + * entrypoints or pthreads should never call with_libc() but we catch this + * here and just execute the application code directly. + */ + if (!Kernel::kernel().main_context()) { + app_code.execute(); + return; + } + + static bool nested = false; + + if (nested) { + + if (Kernel::kernel().main_suspended()) { + Kernel::kernel().nested_execution(app_code); + } else { + app_code.execute(); + } + return; + } + + nested = true; + Kernel::kernel().run(app_code); + nested = false; +} + + +Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap) +: + _env(env), _heap(heap) +{ + init_pthread_support(env, *this, *this); + + _env.ep().register_io_progress_handler(*this); + + if (_cloned) { + _clone_state_from_parent(); + + } else { + _malloc_heap.construct(*_malloc_ram, _env.rm()); + init_malloc(*_malloc_heap); + } + + init_fork(_env, _libc_env, _heap, *_malloc_heap, _pid, *this, *this, *this); + init_execve(_env, _heap, _user_stack, *this); + init_plugin(*this); + init_sleep(*this); + init_vfs_plugin(*this); + init_time(*this, _rtc_path); + init_poll(*this); + init_select(*this, *this, *this); + init_socket_fs(*this); + + _init_file_descriptors(); + + _kernel_ptr = this; +} diff --git a/repos/libports/src/lib/libc/legacy.cc b/repos/libports/src/lib/libc/legacy.cc new file mode 100644 index 000000000..56fce9c9a --- /dev/null +++ b/repos/libports/src/lib/libc/legacy.cc @@ -0,0 +1,43 @@ +/* + * \brief Globally available accessors to Libc kernel functionality + * \author Norman Feske + * \date 2019-09-18 + * + * XXX eliminate the need for these functions, or + * turn them into regular members of 'Libc::Kernel' + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* libc-internal includes */ +#include +#include + + +void Libc::dispatch_pending_io_signals() +{ + Kernel::kernel().dispatch_pending_io_signals(); +} + + +Vfs::Vfs_watch_handle *Libc::watch(char const *path) +{ + return Kernel::kernel().alloc_watch_handle(path); +} + + +void Libc::schedule_suspend(void (*suspended) ()) +{ + Kernel::kernel().schedule_suspend(suspended); +} + + +Genode::Xml_node Libc::libc_config() +{ + return Kernel::kernel().libc_env().libc_config(); +} diff --git a/repos/libports/src/lib/libc/libc_mem_alloc.cc b/repos/libports/src/lib/libc/libc_mem_alloc.cc index 7cb9e7379..f38470b7a 100644 --- a/repos/libports/src/lib/libc/libc_mem_alloc.cc +++ b/repos/libports/src/lib/libc/libc_mem_alloc.cc @@ -17,9 +17,9 @@ #include #include -/* local includes */ -#include "libc_mem_alloc.h" -#include "libc_init.h" +/* libc-internal includes */ +#include +#include using namespace Genode; diff --git a/repos/libports/src/lib/libc/malloc.cc b/repos/libports/src/lib/libc/malloc.cc index 43116c7bd..0567cb518 100644 --- a/repos/libports/src/lib/libc/malloc.cc +++ b/repos/libports/src/lib/libc/malloc.cc @@ -26,10 +26,12 @@ extern "C" { #include } -/* libc-internal includes */ -#include "libc_init.h" +/* Genode-internal includes */ #include -#include + +/* libc-internal includes */ +#include +#include namespace Libc { diff --git a/repos/libports/src/lib/libc/plugin.cc b/repos/libports/src/lib/libc/plugin.cc index dfdd77951..9f2bde01c 100644 --- a/repos/libports/src/lib/libc/plugin.cc +++ b/repos/libports/src/lib/libc/plugin.cc @@ -20,15 +20,29 @@ #include /* local includes */ -#include "task.h" +#include +#include using namespace Genode; using namespace Libc; +static Libc::Resume *_resume_ptr; + + +void Libc::init_plugin(Resume &resume) +{ + _resume_ptr = &resume; +} + + void Plugin::resume_all() { - Libc::resume_all(); + struct Missing_call_of_init_plugin : Exception { }; + if (!_resume_ptr) + throw Missing_call_of_init_plugin(); + + _resume_ptr->resume_all(); } diff --git a/repos/libports/src/lib/libc/poll.cc b/repos/libports/src/lib/libc/poll.cc index 58e5e6e4d..59f78c754 100644 --- a/repos/libports/src/lib/libc/poll.cc +++ b/repos/libports/src/lib/libc/poll.cc @@ -18,9 +18,19 @@ #include /* internal includes */ -#include "libc_errno.h" -#include "libc_file.h" -#include "task.h" +#include +#include +#include +#include + + +static Libc::Suspend *_suspend_ptr; + + +void Libc::init_poll(Suspend &suspend) +{ + _suspend_ptr = &suspend; +} extern "C" __attribute__((weak)) @@ -74,14 +84,23 @@ int poll(struct pollfd fds[], nfds_t nfds, int timeout_ms) return check.nready; } + auto suspend = [&] (Genode::uint64_t timeout_ms) + { + struct Missing_call_of_init_poll : Exception { }; + if (!_suspend_ptr) + throw Missing_call_of_init_poll(); + + return _suspend_ptr->suspend(check, timeout_ms); + }; + if (timeout_ms == -1) { while (check.nready == 0) { - Libc::suspend(check, 0); + suspend(0); } } else { Genode::uint64_t remaining_ms = timeout_ms; while (check.nready == 0 && remaining_ms > 0) { - remaining_ms = Libc::suspend(check, remaining_ms); + remaining_ms = suspend(remaining_ms); } } diff --git a/repos/libports/src/lib/libc/thread.cc b/repos/libports/src/lib/libc/pthread.cc similarity index 96% rename from repos/libports/src/lib/libc/thread.cc rename to repos/libports/src/lib/libc/pthread.cc index 918c50ef1..ad21030b8 100644 --- a/repos/libports/src/lib/libc/thread.cc +++ b/repos/libports/src/lib/libc/pthread.cc @@ -12,19 +12,24 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* Genode includes */ #include #include #include #include #include +/* libc includes */ #include #include #include /* malloc, free */ -#include "thread.h" -#include "task.h" -#include "timed_semaphore.h" -#include "libc_init.h" + +/* libc-internal includes */ +#include +#include +#include +#include +#include using namespace Genode; @@ -34,11 +39,16 @@ static Env *_env_ptr; /* solely needed to spawn the timeout thread for the static Thread *_main_thread_ptr; +static Libc::Suspend *_suspend_ptr; +static Libc::Resume *_resume_ptr; -void Libc::init_pthread_support(Genode::Env &env) + +void Libc::init_pthread_support(Genode::Env &env, Suspend &suspend, Resume &resume) { _env_ptr = &env; _main_thread_ptr = Thread::myself(); + _suspend_ptr = &suspend; + _resume_ptr = &resume; } @@ -84,8 +94,12 @@ void pthread::join(void **retval) } } check(*this); + struct Missing_call_of_init_pthread_support : Exception { }; + if (!_suspend_ptr) + throw Missing_call_of_init_pthread_support(); + do { - Libc::suspend(check); + _suspend_ptr->suspend(check); } while (check.retry); _join_lock.lock(); @@ -98,7 +112,13 @@ void pthread::join(void **retval) void pthread::cancel() { _exiting = true; - Libc::resume_all(); + + struct Missing_call_of_init_pthread_support : Exception { }; + if (!_resume_ptr) + throw Missing_call_of_init_pthread_support(); + + _resume_ptr->resume_all(); + _join_lock.unlock(); } diff --git a/repos/libports/src/lib/libc/thread_create.cc b/repos/libports/src/lib/libc/pthread_create.cc similarity index 93% rename from repos/libports/src/lib/libc/thread_create.cc rename to repos/libports/src/lib/libc/pthread_create.cc index d6b0ba065..8b10b650d 100644 --- a/repos/libports/src/lib/libc/thread_create.cc +++ b/repos/libports/src/lib/libc/pthread_create.cc @@ -14,12 +14,14 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* libc includes */ #include - -#include "thread_create.h" -#include "thread.h" #include +/* libc-internal includes */ +#include +#include + int Libc::pthread_create(pthread_t *thread, void *(*start_routine) (void *), void *arg, diff --git a/repos/libports/src/lib/libc/select.cc b/repos/libports/src/lib/libc/select.cc index 4d82fd9d0..b71848b2a 100644 --- a/repos/libports/src/lib/libc/select.cc +++ b/repos/libports/src/lib/libc/select.cc @@ -3,6 +3,7 @@ * \author Christian Prochaska * \author Christian Helmuth * \author Emery Hemingway + * \author Norman Feske * \date 2010-01-21 * * the 'select()' implementation is partially based on the lwip version as @@ -22,6 +23,7 @@ /* Genode includes */ #include +#include #include /* Libc includes */ @@ -32,8 +34,11 @@ #include #include -#include "task.h" - +/* libc-internal includes */ +#include +#include +#include +#include namespace Libc { struct Select_cb; @@ -41,6 +46,19 @@ namespace Libc { } +static Libc::Suspend *_suspend_ptr; +static Libc::Resume *_resume_ptr; +static Libc::Select *_select_ptr; + + +void Libc::init_select(Suspend &suspend, Resume &resume, Select &select) +{ + _suspend_ptr = &suspend; + _resume_ptr = &resume; + _select_ptr = &select; +} + + void (*libc_select_notify)() __attribute__((weak)); @@ -200,8 +218,13 @@ static void select_notify() } }); - if (resume_all) - Libc::resume_all(); + if (resume_all) { + struct Missing_call_of_init_select : Genode::Exception { }; + if (!_resume_ptr) + throw Missing_call_of_init_select(); + + _resume_ptr->resume_all(); + } } @@ -284,8 +307,14 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, return !timeout->expired() && select_cb->nready == 0; } } check ( &timeout, &*select_cb ); + { + struct Missing_call_of_init_select : Genode::Exception { }; + if (!_suspend_ptr) + throw Missing_call_of_init_select(); + } + while (!timeout.expired() && select_cb->nready == 0) - timeout.duration = Libc::suspend(check, timeout.duration); + timeout.duration = _suspend_ptr->suspend(check, timeout.duration); select_cb_list().remove(&(*select_cb)); @@ -380,7 +409,11 @@ int Libc::Select_handler_base::select(int nfds, fd_set &readfds, select_cb_list().unsynchronized_insert(&(**_select_cb)); } - Libc::schedule_select(this); + struct Missing_call_of_init_select : Exception { }; + if (!_select_ptr) + throw Missing_call_of_init_select(); + + _select_ptr->schedule_select(*this); return 0; } @@ -393,7 +426,9 @@ void Libc::Select_handler_base::dispatch_select() if (select_cb->nready == 0) return; select_cb_list().remove(&(*select_cb)); - Libc::schedule_select(nullptr); + + if (_select_ptr) + _select_ptr->deschedule_select(); select_ready(select_cb->nready, select_cb->readfds, select_cb->writefds, select_cb->exceptfds); diff --git a/repos/libports/src/lib/libc/semaphore.cc b/repos/libports/src/lib/libc/semaphore.cc index 4c8726a25..10a8a0b58 100644 --- a/repos/libports/src/lib/libc/semaphore.cc +++ b/repos/libports/src/lib/libc/semaphore.cc @@ -12,9 +12,12 @@ * under the terms of the GNU Affero General Public License version 3. */ +/* Genode includes */ #include #include #include + +/* libc includes */ #include using namespace Genode; diff --git a/repos/libports/src/lib/libc/sleep.cc b/repos/libports/src/lib/libc/sleep.cc index fcd0b43dc..0b6eb9378 100644 --- a/repos/libports/src/lib/libc/sleep.cc +++ b/repos/libports/src/lib/libc/sleep.cc @@ -12,19 +12,31 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Libc includes */ +/* libc includes */ #include -#include "task.h" +/* libc-internal includes */ +#include +#include -/* Genode includes */ -#include +static Libc::Suspend *_suspend_ptr; + + +void Libc::init_sleep(Suspend &suspend) +{ + _suspend_ptr = &suspend; +} + static void millisleep(Genode::uint64_t timeout_ms) { Genode::uint64_t remaining_ms = timeout_ms; + struct Missing_call_of_init_sleep : Genode::Exception { }; + if (!_suspend_ptr) + throw Missing_call_of_init_sleep(); + struct Check : Libc::Suspend_functor { bool suspend() override { return true; } @@ -32,7 +44,7 @@ static void millisleep(Genode::uint64_t timeout_ms) } check; while (remaining_ms > 0) - remaining_ms = Libc::suspend(check, remaining_ms); + remaining_ms = _suspend_ptr->suspend(check, remaining_ms); } diff --git a/repos/libports/src/lib/libc/socket_fs_plugin.cc b/repos/libports/src/lib/libc/socket_fs_plugin.cc index b8fcfdf2c..41b558062 100644 --- a/repos/libports/src/lib/libc/socket_fs_plugin.cc +++ b/repos/libports/src/lib/libc/socket_fs_plugin.cc @@ -36,10 +36,11 @@ #include /* libc-internal includes */ -#include "socket_fs_plugin.h" -#include "libc_file.h" -#include "libc_errno.h" -#include "task.h" +#include +#include +#include +#include +#include namespace Libc { @@ -48,6 +49,15 @@ namespace Libc { } +static Libc::Suspend *_suspend_ptr; + + +void Libc::init_socket_fs(Suspend &suspend) +{ + _suspend_ptr = &suspend; +} + + /*************** ** Utilities ** ***************/ @@ -432,8 +442,14 @@ static int read_sockaddr_in(Socket_fs::Sockaddr_functor &func, if (!addr) return Errno(EFAULT); if (!addrlen || *addrlen <= 0) return Errno(EINVAL); - while (!func.nonblocking && func.suspend()) - Libc::suspend(func); + while (!func.nonblocking && func.suspend()) { + + struct Missing_call_of_init_socket_fs : Exception { }; + if (!_suspend_ptr) + throw Missing_call_of_init_socket_fs(); + + _suspend_ptr->suspend(func); + } Sockaddr_string addr_string; int const n = read(func.fd(), addr_string.base(), addr_string.capacity() - 1); diff --git a/repos/libports/src/lib/libc/socket_operations.cc b/repos/libports/src/lib/libc/socket_operations.cc index d2647b7f0..2d82d0154 100644 --- a/repos/libports/src/lib/libc/socket_operations.cc +++ b/repos/libports/src/lib/libc/socket_operations.cc @@ -26,8 +26,8 @@ extern "C" { } /* libc-internal includes */ -#include "libc_file.h" -#include "socket_fs_plugin.h" +#include +#include using namespace Libc; diff --git a/repos/libports/src/lib/libc/include/spec/arm/internal/call_func.h b/repos/libports/src/lib/libc/spec/arm/internal/call_func.h similarity index 100% rename from repos/libports/src/lib/libc/include/spec/arm/internal/call_func.h rename to repos/libports/src/lib/libc/spec/arm/internal/call_func.h diff --git a/repos/libports/src/lib/libc/include/spec/arm_64/internal/call_func.h b/repos/libports/src/lib/libc/spec/arm_64/internal/call_func.h similarity index 100% rename from repos/libports/src/lib/libc/include/spec/arm_64/internal/call_func.h rename to repos/libports/src/lib/libc/spec/arm_64/internal/call_func.h diff --git a/repos/libports/src/lib/libc/include/spec/x86_32/internal/call_func.h b/repos/libports/src/lib/libc/spec/x86_32/internal/call_func.h similarity index 100% rename from repos/libports/src/lib/libc/include/spec/x86_32/internal/call_func.h rename to repos/libports/src/lib/libc/spec/x86_32/internal/call_func.h diff --git a/repos/libports/src/lib/libc/include/spec/x86_64/internal/call_func.h b/repos/libports/src/lib/libc/spec/x86_64/internal/call_func.h similarity index 100% rename from repos/libports/src/lib/libc/include/spec/x86_64/internal/call_func.h rename to repos/libports/src/lib/libc/spec/x86_64/internal/call_func.h diff --git a/repos/libports/src/lib/libc/sysctl.cc b/repos/libports/src/lib/libc/sysctl.cc index 81769400e..b7e76f0ae 100644 --- a/repos/libports/src/lib/libc/sysctl.cc +++ b/repos/libports/src/lib/libc/sysctl.cc @@ -19,15 +19,16 @@ #include #include -/* Libc includes */ +/* libc includes */ #include #include #include #include #include -#include "libc_errno.h" -#include "libc_init.h" +/* libc-internal includes */ +#include +#include enum { PAGESIZE = 4096 }; diff --git a/repos/libports/src/lib/libc/task.cc b/repos/libports/src/lib/libc/task.cc deleted file mode 100644 index c854dc245..000000000 --- a/repos/libports/src/lib/libc/task.cc +++ /dev/null @@ -1,1348 +0,0 @@ -/* - * \brief Libc kernel for main and pthreads user contexts - * \author Christian Helmuth - * \author Emery Hemingway - * \date 2016-01-22 - */ - -/* - * Copyright (C) 2016-2019 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -/* libc-internal includes */ -#include -#include -#include -#include "vfs_plugin.h" -#include "libc_init.h" -#include "task.h" - -extern char **environ; - -namespace Libc { - class Env_implementation; - class Cloned_malloc_heap_range; - class Malloc_ram_allocator; - class Kernel; - class Pthreads; - class Timer; - class Timer_accessor; - class Timeout; - class Timeout_handler; - - using Genode::Microseconds; -} - - -class Libc::Env_implementation : public Libc::Env, public Config_accessor -{ - private: - - Genode::Env &_env; - - Genode::Attached_rom_dataspace _config { _env, "config" }; - - Genode::Xml_node _vfs_config() - { - try { return _config.xml().sub_node("vfs"); } - catch (Genode::Xml_node::Nonexistent_sub_node) { } - try { - Genode::Xml_node node = - _config.xml().sub_node("libc").sub_node("vfs"); - Genode::warning("' ' is deprecated, " - "please move to ' '"); - return node; - } - catch (Genode::Xml_node::Nonexistent_sub_node) { } - - return Genode::Xml_node(""); - } - - Genode::Xml_node _libc_config() - { - try { return _config.xml().sub_node("libc"); } - catch (Genode::Xml_node::Nonexistent_sub_node) { } - - return Genode::Xml_node(""); - } - - Vfs::Simple_env _vfs_env; - - Genode::Xml_node _config_xml() const override { - return _config.xml(); }; - - public: - - Env_implementation(Genode::Env &env, Genode::Allocator &alloc) - : _env(env), _vfs_env(_env, alloc, _vfs_config()) { } - - - /************************* - ** Libc::Env interface ** - *************************/ - - Vfs::File_system &vfs() override { - return _vfs_env.root_dir(); } - - Genode::Xml_node libc_config() override { - return _libc_config(); } - - - /************************************* - ** Libc::Config_accessor interface ** - *************************************/ - - Xml_node config() const override { return _config.xml(); } - - - /*************************** - ** Genode::Env interface ** - ***************************/ - - Parent &parent() override { return _env.parent(); } - Cpu_session &cpu() override { return _env.cpu(); } - Region_map &rm() override { return _env.rm(); } - Pd_session &pd() override { return _env.pd(); } - Entrypoint &ep() override { return _env.ep(); } - - Cpu_session_capability cpu_session_cap() override { - return _env.cpu_session_cap(); } - - Pd_session_capability pd_session_cap() override { - return _env.pd_session_cap(); } - - Id_space &id_space() override { - return _env.id_space(); } - - Session_capability session(Parent::Service_name const &name, - Parent::Client::Id id, - Parent::Session_args const &args, - Affinity const &aff) override { - return _env.session(name, id, args, aff); } - - void upgrade(Parent::Client::Id id, - Parent::Upgrade_args const &args) override { - return _env.upgrade(id, args); } - - void close(Parent::Client::Id id) override { - return _env.close(id); } - - /* already done by the libc */ - void exec_static_constructors() override { } - - void reinit(Native_capability::Raw raw) override { - _env.reinit(raw); } - - void reinit_main_thread(Capability &stack_area_rm) override { - _env.reinit_main_thread(stack_area_rm); } -}; - - -struct Libc::Timer -{ - ::Timer::Connection _timer; - - Timer(Genode::Env &env) : _timer(env) { } - - Genode::Duration curr_time() - { - return _timer.curr_time(); - } - - static Microseconds microseconds(Genode::uint64_t timeout_ms) - { - return Microseconds(1000*timeout_ms); - } - - static Genode::uint64_t max_timeout() - { - return ~0UL/1000; - } -}; - - -/** - * Interface for obtaining the libc-global timer instance - * - * The 'Timer' is instantiated on demand whenever the 'Timer_accessor::timer' - * method is first called. This way, libc-using components do not depend of a - * timer connection unless they actually use time-related functionality. - */ -struct Libc::Timer_accessor -{ - virtual Timer &timer() = 0; -}; - - -struct Libc::Timeout_handler -{ - virtual void handle_timeout() = 0; -}; - - -/* - * TODO curr_time wrapping - */ -struct Libc::Timeout -{ - Libc::Timer_accessor &_timer_accessor; - Timeout_handler &_handler; - ::Timer::One_shot_timeout _timeout; - - bool _expired = true; - Genode::uint64_t _absolute_timeout_ms = 0; - - void _handle(Duration now) - { - _expired = true; - _absolute_timeout_ms = 0; - _handler.handle_timeout(); - } - - Timeout(Timer_accessor &timer_accessor, Timeout_handler &handler) - : - _timer_accessor(timer_accessor), - _handler(handler), - _timeout(_timer_accessor.timer()._timer, *this, &Timeout::_handle) - { } - - void start(Genode::uint64_t timeout_ms) - { - Milliseconds const now = _timer_accessor.timer().curr_time().trunc_to_plain_ms(); - - _expired = false; - _absolute_timeout_ms = now.value + timeout_ms; - - _timeout.schedule(_timer_accessor.timer().microseconds(timeout_ms)); - } - - Genode::uint64_t duration_left() const - { - Milliseconds const now = _timer_accessor.timer().curr_time().trunc_to_plain_ms(); - - if (_expired || _absolute_timeout_ms < now.value) - return 0; - - return _absolute_timeout_ms - now.value; - } -}; - - -struct Libc::Pthreads -{ - struct Pthread : Timeout_handler - { - Genode::Lock lock { Genode::Lock::LOCKED }; - Pthread *next { nullptr }; - - Timer_accessor &_timer_accessor; - Constructible _timeout; - - void _construct_timeout_once() - { - if (!_timeout.constructed()) - _timeout.construct(_timer_accessor, *this); - } - - Pthread(Timer_accessor &timer_accessor, Genode::uint64_t timeout_ms) - : _timer_accessor(timer_accessor) - { - if (timeout_ms > 0) { - _construct_timeout_once(); - _timeout->start(timeout_ms); - } - } - - Genode::uint64_t duration_left() - { - _construct_timeout_once(); - return _timeout->duration_left(); - } - - void handle_timeout() override - { - lock.unlock(); - } - }; - - Genode::Lock mutex; - Pthread *pthreads = nullptr; - Timer_accessor &timer_accessor; - - - Pthreads(Timer_accessor &timer_accessor) - : timer_accessor(timer_accessor) { } - - void resume_all() - { - Genode::Lock::Guard g(mutex); - - for (Pthread *p = pthreads; p; p = p->next) - p->lock.unlock(); - } - - Genode::uint64_t suspend_myself(Suspend_functor & check, Genode::uint64_t timeout_ms) - { - Pthread myself { timer_accessor, timeout_ms }; - { - Genode::Lock::Guard g(mutex); - - myself.next = pthreads; - pthreads = &myself; - } - - if (check.suspend()) - myself.lock.lock(); - - { - Genode::Lock::Guard g(mutex); - - /* address of pointer to next pthread allows to change the head */ - for (Pthread **next = &pthreads; *next; next = &(*next)->next) { - if (*next == &myself) { - *next = myself.next; - break; - } - } - } - - return timeout_ms > 0 ? myself.duration_left() : 0; - } -}; - - -extern void (*libc_select_notify)(); - - -/* internal utility */ -static void resumed_callback(); -static void suspended_callback(); - - -struct Libc::Cloned_malloc_heap_range -{ - Genode::Ram_allocator &ram; - Genode::Region_map &rm; - - Genode::Ram_dataspace_capability ds; - - size_t const size; - addr_t const local_addr; - - Cloned_malloc_heap_range(Genode::Ram_allocator &ram, Genode::Region_map &rm, - void *start, size_t size) - try : - ram(ram), rm(rm), ds(ram.alloc(size)), size(size), - local_addr(rm.attach_at(ds, (addr_t)start)) - { } - catch (Region_map::Region_conflict) { - error("could not clone heap region ", Hex_range(local_addr, size)); - throw; - } - - void import_content(Clone_connection &clone_connection) - { - clone_connection.memory_content((void *)local_addr, size); - } - - virtual ~Cloned_malloc_heap_range() - { - rm.detach(local_addr); - ram.free(ds); - } -}; - - -/* - * Utility for tracking the allocation of dataspaces by the malloc heap - */ -struct Libc::Malloc_ram_allocator : Genode::Ram_allocator -{ - Genode::Allocator &_md_alloc; - Genode::Ram_allocator &_ram; - - struct Dataspace - { - Genode::Ram_dataspace_capability cap; - Dataspace(Genode::Ram_dataspace_capability cap) : cap(cap) { } - virtual ~Dataspace() { } - }; - - Genode::Registry > _dataspaces { }; - - void _release(Genode::Registered &ds) - { - _ram.free(ds.cap); - destroy(_md_alloc, &ds); - } - - Malloc_ram_allocator(Allocator &md_alloc, Ram_allocator &ram) - : _md_alloc(md_alloc), _ram(ram) { } - - ~Malloc_ram_allocator() - { - _dataspaces.for_each([&] (Registered &ds) { - _release(ds); }); - } - - Ram_dataspace_capability alloc(size_t size, Cache_attribute cached) override - { - Ram_dataspace_capability cap = _ram.alloc(size, cached); - new (_md_alloc) Registered(_dataspaces, cap); - return cap; - } - - void free(Ram_dataspace_capability ds_cap) override - { - _dataspaces.for_each([&] (Registered &ds) { - if (ds_cap == ds.cap) - _release(ds); }); - } - - size_t dataspace_size(Ram_dataspace_capability ds_cap) const override - { - return _ram.dataspace_size(ds_cap); - } -}; - - -/** - * Libc "kernel" - * - * This class represents the "kernel" of the libc-based application - * Blocking and deblocking happens here on libc functions like read() or - * select(). This combines blocking of the VFS backend and other signal sources - * (e.g., timers). The libc task runs on the component thread and allocates a - * secondary stack for the application task. Context switching uses - * setjmp/longjmp. - */ -struct Libc::Kernel final : Vfs::Io_response_handler, - Genode::Entrypoint::Io_progress_handler, - Reset_malloc_heap -{ - private: - - Genode::Env &_env; - - /** - * Allocator for libc-internal data - * - * Not mirrored to forked processes. Preserved across 'execve' calls. - */ - Genode::Allocator &_heap; - - /** - * Allocator for application-owned data - * - * Mirrored to forked processes. Not preserved across 'execve' calls. - */ - Genode::Reconstructible _malloc_ram { _heap, _env.ram() }; - - Genode::Constructible _malloc_heap { }; - - Genode::Registry > _cloned_heap_ranges { }; - - /** - * Reset_malloc_heap interface used by execve - */ - void reset_malloc_heap() override; - - Env_implementation _libc_env { _env, _heap }; - Vfs_plugin _vfs { _libc_env, _heap, *this }; - - bool const _cloned = _libc_env.libc_config().attribute_value("cloned", false); - pid_t const _pid = _libc_env.libc_config().attribute_value("pid", 0U); - - Genode::Reconstructible> _resume_main_handler { - _env.ep(), *this, &Kernel::_resume_main }; - - jmp_buf _kernel_context; - jmp_buf _user_context; - bool _valid_user_context = false; - bool _dispatch_pending_io_signals = false; - - /* io_progress_handler marker */ - bool _io_ready { false }; - - Genode::Thread &_myself { *Genode::Thread::myself() }; - - addr_t _kernel_stack = Thread::mystack().top; - - size_t _user_stack_size() - { - size_t size = Component::stack_size(); - if (!_cloned) - return size; - - _libc_env.libc_config().with_sub_node("stack", [&] (Xml_node stack) { - size = stack.attribute_value("size", 0UL); }); - - return size; - } - - void *_user_stack = { - _myself.alloc_secondary_stack(_myself.name().string(), - _user_stack_size()) }; - - void (*_original_suspended_callback)() = nullptr; - - enum State { KERNEL, USER }; - - State _state = KERNEL; - - Application_code *_nested_app_code = nullptr; - - Application_code *_app_code = nullptr; - bool _app_returned = false; - - bool _resume_main_once = false; - bool _suspend_scheduled = false; - - Select_handler_base *_scheduled_select_handler = nullptr; - - Kernel_routine *_kernel_routine = nullptr; - - void _resume_main() { _resume_main_once = true; } - - struct Timer_accessor : Libc::Timer_accessor - { - Genode::Env &_env; - - /* - * The '_timer' is constructed by whatever thread (main thread - * of pthread) that uses a time-related function first. Hence, - * the construction must be protected by a lock. - */ - Genode::Lock _lock; - - Genode::Constructible _timer; - - Timer_accessor(Genode::Env &env) : _env(env) { } - - Timer &timer() override - { - Lock::Guard guard(_lock); - - if (!_timer.constructed()) - _timer.construct(_env); - - return *_timer; - } - }; - - Timer_accessor _timer_accessor { _env }; - - struct Main_timeout : Timeout_handler - { - Timer_accessor &_timer_accessor; - Constructible _timeout; - Kernel &_kernel; - - void _construct_timeout_once() - { - if (!_timeout.constructed()) - _timeout.construct(_timer_accessor, *this); - } - - Main_timeout(Timer_accessor &timer_accessor, Kernel &kernel) - : _timer_accessor(timer_accessor), _kernel(kernel) - { } - - void timeout(Genode::uint64_t timeout_ms) - { - _construct_timeout_once(); - _timeout->start(timeout_ms); - } - - Genode::uint64_t duration_left() - { - _construct_timeout_once(); - return _timeout->duration_left(); - } - - void handle_timeout() override - { - _kernel._resume_main(); - } - }; - - Main_timeout _main_timeout { _timer_accessor, *this }; - - Pthreads _pthreads { _timer_accessor }; - - struct Resumer - { - GENODE_RPC(Rpc_resume, void, resume); - GENODE_RPC_INTERFACE(Rpc_resume); - }; - - struct Resumer_component : Rpc_object - { - Kernel &_kernel; - - Resumer_component(Kernel &kernel) : _kernel(kernel) { } - - void resume() { _kernel.run_after_resume(); } - }; - - /** - * Trampoline to application (user) code - * - * This function is called by the main thread. - */ - static void _user_entry(Libc::Kernel *kernel) - { - struct Check : Suspend_functor { - bool suspend() override { return true; } - } check; - - kernel->_app_code->execute(); - kernel->_app_returned = true; - kernel->_suspend_main(check, 0); - } - - bool _main_context() const { return &_myself == Genode::Thread::myself(); } - - /** - * Utility to switch main context to kernel - * - * User context must be saved explicitly before this function is called - * to enable _switch_to_user() later. - */ - void _switch_to_kernel() - { - _state = KERNEL; - _longjmp(_kernel_context, 1); - } - - /** - * Utility to switch main context to user - * - * Kernel context must be saved explicitly before this function is called - * to enable _switch_to_kernel() later. - */ - void _switch_to_user() - { - if (!_valid_user_context) - Genode::error("switching to invalid user context"); - - _resume_main_once = false; - _state = USER; - _longjmp(_user_context, 1); - } - - Genode::uint64_t _suspend_main(Suspend_functor &check, - Genode::uint64_t timeout_ms) - { - /* check that we're not running on libc kernel context */ - if (Thread::mystack().top == _kernel_stack) { - error("libc suspend() called from non-user context (", - __builtin_return_address(0), ") - aborting"); - exit(1); - } - - if (!check.suspend() && !_kernel_routine) - return 0; - - if (timeout_ms > 0) - _main_timeout.timeout(timeout_ms); - - if (!_setjmp(_user_context)) { - _valid_user_context = true; - _switch_to_kernel(); - } else { - _valid_user_context = false; - } - - /* - * During the suspension 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; - } - - void _init_file_descriptors(); - - void _clone_state_from_parent(); - - public: - - Kernel(Genode::Env &env, Genode::Allocator &heap) - : - _env(env), _heap(heap) - { - _env.ep().register_io_progress_handler(*this); - - if (_cloned) { - _clone_state_from_parent(); - - } else { - _malloc_heap.construct(*_malloc_ram, _env.rm()); - init_malloc(*_malloc_heap); - } - - Libc::init_fork(_env, _libc_env, _heap, *_malloc_heap, _pid); - Libc::init_execve(_env, _heap, _user_stack, *this); - - _init_file_descriptors(); - } - - ~Kernel() { Genode::error(__PRETTY_FUNCTION__, " should not be executed!"); } - - Libc::Env & libc_env() { return _libc_env; } - - /** - * Setup kernel context and run libc application main context - * - * This function is called by the component thread on with_libc(). - */ - void run(Libc::Application_code &app_code) - { - if (!_main_context() || _state != KERNEL) { - Genode::error(__PRETTY_FUNCTION__, " called from non-kernel context"); - return; - } - - _resume_main_once = false; - _app_returned = false; - _app_code = &app_code; - - /* save continuation of libc kernel (incl. current stack) */ - if (!_setjmp(_kernel_context)) { - /* _setjmp() returned directly -> switch to user stack and call application code */ - - if (_cloned) { - _switch_to_user(); - } else { - _state = USER; - call_func(_user_stack, (void *)_user_entry, (void *)this); - } - - /* never reached */ - } - - /* _setjmp() returned after _longjmp() - user context suspended */ - - while ((!_app_returned) && (!_suspend_scheduled)) { - - if (_kernel_routine) { - Kernel_routine &routine = *_kernel_routine; - - /* the 'kernel_routine' may install another kernel routine */ - _kernel_routine = nullptr; - routine.execute_in_kernel(); - if (!_kernel_routine) - _switch_to_user(); - } - - if (_dispatch_pending_io_signals) { - /* dispatch pending signals but don't block */ - while (_env.ep().dispatch_pending_io_signal()) ; - } else { - /* block for signals */ - _env.ep().wait_and_dispatch_one_io_signal(); - } - - if (!_kernel_routine && _resume_main_once && !_setjmp(_kernel_context)) - _switch_to_user(); - } - - _suspend_scheduled = false; - } - - /* - * Run libc application main context after suspend and resume - */ - void run_after_resume() - { - if (!_setjmp(_kernel_context)) - _switch_to_user(); - - while ((!_app_returned) && (!_suspend_scheduled)) { - _env.ep().wait_and_dispatch_one_io_signal(); - if (_resume_main_once && !_setjmp(_kernel_context)) - _switch_to_user(); - } - - _suspend_scheduled = false; - } - - /** - * Resume all contexts (main and pthreads) - */ - void resume_all() - { - if (_app_returned) { - if (_scheduled_select_handler) - _scheduled_select_handler->dispatch_select(); - } else { - if (_main_context()) - _resume_main(); - else - Genode::Signal_transmitter(*_resume_main_handler).submit(); - } - - _pthreads.resume_all(); - } - - /** - * Suspend this context (main or pthread) - */ - Genode::uint64_t suspend(Suspend_functor &check, Genode::uint64_t timeout_ms) - { - if (timeout_ms > 0 - && timeout_ms > _timer_accessor.timer().max_timeout()) { - Genode::warning("libc: limiting exceeding timeout of ", - timeout_ms, " ms to maximum of ", - _timer_accessor.timer().max_timeout(), " ms"); - - timeout_ms = min(timeout_ms, _timer_accessor.timer().max_timeout()); - } - - return _main_context() ? _suspend_main(check, timeout_ms) - : _pthreads.suspend_myself(check, timeout_ms); - } - - void dispatch_pending_io_signals() - { - if (!_main_context()) return; - - if (!_setjmp(_user_context)) { - _valid_user_context = true; - _dispatch_pending_io_signals = true; - _resume_main_once = true; /* afterwards resume main */ - _switch_to_kernel(); - } else { - _valid_user_context = false; - _dispatch_pending_io_signals = false; - } - } - - Genode::Duration current_time() - { - return _timer_accessor.timer().curr_time(); - } - - /** - * Called from the main context (by fork) - */ - void schedule_suspend(void(*original_suspended_callback) ()) - { - if (_state != USER) { - Genode::error(__PRETTY_FUNCTION__, " called from non-user context"); - return; - } - - /* - * We hook into suspend-resume callback chain to destruct and - * reconstruct parts of the kernel from the context of the initial - * thread, i.e., without holding any object locks. - */ - _original_suspended_callback = original_suspended_callback; - _env.ep().schedule_suspend(suspended_callback, resumed_callback); - - if (!_setjmp(_user_context)) { - _valid_user_context = true; - _suspend_scheduled = true; - _switch_to_kernel(); - } else { - _valid_user_context = false; - } - } - - void schedule_select(Select_handler_base *h) - { - _scheduled_select_handler = h; - } - - /** - * Called from the context of the initial thread (on fork) - */ - void entrypoint_suspended() - { - _resume_main_handler.destruct(); - - _original_suspended_callback(); - } - - /** - * Called from the context of the initial thread (after fork) - */ - void entrypoint_resumed() - { - _resume_main_handler.construct(_env.ep(), *this, &Kernel::_resume_main); - - Resumer_component resumer { *this }; - - Capability resumer_cap = - _env.ep().rpc_ep().manage(&resumer); - - resumer_cap.call(); - - _env.ep().rpc_ep().dissolve(&resumer); - } - - /** - * Return if main is currently suspended - */ - bool main_suspended() { return _state == KERNEL; } - - /** - * Public alias for _main_context() - */ - bool main_context() const { return _main_context(); } - - /** - * 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(); - } - } - - /** - * Alloc new watch handler for given path - */ - Vfs::Vfs_watch_handle *alloc_watch_handle(char const *path) - { - Vfs::Vfs_watch_handle *watch_handle { nullptr }; - typedef Vfs::Directory_service::Watch_result Result; - return _libc_env.vfs().watch(path, &watch_handle, _heap) == Result::WATCH_OK - ? watch_handle : nullptr; - } - - - /**************************************** - ** Vfs::Io_response_handler interface ** - ****************************************/ - - void read_ready_response() override { - _io_ready = true; } - - void io_progress_response() override { - _io_ready = true; } - - - /********************************************** - * Entrypoint::Io_progress_handler interface ** - **********************************************/ - - void handle_io_progress() override - { - /* - * TODO: make VFS I/O completion checks during - * kernel time to avoid flapping between stacks - */ - - if (_io_ready) { - _io_ready = false; - - /* some contexts may have been deblocked from select() */ - if (libc_select_notify) - libc_select_notify(); - - /* - * resume all as any VFS context may have - * been deblocked from blocking I/O - */ - Kernel::resume_all(); - } - } - - void register_kernel_routine(Kernel_routine &kernel_routine) - { - _kernel_routine = &kernel_routine; - } -}; - - -void Libc::Kernel::reset_malloc_heap() -{ - _malloc_ram.construct(_heap, _env.ram()); - - _cloned_heap_ranges.for_each([&] (Registered &r) { - destroy(_heap, &r); }); - - Heap &raw_malloc_heap = *_malloc_heap; - Genode::construct_at(&raw_malloc_heap, *_malloc_ram, _env.rm()); - - reinit_malloc(raw_malloc_heap); -} - - -void Libc::Kernel::_init_file_descriptors() -{ - auto init_fd = [&] (Genode::Xml_node const &node, char const *attr, - int libc_fd, unsigned flags) - { - if (!node.has_attribute(attr)) - return; - - typedef Genode::String Path; - Path const path = node.attribute_value(attr, Path()); - - struct stat out_stat { }; - if (stat(path.string(), &out_stat) != 0) - return; - - Libc::File_descriptor *fd = _vfs.open(path.string(), flags, libc_fd); - if (fd->libc_fd != libc_fd) { - Genode::error("could not allocate fd ",libc_fd," for ",path,", " - "got fd ",fd->libc_fd); - _vfs.close(fd); - return; - } - - /* - * We need to manually register the path. Normally this is done - * by '_open'. But we call the local 'open' function directly - * because we want to explicitly specify the libc fd ID. - */ - if (fd->fd_path) - Genode::warning("may leak former FD path memory"); - - { - char *dst = (char *)_heap.alloc(path.length()); - Genode::strncpy(dst, path.string(), path.length()); - fd->fd_path = dst; - } - - ::off_t const seek = node.attribute_value("seek", 0ULL); - if (seek) - _vfs.lseek(fd, seek, SEEK_SET); - }; - - if (_vfs.root_dir_has_dirents()) { - - Xml_node const node = _libc_env.libc_config(); - - typedef Genode::String Path; - - if (node.has_attribute("cwd")) - chdir(node.attribute_value("cwd", Path()).string()); - - init_fd(node, "stdin", 0, O_RDONLY); - init_fd(node, "stdout", 1, O_WRONLY); - init_fd(node, "stderr", 2, O_WRONLY); - - node.for_each_sub_node("fd", [&] (Xml_node fd) { - - unsigned const id = fd.attribute_value("id", 0U); - - bool const rd = fd.attribute_value("readable", false); - bool const wr = fd.attribute_value("writeable", false); - - unsigned const flags = rd ? (wr ? O_RDWR : O_RDONLY) - : (wr ? O_WRONLY : 0); - - if (!fd.has_attribute("path")) - warning("Invalid node, 'path' attribute is missing"); - - init_fd(fd, "path", id, flags); - }); - - /* prevent use of IDs of stdin, stdout, and stderr for other files */ - for (unsigned fd = 0; fd <= 2; fd++) - Libc::file_descriptor_allocator()->preserve(fd); - } -} - - -void Libc::Kernel::_clone_state_from_parent() -{ - struct Range { void *at; size_t size; }; - - auto range_attr = [&] (Xml_node node) - { - return Range { - .at = (void *)node.attribute_value("at", 0UL), - .size = node.attribute_value("size", 0UL) - }; - }; - - /* - * Allocate local memory for the backing store of the application heap, - * mirrored from the parent. - * - * This step must precede the creation of the 'Clone_connection' because - * the shared-memory buffer of the clone session may otherwise potentially - * interfere with such a heap region. - */ - _libc_env.libc_config().for_each_sub_node("heap", [&] (Xml_node node) { - Range const range = range_attr(node); - new (_heap) - Registered(_cloned_heap_ranges, - _env.ram(), _env.rm(), - range.at, range.size); }); - - Clone_connection clone_connection(_env); - - /* fetch heap content */ - _cloned_heap_ranges.for_each([&] (Cloned_malloc_heap_range &heap_range) { - heap_range.import_content(clone_connection); }); - - /* fetch user contex of the parent's application */ - clone_connection.memory_content(&_user_context, sizeof(_user_context)); - _valid_user_context = true; - - _libc_env.libc_config().for_each_sub_node([&] (Xml_node node) { - - auto copy_from_parent = [&] (Range range) - { - clone_connection.memory_content(range.at, range.size); - }; - - /* clone application stack */ - if (node.type() == "stack") - copy_from_parent(range_attr(node)); - - /* clone RW segment of a shared library or the binary */ - if (node.type() == "rw") { - typedef String<64> Name; - Name const name = node.attribute_value("name", Name()); - - /* - * The blacklisted segments are initialized via the - * regular startup of the child. - */ - bool const blacklisted = (name == "ld.lib.so") - || (name == "libc.lib.so") - || (name == "libm.lib.so") - || (name == "posix.lib.so") - || (strcmp(name.string(), "vfs", 3) == 0); - if (!blacklisted) - copy_from_parent(range_attr(node)); - } - }); - - /* import application-heap state from parent */ - clone_connection.object_content(_malloc_heap); - init_malloc_cloned(clone_connection); -} - - -/** - * Libc kernel singleton - * - * The singleton is implemented with the unmanaged-singleton utility - * in Component::construct() to ensure it is never destructed - * like normal static global objects. Otherwise, the task object may be - * destructed in a RPC to Rpc_resume, which would result in a deadlock. - */ -static Libc::Kernel *kernel; - - -/** - * Main context execution was suspended (on fork) - * - * This function is executed in the context of the initial thread. - */ -static void suspended_callback() { kernel->entrypoint_suspended(); } - - -/** - * Resume main context execution (after fork) - * - * This function is executed in the context of the initial thread. - */ -static void resumed_callback() { kernel->entrypoint_resumed(); } - - -/******************* - ** Libc task API ** - *******************/ - -void Libc::resume_all() { kernel->resume_all(); } - - -Genode::uint64_t Libc::suspend(Suspend_functor &s, Genode::uint64_t timeout_ms) -{ - if (!kernel) { - error("libc kernel not initialized, needed for suspend()"); - exit(1); - } - return kernel->suspend(s, timeout_ms); -} - - -void Libc::dispatch_pending_io_signals() -{ - kernel->dispatch_pending_io_signals(); -} - - -Vfs::Vfs_watch_handle *Libc::watch(char const *path) -{ - return kernel->alloc_watch_handle(path); -} - - -Genode::Duration Libc::current_time() -{ - return kernel->current_time(); -} - - -void Libc::schedule_suspend(void (*suspended) ()) -{ - if (!kernel) { - error("libc kernel not initialized, needed for fork()"); - exit(1); - } - kernel->schedule_suspend(suspended); -} - - -void Libc::schedule_select(Libc::Select_handler_base *h) -{ - if (!kernel) { - error("libc kernel not initialized, needed for select()"); - exit(1); - } - kernel->schedule_select(h); -} - - -void Libc::execute_in_application_context(Libc::Application_code &app_code) -{ - if (!kernel) { - error("libc kernel not initialized, needed for with_libc()"); - exit(1); - } - - /* - * The libc execution model builds on the main entrypoint, which handles - * all relevant signals (e.g., timing and VFS). Additional component - * entrypoints or pthreads should never call with_libc() but we catch this - * here and just execute the application code directly. - */ - if (!kernel->main_context()) { - app_code.execute(); - return; - } - - static bool nested = false; - - if (nested) { - - if (kernel->main_suspended()) { - kernel->nested_execution(app_code); - } else { - app_code.execute(); - } - return; - } - - nested = true; - kernel->run(app_code); - nested = false; -} - - -void Libc::register_kernel_routine(Kernel_routine &kernel_routine) -{ - kernel->register_kernel_routine(kernel_routine); -} - - -Genode::Xml_node Libc::libc_config() -{ - return kernel->libc_env().libc_config(); -} - - -/*************************** - ** Component entry point ** - ***************************/ - -Genode::size_t Component::stack_size() { return Libc::Component::stack_size(); } - - -void Component::construct(Genode::Env &env) -{ - /* initialize the global pointer to environment variables */ - static char *null_env = nullptr; - if (!environ) environ = &null_env; - - Genode::Allocator &heap = - *unmanaged_singleton(env.ram(), env.rm()); - - /* pass Genode::Env to libc subsystems that depend on it */ - Libc::init_fd_alloc(heap); - Libc::init_mem_alloc(env); - Libc::init_dl(env); - Libc::sysctl_init(env); - Libc::init_pthread_support(env); - - kernel = unmanaged_singleton(env, heap); - - Libc::libc_config_init(kernel->libc_env().libc_config()); - - /* - * XXX The following two steps leave us with the dilemma that we don't know - * which linked library may depend on the successfull initialization of a - * plugin. For example, some high-level library may try to open a network - * connection in its constructor before the network-stack library is - * initialized. But, we can't initialize plugins before calling static - * constructors as those are needed to know about the libc plugin. The only - * solution is to remove all libc plugins beside the VFS implementation, - * which is our final goal anyway. - */ - - /* finish static construction of component and libraries */ - Libc::with_libc([&] () { env.exec_static_constructors(); }); - - /* initialize plugins that require Genode::Env */ - auto init_plugin = [&] (Libc::Plugin &plugin) { - plugin.init(env); - }; - Libc::plugin_registry()->for_each_plugin(init_plugin); - - /* construct libc component on kernel stack */ - Libc::Component::construct(kernel->libc_env()); -} - - -/** - * Default stack size for libc-using components - */ -Genode::size_t Libc::Component::stack_size() __attribute__((weak)); -Genode::size_t Libc::Component::stack_size() { return 32UL*1024*sizeof(long); } diff --git a/repos/libports/src/lib/libc/task.h b/repos/libports/src/lib/libc/task.h deleted file mode 100644 index 1df9512c3..000000000 --- a/repos/libports/src/lib/libc/task.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * \brief Libc-internal kernel API - * \author Christian Helmuth - * \author Emery Hemingway - * \date 2016-12-14 - * - * TODO document libc tasking including - * - the initial thread (which is neither component nor pthread) - * - processes incoming signals and forwards to entrypoint - * - the main thread (which is the kernel and the main user context) - * - pthreads (which are pthread user contexts only) - */ - -/* - * Copyright (C) 2016-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _LIBC__TASK_H_ -#define _LIBC__TASK_H_ - -#include -#include -#include - -namespace Libc { - - /** - * Resume all user contexts - * - * This resumes the main user context as well as any pthread context. - */ - void resume_all(); - - /** - * Suspend the execution of the calling user context - * - * \param timeout_ms maximum time to stay suspended in milliseconds, - * 0 for infinite suspend - * - * \return remaining duration until timeout, - * 0 if the timeout expired - * - * The context could be running on the component entrypoint as main context - * or as separate pthread. This function returns after the libc kernel - * resumed the user context execution. - */ - struct Suspend_functor { virtual bool suspend() = 0; }; - Genode::uint64_t suspend(Suspend_functor &, Genode::uint64_t timeout_ms = 0); - - void dispatch_pending_io_signals(); - - /** - * Get watch handle for given path - * - * \param path path that should be be watched - * - * \return point to the watch handle object or a nullptr - * when the watch operation failed - */ - Vfs::Vfs_watch_handle *watch(char const *path); - - /** - * Get time since startup in ms - */ - Genode::Duration current_time(); - - /** - * Suspend main user context and the component entrypoint - * - * This interface is solely used by the implementation of fork(). - */ - void schedule_suspend(void (*suspended) ()); - - struct Select_handler_base; - - /** - * Schedule select handler that is deblocked by ready fd sets - */ - void schedule_select(Select_handler_base *); - - struct Kernel_routine : Genode::Interface - { - virtual void execute_in_kernel() = 0; - }; - - /** - * Register routine to be called once on the next libc-kernel activation - * - * The specified routine is executed only once. For a repeated execution, - * the routine must call 'register_kernel_routine' with itself as - * argument. - * - * This mechanism is used by 'fork' to implement the blocking for the - * startup of a new child and for 'wait4'. - */ - void register_kernel_routine(Kernel_routine &); - - /** - * Access libc configuration Xml_node. - */ - Genode::Xml_node libc_config(); -} - -#endif /* _LIBC__TASK_H_ */ diff --git a/repos/libports/src/lib/libc/time.cc b/repos/libports/src/lib/libc/time.cc index 676e88545..e6ff9c4a4 100644 --- a/repos/libports/src/lib/libc/time.cc +++ b/repos/libports/src/lib/libc/time.cc @@ -12,44 +12,60 @@ * under the terms of the GNU Affero General Public License version 3. */ -/* Libc includes */ +/* Genode includes */ +#include +#include + +/* libc includes */ #include #include #include #include #include +/* libc-internal includes */ +#include +#include +#include +#include + +static Libc::Current_time *_current_time_ptr; +static char const *_rtc_path; -#include "task.h" -#include "libc_errno.h" +void Libc::init_time(Current_time ¤t_time, Rtc_path const &rtc_path) +{ + static Rtc_path rtc_path_inst = rtc_path; -/* Genode includes */ -#include -#include - - -namespace Libc { - extern char const *config_rtc(); + _current_time_ptr = ¤t_time; + _rtc_path = rtc_path_inst.string(); } -struct Rtc : Vfs::Watch_response_handler +namespace Libc { struct Rtc; } + + +struct Libc::Rtc : Vfs::Watch_response_handler { Vfs::Vfs_watch_handle *_watch_handle { nullptr }; - char const *_file { nullptr }; - bool _read_file { true }; - time_t _rtc_value { 0 }; - Rtc(char const *rtc_file) - : _file(rtc_file) + Rtc_path const _rtc_path; + + bool _read_file { true }; + time_t _rtc_value { 0 }; + + bool const _rtc_path_valid = (_rtc_path != ""); + + Rtc(Rtc_path const &rtc_path) + : + _rtc_path(rtc_path) { - if (!Genode::strcmp(_file, "")) { + if (!_rtc_path_valid) { Genode::warning("rtc not configured, returning ", _rtc_value); return; } - _watch_handle = Libc::watch(_file); + _watch_handle = Libc::watch(_rtc_path.string()); if (_watch_handle) { _watch_handle->handler(this); } @@ -66,16 +82,16 @@ struct Rtc : Vfs::Watch_response_handler time_t read() { - if (!_file) { return 0; } + if (!_rtc_path_valid) { return 0; } /* return old value */ if (!_read_file) { return _rtc_value; } _read_file = false; - int fd = open(_file, O_RDONLY); + int fd = open(_rtc_path.string(), O_RDONLY); if (fd == -1) { - Genode::warning(Genode::Cstring(Libc::config_rtc()), " not readable, returning ", _rtc_value); + Genode::warning(_rtc_path, " not readable, returning ", _rtc_value); return _rtc_value; } @@ -95,8 +111,12 @@ struct Rtc : Vfs::Watch_response_handler close(fd); - uint64_t const ts_value = - Libc::current_time().trunc_to_plain_ms().value; + struct Missing_call_of_init_time : Exception { }; + if (!_current_time_ptr) + throw Missing_call_of_init_time(); + + Genode::uint64_t const ts_value = + _current_time_ptr->current_time().trunc_to_plain_ms().value; _rtc_value += (time_t)ts_value / 1000; return _rtc_value; @@ -109,6 +129,15 @@ int clock_gettime(clockid_t clk_id, struct timespec *ts) { if (!ts) return Libc::Errno(EFAULT); + auto current_time = [&] () + { + struct Missing_call_of_init_time : Genode::Exception { }; + if (!_current_time_ptr) + throw Missing_call_of_init_time(); + + return _current_time_ptr->current_time(); + }; + /* initialize timespec just in case users do not check for errors */ ts->tv_sec = 0; ts->tv_nsec = 0; @@ -119,12 +148,15 @@ int clock_gettime(clockid_t clk_id, struct timespec *ts) case CLOCK_REALTIME: case CLOCK_SECOND: /* FreeBSD specific */ { - static Rtc rtc(Libc::config_rtc()); + /* + * XXX move instance to Libc::Kernel + */ + static Libc::Rtc rtc(_rtc_path); time_t const rtc_value = rtc.read(); if (!rtc_value) return Libc::Errno(EINVAL); - Genode::uint64_t const time = Libc::current_time().trunc_to_plain_ms().value; + Genode::uint64_t const time = current_time().trunc_to_plain_ms().value; ts->tv_sec = rtc_value + time/1000; ts->tv_nsec = (time % 1000) * (1000*1000); @@ -135,7 +167,7 @@ int clock_gettime(clockid_t clk_id, struct timespec *ts) case CLOCK_MONOTONIC: case CLOCK_UPTIME: { - Genode::uint64_t us = Libc::current_time().trunc_to_plain_us().value; + Genode::uint64_t us = current_time().trunc_to_plain_us().value; ts->tv_sec = us / (1000*1000); ts->tv_nsec = (us % (1000*1000)) * 1000; diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index 6ca429e5c..459571b5a 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -34,12 +34,34 @@ /* libc plugin interface */ #include -#include /* libc-internal includes */ -#include "libc_mem_alloc.h" -#include "libc_errno.h" -#include "task.h" +#include +#include +#include +#include +#include +#include + + +static Libc::Suspend *_suspend_ptr; + + +void Libc::init_vfs_plugin(Suspend &suspend) +{ + _suspend_ptr = &suspend; +} + + +static void suspend(Libc::Suspend_functor &check) +{ + struct Missing_call_of_init_vfs_plugin : Genode::Exception { }; + if (!_suspend_ptr) + throw Missing_call_of_init_vfs_plugin(); + + _suspend_ptr->suspend(check); +}; + static Genode::Lock &vfs_lock() { @@ -124,13 +146,6 @@ namespace Libc { char const *string() const { return _value.string(); } }; - char const *config_rtc() __attribute__((weak)); - char const *config_rtc() - { - static Config_attr rtc("rtc", ""); - return rtc.string(); - } - char const *config_rng() __attribute__((weak)); char const *config_rng() { @@ -351,12 +366,12 @@ int Libc::Vfs_plugin::_vfs_sync(Vfs::Vfs_handle &vfs_handle) } check(vfs_handle); /* - * Cannot call Libc::suspend() immediately, because the Libc kernel + * Cannot call suspend() immediately, because the Libc kernel * might not be running yet. */ if (!VFS_THREAD_SAFE(vfs_handle.fs().queue_sync(&vfs_handle))) { do { - Libc::suspend(check); + suspend(check); } while (check.retry); } } @@ -381,13 +396,13 @@ int Libc::Vfs_plugin::_vfs_sync(Vfs::Vfs_handle &vfs_handle) } check(vfs_handle, result); /* - * Cannot call Libc::suspend() immediately, because the Libc kernel + * Cannot call suspend() immediately, because the Libc kernel * might not be running yet. */ result = VFS_THREAD_SAFE(vfs_handle.fs().complete_sync(&vfs_handle)); if (result == Result::SYNC_QUEUED) { do { - Libc::suspend(check); + suspend(check); } while (check.retry); } } @@ -500,8 +515,7 @@ ssize_t Libc::Vfs_plugin::write(Libc::File_descriptor *fd, const void *buf, try { out_result = VFS_THREAD_SAFE(handle->fs().write(handle, (char const *)buf, count, out_count)); - /* wake up threads blocking for 'queue_*()' or 'write()' */ - Libc::resume_all(); + Plugin::resume_all(); } catch (Vfs::File_io_service::Insufficient_buffer) { } @@ -539,12 +553,11 @@ ssize_t Libc::Vfs_plugin::write(Libc::File_descriptor *fd, const void *buf, } check(handle, buf, count, out_count, out_result); do { - Libc::suspend(check); + suspend(check); } while (check.retry); } - /* wake up threads blocking for 'queue_*()' or 'write()' */ - Libc::resume_all(); + Plugin::resume_all(); switch (out_result) { case Result::WRITE_ERR_AGAIN: return Errno(EAGAIN); @@ -595,7 +608,7 @@ ssize_t Libc::Vfs_plugin::read(Libc::File_descriptor *fd, void *buf, } check ( handle, count); do { - Libc::suspend(check); + suspend(check); } while (check.retry); } @@ -632,12 +645,11 @@ ssize_t Libc::Vfs_plugin::read(Libc::File_descriptor *fd, void *buf, } check ( handle, buf, count, out_count, out_result); do { - Libc::suspend(check); + suspend(check); } while (check.retry); } - /* wake up threads blocking for 'queue_*()' or 'write()' */ - Libc::resume_all(); + Plugin::resume_all(); switch (out_result) { case Result::READ_ERR_AGAIN: return Errno(EAGAIN); @@ -690,7 +702,7 @@ ssize_t Libc::Vfs_plugin::getdirentries(Libc::File_descriptor *fd, char *buf, } check(handle); do { - Libc::suspend(check); + suspend(check); } while (check.retry); } @@ -728,12 +740,11 @@ ssize_t Libc::Vfs_plugin::getdirentries(Libc::File_descriptor *fd, char *buf, } check(handle, dirent_out, out_count, out_result); do { - Libc::suspend(check); + suspend(check); } while (check.retry); } - /* wake up threads blocking for 'queue_*()' or 'write()' */ - Libc::resume_all(); + Plugin::resume_all(); if ((out_result != Result::READ_OK) || (out_count < sizeof(Dirent))) { @@ -1076,11 +1087,10 @@ int Libc::Vfs_plugin::symlink(const char *oldpath, const char *newpath) } check ( handle, oldpath, count, out_count); do { - Libc::suspend(check); + suspend(check); } while (check.retry); - /* wake up threads blocking for 'queue_*()' or 'write()' */ - Libc::resume_all(); + Plugin::resume_all(); _vfs_sync(*handle); VFS_THREAD_SAFE(handle->close()); @@ -1138,7 +1148,7 @@ ssize_t Libc::Vfs_plugin::readlink(const char *path, char *buf, ::size_t buf_siz } check(symlink_handle, buf_size); do { - Libc::suspend(check); + suspend(check); } while (check.retry); } @@ -1179,12 +1189,11 @@ ssize_t Libc::Vfs_plugin::readlink(const char *path, char *buf, ::size_t buf_siz } check(symlink_handle, buf, buf_size, out_len, out_result); do { - Libc::suspend(check); + suspend(check); } while (check.retry); } - /* wake up threads blocking for 'queue_*()' or 'write()' */ - Libc::resume_all(); + Plugin::resume_all(); switch (out_result) { case Result::READ_ERR_AGAIN: return Errno(EAGAIN); diff --git a/repos/libports/src/test/timed_semaphore/target.mk b/repos/libports/src/test/timed_semaphore/target.mk index e0439f85b..d850f3780 100644 --- a/repos/libports/src/test/timed_semaphore/target.mk +++ b/repos/libports/src/test/timed_semaphore/target.mk @@ -1,4 +1,4 @@ TARGET = test-timed_semaphore SRC_CC = main.cc LIBS = base -INC_DIR += $(REP_DIR)/src/lib/libc +INC_DIR += $(REP_DIR)/src/lib/libc/internal diff --git a/repos/ports/recipes/src/noux/content.mk b/repos/ports/recipes/src/noux/content.mk index 780eecd47..d710e432d 100644 --- a/repos/ports/recipes/src/noux/content.mk +++ b/repos/ports/recipes/src/noux/content.mk @@ -5,7 +5,10 @@ content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_REP_DIR): $(mirror_from_rep_dir) -MIRROR_FROM_LIBPORTS := include/libc-plugin src/lib/libc/libc_mem_alloc.h +MIRROR_FROM_LIBPORTS := include/libc-plugin \ + src/lib/libc/internal/mem_alloc.h \ + src/lib/libc/internal/types.h \ + src/lib/libc/internal/legacy.h content: $(MIRROR_FROM_LIBPORTS) diff --git a/repos/ports/recipes/src/vbox5-nova/content.mk b/repos/ports/recipes/src/vbox5-nova/content.mk index 6eeff2930..4a283df5f 100644 --- a/repos/ports/recipes/src/vbox5-nova/content.mk +++ b/repos/ports/recipes/src/vbox5-nova/content.mk @@ -38,10 +38,11 @@ MIRROR_FROM_LIBPORTS := lib/mk/libc_pipe.mk \ lib/mk/libc-mem.mk \ lib/mk/libc-common.inc \ src/lib/libc/libc_mem_alloc.cc \ - src/lib/libc/libc_mem_alloc.h \ - src/lib/libc/libc_init.h \ - src/lib/libc/thread_create.h \ - src/lib/libc/thread.h \ + src/lib/libc/internal/mem_alloc.h \ + src/lib/libc/internal/init.h \ + src/lib/libc/internal/thread_create.h \ + src/lib/libc/internal/pthread.h \ + src/lib/libc/internal/types.h \ include/libc-plugin \ lib/import/import-qemu-usb_include.mk \ lib/mk/qemu-usb_include.mk \ diff --git a/repos/ports/recipes/src/vbox5/content.mk b/repos/ports/recipes/src/vbox5/content.mk index 2f6f5d16e..5a7ac4838 100644 --- a/repos/ports/recipes/src/vbox5/content.mk +++ b/repos/ports/recipes/src/vbox5/content.mk @@ -39,10 +39,11 @@ MIRROR_FROM_LIBPORTS := lib/mk/libc_pipe.mk \ lib/mk/libc-mem.mk \ lib/mk/libc-common.inc \ src/lib/libc/libc_mem_alloc.cc \ - src/lib/libc/libc_mem_alloc.h \ - src/lib/libc/libc_init.h \ - src/lib/libc/thread_create.h \ - src/lib/libc/thread.h \ + src/lib/libc/internal/mem_alloc.h \ + src/lib/libc/internal/init.h \ + src/lib/libc/internal/thread_create.h \ + src/lib/libc/internal/pthread.h \ + src/lib/libc/internal/types.h \ include/libc-plugin \ lib/import/import-qemu-usb_include.mk \ lib/mk/qemu-usb_include.mk \ diff --git a/repos/ports/src/lib/libc_noux/plugin.cc b/repos/ports/src/lib/libc_noux/plugin.cc index 658f268e6..9a5dbd32f 100644 --- a/repos/ports/src/lib/libc_noux/plugin.cc +++ b/repos/ports/src/lib/libc_noux/plugin.cc @@ -58,7 +58,8 @@ /* libc-internal includes */ -#include +#include +#include using Genode::log; diff --git a/repos/ports/src/virtualbox5/devxhci.cc b/repos/ports/src/virtualbox5/devxhci.cc index 1e8640661..db385bf13 100644 --- a/repos/ports/src/virtualbox5/devxhci.cc +++ b/repos/ports/src/virtualbox5/devxhci.cc @@ -21,7 +21,7 @@ #include /* libc internal includes */ -#include +#include /* Virtualbox includes */ #define LOG_GROUP LOG_GROUP_DEV_EHCI diff --git a/repos/ports/src/virtualbox5/generic/sup_vmm.cc b/repos/ports/src/virtualbox5/generic/sup_vmm.cc index 8074d83a5..703b885ff 100644 --- a/repos/ports/src/virtualbox5/generic/sup_vmm.cc +++ b/repos/ports/src/virtualbox5/generic/sup_vmm.cc @@ -33,10 +33,10 @@ #include "vcpu_vmx.h" /* libc memory allocator */ -#include +#include /* Genode libc pthread binding */ -#include +#include /* libc */ #include diff --git a/repos/ports/src/virtualbox5/libc.cc b/repos/ports/src/virtualbox5/libc.cc index 47689b119..99a1028b8 100644 --- a/repos/ports/src/virtualbox5/libc.cc +++ b/repos/ports/src/virtualbox5/libc.cc @@ -29,7 +29,7 @@ #include "vmm.h" /* libc memory allocator */ -#include +#include /* VirtualBox includes */ #include diff --git a/repos/ports/src/virtualbox5/mm.cc b/repos/ports/src/virtualbox5/mm.cc index 8077c8e50..f6d617e2e 100644 --- a/repos/ports/src/virtualbox5/mm.cc +++ b/repos/ports/src/virtualbox5/mm.cc @@ -31,7 +31,7 @@ #include /* libc memory allocator */ -#include +#include #include "util.h" #include "mm.h" diff --git a/repos/ports/src/virtualbox5/network.cpp b/repos/ports/src/virtualbox5/network.cpp index a73cc302d..8d6cc2d3c 100644 --- a/repos/ports/src/virtualbox5/network.cpp +++ b/repos/ports/src/virtualbox5/network.cpp @@ -41,7 +41,7 @@ #include #include -#include +#include /* VBox Genode specific */ #include "vmm.h" diff --git a/repos/ports/src/virtualbox5/spec/nova/sup.cc b/repos/ports/src/virtualbox5/spec/nova/sup.cc index bcd8e0a62..71b968e16 100644 --- a/repos/ports/src/virtualbox5/spec/nova/sup.cc +++ b/repos/ports/src/virtualbox5/spec/nova/sup.cc @@ -39,7 +39,7 @@ #include "vcpu_vmx.h" /* libc memory allocator */ -#include +#include /* libc */ #include /* sched_yield */ diff --git a/repos/ports/src/virtualbox5/spec/nova/vcpu.h b/repos/ports/src/virtualbox5/spec/nova/vcpu.h index 5b67b949d..7d77d2ee3 100644 --- a/repos/ports/src/virtualbox5/spec/nova/vcpu.h +++ b/repos/ports/src/virtualbox5/spec/nova/vcpu.h @@ -48,7 +48,7 @@ #include "sup.h" /* Genode libc pthread binding */ -#include "thread.h" +#include /* LibC includes */ #include diff --git a/repos/ports/src/virtualbox5/thread.cc b/repos/ports/src/virtualbox5/thread.cc index 67819b7e8..e8d8ff944 100644 --- a/repos/ports/src/virtualbox5/thread.cc +++ b/repos/ports/src/virtualbox5/thread.cc @@ -18,7 +18,7 @@ #include /* Genode libc pthread binding */ -#include +#include #include "sup.h" #include "vmm.h" diff --git a/repos/ports/src/virtualbox5/vcpu.h b/repos/ports/src/virtualbox5/vcpu.h index 8c7a4f3f1..2dfee83fa 100644 --- a/repos/ports/src/virtualbox5/vcpu.h +++ b/repos/ports/src/virtualbox5/vcpu.h @@ -41,7 +41,7 @@ #include "sup.h" /* Genode libc pthread binding */ -#include "thread.h" +#include #include