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