mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
parent
a891b3832c
commit
a0a112ffe7
@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
#include <base/thread.h>
|
||||
#include <base/registry.h>
|
||||
#include <base/child.h>
|
||||
@ -34,9 +33,7 @@
|
||||
/* libc-internal includes */
|
||||
#include <internal/init.h>
|
||||
#include <internal/clone_session.h>
|
||||
#include <internal/kernel_routine.h>
|
||||
#include <internal/suspend.h>
|
||||
#include <internal/resume.h>
|
||||
#include <internal/monitor.h>
|
||||
#include <internal/signal.h>
|
||||
|
||||
namespace Libc {
|
||||
@ -58,15 +55,15 @@ namespace Libc {
|
||||
|
||||
using namespace Libc;
|
||||
|
||||
namespace { using Fn = Monitor::Function_result; }
|
||||
|
||||
|
||||
static pid_t fork_result;
|
||||
|
||||
static Env *_env_ptr;
|
||||
static Allocator *_alloc_ptr;
|
||||
static Suspend *_suspend_ptr;
|
||||
static Resume *_resume_ptr;
|
||||
static Monitor *_monitor_ptr;
|
||||
static Libc::Signal *_signal_ptr;
|
||||
static Kernel_routine_scheduler *_kernel_routine_scheduler_ptr;
|
||||
static Heap *_malloc_heap_ptr;
|
||||
static void *_user_stack_base_ptr;
|
||||
static size_t _user_stack_size;
|
||||
@ -77,6 +74,15 @@ static Binary_name const *_binary_name_ptr;
|
||||
static Forked_children *_forked_children_ptr;
|
||||
|
||||
|
||||
static Libc::Monitor & monitor()
|
||||
{
|
||||
struct Missing_call_of_init_fork : Genode::Exception { };
|
||||
if (!_monitor_ptr)
|
||||
throw Missing_call_of_init_fork();
|
||||
return *_monitor_ptr;
|
||||
}
|
||||
|
||||
|
||||
struct Libc::Child_config
|
||||
{
|
||||
Constructible<Attached_ram_dataspace> _ds { };
|
||||
@ -348,44 +354,35 @@ struct Libc::Local_clone_service : Noncopyable
|
||||
|
||||
typedef Local_service<Session> Service;
|
||||
|
||||
Child_ready &_child_ready;
|
||||
|
||||
Resume &_resume;
|
||||
|
||||
Io_signal_handler<Local_clone_service> _child_ready_handler;
|
||||
|
||||
void _handle_child_ready()
|
||||
{
|
||||
_child_ready.child_ready();
|
||||
|
||||
_resume.resume_all();
|
||||
}
|
||||
|
||||
struct Factory : Local_service<Session>::Factory
|
||||
{
|
||||
Session &_session;
|
||||
Signal_context_capability _started_sigh;
|
||||
Session &_session;
|
||||
Child_ready &_child_ready;
|
||||
|
||||
Factory(Session &session, Signal_context_capability started_sigh)
|
||||
: _session(session), _started_sigh(started_sigh) { }
|
||||
Factory(Session &session, Child_ready &child_ready)
|
||||
: _session(session), _child_ready(child_ready) { }
|
||||
|
||||
Session &create(Args const &, Affinity) override { return _session; }
|
||||
|
||||
void upgrade(Session &, Args const &) override { }
|
||||
|
||||
void destroy(Session &) override { Signal_transmitter(_started_sigh).submit(); }
|
||||
void destroy(Session &) override
|
||||
{
|
||||
Mutex mutex { };
|
||||
mutex.acquire();
|
||||
|
||||
monitor().monitor(mutex, [&] {
|
||||
_child_ready.child_ready();
|
||||
return Fn::COMPLETE;
|
||||
});
|
||||
}
|
||||
|
||||
} _factory;
|
||||
|
||||
Service service { _factory };
|
||||
|
||||
Local_clone_service(Env &env, Entrypoint &ep, Child_ready &child_ready,
|
||||
Resume &resume)
|
||||
:
|
||||
_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)
|
||||
{ }
|
||||
Local_clone_service(Env &env, Entrypoint &ep, Child_ready &child_ready)
|
||||
: _session(env, ep), _factory(_session, child_ready) { }
|
||||
};
|
||||
|
||||
|
||||
@ -395,8 +392,6 @@ struct Libc::Forked_child : Child_policy, Child_ready
|
||||
|
||||
Binary_name const _binary_name;
|
||||
|
||||
Resume &_resume;
|
||||
|
||||
Signal &_signal;
|
||||
|
||||
pid_t const _pid;
|
||||
@ -408,8 +403,8 @@ struct Libc::Forked_child : Child_policy, Child_ready
|
||||
Name const _name { _pid };
|
||||
|
||||
/*
|
||||
* Signal handler triggered at the main entrypoint, waking up the libc
|
||||
* suspend mechanism.
|
||||
* Signal handler triggered at the main entrypoint, charging 'SIGCHILD'
|
||||
* and waking up the libc monitor mechanism.
|
||||
*/
|
||||
Io_signal_handler<Libc::Forked_child> _exit_handler {
|
||||
_env.ep(), *this, &Forked_child::_handle_exit };
|
||||
@ -417,7 +412,7 @@ struct Libc::Forked_child : Child_policy, Child_ready
|
||||
void _handle_exit()
|
||||
{
|
||||
_signal.charge(SIGCHLD);
|
||||
_resume.resume_all();
|
||||
monitor().trigger_monitor_examination();
|
||||
}
|
||||
|
||||
Child_config _child_config;
|
||||
@ -427,20 +422,6 @@ struct Libc::Forked_child : Child_policy, Child_ready
|
||||
Local_clone_service _local_clone_service;
|
||||
Local_rom_service _config_rom_service;
|
||||
|
||||
struct Wait_fork_ready : Kernel_routine
|
||||
{
|
||||
Forked_child const &child;
|
||||
|
||||
Wait_fork_ready(Forked_child const &child) : child(child) { }
|
||||
|
||||
void execute_in_kernel() override
|
||||
{
|
||||
/* keep executing this kernel routine until child is running */
|
||||
if (!child.running() && !child.exited())
|
||||
_kernel_routine_scheduler_ptr->register_kernel_routine(*this);
|
||||
}
|
||||
} wait_fork_ready { *this };
|
||||
|
||||
pid_t pid() const { return _pid; }
|
||||
|
||||
bool running() const { return _state == State::RUNNING; }
|
||||
@ -459,7 +440,7 @@ struct Libc::Forked_child : Child_policy, Child_ready
|
||||
/*
|
||||
* Don't modify the state if the child already exited.
|
||||
* This can happen for short-lived children where the asynchronous
|
||||
* notification for '_handle_exit' arrives before '_handle_child_ready'
|
||||
* notification for 'Child_exit' arrives before 'Child_ready'
|
||||
* (while the parent is still blocking in the fork call).
|
||||
*/
|
||||
if (_state == State::STARTING_UP)
|
||||
@ -544,6 +525,10 @@ struct Libc::Forked_child : Child_policy, Child_ready
|
||||
_exit_code = code;
|
||||
_state = State::EXITED;
|
||||
|
||||
/*
|
||||
* We can't destroy the child object in a monitor from this RPC
|
||||
* function as this would deadlock in an 'Entrypoint::dissolve()'.
|
||||
*/
|
||||
Signal_transmitter(_exit_handler).submit();
|
||||
}
|
||||
|
||||
@ -553,7 +538,6 @@ struct Libc::Forked_child : Child_policy, Child_ready
|
||||
Entrypoint &fork_ep,
|
||||
Allocator &alloc,
|
||||
Binary_name const &binary_name,
|
||||
Resume &resume,
|
||||
Signal &signal,
|
||||
pid_t pid,
|
||||
Config_accessor const &config_accessor,
|
||||
@ -561,11 +545,11 @@ struct Libc::Forked_child : Child_policy, Child_ready
|
||||
Local_rom_services &local_rom_services)
|
||||
:
|
||||
_env(env), _binary_name(binary_name),
|
||||
_resume(resume), _signal(signal), _pid(pid),
|
||||
_signal(signal), _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, resume),
|
||||
_local_clone_service(env, fork_ep, *this),
|
||||
_config_rom_service(fork_ep, "config", _child_config.ds_cap()),
|
||||
_child(env.rm(), fork_ep.rpc_ep(), *this)
|
||||
{ }
|
||||
@ -574,7 +558,7 @@ struct Libc::Forked_child : Child_policy, Child_ready
|
||||
};
|
||||
|
||||
|
||||
static void fork_kernel_routine()
|
||||
static Forked_child * fork_kernel_routine()
|
||||
{
|
||||
fork_result = 0;
|
||||
|
||||
@ -585,7 +569,6 @@ static void fork_kernel_routine()
|
||||
|
||||
Env &env = *_env_ptr;
|
||||
Allocator &alloc = *_alloc_ptr;
|
||||
Resume &resume = *_resume_ptr;
|
||||
Libc::Signal &signal = *_signal_ptr;
|
||||
|
||||
pid_t const child_pid = ++_pid_cnt;
|
||||
@ -597,15 +580,15 @@ static void fork_kernel_routine()
|
||||
|
||||
static Local_rom_services local_rom_services(env, fork_ep, alloc);
|
||||
|
||||
Registered<Forked_child> &child = *new (alloc)
|
||||
Registered<Forked_child> *child = new (alloc)
|
||||
Registered<Forked_child>(*_forked_children_ptr, env, fork_ep, alloc,
|
||||
*_binary_name_ptr, resume,
|
||||
*_binary_name_ptr,
|
||||
signal, child_pid, *_config_accessor_ptr,
|
||||
parent_services, local_rom_services);
|
||||
|
||||
fork_result = child_pid;
|
||||
|
||||
_kernel_routine_scheduler_ptr->register_kernel_routine(child.wait_fork_ready);
|
||||
return child;
|
||||
}
|
||||
|
||||
|
||||
@ -627,25 +610,28 @@ extern "C" pid_t __sys_fork(void)
|
||||
_user_stack_base_ptr = (void *)mystack.base;
|
||||
_user_stack_size = mystack.top - mystack.base;
|
||||
|
||||
struct Fork_kernel_routine : Kernel_routine
|
||||
{
|
||||
void execute_in_kernel() override { fork_kernel_routine(); }
|
||||
Mutex mutex { };
|
||||
mutex.acquire();
|
||||
|
||||
} kernel_routine { };
|
||||
enum class Stage { FORK, WAIT_FORK_READY };
|
||||
|
||||
Stage stage { Stage::FORK };
|
||||
Forked_child *child { nullptr };
|
||||
|
||||
struct Missing_call_of_init_fork : Exception { };
|
||||
if (!_kernel_routine_scheduler_ptr || !_suspend_ptr)
|
||||
throw Missing_call_of_init_fork();
|
||||
monitor().monitor(mutex, [&] {
|
||||
switch (stage) {
|
||||
case Stage::FORK:
|
||||
child = fork_kernel_routine();
|
||||
stage = Stage::WAIT_FORK_READY; [[ fallthrough ]]
|
||||
case Stage::WAIT_FORK_READY:
|
||||
if (child->running() || child->exited()) {
|
||||
return Fn::COMPLETE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_kernel_routine_scheduler_ptr->register_kernel_routine(kernel_routine);
|
||||
|
||||
struct Suspend_functor_impl : Suspend_functor
|
||||
{
|
||||
bool suspend() override { return false; }
|
||||
|
||||
} suspend_functor { };
|
||||
|
||||
_suspend_ptr->suspend(suspend_functor, 0);
|
||||
return Fn::INCOMPLETE;
|
||||
});
|
||||
|
||||
return fork_result;
|
||||
}
|
||||
@ -669,15 +655,15 @@ pid_t getpid(void) __attribute__((weak, alias("__sys_getpid")));
|
||||
** wait4 **
|
||||
***********/
|
||||
|
||||
namespace Libc { struct Wait4_suspend_functor; }
|
||||
namespace Libc { struct Wait4_functor; }
|
||||
|
||||
struct Libc::Wait4_suspend_functor : Suspend_functor
|
||||
struct Libc::Wait4_functor
|
||||
{
|
||||
Forked_children &_children;
|
||||
|
||||
pid_t const _pid;
|
||||
|
||||
Wait4_suspend_functor(pid_t pid, Forked_children &children)
|
||||
Wait4_functor(pid_t pid, Forked_children &children)
|
||||
: _children(children), _pid(pid) { }
|
||||
|
||||
template <typename FN>
|
||||
@ -700,14 +686,6 @@ struct Libc::Wait4_suspend_functor : Suspend_functor
|
||||
fn(*child_ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool suspend() override
|
||||
{
|
||||
bool const any_child_exited =
|
||||
with_exited_child([] (Forked_child const &) { });
|
||||
|
||||
return !any_child_exited;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -724,25 +702,23 @@ extern "C" pid_t __sys_wait4(pid_t pid, int *status, int options, rusage *rusage
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct Missing_call_of_init_fork : Exception { };
|
||||
if (!_suspend_ptr)
|
||||
throw Missing_call_of_init_fork();
|
||||
Wait4_functor functor { pid, *_forked_children_ptr };
|
||||
|
||||
Wait4_suspend_functor suspend_functor { pid, *_forked_children_ptr };
|
||||
Mutex mutex { };
|
||||
mutex.acquire();
|
||||
|
||||
for (;;) {
|
||||
|
||||
suspend_functor.with_exited_child([&] (Registered<Forked_child> &child) {
|
||||
monitor().monitor(mutex, [&] {
|
||||
functor.with_exited_child([&] (Registered<Forked_child> &child) {
|
||||
result = child.pid();
|
||||
exit_code = child.exit_code();
|
||||
destroy(*_alloc_ptr, &child);
|
||||
});
|
||||
|
||||
if (result >= 0 || (options & WNOHANG))
|
||||
break;
|
||||
return Fn::COMPLETE;
|
||||
|
||||
_suspend_ptr->suspend(suspend_functor, 0);
|
||||
}
|
||||
return Fn::INCOMPLETE;
|
||||
});
|
||||
|
||||
/*
|
||||
* The libc expects status information in bits 0..6 and the exit value
|
||||
@ -761,16 +737,13 @@ extern "C" pid_t wait4(pid_t, int *, int, rusage *) __attribute__((weak, alias("
|
||||
|
||||
void Libc::init_fork(Env &env, Config_accessor const &config_accessor,
|
||||
Allocator &alloc, Heap &malloc_heap, pid_t pid,
|
||||
Suspend &suspend, Resume &resume, Signal &signal,
|
||||
Kernel_routine_scheduler &kernel_routine_scheduler,
|
||||
Monitor &monitor, Signal &signal,
|
||||
Binary_name const &binary_name)
|
||||
{
|
||||
_env_ptr = &env;
|
||||
_alloc_ptr = &alloc;
|
||||
_suspend_ptr = &suspend;
|
||||
_resume_ptr = &resume;
|
||||
_monitor_ptr = &monitor;
|
||||
_signal_ptr = &signal;
|
||||
_kernel_routine_scheduler_ptr = &kernel_routine_scheduler;
|
||||
_malloc_heap_ptr = &malloc_heap;
|
||||
_config_accessor_ptr = &config_accessor;
|
||||
_pid = pid;
|
||||
|
@ -35,7 +35,6 @@ namespace Libc {
|
||||
struct Current_time;
|
||||
struct Current_real_time;
|
||||
struct Clone_connection;
|
||||
struct Kernel_routine_scheduler;
|
||||
struct Watch;
|
||||
struct Signal;
|
||||
struct File_descriptor_allocator;
|
||||
@ -126,8 +125,7 @@ namespace Libc {
|
||||
*/
|
||||
void init_fork(Genode::Env &, Config_accessor const &,
|
||||
Genode::Allocator &heap, Heap &malloc_heap, int pid,
|
||||
Suspend &, Resume &, Signal &, Kernel_routine_scheduler &,
|
||||
Binary_name const &);
|
||||
Monitor &, Signal &, Binary_name const &);
|
||||
|
||||
struct Reset_malloc_heap : Interface
|
||||
{
|
||||
|
@ -34,7 +34,6 @@
|
||||
#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>
|
||||
#include <internal/watch.h>
|
||||
@ -108,7 +107,6 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
Suspend,
|
||||
Monitor,
|
||||
Select,
|
||||
Kernel_routine_scheduler,
|
||||
Current_time,
|
||||
Current_real_time,
|
||||
Watch,
|
||||
@ -236,8 +234,6 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
|
||||
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 };
|
||||
@ -356,7 +352,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!check.suspend() && !_kernel_routine)
|
||||
if (!check.suspend())
|
||||
return timeout_ms;
|
||||
|
||||
if (timeout_ms > 0)
|
||||
@ -425,6 +421,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
/* _setjmp() returned directly -> switch to user stack and call application code */
|
||||
|
||||
if (_cloned) {
|
||||
_main_monitor_job->complete();
|
||||
_switch_to_user();
|
||||
} else {
|
||||
_state = USER;
|
||||
@ -438,22 +435,6 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
|
||||
while ((!_app_returned)) {
|
||||
|
||||
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 (_kernel_routine) {
|
||||
_env.ep().wait_and_dispatch_one_io_signal();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch all pending I/O signals at once and execute
|
||||
* monitors that may now become able to complete.
|
||||
@ -521,7 +502,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
/*
|
||||
* Return to the application
|
||||
*/
|
||||
if (!_kernel_routine && _resume_main_once && !_setjmp(_kernel_context)) {
|
||||
if (_resume_main_once && !_setjmp(_kernel_context)) {
|
||||
_switch_to_user();
|
||||
}
|
||||
}
|
||||
@ -701,14 +682,6 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
|
||||
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 **
|
||||
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* \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_ */
|
@ -348,6 +348,7 @@ void Libc::Kernel::_clone_state_from_parent()
|
||||
|
||||
/* fetch user contex of the parent's application */
|
||||
_clone_connection->memory_content(&_user_context, sizeof(_user_context));
|
||||
_clone_connection->memory_content(&_main_monitor_job, sizeof(_main_monitor_job));
|
||||
_valid_user_context = true;
|
||||
|
||||
_libc_env.libc_config().for_each_sub_node([&] (Xml_node node) {
|
||||
@ -466,8 +467,8 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap)
|
||||
init_malloc(*_malloc_heap);
|
||||
}
|
||||
|
||||
init_fork(_env, _libc_env, _heap, *_malloc_heap, _pid, *this, *this, _signal,
|
||||
*this, _binary_name);
|
||||
init_fork(_env, _libc_env, _heap, *_malloc_heap, _pid, *this, _signal,
|
||||
_binary_name);
|
||||
init_execve(_env, _heap, _user_stack, *this, _binary_name,
|
||||
*file_descriptor_allocator());
|
||||
init_plugin(*this);
|
||||
|
Loading…
Reference in New Issue
Block a user