2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Noux child process
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2011-02-17
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2011-2017 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _NOUX__CHILD_H_
|
|
|
|
#define _NOUX__CHILD_H_
|
|
|
|
|
|
|
|
/* Genode includes */
|
2017-01-06 12:12:39 +01:00
|
|
|
#include <base/attached_ram_dataspace.h>
|
|
|
|
#include <base/attached_rom_dataspace.h>
|
|
|
|
#include <vfs/dir_file_system.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/* Noux includes */
|
|
|
|
#include <file_descriptor_registry.h>
|
|
|
|
#include <noux_session/capability.h>
|
|
|
|
#include <args.h>
|
|
|
|
#include <environment.h>
|
2012-02-22 22:24:32 +01:00
|
|
|
#include <cpu_session_component.h>
|
2016-04-15 15:19:22 +02:00
|
|
|
#include <pd_session_component.h>
|
2012-02-25 20:41:59 +01:00
|
|
|
#include <child_policy.h>
|
2012-10-24 18:31:24 +02:00
|
|
|
#include <io_receptor_registry.h>
|
2013-01-03 15:52:27 +01:00
|
|
|
#include <destruct_queue.h>
|
2013-10-17 12:48:45 +02:00
|
|
|
#include <interrupt_handler.h>
|
2014-01-23 17:21:35 +01:00
|
|
|
#include <kill_broadcaster.h>
|
|
|
|
#include <parent_execve.h>
|
2017-01-31 18:03:11 +01:00
|
|
|
#include <empty_rom_service.h>
|
2013-07-18 16:27:42 +02:00
|
|
|
#include <local_rom_service.h>
|
2017-01-06 12:12:39 +01:00
|
|
|
#include <verbose.h>
|
|
|
|
#include <user_info.h>
|
2019-01-18 15:18:03 +01:00
|
|
|
#include <armed_timeout.h>
|
2019-04-09 17:52:44 +02:00
|
|
|
#include <time_info.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
namespace Noux {
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
class Pid_allocator;
|
2012-08-20 18:24:11 +02:00
|
|
|
|
2012-10-24 18:31:24 +02:00
|
|
|
/**
|
|
|
|
* Return singleton instance of Io_receptor_registry
|
|
|
|
*/
|
|
|
|
Io_receptor_registry *io_receptor_registry();
|
|
|
|
|
2014-01-23 17:21:35 +01:00
|
|
|
/*
|
|
|
|
* Return lock for protecting the signal queue
|
|
|
|
*/
|
|
|
|
Genode::Lock &signal_lock();
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
class Child_config;
|
2011-12-22 16:19:25 +01:00
|
|
|
class Child;
|
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
/**
|
|
|
|
* Return true is child is the init process
|
|
|
|
*/
|
|
|
|
bool init_process(Child *child);
|
2015-07-19 21:38:02 +02:00
|
|
|
void init_process_exited(int);
|
2017-01-06 12:12:39 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-05-23 14:08:39 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Allocator for process IDs
|
|
|
|
*/
|
|
|
|
class Noux::Pid_allocator
|
|
|
|
{
|
|
|
|
private:
|
2016-05-23 14:08:39 +02:00
|
|
|
|
2019-01-18 16:18:19 +01:00
|
|
|
Lock _lock { };
|
|
|
|
int _num_pids { 0 };
|
2017-01-06 12:12:39 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
int alloc()
|
|
|
|
{
|
|
|
|
Lock::Guard guard(_lock);
|
|
|
|
return _num_pids++;
|
2016-05-23 14:08:39 +02:00
|
|
|
}
|
2017-01-06 12:12:39 +01:00
|
|
|
};
|
|
|
|
|
2016-05-23 14:08:39 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
struct Noux::Child_config : Attached_ram_dataspace
|
|
|
|
{
|
|
|
|
enum { CONFIG_DS_SIZE = 4096 };
|
|
|
|
|
2017-05-11 20:03:28 +02:00
|
|
|
Child_config(Ram_allocator &ram, Region_map &local_rm, Verbose const &verbose)
|
2017-01-06 12:12:39 +01:00
|
|
|
:
|
|
|
|
Attached_ram_dataspace(ram, local_rm, CONFIG_DS_SIZE)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2017-01-06 12:12:39 +01:00
|
|
|
Xml_generator xml(local_addr<char>(), CONFIG_DS_SIZE, "config", [&] ()
|
|
|
|
{
|
|
|
|
if (verbose.ld())
|
|
|
|
xml.attribute("ld_verbose", "yes");
|
2019-08-13 14:28:34 +02:00
|
|
|
|
|
|
|
xml.node("ld", [&] () {
|
|
|
|
xml.node("library", [&] () {
|
|
|
|
xml.attribute("rom", "libc_noux.lib.so"); }); });
|
2017-01-06 12:12:39 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-23 17:07:49 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
class Noux::Child : public Rpc_object<Session>,
|
|
|
|
public File_descriptor_registry,
|
|
|
|
public Family_member,
|
|
|
|
public Destruct_queue::Element<Child>,
|
|
|
|
public Interrupt_handler
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2019-01-18 16:18:19 +01:00
|
|
|
/*
|
|
|
|
* Noncopyable
|
|
|
|
*/
|
|
|
|
Child(Child const &);
|
|
|
|
Child &operator = (Child const &);
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Child_policy::Name const _name;
|
|
|
|
|
|
|
|
Verbose const &_verbose;
|
|
|
|
|
|
|
|
User_info const &_user_info;
|
|
|
|
|
2019-04-09 17:52:44 +02:00
|
|
|
Time_info const &_time_info;
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Parent_exit *_parent_exit;
|
|
|
|
Kill_broadcaster &_kill_broadcaster;
|
2019-01-18 15:18:03 +01:00
|
|
|
Timer::Connection &_timer_connection;
|
2017-01-06 12:12:39 +01:00
|
|
|
Parent_execve &_parent_execve;
|
|
|
|
Pid_allocator &_pid_allocator;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Env &_env;
|
2016-11-23 17:07:49 +01:00
|
|
|
|
2018-04-03 15:59:35 +02:00
|
|
|
Vfs::File_system &_root_dir;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
Vfs_io_waiter_registry &_vfs_io_waiter_registry;
|
2019-01-18 16:18:19 +01:00
|
|
|
Vfs_handle_context _vfs_handle_context { };
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Destruct_queue &_destruct_queue;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
void _handle_destruct() { _destruct_queue.insert(this); }
|
2012-02-15 22:44:05 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Signal_handler<Child> _destruct_handler {
|
|
|
|
_env.ep(), *this, &Child::_handle_destruct };
|
2016-11-23 17:07:49 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Allocator &_heap;
|
2012-02-15 22:44:05 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Entrypoint used to serve the RPC interfaces of the
|
|
|
|
* locally-provided services
|
|
|
|
*/
|
2019-02-07 15:46:58 +01:00
|
|
|
enum { STACK_SIZE = 64*1024 };
|
2017-01-06 12:12:39 +01:00
|
|
|
Rpc_entrypoint _ep { &_env.pd(), STACK_SIZE, "noux_process", false };
|
2016-04-20 21:12:57 +02:00
|
|
|
|
Capability quota accounting and trading
This patch mirrors the accounting and trading scheme that Genode employs
for physical memory to the accounting of capability allocations.
Capability quotas must now be explicitly assigned to subsystems by
specifying a 'caps=<amount>' attribute to init's start nodes.
Analogously to RAM quotas, cap quotas can be traded between clients and
servers as part of the session protocol. The capability budget of each
component is maintained by the component's corresponding PD session at
core.
At the current stage, the accounting is applied to RPC capabilities,
signal-context capabilities, and dataspace capabilities. Capabilities
that are dynamically allocated via core's CPU and TRACE service are not
yet covered. Also, the capabilities allocated by resource multiplexers
outside of core (like nitpicker) must be accounted by the respective
servers, which is not covered yet.
If a component runs out of capabilities, core's PD service prints a
warning to the log. To observe the consumption of capabilities per
component in detail, the PD service is equipped with a diagnostic
mode, which can be enabled via the 'diag' attribute in the target
node of init's routing rules. E.g., the following route enables the
diagnostic mode for the PD session of the "timer" component:
<default-route>
<service name="PD" unscoped_label="timer">
<parent diag="yes"/>
</service>
...
</default-route>
For subsystems based on a sub-init instance, init can be configured
to report the capability-quota information of its subsystems by
adding the attribute 'child_caps="yes"' to init's '<report>'
config node. Init's own capability quota can be reported by adding
the attribute 'init_caps="yes"'.
Fixes #2398
2017-05-08 21:35:43 +02:00
|
|
|
Pd_session &_ref_pd;
|
|
|
|
Pd_session_capability const _ref_pd_cap;
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Registry of dataspaces owned by the Noux process
|
|
|
|
*/
|
|
|
|
Dataspace_registry _ds_registry { _heap };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Locally-provided PD service
|
|
|
|
*/
|
|
|
|
typedef Local_service<Pd_session_component> Pd_service;
|
|
|
|
Pd_session_component _pd { _heap, _env, _ep, _name, _ds_registry };
|
|
|
|
Pd_service::Single_session_factory _pd_factory { _pd };
|
|
|
|
Pd_service _pd_service { _pd_factory };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Locally-provided CPU service
|
|
|
|
*/
|
|
|
|
typedef Local_service<Cpu_session_component> Cpu_service;
|
|
|
|
Cpu_session_component _cpu { _env, _ep, _name, false, _ds_registry };
|
|
|
|
Cpu_service::Single_session_factory _cpu_factory { _cpu };
|
|
|
|
Cpu_service _cpu_service { _cpu_factory };
|
2016-05-10 18:05:38 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/*
|
|
|
|
* Locally-provided Noux service
|
|
|
|
*/
|
2017-05-11 20:03:28 +02:00
|
|
|
Capability_guard _cap_guard { _ep, *this };
|
2016-04-15 15:19:22 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
typedef Local_service<Rpc_object<Session> > Noux_service;
|
|
|
|
Noux_service::Single_session_factory _noux_factory { *this };
|
|
|
|
Noux_service _noux_service { _noux_factory };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/*
|
|
|
|
* Locally-provided ROM service
|
|
|
|
*/
|
2017-01-31 18:03:11 +01:00
|
|
|
Empty_rom_factory _empty_rom_factory { _heap, _ep };
|
|
|
|
Empty_rom_service _empty_rom_service { _empty_rom_factory };
|
2017-08-15 20:51:53 +02:00
|
|
|
Local_rom_factory _rom_factory { _heap, _env, _ep, _root_dir,
|
|
|
|
_vfs_io_waiter_registry, _ds_registry };
|
2017-01-06 12:12:39 +01:00
|
|
|
Local_rom_service _rom_service { _rom_factory };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Command line arguments
|
|
|
|
*/
|
2019-02-07 15:46:58 +01:00
|
|
|
enum { ARGS_DS_SIZE = sizeof(Sysio::Args) };
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Args_dataspace _args;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Environment variables
|
|
|
|
*/
|
|
|
|
Environment _sysio_env;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/*
|
|
|
|
* Child configuration
|
|
|
|
*/
|
2017-05-11 20:03:28 +02:00
|
|
|
Child_config _config { _ref_pd, _env.rm(), _verbose };
|
2017-01-06 12:12:39 +01:00
|
|
|
|
|
|
|
enum { PAGE_SIZE = 4096, PAGE_MASK = ~(PAGE_SIZE - 1) };
|
|
|
|
enum { SYSIO_DS_SIZE = PAGE_MASK & (sizeof(Sysio) + PAGE_SIZE - 1) };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-05-11 20:03:28 +02:00
|
|
|
Attached_ram_dataspace _sysio_ds { _ref_pd, _env.rm(), SYSIO_DS_SIZE };
|
2017-01-06 12:12:39 +01:00
|
|
|
Sysio &_sysio = *_sysio_ds.local_addr<Sysio>();
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
typedef Ring_buffer<enum Sysio::Signal, Sysio::SIGNAL_QUEUE_SIZE>
|
|
|
|
Signal_queue;
|
2019-01-18 16:18:19 +01:00
|
|
|
Signal_queue _pending_signals { };
|
2017-01-06 12:12:39 +01:00
|
|
|
|
|
|
|
Parent_services &_parent_services;
|
|
|
|
|
|
|
|
Static_dataspace_info _sysio_ds_info;
|
|
|
|
Static_dataspace_info _args_ds_info;
|
|
|
|
Static_dataspace_info _sysio_env_ds_info;
|
|
|
|
Static_dataspace_info _config_ds_info;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Child_policy _child_policy;
|
|
|
|
|
|
|
|
Genode::Child _child;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Exception type for failed file-descriptor lookup
|
|
|
|
*/
|
|
|
|
class Invalid_fd { };
|
|
|
|
|
|
|
|
Shared_pointer<Io_channel> _lookup_channel(int fd) const
|
|
|
|
{
|
|
|
|
Shared_pointer<Io_channel> channel = io_channel_by_fd(fd);
|
2013-07-18 16:27:42 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
if (channel)
|
|
|
|
return channel;
|
2013-07-18 16:27:42 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
throw Invalid_fd();
|
|
|
|
}
|
2012-02-18 01:46:54 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Let specified child inherit our file descriptors
|
|
|
|
*/
|
2018-01-30 16:39:41 +01:00
|
|
|
void _assign_io_channels_to(Child *child, bool skip_when_close_on_execve_set)
|
2017-01-06 12:12:39 +01:00
|
|
|
{
|
|
|
|
for (int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++)
|
2018-01-30 16:39:41 +01:00
|
|
|
if (fd_in_use(fd)) {
|
|
|
|
if (skip_when_close_on_execve_set && close_fd_on_execve(fd))
|
|
|
|
continue;
|
2017-01-06 12:12:39 +01:00
|
|
|
child->add_io_channel(io_channel_by_fd(fd), fd);
|
2018-01-30 16:39:41 +01:00
|
|
|
child->close_fd_on_execve(fd, close_fd_on_execve(fd));
|
|
|
|
}
|
2017-01-06 12:12:39 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Block until the IO channel is ready for reading or writing or an
|
|
|
|
* exception occured.
|
|
|
|
*
|
|
|
|
* \param io the IO channel
|
|
|
|
* \param rd check for data available for reading
|
|
|
|
* \param wr check for readiness for writing
|
|
|
|
* \param ex check for exceptions
|
|
|
|
*/
|
|
|
|
void _block_for_io_channel(Shared_pointer<Io_channel> &io,
|
|
|
|
bool rd, bool wr, bool ex)
|
|
|
|
{
|
|
|
|
/* reset the blocker lock to the 'locked' state */
|
|
|
|
_blocker.unlock();
|
|
|
|
_blocker.lock();
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Wake_up_notifier notifier(&_blocker);
|
|
|
|
io->register_wake_up_notifier(¬ifier);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
for (;;) {
|
|
|
|
if (io->check_unblock(rd, wr, ex) ||
|
|
|
|
!_pending_signals.empty())
|
|
|
|
break;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/* block (unless the lock got unlocked in the meantime) */
|
|
|
|
_blocker.lock();
|
2012-02-18 01:46:54 +01:00
|
|
|
}
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
io->unregister_wake_up_notifier(¬ifier);
|
|
|
|
}
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
void _destruct()
|
|
|
|
{
|
|
|
|
_ep.dissolve(this);
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
if (init_process(this))
|
|
|
|
init_process_exited(_child_policy.exit_value());
|
|
|
|
}
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
public:
|
|
|
|
|
|
|
|
struct Insufficient_memory : Exception { };
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* \param forked false if the child is spawned directly from
|
|
|
|
* an executable binary (i.e., the init process,
|
|
|
|
* or children created via execve, or
|
|
|
|
* true if the child is a fork from another child
|
|
|
|
*
|
|
|
|
* \throw Insufficent_memory if the child could not be started by
|
|
|
|
* the parent
|
|
|
|
*/
|
|
|
|
Child(Child_policy::Name const &name,
|
|
|
|
Verbose const &verbose,
|
|
|
|
User_info const &user_info,
|
2019-04-09 17:52:44 +02:00
|
|
|
Time_info const &time_info,
|
2017-01-06 12:12:39 +01:00
|
|
|
Parent_exit *parent_exit,
|
|
|
|
Kill_broadcaster &kill_broadcaster,
|
2019-01-18 15:18:03 +01:00
|
|
|
Timer::Connection &timer_connection,
|
2017-01-06 12:12:39 +01:00
|
|
|
Parent_execve &parent_execve,
|
|
|
|
Pid_allocator &pid_allocator,
|
|
|
|
int pid,
|
|
|
|
Env &env,
|
2018-04-03 15:59:35 +02:00
|
|
|
Vfs::File_system &root_dir,
|
2017-08-15 20:51:53 +02:00
|
|
|
Vfs_io_waiter_registry &vfs_io_waiter_registry,
|
2017-01-06 12:12:39 +01:00
|
|
|
Args const &args,
|
|
|
|
Sysio::Env const &sysio_env,
|
|
|
|
Allocator &heap,
|
Capability quota accounting and trading
This patch mirrors the accounting and trading scheme that Genode employs
for physical memory to the accounting of capability allocations.
Capability quotas must now be explicitly assigned to subsystems by
specifying a 'caps=<amount>' attribute to init's start nodes.
Analogously to RAM quotas, cap quotas can be traded between clients and
servers as part of the session protocol. The capability budget of each
component is maintained by the component's corresponding PD session at
core.
At the current stage, the accounting is applied to RPC capabilities,
signal-context capabilities, and dataspace capabilities. Capabilities
that are dynamically allocated via core's CPU and TRACE service are not
yet covered. Also, the capabilities allocated by resource multiplexers
outside of core (like nitpicker) must be accounted by the respective
servers, which is not covered yet.
If a component runs out of capabilities, core's PD service prints a
warning to the log. To observe the consumption of capabilities per
component in detail, the PD service is equipped with a diagnostic
mode, which can be enabled via the 'diag' attribute in the target
node of init's routing rules. E.g., the following route enables the
diagnostic mode for the PD session of the "timer" component:
<default-route>
<service name="PD" unscoped_label="timer">
<parent diag="yes"/>
</service>
...
</default-route>
For subsystems based on a sub-init instance, init can be configured
to report the capability-quota information of its subsystems by
adding the attribute 'child_caps="yes"' to init's '<report>'
config node. Init's own capability quota can be reported by adding
the attribute 'init_caps="yes"'.
Fixes #2398
2017-05-08 21:35:43 +02:00
|
|
|
Pd_session &ref_pd,
|
|
|
|
Pd_session_capability ref_pd_cap,
|
2017-01-06 12:12:39 +01:00
|
|
|
Parent_services &parent_services,
|
|
|
|
bool forked,
|
|
|
|
Destruct_queue &destruct_queue)
|
|
|
|
:
|
|
|
|
Family_member(pid),
|
|
|
|
Destruct_queue::Element<Child>(heap),
|
|
|
|
_name(name),
|
|
|
|
_verbose(verbose),
|
|
|
|
_user_info(user_info),
|
2019-04-09 17:52:44 +02:00
|
|
|
_time_info(time_info),
|
2017-01-06 12:12:39 +01:00
|
|
|
_parent_exit(parent_exit),
|
|
|
|
_kill_broadcaster(kill_broadcaster),
|
2019-01-18 15:18:03 +01:00
|
|
|
_timer_connection(timer_connection),
|
2017-01-06 12:12:39 +01:00
|
|
|
_parent_execve(parent_execve),
|
|
|
|
_pid_allocator(pid_allocator),
|
|
|
|
_env(env),
|
|
|
|
_root_dir(root_dir),
|
2017-08-15 20:51:53 +02:00
|
|
|
_vfs_io_waiter_registry(vfs_io_waiter_registry),
|
2017-01-06 12:12:39 +01:00
|
|
|
_destruct_queue(destruct_queue),
|
|
|
|
_heap(heap),
|
2017-05-11 20:03:28 +02:00
|
|
|
_ref_pd (ref_pd), _ref_pd_cap (ref_pd_cap),
|
|
|
|
_args(ref_pd, _env.rm(), ARGS_DS_SIZE, args),
|
|
|
|
_sysio_env(_ref_pd, _env.rm(), sysio_env),
|
2017-01-06 12:12:39 +01:00
|
|
|
_parent_services(parent_services),
|
|
|
|
_sysio_ds_info(_ds_registry, _sysio_ds.cap()),
|
|
|
|
_args_ds_info(_ds_registry, _args.cap()),
|
|
|
|
_sysio_env_ds_info(_ds_registry, _sysio_env.cap()),
|
|
|
|
_config_ds_info(_ds_registry, _config.cap()),
|
2017-01-31 18:03:11 +01:00
|
|
|
_child_policy(name, forked,
|
2017-01-06 12:12:39 +01:00
|
|
|
_args.cap(), _sysio_env.cap(), _config.cap(),
|
2017-05-11 20:03:28 +02:00
|
|
|
_ep, _pd_service, _cpu_service,
|
2017-01-31 18:03:11 +01:00
|
|
|
_noux_service, _empty_rom_service,
|
|
|
|
_rom_service, _parent_services,
|
2017-01-06 12:12:39 +01:00
|
|
|
*this, parent_exit, *this, _destruct_handler,
|
2017-05-11 20:03:28 +02:00
|
|
|
ref_pd, ref_pd_cap,
|
Capability quota accounting and trading
This patch mirrors the accounting and trading scheme that Genode employs
for physical memory to the accounting of capability allocations.
Capability quotas must now be explicitly assigned to subsystems by
specifying a 'caps=<amount>' attribute to init's start nodes.
Analogously to RAM quotas, cap quotas can be traded between clients and
servers as part of the session protocol. The capability budget of each
component is maintained by the component's corresponding PD session at
core.
At the current stage, the accounting is applied to RPC capabilities,
signal-context capabilities, and dataspace capabilities. Capabilities
that are dynamically allocated via core's CPU and TRACE service are not
yet covered. Also, the capabilities allocated by resource multiplexers
outside of core (like nitpicker) must be accounted by the respective
servers, which is not covered yet.
If a component runs out of capabilities, core's PD service prints a
warning to the log. To observe the consumption of capabilities per
component in detail, the PD service is equipped with a diagnostic
mode, which can be enabled via the 'diag' attribute in the target
node of init's routing rules. E.g., the following route enables the
diagnostic mode for the PD session of the "timer" component:
<default-route>
<service name="PD" unscoped_label="timer">
<parent diag="yes"/>
</service>
...
</default-route>
For subsystems based on a sub-init instance, init can be configured
to report the capability-quota information of its subsystems by
adding the attribute 'child_caps="yes"' to init's '<report>'
config node. Init's own capability quota can be reported by adding
the attribute 'init_caps="yes"'.
Fixes #2398
2017-05-08 21:35:43 +02:00
|
|
|
_verbose.enabled()),
|
2017-01-06 12:12:39 +01:00
|
|
|
_child(_env.rm(), _ep, _child_policy)
|
|
|
|
{
|
|
|
|
if (_verbose.enabled())
|
|
|
|
_args.dump();
|
2012-03-19 22:52:26 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
if (!_child.main_thread_cap().valid()) {
|
|
|
|
_destruct();
|
|
|
|
throw Insufficient_memory();
|
|
|
|
}
|
|
|
|
}
|
2012-05-24 17:06:54 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
~Child() { _destruct(); }
|
2015-09-28 12:36:50 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
void start() { _ep.activate(); }
|
2015-09-28 12:36:50 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
void start_forked_main_thread(addr_t ip, addr_t sp, addr_t parent_cap_addr)
|
|
|
|
{
|
|
|
|
/* poke parent_cap_addr into child's address space */
|
|
|
|
Capability<Parent>::Raw const raw = _child.parent_cap().raw();
|
2015-09-28 12:36:50 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
_pd.poke(_env.rm(), parent_cap_addr, (char *)&raw, sizeof(raw));
|
2015-09-28 12:36:50 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/* start execution of new main thread at supplied trampoline */
|
|
|
|
_cpu.start_main_thread(ip, sp);
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
void submit_exit_signal()
|
|
|
|
{
|
|
|
|
if (init_process(this)) {
|
|
|
|
log("init process exited");
|
2012-05-18 17:10:54 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/* trigger exit of main event loop */
|
|
|
|
init_process_exited(_child_policy.exit_value());
|
|
|
|
} else {
|
|
|
|
Signal_transmitter(_destruct_handler).submit();
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2017-01-06 12:12:39 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-05-11 20:03:28 +02:00
|
|
|
Pd_session_component &pd() { return _pd; }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Dataspace_registry &ds_registry() { return _ds_registry; }
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-04-15 15:19:22 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/****************************
|
|
|
|
** Noux session interface **
|
|
|
|
****************************/
|
2012-02-22 12:45:13 +01:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
Dataspace_capability sysio_dataspace() override
|
2017-01-06 12:12:39 +01:00
|
|
|
{
|
|
|
|
return _sysio_ds.cap();
|
|
|
|
}
|
2013-01-03 15:52:27 +01:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
Capability<Region_map> lookup_region_map(addr_t const addr) override
|
2017-01-06 12:12:39 +01:00
|
|
|
{
|
|
|
|
return _pd.lookup_region_map(addr);
|
|
|
|
}
|
2012-03-19 22:52:26 +01:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
bool syscall(Syscall sc) override;
|
2016-11-23 17:07:49 +01:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
int next_open_fd(int start_fd) override
|
2017-01-06 12:12:39 +01:00
|
|
|
{
|
|
|
|
if (start_fd >= 0)
|
|
|
|
for (int fd = start_fd; fd < MAX_FILE_DESCRIPTORS; fd++)
|
|
|
|
if (fd_in_use(fd))
|
|
|
|
return fd;
|
|
|
|
return -1;
|
|
|
|
}
|
2012-02-22 12:45:13 +01:00
|
|
|
|
2012-02-18 01:46:54 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/****************************************
|
|
|
|
** File_descriptor_registry overrides **
|
|
|
|
****************************************/
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/**
|
|
|
|
* Find out if the IO channel associated with 'fd' has more file
|
|
|
|
* descriptors associated with it
|
|
|
|
*/
|
|
|
|
bool _is_the_only_fd_for_io_channel(int fd,
|
|
|
|
Shared_pointer<Io_channel> io_channel)
|
|
|
|
{
|
|
|
|
for (int f = 0; f < MAX_FILE_DESCRIPTORS; f++) {
|
|
|
|
if ((f != fd) &&
|
|
|
|
fd_in_use(f) &&
|
|
|
|
(io_channel_by_fd(f) == io_channel))
|
|
|
|
return false;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
return true;
|
|
|
|
}
|
2014-01-28 14:07:36 +01:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
int add_io_channel(Shared_pointer<Io_channel> io_channel, int fd = -1) override
|
2017-01-06 12:12:39 +01:00
|
|
|
{
|
|
|
|
fd = File_descriptor_registry::add_io_channel(io_channel, fd);
|
2013-09-06 21:10:23 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/* Register the interrupt handler only once per IO channel */
|
|
|
|
if (_is_the_only_fd_for_io_channel(fd, io_channel)) {
|
|
|
|
Io_channel_listener *l = new (_heap) Io_channel_listener(this);
|
|
|
|
io_channel->register_interrupt_handler(l);
|
2013-09-06 21:10:23 +02:00
|
|
|
}
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
return fd;
|
|
|
|
}
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
void remove_io_channel(int fd) override
|
2017-01-06 12:12:39 +01:00
|
|
|
{
|
|
|
|
Shared_pointer<Io_channel> io_channel = _lookup_channel(fd);
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/*
|
|
|
|
* Unregister the interrupt handler only if there are no other
|
|
|
|
* file descriptors associated with the IO channel.
|
2013-10-17 12:48:45 +02:00
|
|
|
*/
|
2017-01-06 12:12:39 +01:00
|
|
|
if (_is_the_only_fd_for_io_channel(fd, io_channel)) {
|
|
|
|
Io_channel_listener *l = io_channel->lookup_io_channel_listener(this);
|
|
|
|
io_channel->unregister_interrupt_handler(l);
|
|
|
|
Genode::destroy(_heap, l);
|
2013-10-17 12:48:45 +02:00
|
|
|
}
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
File_descriptor_registry::remove_io_channel(fd);
|
|
|
|
}
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
void flush() override
|
2017-01-06 12:12:39 +01:00
|
|
|
{
|
|
|
|
for (int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++)
|
|
|
|
try {
|
|
|
|
remove_io_channel(fd);
|
|
|
|
} catch (Invalid_fd) { }
|
|
|
|
}
|
2013-10-17 12:48:45 +02:00
|
|
|
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/*****************************
|
|
|
|
** Family_member interface **
|
|
|
|
*****************************/
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
void submit_signal(Noux::Sysio::Signal sig) override
|
2017-01-06 12:12:39 +01:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
_pending_signals.add(sig);
|
|
|
|
} catch (Signal_queue::Overflow) {
|
|
|
|
error("signal queue is full - signal dropped");
|
2013-10-17 12:48:45 +02:00
|
|
|
}
|
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
_blocker.unlock();
|
|
|
|
}
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
Family_member *do_execve(const char *filename,
|
|
|
|
Args const &args,
|
|
|
|
Sysio::Env const &env) override
|
|
|
|
{
|
|
|
|
Lock::Guard signal_lock_guard(signal_lock());
|
|
|
|
|
|
|
|
Child *child = new (_heap) Child(filename,
|
|
|
|
_verbose,
|
|
|
|
_user_info,
|
2019-04-09 17:52:44 +02:00
|
|
|
_time_info,
|
2017-01-06 12:12:39 +01:00
|
|
|
_parent_exit,
|
|
|
|
_kill_broadcaster,
|
2019-01-18 15:18:03 +01:00
|
|
|
_timer_connection,
|
2017-01-06 12:12:39 +01:00
|
|
|
_parent_execve,
|
|
|
|
_pid_allocator,
|
|
|
|
pid(),
|
|
|
|
_env,
|
|
|
|
_root_dir,
|
2017-08-15 20:51:53 +02:00
|
|
|
_vfs_io_waiter_registry,
|
2017-01-06 12:12:39 +01:00
|
|
|
args,
|
|
|
|
env,
|
|
|
|
_heap,
|
2017-05-11 20:03:28 +02:00
|
|
|
_ref_pd, _ref_pd_cap,
|
2017-01-06 12:12:39 +01:00
|
|
|
_parent_services,
|
|
|
|
false,
|
|
|
|
_destruct_queue);
|
|
|
|
|
2018-01-30 16:39:41 +01:00
|
|
|
_assign_io_channels_to(child, true);
|
2017-01-06 12:12:39 +01:00
|
|
|
|
|
|
|
/* move the signal queue */
|
|
|
|
while (!_pending_signals.empty())
|
|
|
|
child->_pending_signals.add(_pending_signals.get());
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/*
|
|
|
|
* Close all open files.
|
|
|
|
*
|
|
|
|
* This action is not part of the child destructor,
|
|
|
|
* because in the case that a child exits itself,
|
|
|
|
* it may need to close all files to unblock the
|
|
|
|
* parent (which might be reading from a pipe) before
|
|
|
|
* the parent can destroy the child object.
|
|
|
|
*/
|
|
|
|
flush();
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/* signal main thread to remove ourself */
|
|
|
|
Signal_transmitter(_destruct_handler).submit();
|
2013-10-17 12:48:45 +02:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/* start executing the new process */
|
|
|
|
child->start();
|
2014-01-23 17:21:35 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/* this child will be removed by the execve_finalization_dispatcher */
|
2014-01-23 17:21:35 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
return child;
|
|
|
|
}
|
2014-01-23 17:21:35 +01:00
|
|
|
|
2018-02-07 17:49:57 +01:00
|
|
|
|
2017-01-06 12:12:39 +01:00
|
|
|
/*********************************
|
|
|
|
** Interrupt_handler interface **
|
|
|
|
*********************************/
|
|
|
|
|
2019-02-14 22:39:08 +01:00
|
|
|
void handle_interrupt(Sysio::Signal signal) override
|
2017-01-06 12:12:39 +01:00
|
|
|
{
|
2018-02-07 17:49:57 +01:00
|
|
|
submit_signal(signal);
|
2017-01-06 12:12:39 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* _NOUX__CHILD_H_ */
|