libc: split task.cc into multiple files

This patch is the first step of re-organizing the internal structure of
the libc. The original version involved many direct calls of global
functions (often with side effects) across compilation units, which
made the control flow (e.g., the initialization sequence) hard to
follow.

The new version replaces those ad-hoc interactions with dedicated
interfaces (like suspend.h, resume.h, select.h, current_time.h). The
underlying facilities are provided by the central Libc::Kernel and
selectively propagated to the various compilation units. The latter is
done by a sequence of 'init_*' calls, which eventually will be replaced
by constructor calls.

The addition of new headers increases the chance for name clashes with
existing (public) headers. To disambiguate libc-internal header files
from public headers, this patch moves the former into a new 'internal/'
subdirectory. This makes the include directives easier to follow and the
libc's source-tree structure more tidy.

There are still a few legacies left, which cannot easily be removed
right now (e.g., because noux relies on them). However, the patch moves
those bad apples to legacy.h and legacy.cc, which highlights the
deprecation of those functions.

Issue #3497
This commit is contained in:
Norman Feske 2019-09-18 20:19:10 +02:00 committed by Christian Helmuth
parent aec1178ab1
commit bf92232698
78 changed files with 2324 additions and 1689 deletions

View File

@ -14,7 +14,10 @@
#ifndef _INCLUDE__LIBC__SELECT_H_
#define _INCLUDE__LIBC__SELECT_H_
/* Libc includes */
/* Genode includes */
#include <util/reconstructible.h>
/* libc includes */
#include <sys/select.h> /* for fd_set */

View File

@ -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 =

View File

@ -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

View File

@ -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 =

View File

@ -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 =

View File

@ -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

View File

@ -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 =

View File

@ -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

View File

@ -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)

View File

@ -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 <base/component.h>
/* libc includes */
#include <libc-plugin/plugin_registry.h>
/* base-internal includes */
#include <base/internal/unmanaged_singleton.h>
/* libc-internal includes */
#include <internal/kernel.h>
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<Genode::Heap>(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<Libc::Kernel>(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); }

View File

@ -15,7 +15,7 @@
#include <libc/allocator.h>
/* libc-internal includes */
#include <libc_init.h>
#include <internal/init.h>
/* libc includes */
extern "C" {

View File

@ -19,13 +19,12 @@
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <libc/allocator.h>
/* libc-internal includes */
#include <libc/allocator.h>
#include <internal/call_func.h>
#include <libc_init.h>
#include <libc_errno.h>
#include <task.h>
#include <internal/init.h>
#include <internal/errno.h>
using namespace Genode;

View File

@ -17,6 +17,9 @@
#include <base/env.h>
#include <base/log.h>
/* Genode-internal includes */
#include <base/internal/unmanaged_singleton.h>
/* libc plugin interface */
#include <libc-plugin/fd_alloc.h>
@ -25,8 +28,7 @@
#include <unistd.h>
/* libc-internal includes */
#include <libc_init.h>
#include <base/internal/unmanaged_singleton.h>
#include <internal/init.h>
using namespace Libc;
using namespace Genode;

View File

@ -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 <internal/file.h>
#include <internal/mem_alloc.h>
#include <internal/mmap_registry.h>
#include <internal/errno.h>
using namespace Libc;

View File

@ -32,34 +32,45 @@
#include <libc-plugin/fd_alloc.h>
/* libc-internal includes */
#include <task.h>
#include <libc_init.h>
#include <clone_session.h>
#include <internal/init.h>
#include <internal/clone_session.h>
#include <internal/legacy.h>
#include <internal/kernel_routine.h>
#include <internal/suspend.h>
#include <internal/resume.h>
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<Local_clone_service> _child_ready_handler;
void _handle_child_ready()
{
_child_ready.child_ready();
Libc::resume_all();
_resume.resume_all();
}
struct Factory : Local_service<Session>::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<Libc::Forked_child> _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<Libc::Forked_child> &child = *new (alloc)
Registered<Libc::Forked_child>(forked_children, env, fork_ep, alloc,
Registered<Libc::Forked_child>(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);
}
/*

View File

@ -14,15 +14,16 @@
/* Genode includes */
#include <base/log.h>
#include <util/string.h>
#include <util/xml_node.h>
/* Libc includes */
/* libc includes */
#include <sys/types.h>
#include <pwd.h>
#include <stdlib.h>
/* local includes */
#include "libc_errno.h"
#include "task.h"
/* libc-local includes */
#include <internal/legacy.h>
#include <internal/errno.h>
typedef Genode::String<128> Passwd_string;

View File

@ -20,8 +20,8 @@ extern "C" {
#include <sys/random.h>
}
/* local includes */
#include "libc_errno.h"
/* libc-internal includes */
#include <internal/errno.h>
/* Genode includes */
#include <trace/timestamp.h>

View File

@ -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 <base/rpc_server.h>
@ -92,4 +92,4 @@ struct Libc::Clone_connection : Genode::Connection<Clone_session>,
void object_content(OBJ &obj) { memory_content(&obj, sizeof(obj)); }
};
#endif /* _CLONE_SESSION_H_ */
#endif /* _LIBC__INTERNAL__CLONE_SESSION_H_ */

View File

@ -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 <region_map/region_map.h>
/* libc-internal includes */
#include <internal/clone_session.h>
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_ */

View File

@ -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 <base/duration.h>
/* libc-internal includes */
#include <internal/types.h>
namespace Libc {
struct Current_time : Interface
{
virtual Duration current_time() = 0;
};
}
#endif /* _LIBC__INTERNAL__CURRENT_TIME_H_ */

View File

@ -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 <base/attached_rom_dataspace.h>
#include <vfs/simple_env.h>
/* libc includes */
#include <libc/component.h> /* '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("'<config> <libc> <vfs/>' is deprecated, "
"please move to '<config> <vfs/>'");
return node;
}
catch (Genode::Xml_node::Nonexistent_sub_node) { }
return Genode::Xml_node("<vfs/>");
}
Genode::Xml_node _libc_config()
{
try { return _config.xml().sub_node("libc"); }
catch (Genode::Xml_node::Nonexistent_sub_node) { }
return Genode::Xml_node("<libc/>");
}
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<Parent::Client> &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<Region_map> &stack_area_rm) override {
_env.reinit_main_thread(stack_area_rm); }
};
#endif /* _LIBC__INTERNAL__ENV_H_ */

View File

@ -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 <errno.h>
@ -28,4 +28,4 @@ struct Libc::Errno
operator int() const { return -1; }
};
#endif /* _LIBC_ERRNO_H_ */
#endif /* _LIBC__INTERNAL__ERRNO_H_ */

View File

@ -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 <base/log.h>
@ -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_ */

View File

@ -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 <base/env.h>
#include <base/heap.h>
#include <util/xml_node.h>
#include <vfs/types.h> /* for 'MAX_PATH_LEN' */
/* libc includes */
#include <setjmp.h> /* for 'jmp_buf' type */
/* libc-internal includes */
#include <internal/types.h>
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<Vfs::MAX_PATH_LEN> 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_ */

View File

@ -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 <internal/call_func.h>
/* libc includes */
#include <libc/select.h>
/* libc-internal includes */
#include <internal/types.h>
#include <internal/malloc_ram_allocator.h>
#include <internal/cloned_malloc_heap_range.h>
#include <internal/timer.h>
#include <internal/pthread_pool.h>
#include <internal/init.h>
#include <internal/env.h>
#include <internal/vfs_plugin.h>
#include <internal/suspend.h>
#include <internal/resume.h>
#include <internal/select.h>
#include <internal/kernel_routine.h>
#include <internal/current_time.h>
#include <internal/kernel_timer_accessor.h>
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_allocator> _malloc_ram { _heap, _env.ram() };
Constructible<Heap> _malloc_heap { };
Registry<Registered<Cloned_malloc_heap_range> > _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<Vfs::MAX_PATH_LEN> Config_attr;
Config_attr const _rtc_path = _libc_env.libc_config().attribute_value("rtc", Config_attr());
Reconstructible<Io_signal_handler<Kernel>> _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> _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<Resumer, Resumer_component>
{
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> resumer_cap =
_env.ep().rpc_ep().manage(&resumer);
resumer_cap.call<Resumer::Rpc_resume>();
_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_ */

View File

@ -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 <internal/types.h>
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_ */

View File

@ -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 <base/env.h>
#include <base/lock.h>
#include <timer_session/connection.h>
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> _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_ */

View File

@ -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 <vfs/vfs_handle.h> /* needed for 'watch' */
/* libc-internal includes */
#include <internal/types.h>
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_ */

View File

@ -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 <base/registry.h>
#include <base/allocator.h>
#include <base/ram_allocator.h>
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<Genode::Registered<Dataspace> > _dataspaces { };
void _release(Genode::Registered<Dataspace> &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<Dataspace> &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<Dataspace>(_dataspaces, cap);
return cap;
}
void free(Ram_dataspace_capability ds_cap) override
{
_dataspaces.for_each([&] (Registered<Dataspace> &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_ */

View File

@ -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 <base/ram_allocator.h>
@ -126,4 +133,4 @@ namespace Libc {
};
}
#endif /* _LIBC_MEM_ALLOC_H_ */
#endif /* _LIBC__INTERNAL__MEM_ALLOC_H_ */

View File

@ -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 <base/lock.h>
@ -13,11 +20,9 @@
#include <base/log.h>
#include <libc/allocator.h>
/* libc-internal includes */
#include <libc-plugin/plugin.h>
/* libc includes */
#include <errno.h>
#include <libc-plugin/plugin.h>
namespace Libc {
@ -122,4 +127,4 @@ class Libc::Mmap_registry
};
#endif /* _LIBC_MMAP_REGISTRY_H_ */
#endif /* _LIBC__INTERNAL__MMAP_REGISTRY_H_ */

View File

@ -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 <libc/component.h>
#include <util/reconstructible.h>
/* libc includes */
#include <pthread.h>
/*
@ -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_ */

View File

@ -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 <internal/legacy.h>
#include <internal/suspend.h>
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> _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_ */

View File

@ -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 <internal/types.h>
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_ */

View File

@ -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 <internal/types.h>
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_ */

View File

@ -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 <sys/types.h>
@ -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_ */

View File

@ -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 <internal/types.h>
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_ */

View File

@ -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 <pthread.h>
/* Genode includes */
#include <base/thread.h>
/* libc includes */
#include <pthread.h>
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_ */

View File

@ -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 <base/thread.h>
#include <base/semaphore.h>
@ -259,4 +259,4 @@ class Libc::Timed_semaphore : public Semaphore
void up() { Semaphore::up(); }
};
#endif /* _TIMED_SEMAPHORE_H_ */
#endif /* _LIBC__INTERNAL__TIMED_SEMAPHORE_H_ */

View File

@ -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 <timer_session/connection.h>
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> _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_ */

View File

@ -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 <base/log.h>
namespace Libc { using namespace Genode; }
#endif /* _LIBC__INTERNAL__TYPES_H_ */

View File

@ -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 <libc/component.h>
#include <vfs/file_system.h>
/* libc includes */
#include <fcntl.h>
@ -27,9 +28,8 @@
#include <libc-plugin/plugin.h>
#include <libc-plugin/fd_alloc.h>
/* local includes */
#include "task.h"
#include "libc_errno.h"
/* libc-internal includes */
#include <internal/errno.h>
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_ */

View File

@ -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 <internal/kernel.h>
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<Cloned_malloc_heap_range> &r) {
destroy(_heap, &r); });
Heap &raw_malloc_heap = *_malloc_heap;
Genode::construct_at<Heap>(&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<Vfs::MAX_PATH_LEN> 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<Vfs::MAX_PATH_LEN> 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 <fd> 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_malloc_heap_range>(_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;
}

View File

@ -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 <internal/legacy.h>
#include <internal/kernel.h>
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();
}

View File

@ -17,9 +17,9 @@
#include <base/env.h>
#include <base/allocator_avl.h>
/* local includes */
#include "libc_mem_alloc.h"
#include "libc_init.h"
/* libc-internal includes */
#include <internal/mem_alloc.h>
#include <internal/init.h>
using namespace Genode;

View File

@ -26,10 +26,12 @@ extern "C" {
#include <stdlib.h>
}
/* libc-internal includes */
#include "libc_init.h"
/* Genode-internal includes */
#include <base/internal/unmanaged_singleton.h>
#include <clone_session.h>
/* libc-internal includes */
#include <internal/init.h>
#include <internal/clone_session.h>
namespace Libc {

View File

@ -20,15 +20,29 @@
#include <libc-plugin/plugin.h>
/* local includes */
#include "task.h"
#include <internal/init.h>
#include <internal/resume.h>
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();
}

View File

@ -18,9 +18,19 @@
#include <sys/poll.h>
/* internal includes */
#include "libc_errno.h"
#include "libc_file.h"
#include "task.h"
#include <internal/errno.h>
#include <internal/file.h>
#include <internal/init.h>
#include <internal/suspend.h>
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);
}
}

View File

@ -12,19 +12,24 @@
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <util/list.h>
#include <libc/allocator.h>
/* libc includes */
#include <errno.h>
#include <pthread.h>
#include <stdlib.h> /* malloc, free */
#include "thread.h"
#include "task.h"
#include "timed_semaphore.h"
#include "libc_init.h"
/* libc-internal includes */
#include <internal/pthread.h>
#include <internal/timed_semaphore.h>
#include <internal/init.h>
#include <internal/suspend.h>
#include <internal/resume.h>
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();
}

View File

@ -14,12 +14,14 @@
* under the terms of the GNU Affero General Public License version 3.
*/
/* libc includes */
#include <libc/allocator.h>
#include "thread_create.h"
#include "thread.h"
#include <errno.h>
/* libc-internal includes */
#include <internal/thread_create.h>
#include <internal/pthread.h>
int Libc::pthread_create(pthread_t *thread,
void *(*start_routine) (void *), void *arg,

View File

@ -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 <base/log.h>
#include <base/exception.h>
#include <util/reconstructible.h>
/* Libc includes */
@ -32,8 +34,11 @@
#include <sys/select.h>
#include <signal.h>
#include "task.h"
/* libc-internal includes */
#include <internal/init.h>
#include <internal/suspend.h>
#include <internal/resume.h>
#include <internal/select.h>
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);

View File

@ -12,9 +12,12 @@
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
#include <base/semaphore.h>
#include <semaphore.h>
/* libc includes */
#include <libc/allocator.h>
using namespace Genode;

View File

@ -12,19 +12,31 @@
* under the terms of the GNU Affero General Public License version 3.
*/
/* Libc includes */
/* libc includes */
#include <sys/time.h>
#include "task.h"
/* libc-internal includes */
#include <internal/suspend.h>
#include <internal/init.h>
/* Genode includes */
#include <base/log.h>
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);
}

View File

@ -36,10 +36,11 @@
#include <net/if.h>
/* libc-internal includes */
#include "socket_fs_plugin.h"
#include "libc_file.h"
#include "libc_errno.h"
#include "task.h"
#include <internal/socket_fs_plugin.h>
#include <internal/file.h>
#include <internal/errno.h>
#include <internal/init.h>
#include <internal/suspend.h>
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);

View File

@ -26,8 +26,8 @@ extern "C" {
}
/* libc-internal includes */
#include "libc_file.h"
#include "socket_fs_plugin.h"
#include <internal/file.h>
#include <internal/socket_fs_plugin.h>
using namespace Libc;

View File

@ -19,15 +19,16 @@
#include <libc-plugin/plugin.h>
#include <libc-plugin/fd_alloc.h>
/* Libc includes */
/* libc includes */
#include <sys/sysctl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "libc_errno.h"
#include "libc_init.h"
/* libc-internal includes */
#include <internal/errno.h>
#include <internal/init.h>
enum { PAGESIZE = 4096 };

File diff suppressed because it is too large Load Diff

View File

@ -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 <base/duration.h>
#include <util/xml_node.h>
#include <vfs/vfs_handle.h>
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_ */

View File

@ -12,44 +12,60 @@
* under the terms of the GNU Affero General Public License version 3.
*/
/* Libc includes */
/* Genode includes */
#include <base/log.h>
#include <vfs/vfs_handle.h>
/* libc includes */
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/* libc-internal includes */
#include <internal/legacy.h>
#include <internal/errno.h>
#include <internal/init.h>
#include <internal/current_time.h>
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 &current_time, Rtc_path const &rtc_path)
{
static Rtc_path rtc_path_inst = rtc_path;
/* Genode includes */
#include <base/log.h>
#include <vfs/vfs_handle.h>
namespace Libc {
extern char const *config_rtc();
_current_time_ptr = &current_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;

View File

@ -34,12 +34,34 @@
/* libc plugin interface */
#include <libc-plugin/plugin.h>
#include <vfs_plugin.h>
/* libc-internal includes */
#include "libc_mem_alloc.h"
#include "libc_errno.h"
#include "task.h"
#include <internal/vfs_plugin.h>
#include <internal/mem_alloc.h>
#include <internal/errno.h>
#include <internal/init.h>
#include <internal/legacy.h>
#include <internal/suspend.h>
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);

View File

@ -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

View File

@ -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)

View File

@ -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 \

View File

@ -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 \

View File

@ -58,7 +58,8 @@
/* libc-internal includes */
#include <libc_mem_alloc.h>
#include <internal/mem_alloc.h>
#include <internal/legacy.h>
using Genode::log;

View File

@ -21,7 +21,7 @@
#include <qemu/usb.h>
/* libc internal includes */
#include <thread_create.h>
#include <internal/thread_create.h>
/* Virtualbox includes */
#define LOG_GROUP LOG_GROUP_DEV_EHCI

View File

@ -33,10 +33,10 @@
#include "vcpu_vmx.h"
/* libc memory allocator */
#include <libc_mem_alloc.h>
#include <internal/mem_alloc.h>
/* Genode libc pthread binding */
#include <thread_create.h>
#include <internal/thread_create.h>
/* libc */
#include <pthread.h>

View File

@ -29,7 +29,7 @@
#include "vmm.h"
/* libc memory allocator */
#include <libc_mem_alloc.h>
#include <internal/mem_alloc.h>
/* VirtualBox includes */
#include <iprt/mem.h>

View File

@ -31,7 +31,7 @@
#include <iprt/string.h>
/* libc memory allocator */
#include <libc_mem_alloc.h>
#include <internal/mem_alloc.h>
#include "util.h"
#include "mm.h"

View File

@ -41,7 +41,7 @@
#include <nic/packet_allocator.h>
#include <base/snprintf.h>
#include <thread_create.h>
#include <internal/thread_create.h>
/* VBox Genode specific */
#include "vmm.h"

View File

@ -39,7 +39,7 @@
#include "vcpu_vmx.h"
/* libc memory allocator */
#include <libc_mem_alloc.h>
#include <internal/mem_alloc.h>
/* libc */
#include <sched.h> /* sched_yield */

View File

@ -48,7 +48,7 @@
#include "sup.h"
/* Genode libc pthread binding */
#include "thread.h"
#include <internal/pthread.h>
/* LibC includes */
#include <setjmp.h>

View File

@ -18,7 +18,7 @@
#include <cpu_session/connection.h>
/* Genode libc pthread binding */
#include <thread_create.h>
#include <internal/thread_create.h>
#include "sup.h"
#include "vmm.h"

View File

@ -41,7 +41,7 @@
#include "sup.h"
/* Genode libc pthread binding */
#include "thread.h"
#include <internal/pthread.h>
#include <VBox/vmm/rem.h>