mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 22:23:16 +00:00
New sandbox library extracted from init component
This patch extracts the child-management functionality from the init component into a new library called "sandbox". The library API is located at 'os/include/os/sandbox.h'. The sandbox API allows for the interaction of the component with the sandboxed children by providing locally implemented services. This mechanism is illustrated by the new test at os/src/test/sandbox. Issue #3601
This commit is contained in:
parent
f82e7df0ba
commit
78c0e5f6b6
260
repos/os/include/os/sandbox.h
Normal file
260
repos/os/include/os/sandbox.h
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* \brief Sandbox library interface
|
||||
* \author Norman Feske
|
||||
* \date 2020-01-09
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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 _INCLUDE__OS__SANDBOX_H_
|
||||
#define _INCLUDE__OS__SANDBOX_H_
|
||||
|
||||
#include <util/xml_node.h>
|
||||
#include <util/noncopyable.h>
|
||||
#include <base/registry.h>
|
||||
#include <base/service.h>
|
||||
#include <base/heap.h>
|
||||
|
||||
namespace Genode { class Sandbox; }
|
||||
|
||||
|
||||
class Genode::Sandbox : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
class Local_service_base;
|
||||
|
||||
template <typename>
|
||||
class Local_service;
|
||||
|
||||
private:
|
||||
|
||||
friend class Local_service_base;
|
||||
|
||||
Heap _heap;
|
||||
|
||||
class Library;
|
||||
|
||||
Library &_library;
|
||||
|
||||
Registry<Local_service_base> _local_services { };
|
||||
|
||||
public:
|
||||
|
||||
Sandbox(Env &env);
|
||||
|
||||
void apply_config(Xml_node const &);
|
||||
};
|
||||
|
||||
|
||||
class Genode::Sandbox::Local_service_base : public Service
|
||||
{
|
||||
public:
|
||||
|
||||
struct Wakeup : Interface, Noncopyable
|
||||
{
|
||||
virtual void wakeup_local_service() = 0;
|
||||
};
|
||||
|
||||
bool abandoned() const { return false; }
|
||||
|
||||
enum class Upgrade_response { CONFIRMED, DEFERRED };
|
||||
|
||||
enum class Close_response { CLOSED, DEFERRED };
|
||||
|
||||
class Request : Interface, Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
Session *_session_ptr = nullptr;
|
||||
Capability<Session> _session_cap { };
|
||||
|
||||
bool _denied = false;
|
||||
|
||||
friend class Local_service_base;
|
||||
|
||||
Request(Session_state const &session)
|
||||
:
|
||||
resources(session_resources_from_args(session.args().string())),
|
||||
label(session.label()),
|
||||
diag(session_diag_from_args(session.args().string()))
|
||||
{ }
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Request(Request const &);
|
||||
void operator = (Request const &);
|
||||
|
||||
public:
|
||||
|
||||
Session::Resources const resources;
|
||||
Session::Label const label;
|
||||
Session::Diag const diag;
|
||||
|
||||
template <typename ST>
|
||||
void deliver_session(ST &session)
|
||||
{
|
||||
_session_ptr = &session;
|
||||
_session_cap = session.cap();
|
||||
}
|
||||
|
||||
void deny() { _denied = false; }
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Registry<Local_service_base>::Element _element;
|
||||
|
||||
Session_state::Factory _session_factory;
|
||||
|
||||
/**
|
||||
* Async_service::Wakeup interface
|
||||
*/
|
||||
struct Async_wakeup : Async_service::Wakeup
|
||||
{
|
||||
Local_service_base::Wakeup &_wakeup;
|
||||
|
||||
Async_wakeup(Local_service_base::Wakeup &wakeup) : _wakeup(wakeup) { }
|
||||
|
||||
void wakeup_async_service() override
|
||||
{
|
||||
_wakeup.wakeup_local_service();
|
||||
}
|
||||
} _async_wakeup;
|
||||
|
||||
Async_service _async_service;
|
||||
|
||||
/**
|
||||
* Service interface
|
||||
*/
|
||||
void initiate_request(Session_state &session) override
|
||||
{
|
||||
_async_service.initiate_request(session);
|
||||
}
|
||||
|
||||
void wakeup() override { _async_service.wakeup(); }
|
||||
|
||||
protected:
|
||||
|
||||
using Resources = Session::Resources;
|
||||
|
||||
struct Request_fn : Interface
|
||||
{
|
||||
virtual void with_requested_session(Request &) = 0;
|
||||
};
|
||||
|
||||
void _for_each_requested_session(Request_fn &);
|
||||
|
||||
struct Upgrade_fn : Interface
|
||||
{
|
||||
virtual Upgrade_response with_upgraded_session(Session &, Resources) = 0;
|
||||
};
|
||||
|
||||
void _for_each_upgraded_session(Upgrade_fn &);
|
||||
|
||||
struct Close_fn : Interface
|
||||
{
|
||||
virtual Close_response close_session(Session &) = 0;
|
||||
};
|
||||
|
||||
void _for_each_session_to_close(Close_fn &);
|
||||
|
||||
Id_space<Parent::Server> _server_id_space { };
|
||||
|
||||
Local_service_base(Sandbox &, Service::Name const &, Wakeup &);
|
||||
};
|
||||
|
||||
|
||||
template <typename ST>
|
||||
struct Genode::Sandbox::Local_service : private Local_service_base
|
||||
{
|
||||
Local_service(Sandbox &sandbox, Wakeup &wakeup)
|
||||
: Local_service_base(sandbox, ST::service_name(), wakeup) { }
|
||||
|
||||
using Upgrade_response = Local_service_base::Upgrade_response;
|
||||
using Close_response = Local_service_base::Close_response;
|
||||
using Request = Local_service_base::Request;
|
||||
|
||||
/**
|
||||
* Call functor 'fn' for each session requested by the sandbox
|
||||
*
|
||||
* The functor is called with a 'Request &' as argument. The 'Request'
|
||||
* provides the caller with information about the requested session
|
||||
* ('resources', 'label', 'diag') and allows the caller to respond
|
||||
* to the session request ('deliver_session', 'deny').
|
||||
*/
|
||||
template <typename FN>
|
||||
void for_each_requested_session(FN const &fn)
|
||||
{
|
||||
struct Untyped_fn : Local_service_base::Request_fn
|
||||
{
|
||||
FN const &_fn;
|
||||
Untyped_fn(FN const &fn) : _fn(fn) { }
|
||||
|
||||
void with_requested_session(Request &request) override
|
||||
{
|
||||
_fn(request);
|
||||
}
|
||||
} untyped_fn(fn);
|
||||
|
||||
_for_each_requested_session(untyped_fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call functor 'fn' for each session that received a quota upgrade
|
||||
*
|
||||
* The functor is called with a reference to the session object (type
|
||||
* 'ST') and a 'Session::Resources' object as arguments. The latter
|
||||
* contains the amount of additional resources provided by the client.
|
||||
*
|
||||
* The functor must return an 'Upgrade_response'.
|
||||
*/
|
||||
template <typename FN>
|
||||
void for_each_upgraded_session(FN const &fn)
|
||||
{
|
||||
struct Untyped_fn : Local_service_base::Upgrade_fn
|
||||
{
|
||||
FN const &_fn;
|
||||
Untyped_fn(FN const &fn) : _fn(fn) { }
|
||||
|
||||
Upgrade_response with_upgraded_session(Session &session,
|
||||
Resources resources) override
|
||||
{
|
||||
return _fn(static_cast<ST &>(session), resources);
|
||||
}
|
||||
} untyped_fn(fn);
|
||||
|
||||
_for_each_upgraded_session(untyped_fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call functor 'fn' for each session to close
|
||||
*
|
||||
* The functor is called with a reference to the session object (type
|
||||
* 'ST') as argument and must return a 'Close_response'.
|
||||
*/
|
||||
template <typename FN>
|
||||
void for_each_session_to_close(FN const &fn)
|
||||
{
|
||||
struct Untyped_fn : Local_service_base::Close_fn
|
||||
{
|
||||
FN const &_fn;
|
||||
Untyped_fn(FN const &fn) : _fn(fn) { }
|
||||
|
||||
Close_response close_session(Session &session) override
|
||||
{
|
||||
return _fn(static_cast<ST &>(session));
|
||||
}
|
||||
} untyped_fn(fn);
|
||||
|
||||
_for_each_session_to_close(untyped_fn);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__OS__SANDBOX_H_ */
|
7
repos/os/lib/mk/sandbox.mk
Normal file
7
repos/os/lib/mk/sandbox.mk
Normal file
@ -0,0 +1,7 @@
|
||||
SRC_CC = library.cc child.cc server.cc
|
||||
INC_DIR += $(REP_DIR)/src/lib/sandbox
|
||||
LIBS += base
|
||||
|
||||
SHARED_LIB = yes
|
||||
|
||||
vpath %.cc $(REP_DIR)/src/lib/sandbox
|
@ -1,2 +1,8 @@
|
||||
SRC_DIR = src/init
|
||||
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
|
||||
|
||||
MIRROR_FROM_REP_DIR += src/lib/sandbox
|
||||
content: $(MIRROR_FROM_REP_DIR)
|
||||
|
||||
$(MIRROR_FROM_REP_DIR):
|
||||
$(mirror_from_rep_dir)
|
||||
|
13
repos/os/recipes/src/sandbox/content.mk
Normal file
13
repos/os/recipes/src/sandbox/content.mk
Normal file
@ -0,0 +1,13 @@
|
||||
SRC_DIR = src/lib/sandbox
|
||||
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
|
||||
|
||||
MIRROR_FROM_REP_DIR += lib/mk/sandbox.mk
|
||||
content: $(MIRROR_FROM_REP_DIR)
|
||||
|
||||
$(MIRROR_FROM_REP_DIR):
|
||||
$(mirror_from_rep_dir)
|
||||
|
||||
content: src/lib/sandbox/target.mk
|
||||
|
||||
src/lib/sandbox/target.mk:
|
||||
echo "LIBS += sandbox" > $@
|
1
repos/os/recipes/src/sandbox/hash
Normal file
1
repos/os/recipes/src/sandbox/hash
Normal file
@ -0,0 +1 @@
|
||||
2020-01-12 0ad1e14e664613b8ef9057c1fc91fed5f17d8a74
|
3
repos/os/recipes/src/sandbox/used_apis
Normal file
3
repos/os/recipes/src/sandbox/used_apis
Normal file
@ -0,0 +1,3 @@
|
||||
base
|
||||
os
|
||||
report_session
|
27
repos/os/run/sandbox.run
Normal file
27
repos/os/run/sandbox.run
Normal file
@ -0,0 +1,27 @@
|
||||
build "core init test/sandbox app/dummy"
|
||||
|
||||
create_boot_directory
|
||||
|
||||
install_config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="CPU"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> </any-service>
|
||||
</default-route>
|
||||
<default caps="500"/>
|
||||
<start name="test-sandbox">
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
||||
build_boot_image { core ld.lib.so init test-sandbox sandbox.lib.so dummy }
|
||||
|
||||
append qemu_args " -nographic "
|
||||
|
||||
run_genode_until "child \"dummy\" exited with exit value 0.*\n" 20
|
@ -1,82 +0,0 @@
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<start name="timer">
|
||||
<binary name="timer"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
<route>
|
||||
<service name="IO_PORT"> <parent/> </service>
|
||||
<service name="IRQ"> <parent/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="fb_sdl">
|
||||
<binary name="fb_sdl"/>
|
||||
<resource name="RAM" quantum="3M"/>
|
||||
<provides>
|
||||
<service name="Framebuffer"/>
|
||||
<service name="Input"/>
|
||||
</provides>
|
||||
<route>
|
||||
<service name="LOG"><parent/></service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="nitpicker">
|
||||
<binary name="nitpicker"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="Framebuffer"> <child name="fb_sdl"/> </service>
|
||||
<service name="Input"> <child name="fb_sdl"/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="liquid_fb">
|
||||
<binary name="liquid_fb"/>
|
||||
<resource name="RAM" quantum="6M"/>
|
||||
<provides>
|
||||
<service name="Framebuffer"/>
|
||||
<service name="Input"/>
|
||||
</provides>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="nested_nitpicker">
|
||||
<binary name="nitpicker"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="Framebuffer"> <child name="liquid_fb"/> </service>
|
||||
<service name="Input"> <child name="liquid_fb"/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="launchpad">
|
||||
<binary name="launchpad"/>
|
||||
<resource name="RAM" quantum="32M"/>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="Nitpicker"> <child name="nested_nitpicker"/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<service name="ROM"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
</route>
|
||||
</start>
|
||||
</config>
|
||||
|
||||
<!-- vim:set syntax=xml:-->
|
@ -1,67 +0,0 @@
|
||||
<config prio_levels="4" verbose="yes">
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="fb_sdl">
|
||||
<resource name="RAM" quantum="3M"/>
|
||||
<provides>
|
||||
<service name="Framebuffer"/>
|
||||
<service name="Input"/>
|
||||
</provides>
|
||||
</start>
|
||||
<start name="nitpicker">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<route>
|
||||
<any-service>
|
||||
<parent/> <child name="fb_sdl"/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="liquid_fb">
|
||||
<resource name="RAM" quantum="6M"/>
|
||||
<provides>
|
||||
<service name="Framebuffer"/>
|
||||
<service name="Input"/>
|
||||
</provides>
|
||||
<route>
|
||||
<any-service>
|
||||
<parent/> <child name="nitpicker"/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="nested_nitpicker">
|
||||
<binary name="nitpicker"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<route>
|
||||
<any-service>
|
||||
<parent/> <child name="liquid_fb"/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="launchpad" priority="-1">
|
||||
<resource name="RAM" quantum="32M"/>
|
||||
<route>
|
||||
<any-service>
|
||||
<parent/> <child name="nested_nitpicker"/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>
|
||||
|
||||
<!-- vim:set syntax=xml:-->
|
@ -14,149 +14,38 @@
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <os/sandbox.h>
|
||||
|
||||
/* local includes */
|
||||
#include <child.h>
|
||||
#include <alias.h>
|
||||
#include <server.h>
|
||||
#include <heartbeat.h>
|
||||
namespace Init {
|
||||
|
||||
namespace Init { struct Main; }
|
||||
using namespace Genode;
|
||||
|
||||
struct Main;
|
||||
}
|
||||
|
||||
|
||||
struct Init::Main : State_reporter::Producer,
|
||||
Child::Default_route_accessor, Child::Default_caps_accessor,
|
||||
Child::Ram_limit_accessor, Child::Cap_limit_accessor
|
||||
struct Init::Main
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
Registry<Init::Parent_service> _parent_services { };
|
||||
Registry<Routed_service> _child_services { };
|
||||
Child_registry _children { };
|
||||
|
||||
Heap _heap { _env.ram(), _env.rm() };
|
||||
Sandbox _sandbox { _env };
|
||||
|
||||
Attached_rom_dataspace _config { _env, "config" };
|
||||
|
||||
Xml_node _config_xml = _config.xml();
|
||||
|
||||
Reconstructible<Verbose> _verbose { _config_xml };
|
||||
|
||||
Constructible<Buffered_xml> _default_route { };
|
||||
|
||||
Cap_quota _default_caps { 0 };
|
||||
|
||||
unsigned _child_cnt = 0;
|
||||
|
||||
static Ram_quota _preserved_ram_from_config(Xml_node config)
|
||||
{
|
||||
Number_of_bytes preserve { 40*sizeof(long)*1024 };
|
||||
|
||||
config.for_each_sub_node("resource", [&] (Xml_node node) {
|
||||
if (node.attribute_value("name", String<16>()) == "RAM")
|
||||
preserve = node.attribute_value("preserve", preserve); });
|
||||
|
||||
return Ram_quota { preserve };
|
||||
}
|
||||
|
||||
Ram_quota _avail_ram() const
|
||||
{
|
||||
Ram_quota const preserved_ram = _preserved_ram_from_config(_config_xml);
|
||||
|
||||
Ram_quota avail_ram = _env.pd().avail_ram();
|
||||
|
||||
if (preserved_ram.value > avail_ram.value) {
|
||||
error("RAM preservation exceeds available memory");
|
||||
return Ram_quota { 0 };
|
||||
}
|
||||
|
||||
/* deduce preserved quota from available quota */
|
||||
return Ram_quota { avail_ram.value - preserved_ram.value };
|
||||
}
|
||||
|
||||
static Cap_quota _preserved_caps_from_config(Xml_node config)
|
||||
{
|
||||
size_t preserve = 20;
|
||||
|
||||
config.for_each_sub_node("resource", [&] (Xml_node node) {
|
||||
if (node.attribute_value("name", String<16>()) == "CAP")
|
||||
preserve = node.attribute_value("preserve", preserve); });
|
||||
|
||||
return Cap_quota { preserve };
|
||||
}
|
||||
|
||||
Cap_quota _avail_caps() const
|
||||
{
|
||||
Cap_quota const preserved_caps = _preserved_caps_from_config(_config_xml);
|
||||
|
||||
Cap_quota avail_caps { _env.pd().avail_caps().value };
|
||||
|
||||
if (preserved_caps.value > avail_caps.value) {
|
||||
error("Capability preservation exceeds available capabilities");
|
||||
return Cap_quota { 0 };
|
||||
}
|
||||
|
||||
/* deduce preserved quota from available quota */
|
||||
return Cap_quota { avail_caps.value - preserved_caps.value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Child::Ram_limit_accessor interface
|
||||
*/
|
||||
Ram_quota resource_limit(Ram_quota const &) const override { return _avail_ram(); }
|
||||
|
||||
/**
|
||||
* Child::Cap_limit_accessor interface
|
||||
*/
|
||||
Cap_quota resource_limit(Cap_quota const &) const override { return _avail_caps(); }
|
||||
|
||||
void _handle_resource_avail() { }
|
||||
|
||||
void produce_state_report(Xml_generator &xml, Report_detail const &detail) const override
|
||||
{
|
||||
if (detail.init_ram())
|
||||
xml.node("ram", [&] () { generate_ram_info (xml, _env.pd()); });
|
||||
|
||||
if (detail.init_caps())
|
||||
xml.node("caps", [&] () { generate_caps_info(xml, _env.pd()); });
|
||||
|
||||
if (detail.children())
|
||||
_children.report_state(xml, detail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default_route_accessor interface
|
||||
*/
|
||||
Xml_node default_route() override
|
||||
{
|
||||
return _default_route.constructed() ? _default_route->xml()
|
||||
: Xml_node("<empty/>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Default_caps_accessor interface
|
||||
*/
|
||||
Cap_quota default_caps() override { return _default_caps; }
|
||||
|
||||
State_reporter _state_reporter { _env, *this };
|
||||
|
||||
Heartbeat _heartbeat { _env, _children, _state_reporter };
|
||||
|
||||
Signal_handler<Main> _resource_avail_handler {
|
||||
_env.ep(), *this, &Main::_handle_resource_avail };
|
||||
|
||||
void _update_aliases_from_config();
|
||||
void _update_parent_services_from_config();
|
||||
void _abandon_obsolete_children();
|
||||
void _update_children_config();
|
||||
void _destroy_abandoned_parent_services();
|
||||
void _handle_config();
|
||||
void _handle_config()
|
||||
{
|
||||
_config.update();
|
||||
_sandbox.apply_config(_config.xml());
|
||||
}
|
||||
|
||||
Signal_handler<Main> _config_handler {
|
||||
_env.ep(), *this, &Main::_handle_config };
|
||||
|
||||
Server _server { _env, _heap, _child_services, _state_reporter };
|
||||
|
||||
Main(Env &env) : _env(env)
|
||||
{
|
||||
_config.sigh(_config_handler);
|
||||
@ -169,312 +58,5 @@ struct Init::Main : State_reporter::Producer,
|
||||
};
|
||||
|
||||
|
||||
void Init::Main::_update_parent_services_from_config()
|
||||
{
|
||||
Xml_node const node = _config_xml.has_sub_node("parent-provides")
|
||||
? _config_xml.sub_node("parent-provides")
|
||||
: Xml_node("<empty/>");
|
||||
|
||||
/* remove services that are no longer present in config */
|
||||
_parent_services.for_each([&] (Parent_service &service) {
|
||||
|
||||
Service::Name const name = service.name();
|
||||
|
||||
bool obsolete = true;
|
||||
node.for_each_sub_node("service", [&] (Xml_node service) {
|
||||
if (name == service.attribute_value("name", Service::Name())) {
|
||||
obsolete = false; }});
|
||||
|
||||
if (obsolete)
|
||||
service.abandon();
|
||||
});
|
||||
|
||||
/* used to prepend the list of new parent services with title */
|
||||
bool first_log = true;
|
||||
|
||||
/* register new services */
|
||||
node.for_each_sub_node("service", [&] (Xml_node service) {
|
||||
|
||||
Service::Name const name = service.attribute_value("name", Service::Name());
|
||||
|
||||
bool registered = false;
|
||||
_parent_services.for_each([&] (Parent_service const &service) {
|
||||
if (service.name() == name)
|
||||
registered = true; });
|
||||
|
||||
if (!registered) {
|
||||
new (_heap) Init::Parent_service(_parent_services, _env, name);
|
||||
if (_verbose->enabled()) {
|
||||
if (first_log)
|
||||
log("parent provides");
|
||||
log(" service \"", name, "\"");
|
||||
first_log = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Init::Main::_destroy_abandoned_parent_services()
|
||||
{
|
||||
_parent_services.for_each([&] (Parent_service &service) {
|
||||
if (service.abandoned())
|
||||
destroy(_heap, &service); });
|
||||
}
|
||||
|
||||
|
||||
void Init::Main::_update_aliases_from_config()
|
||||
{
|
||||
/* remove all known aliases */
|
||||
while (_children.any_alias()) {
|
||||
Init::Alias *alias = _children.any_alias();
|
||||
_children.remove_alias(alias);
|
||||
destroy(_heap, alias);
|
||||
}
|
||||
|
||||
/* create aliases */
|
||||
_config_xml.for_each_sub_node("alias", [&] (Xml_node alias_node) {
|
||||
|
||||
try {
|
||||
_children.insert_alias(new (_heap) Alias(alias_node)); }
|
||||
catch (Alias::Name_is_missing) {
|
||||
warning("missing 'name' attribute in '<alias>' entry"); }
|
||||
catch (Alias::Child_is_missing) {
|
||||
warning("missing 'child' attribute in '<alias>' entry"); }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Init::Main::_abandon_obsolete_children()
|
||||
{
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
|
||||
bool obsolete = true;
|
||||
_config_xml.for_each_sub_node("start", [&] (Xml_node node) {
|
||||
if (child.has_name (node.attribute_value("name", Child_policy::Name()))
|
||||
&& child.has_version(node.attribute_value("version", Child::Version())))
|
||||
obsolete = false; });
|
||||
|
||||
if (obsolete)
|
||||
child.abandon();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Init::Main::_update_children_config()
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
/*
|
||||
* Children are abandoned if any of their client sessions can no longer
|
||||
* be routed or result in a different route. As each child may be a
|
||||
* service, an avalanche effect may occur. It stops if no update causes
|
||||
* a potential side effect in one iteration over all chilren.
|
||||
*/
|
||||
bool side_effects = false;
|
||||
|
||||
_config_xml.for_each_sub_node("start", [&] (Xml_node node) {
|
||||
|
||||
Child_policy::Name const start_node_name =
|
||||
node.attribute_value("name", Child_policy::Name());
|
||||
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
if (!child.abandoned() && child.name() == start_node_name) {
|
||||
switch (child.apply_config(node)) {
|
||||
case Child::NO_SIDE_EFFECTS: break;
|
||||
case Child::MAY_HAVE_SIDE_EFFECTS: side_effects = true; break;
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!side_effects)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Init::Main::_handle_config()
|
||||
{
|
||||
bool update_state_report = false;
|
||||
|
||||
_config.update();
|
||||
|
||||
_config_xml = _config.xml();
|
||||
|
||||
_verbose.construct(_config_xml);
|
||||
_state_reporter.apply_config(_config_xml);
|
||||
_heartbeat.apply_config(_config_xml);
|
||||
|
||||
/* determine default route for resolving service requests */
|
||||
try {
|
||||
_default_route.construct(_heap, _config_xml.sub_node("default-route")); }
|
||||
catch (...) { }
|
||||
|
||||
_default_caps = Cap_quota { 0 };
|
||||
try {
|
||||
_default_caps = Cap_quota { _config_xml.sub_node("default")
|
||||
.attribute_value("caps", 0UL) }; }
|
||||
catch (...) { }
|
||||
|
||||
Prio_levels const prio_levels = prio_levels_from_xml(_config_xml);
|
||||
Affinity::Space const affinity_space = affinity_space_from_xml(_config_xml);
|
||||
bool const space_defined = _config_xml.has_sub_node("affinity-space");
|
||||
|
||||
_update_aliases_from_config();
|
||||
_update_parent_services_from_config();
|
||||
_abandon_obsolete_children();
|
||||
_update_children_config();
|
||||
|
||||
/* kill abandoned children */
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
|
||||
if (!child.abandoned())
|
||||
return;
|
||||
|
||||
/* make the child's services unavailable */
|
||||
child.destroy_services();
|
||||
child.close_all_sessions();
|
||||
update_state_report = true;
|
||||
|
||||
/* destroy child once all environment sessions are gone */
|
||||
if (child.env_sessions_closed()) {
|
||||
_children.remove(&child);
|
||||
destroy(_heap, &child);
|
||||
}
|
||||
});
|
||||
|
||||
_destroy_abandoned_parent_services();
|
||||
|
||||
/* initial RAM and caps limit before starting new children */
|
||||
Ram_quota const avail_ram = _avail_ram();
|
||||
Cap_quota const avail_caps = _avail_caps();
|
||||
|
||||
/* variable used to track the RAM and caps taken by new started children */
|
||||
Ram_quota used_ram { 0 };
|
||||
Cap_quota used_caps { 0 };
|
||||
|
||||
/* create new children */
|
||||
try {
|
||||
_config_xml.for_each_sub_node("start", [&] (Xml_node start_node) {
|
||||
|
||||
bool exists = false;
|
||||
|
||||
unsigned num_abandoned = 0;
|
||||
|
||||
Child_policy::Name const child_name(start_node.attribute_value("name", Child_policy::Name()));
|
||||
|
||||
_children.for_each_child([&] (Child const &child) {
|
||||
if (child.name() == child_name) {
|
||||
if (child.abandoned())
|
||||
num_abandoned++;
|
||||
else
|
||||
exists = true;
|
||||
}
|
||||
});
|
||||
|
||||
/* skip start node if corresponding child already exists */
|
||||
if (exists)
|
||||
return;
|
||||
|
||||
/* prevent queuing up abandoned children with the same name */
|
||||
if (num_abandoned > 1)
|
||||
return;
|
||||
|
||||
if (used_ram.value > avail_ram.value) {
|
||||
error("RAM exhausted while starting child: ", child_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (used_caps.value > avail_caps.value) {
|
||||
error("capabilities exhausted while starting child: ", child_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!space_defined && start_node.has_sub_node("affinity")) {
|
||||
warning("affinity-space configuration missing, "
|
||||
"but affinity defined for child: ", child_name);
|
||||
}
|
||||
|
||||
try {
|
||||
Init::Child &child = *new (_heap)
|
||||
Init::Child(_env, _heap, *_verbose,
|
||||
Init::Child::Id { ++_child_cnt }, _state_reporter,
|
||||
start_node, *this, *this, _children,
|
||||
Ram_quota { avail_ram.value - used_ram.value },
|
||||
Cap_quota { avail_caps.value - used_caps.value },
|
||||
*this, *this, prio_levels, affinity_space,
|
||||
_parent_services, _child_services);
|
||||
_children.insert(&child);
|
||||
|
||||
update_state_report = true;
|
||||
|
||||
/* account for the start XML node buffered in the child */
|
||||
size_t const metadata_overhead = start_node.size()
|
||||
+ sizeof(Init::Child);
|
||||
/* track used memory and RAM limit */
|
||||
used_ram = Ram_quota { used_ram.value
|
||||
+ child.ram_quota().value
|
||||
+ metadata_overhead };
|
||||
|
||||
used_caps = Cap_quota { used_caps.value
|
||||
+ child.cap_quota().value };
|
||||
}
|
||||
catch (Rom_connection::Rom_connection_failed) {
|
||||
/*
|
||||
* The binary does not exist. An error message is printed
|
||||
* by the Rom_connection constructor.
|
||||
*/
|
||||
}
|
||||
catch (Out_of_ram) {
|
||||
warning("memory exhausted during child creation"); }
|
||||
catch (Out_of_caps) {
|
||||
warning("local capabilities exhausted during child creation"); }
|
||||
catch (Child::Missing_name_attribute) {
|
||||
warning("skipped startup of nameless child"); }
|
||||
catch (Region_map::Region_conflict) {
|
||||
warning("failed to attach dataspace to local address space "
|
||||
"during child construction"); }
|
||||
catch (Region_map::Invalid_dataspace) {
|
||||
warning("attempt to attach invalid dataspace to local address space "
|
||||
"during child construction"); }
|
||||
catch (Service_denied) {
|
||||
warning("failed to create session during child construction"); }
|
||||
});
|
||||
}
|
||||
catch (Xml_node::Nonexistent_sub_node) { error("no children to start"); }
|
||||
catch (Xml_node::Invalid_syntax) { error("config has invalid syntax"); }
|
||||
catch (Init::Child_registry::Alias_name_is_not_unique) { }
|
||||
|
||||
/*
|
||||
* Initiate RAM sessions of all new children
|
||||
*/
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
if (!child.abandoned())
|
||||
child.initiate_env_pd_session(); });
|
||||
|
||||
/*
|
||||
* Initiate remaining environment sessions of all new children
|
||||
*/
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
if (!child.abandoned())
|
||||
child.initiate_env_sessions(); });
|
||||
|
||||
/*
|
||||
* (Re-)distribute RAM and capability quota among the children, given their
|
||||
* resource assignments and the available slack memory. We first apply
|
||||
* possible downgrades to free as much resources as we can. These resources
|
||||
* are then incorporated in the subsequent upgrade step.
|
||||
*/
|
||||
_children.for_each_child([&] (Child &child) { child.apply_downgrade(); });
|
||||
_children.for_each_child([&] (Child &child) { child.apply_upgrade(); });
|
||||
|
||||
_server.apply_config(_config_xml);
|
||||
|
||||
if (update_state_report)
|
||||
_state_reporter.trigger_immediate_report_update();
|
||||
}
|
||||
|
||||
|
||||
void Component::construct(Genode::Env &env) { static Init::Main main(env); }
|
||||
|
||||
|
@ -1,6 +1,11 @@
|
||||
TARGET = init
|
||||
SRC_CC = main.cc child.cc server.cc
|
||||
SRC_CC = main.cc
|
||||
LIBS = base
|
||||
INC_DIR += $(PRG_DIR)
|
||||
|
||||
CONFIG_XSD = config.xsd
|
||||
|
||||
# statically link sandbox library to avoid dependency from sandbox.lib.so
|
||||
SRC_CC += library.cc child.cc server.cc
|
||||
INC_DIR += $(REP_DIR)/src/lib/sandbox
|
||||
vpath %.cc $(REP_DIR)/src/lib/sandbox
|
||||
|
@ -11,15 +11,15 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__ALIAS_H_
|
||||
#define _SRC__INIT__ALIAS_H_
|
||||
#ifndef _LIB__SANDBOX__ALIAS_H_
|
||||
#define _LIB__SANDBOX__ALIAS_H_
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
|
||||
namespace Init { struct Alias; }
|
||||
namespace Sandbox { struct Alias; }
|
||||
|
||||
struct Init::Alias : List<Alias>::Element
|
||||
struct Sandbox::Alias : List<Alias>::Element
|
||||
{
|
||||
typedef String<128> Name;
|
||||
typedef String<128> Child;
|
||||
@ -50,4 +50,4 @@ struct Init::Alias : List<Alias>::Element
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__ALIAS_H_ */
|
||||
#endif /* _LIB__SANDBOX__ALIAS_H_ */
|
@ -17,7 +17,7 @@
|
||||
#include <child.h>
|
||||
|
||||
|
||||
void Init::Child::destroy_services()
|
||||
void Sandbox::Child::destroy_services()
|
||||
{
|
||||
_child_services.for_each([&] (Routed_service &service) {
|
||||
if (service.has_id_space(_session_requester.id_space()))
|
||||
@ -25,8 +25,8 @@ void Init::Child::destroy_services()
|
||||
}
|
||||
|
||||
|
||||
Init::Child::Apply_config_result
|
||||
Init::Child::apply_config(Xml_node start_node)
|
||||
Sandbox::Child::Apply_config_result
|
||||
Sandbox::Child::apply_config(Xml_node start_node)
|
||||
{
|
||||
if (_state == STATE_ABANDONED || _exited)
|
||||
return NO_SIDE_EFFECTS;
|
||||
@ -166,7 +166,7 @@ Init::Child::apply_config(Xml_node start_node)
|
||||
}
|
||||
|
||||
|
||||
Init::Ram_quota Init::Child::_configured_ram_quota() const
|
||||
Sandbox::Ram_quota Sandbox::Child::_configured_ram_quota() const
|
||||
{
|
||||
size_t assigned = 0;
|
||||
|
||||
@ -178,7 +178,7 @@ Init::Ram_quota Init::Child::_configured_ram_quota() const
|
||||
}
|
||||
|
||||
|
||||
Init::Cap_quota Init::Child::_configured_cap_quota() const
|
||||
Sandbox::Cap_quota Sandbox::Child::_configured_cap_quota() const
|
||||
{
|
||||
size_t const default_caps = _default_caps_accessor.default_caps().value;
|
||||
|
||||
@ -187,8 +187,8 @@ Init::Cap_quota Init::Child::_configured_cap_quota() const
|
||||
|
||||
|
||||
template <typename QUOTA, typename LIMIT_ACCESSOR>
|
||||
void Init::Child::_apply_resource_upgrade(QUOTA &assigned, QUOTA const configured,
|
||||
LIMIT_ACCESSOR const &limit_accessor)
|
||||
void Sandbox::Child::_apply_resource_upgrade(QUOTA &assigned, QUOTA const configured,
|
||||
LIMIT_ACCESSOR const &limit_accessor)
|
||||
{
|
||||
if (configured.value <= assigned.value)
|
||||
return;
|
||||
@ -230,7 +230,7 @@ void Init::Child::_apply_resource_upgrade(QUOTA &assigned, QUOTA const configure
|
||||
}
|
||||
|
||||
|
||||
void Init::Child::apply_upgrade()
|
||||
void Sandbox::Child::apply_upgrade()
|
||||
{
|
||||
/* pd_session_cap of exited child is invalid and unusable for transfers */
|
||||
if (_exited)
|
||||
@ -251,9 +251,9 @@ void Init::Child::apply_upgrade()
|
||||
|
||||
|
||||
template <typename QUOTA, typename CHILD_AVAIL_QUOTA_FN>
|
||||
void Init::Child::_apply_resource_downgrade(QUOTA &assigned, QUOTA const configured,
|
||||
QUOTA const preserved,
|
||||
CHILD_AVAIL_QUOTA_FN const &child_avail_quota_fn)
|
||||
void Sandbox::Child::_apply_resource_downgrade(QUOTA &assigned, QUOTA const configured,
|
||||
QUOTA const preserved,
|
||||
CHILD_AVAIL_QUOTA_FN const &child_avail_quota_fn)
|
||||
{
|
||||
if (configured.value >= assigned.value)
|
||||
return;
|
||||
@ -287,7 +287,7 @@ void Init::Child::_apply_resource_downgrade(QUOTA &assigned, QUOTA const configu
|
||||
}
|
||||
|
||||
|
||||
void Init::Child::apply_downgrade()
|
||||
void Sandbox::Child::apply_downgrade()
|
||||
{
|
||||
Ram_quota const configured_ram_quota = _configured_ram_quota();
|
||||
Cap_quota const configured_cap_quota = _configured_cap_quota();
|
||||
@ -322,7 +322,7 @@ void Init::Child::apply_downgrade()
|
||||
}
|
||||
|
||||
|
||||
void Init::Child::report_state(Xml_generator &xml, Report_detail const &detail) const
|
||||
void Sandbox::Child::report_state(Xml_generator &xml, Report_detail const &detail) const
|
||||
{
|
||||
if (abandoned())
|
||||
return;
|
||||
@ -402,7 +402,7 @@ void Init::Child::report_state(Xml_generator &xml, Report_detail const &detail)
|
||||
}
|
||||
|
||||
|
||||
void Init::Child::init(Pd_session &session, Pd_session_capability cap)
|
||||
void Sandbox::Child::init(Pd_session &session, Pd_session_capability cap)
|
||||
{
|
||||
session.ref_account(_env.pd_session_cap());
|
||||
|
||||
@ -425,7 +425,7 @@ void Init::Child::init(Pd_session &session, Pd_session_capability cap)
|
||||
}
|
||||
|
||||
|
||||
void Init::Child::init(Cpu_session &session, Cpu_session_capability cap)
|
||||
void Sandbox::Child::init(Cpu_session &session, Cpu_session_capability cap)
|
||||
{
|
||||
static size_t avail = Cpu_session::quota_lim_upscale( 100, 100);
|
||||
size_t const need = Cpu_session::quota_lim_upscale(_resources.cpu_quota_pc, 100);
|
||||
@ -444,8 +444,9 @@ void Init::Child::init(Cpu_session &session, Cpu_session_capability cap)
|
||||
}
|
||||
|
||||
|
||||
Init::Child::Route Init::Child::resolve_session_request(Service::Name const &service_name,
|
||||
Session_label const &label)
|
||||
Sandbox::Child::Route
|
||||
Sandbox::Child::resolve_session_request(Service::Name const &service_name,
|
||||
Session_label const &label)
|
||||
{
|
||||
/* check for "config" ROM request */
|
||||
if (service_name == Rom_session::service_name() &&
|
||||
@ -550,6 +551,14 @@ Init::Child::Route Init::Child::resolve_session_request(Service::Name const &ser
|
||||
} catch (Service_denied) { }
|
||||
}
|
||||
|
||||
if (target.has_type("local")) {
|
||||
|
||||
try {
|
||||
return Route { find_service(_local_services, service_name, no_filter),
|
||||
target_label, target_diag };
|
||||
} catch (Service_denied) { }
|
||||
}
|
||||
|
||||
if (target.has_type("child")) {
|
||||
|
||||
typedef Name_registry::Name Name;
|
||||
@ -596,8 +605,8 @@ Init::Child::Route Init::Child::resolve_session_request(Service::Name const &ser
|
||||
}
|
||||
|
||||
|
||||
void Init::Child::filter_session_args(Service::Name const &service,
|
||||
char *args, size_t args_len)
|
||||
void Sandbox::Child::filter_session_args(Service::Name const &service,
|
||||
char *args, size_t args_len)
|
||||
{
|
||||
/*
|
||||
* Intercept CPU session requests to scale priorities
|
||||
@ -655,7 +664,7 @@ void Init::Child::filter_session_args(Service::Name const &service,
|
||||
}
|
||||
|
||||
|
||||
Genode::Affinity Init::Child::filter_session_affinity(Affinity const &session_affinity)
|
||||
Genode::Affinity Sandbox::Child::filter_session_affinity(Affinity const &session_affinity)
|
||||
{
|
||||
Affinity::Space const &child_space = _resources.affinity.space();
|
||||
Affinity::Location const &child_location = _resources.affinity.location();
|
||||
@ -680,7 +689,7 @@ Genode::Affinity Init::Child::filter_session_affinity(Affinity const &session_af
|
||||
}
|
||||
|
||||
|
||||
void Init::Child::announce_service(Service::Name const &service_name)
|
||||
void Sandbox::Child::announce_service(Service::Name const &service_name)
|
||||
{
|
||||
if (_verbose.enabled())
|
||||
log("child \"", name(), "\" announces service \"", service_name, "\"");
|
||||
@ -697,7 +706,7 @@ void Init::Child::announce_service(Service::Name const &service_name)
|
||||
}
|
||||
|
||||
|
||||
void Init::Child::resource_request(Parent::Resource_args const &args)
|
||||
void Sandbox::Child::resource_request(Parent::Resource_args const &args)
|
||||
{
|
||||
log("child \"", name(), "\" requests resources: ", args);
|
||||
|
||||
@ -706,23 +715,24 @@ void Init::Child::resource_request(Parent::Resource_args const &args)
|
||||
}
|
||||
|
||||
|
||||
Init::Child::Child(Env &env,
|
||||
Allocator &alloc,
|
||||
Verbose const &verbose,
|
||||
Id id,
|
||||
Report_update_trigger &report_update_trigger,
|
||||
Xml_node start_node,
|
||||
Default_route_accessor &default_route_accessor,
|
||||
Default_caps_accessor &default_caps_accessor,
|
||||
Name_registry &name_registry,
|
||||
Ram_quota ram_limit,
|
||||
Cap_quota cap_limit,
|
||||
Ram_limit_accessor &ram_limit_accessor,
|
||||
Cap_limit_accessor &cap_limit_accessor,
|
||||
Prio_levels prio_levels,
|
||||
Affinity::Space const &affinity_space,
|
||||
Registry<Parent_service> &parent_services,
|
||||
Registry<Routed_service> &child_services)
|
||||
Sandbox::Child::Child(Env &env,
|
||||
Allocator &alloc,
|
||||
Verbose const &verbose,
|
||||
Id id,
|
||||
Report_update_trigger &report_update_trigger,
|
||||
Xml_node start_node,
|
||||
Default_route_accessor &default_route_accessor,
|
||||
Default_caps_accessor &default_caps_accessor,
|
||||
Name_registry &name_registry,
|
||||
Ram_quota ram_limit,
|
||||
Cap_quota cap_limit,
|
||||
Ram_limit_accessor &ram_limit_accessor,
|
||||
Cap_limit_accessor &cap_limit_accessor,
|
||||
Prio_levels prio_levels,
|
||||
Affinity::Space const &affinity_space,
|
||||
Registry<Parent_service> &parent_services,
|
||||
Registry<Routed_service> &child_services,
|
||||
Registry<Local_service> &local_services)
|
||||
:
|
||||
_env(env), _alloc(alloc), _verbose(verbose), _id(id),
|
||||
_report_update_trigger(report_update_trigger),
|
||||
@ -739,6 +749,7 @@ Init::Child::Child(Env &env,
|
||||
_resources_clamped_to_limit((_clamp_resources(ram_limit, cap_limit), true)),
|
||||
_parent_services(parent_services),
|
||||
_child_services(child_services),
|
||||
_local_services(local_services),
|
||||
_session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm())
|
||||
{
|
||||
if (_verbose.enabled()) {
|
||||
@ -764,4 +775,4 @@ Init::Child::Child(Env &env,
|
||||
}
|
||||
|
||||
|
||||
Init::Child::~Child() { }
|
||||
Sandbox::Child::~Child() { }
|
@ -11,8 +11,8 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__CHILD_H_
|
||||
#define _SRC__INIT__CHILD_H_
|
||||
#ifndef _LIB__SANDBOX__CHILD_H_
|
||||
#define _LIB__SANDBOX__CHILD_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/log.h>
|
||||
@ -20,6 +20,7 @@
|
||||
#include <os/session_requester.h>
|
||||
#include <os/session_policy.h>
|
||||
#include <os/buffered_xml.h>
|
||||
#include <os/sandbox.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
@ -29,9 +30,9 @@
|
||||
#include <service.h>
|
||||
#include <utils.h>
|
||||
|
||||
namespace Init { class Child; }
|
||||
namespace Sandbox { class Child; }
|
||||
|
||||
class Init::Child : Child_policy, Routed_service::Wakeup
|
||||
class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
{
|
||||
public:
|
||||
|
||||
@ -255,12 +256,15 @@ class Init::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
bool const _resources_clamped_to_limit;
|
||||
|
||||
using Local_service = Genode::Sandbox::Local_service_base;
|
||||
|
||||
Registry<Parent_service> &_parent_services;
|
||||
Registry<Routed_service> &_child_services;
|
||||
Registry<Local_service> &_local_services;
|
||||
|
||||
struct Inline_config_rom_service : Abandonable, Dynamic_rom_session::Content_producer
|
||||
{
|
||||
typedef Local_service<Dynamic_rom_session> Service;
|
||||
typedef Genode::Local_service<Dynamic_rom_session> Service;
|
||||
|
||||
Child &_child;
|
||||
|
||||
@ -480,7 +484,8 @@ class Init::Child : Child_policy, Routed_service::Wakeup
|
||||
Prio_levels prio_levels,
|
||||
Affinity::Space const &affinity_space,
|
||||
Registry<Parent_service> &parent_services,
|
||||
Registry<Routed_service> &child_services);
|
||||
Registry<Routed_service> &child_services,
|
||||
Registry<Local_service> &local_services);
|
||||
|
||||
virtual ~Child();
|
||||
|
||||
@ -645,4 +650,4 @@ class Init::Child : Child_policy, Routed_service::Wakeup
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__CHILD_H_ */
|
||||
#endif /* _LIB__SANDBOX__CHILD_H_ */
|
@ -11,8 +11,8 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__CHILD_REGISTRY_H_
|
||||
#define _SRC__INIT__CHILD_REGISTRY_H_
|
||||
#ifndef _LIB__SANDBOX__CHILD_REGISTRY_H_
|
||||
#define _LIB__SANDBOX__CHILD_REGISTRY_H_
|
||||
|
||||
/* local includes */
|
||||
#include <child.h>
|
||||
@ -20,10 +20,10 @@
|
||||
#include <alias.h>
|
||||
#include <report.h>
|
||||
|
||||
namespace Init { struct Child_registry; }
|
||||
namespace Sandbox { struct Child_registry; }
|
||||
|
||||
|
||||
class Init::Child_registry : public Name_registry, Child_list
|
||||
class Sandbox::Child_registry : public Name_registry, Child_list
|
||||
{
|
||||
private:
|
||||
|
||||
@ -32,7 +32,7 @@ class Init::Child_registry : public Name_registry, Child_list
|
||||
bool _unique(const char *name) const
|
||||
{
|
||||
/* check for name clash with an existing child */
|
||||
Genode::List_element<Init::Child> const *curr = first();
|
||||
List_element<Sandbox::Child> const *curr = first();
|
||||
for (; curr; curr = curr->next())
|
||||
if (curr->object()->has_name(name))
|
||||
return false;
|
||||
@ -146,4 +146,4 @@ class Init::Child_registry : public Name_registry, Child_list
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__CHILD_REGISTRY_H_ */
|
||||
#endif /* _LIB__SANDBOX__CHILD_REGISTRY_H_ */
|
@ -11,18 +11,18 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__HEARTBEAT_H_
|
||||
#define _SRC__INIT__HEARTBEAT_H_
|
||||
#ifndef _LIB__SANDBOX__HEARTBEAT_H_
|
||||
#define _LIB__SANDBOX__HEARTBEAT_H_
|
||||
|
||||
/* local includes */
|
||||
#include <state_reporter.h>
|
||||
#include <child_registry.h>
|
||||
#include <util/noncopyable.h>
|
||||
|
||||
namespace Init { class Heartbeat; }
|
||||
namespace Sandbox { class Heartbeat; }
|
||||
|
||||
|
||||
class Init::Heartbeat : Genode::Noncopyable
|
||||
class Sandbox::Heartbeat : Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
@ -86,4 +86,4 @@ class Init::Heartbeat : Genode::Noncopyable
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__HEARTBEAT_H_ */
|
||||
#endif /* _LIB__SANDBOX__HEARTBEAT_H_ */
|
620
repos/os/src/lib/sandbox/library.cc
Normal file
620
repos/os/src/lib/sandbox/library.cc
Normal file
@ -0,0 +1,620 @@
|
||||
/*
|
||||
* \brief Sandbox library
|
||||
* \author Norman Feske
|
||||
* \date 2020-01-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-2020 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/attached_rom_dataspace.h>
|
||||
#include <os/sandbox.h>
|
||||
|
||||
/* local includes */
|
||||
#include <child.h>
|
||||
#include <alias.h>
|
||||
#include <server.h>
|
||||
#include <heartbeat.h>
|
||||
|
||||
struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer,
|
||||
::Sandbox::Child::Default_route_accessor,
|
||||
::Sandbox::Child::Default_caps_accessor,
|
||||
::Sandbox::Child::Ram_limit_accessor,
|
||||
::Sandbox::Child::Cap_limit_accessor
|
||||
{
|
||||
using Routed_service = ::Sandbox::Routed_service;
|
||||
using Parent_service = ::Sandbox::Parent_service;
|
||||
using Local_service = ::Genode::Sandbox::Local_service_base;
|
||||
using Report_detail = ::Sandbox::Report_detail;
|
||||
using Child_registry = ::Sandbox::Child_registry;
|
||||
using Verbose = ::Sandbox::Verbose;
|
||||
using State_reporter = ::Sandbox::State_reporter;
|
||||
using Heartbeat = ::Sandbox::Heartbeat;
|
||||
using Server = ::Sandbox::Server;
|
||||
using Alias = ::Sandbox::Alias;
|
||||
using Child = ::Sandbox::Child;
|
||||
using Prio_levels = ::Sandbox::Prio_levels;
|
||||
|
||||
Env &_env;
|
||||
Heap &_heap;
|
||||
|
||||
Registry<Parent_service> _parent_services { };
|
||||
Registry<Routed_service> _child_services { };
|
||||
Registry<Local_service> &_local_services;
|
||||
Child_registry _children { };
|
||||
|
||||
Reconstructible<Verbose> _verbose { };
|
||||
|
||||
Constructible<Buffered_xml> _default_route { };
|
||||
|
||||
Cap_quota _default_caps { 0 };
|
||||
|
||||
unsigned _child_cnt = 0;
|
||||
|
||||
static Ram_quota _preserved_ram_from_config(Xml_node config)
|
||||
{
|
||||
Number_of_bytes preserve { 40*sizeof(long)*1024 };
|
||||
|
||||
config.for_each_sub_node("resource", [&] (Xml_node node) {
|
||||
if (node.attribute_value("name", String<16>()) == "RAM")
|
||||
preserve = node.attribute_value("preserve", preserve); });
|
||||
|
||||
return Ram_quota { preserve };
|
||||
}
|
||||
|
||||
Ram_quota _preserved_ram { 0 };
|
||||
Cap_quota _preserved_caps { 0 };
|
||||
|
||||
Ram_quota _avail_ram() const
|
||||
{
|
||||
Ram_quota avail_ram = _env.pd().avail_ram();
|
||||
|
||||
if (_preserved_ram.value > avail_ram.value) {
|
||||
error("RAM preservation exceeds available memory");
|
||||
return Ram_quota { 0 };
|
||||
}
|
||||
|
||||
/* deduce preserved quota from available quota */
|
||||
return Ram_quota { avail_ram.value - _preserved_ram.value };
|
||||
}
|
||||
|
||||
static Cap_quota _preserved_caps_from_config(Xml_node config)
|
||||
{
|
||||
size_t preserve = 20;
|
||||
|
||||
config.for_each_sub_node("resource", [&] (Xml_node node) {
|
||||
if (node.attribute_value("name", String<16>()) == "CAP")
|
||||
preserve = node.attribute_value("preserve", preserve); });
|
||||
|
||||
return Cap_quota { preserve };
|
||||
}
|
||||
|
||||
Cap_quota _avail_caps() const
|
||||
{
|
||||
Cap_quota avail_caps { _env.pd().avail_caps().value };
|
||||
|
||||
if (_preserved_caps.value > avail_caps.value) {
|
||||
error("Capability preservation exceeds available capabilities");
|
||||
return Cap_quota { 0 };
|
||||
}
|
||||
|
||||
/* deduce preserved quota from available quota */
|
||||
return Cap_quota { avail_caps.value - _preserved_caps.value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Child::Ram_limit_accessor interface
|
||||
*/
|
||||
Ram_quota resource_limit(Ram_quota const &) const override { return _avail_ram(); }
|
||||
|
||||
/**
|
||||
* Child::Cap_limit_accessor interface
|
||||
*/
|
||||
Cap_quota resource_limit(Cap_quota const &) const override { return _avail_caps(); }
|
||||
|
||||
void _handle_resource_avail() { }
|
||||
|
||||
void produce_state_report(Xml_generator &xml, Report_detail const &detail) const override
|
||||
{
|
||||
if (detail.init_ram())
|
||||
xml.node("ram", [&] () { ::Sandbox::generate_ram_info (xml, _env.pd()); });
|
||||
|
||||
if (detail.init_caps())
|
||||
xml.node("caps", [&] () { ::Sandbox::generate_caps_info(xml, _env.pd()); });
|
||||
|
||||
if (detail.children())
|
||||
_children.report_state(xml, detail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default_route_accessor interface
|
||||
*/
|
||||
Xml_node default_route() override
|
||||
{
|
||||
return _default_route.constructed() ? _default_route->xml()
|
||||
: Xml_node("<empty/>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Default_caps_accessor interface
|
||||
*/
|
||||
Cap_quota default_caps() override { return _default_caps; }
|
||||
|
||||
State_reporter _state_reporter { _env, *this };
|
||||
|
||||
Heartbeat _heartbeat { _env, _children, _state_reporter };
|
||||
|
||||
void _update_aliases_from_config(Xml_node const &);
|
||||
void _update_parent_services_from_config(Xml_node const &);
|
||||
void _abandon_obsolete_children(Xml_node const &);
|
||||
void _update_children_config(Xml_node const &);
|
||||
void _destroy_abandoned_parent_services();
|
||||
|
||||
Server _server { _env, _heap, _child_services, _state_reporter };
|
||||
|
||||
Library(Env &env, Heap &heap, Registry<Local_service> &local_services)
|
||||
:
|
||||
_env(env), _heap(heap), _local_services(local_services)
|
||||
{ }
|
||||
|
||||
void apply_config(Xml_node const &);
|
||||
};
|
||||
|
||||
|
||||
void Genode::Sandbox::Library::_update_parent_services_from_config(Xml_node const &config)
|
||||
{
|
||||
Xml_node const node = config.has_sub_node("parent-provides")
|
||||
? config.sub_node("parent-provides")
|
||||
: Xml_node("<empty/>");
|
||||
|
||||
/* remove services that are no longer present in config */
|
||||
_parent_services.for_each([&] (Parent_service &service) {
|
||||
|
||||
Service::Name const name = service.name();
|
||||
|
||||
bool obsolete = true;
|
||||
node.for_each_sub_node("service", [&] (Xml_node service) {
|
||||
if (name == service.attribute_value("name", Service::Name())) {
|
||||
obsolete = false; }});
|
||||
|
||||
if (obsolete)
|
||||
service.abandon();
|
||||
});
|
||||
|
||||
/* used to prepend the list of new parent services with title */
|
||||
bool first_log = true;
|
||||
|
||||
/* register new services */
|
||||
node.for_each_sub_node("service", [&] (Xml_node service) {
|
||||
|
||||
Service::Name const name = service.attribute_value("name", Service::Name());
|
||||
|
||||
bool registered = false;
|
||||
_parent_services.for_each([&] (Parent_service const &service) {
|
||||
if (service.name() == name)
|
||||
registered = true; });
|
||||
|
||||
if (!registered) {
|
||||
new (_heap) ::Sandbox::Parent_service(_parent_services, _env, name);
|
||||
if (_verbose->enabled()) {
|
||||
if (first_log)
|
||||
log("parent provides");
|
||||
log(" service \"", name, "\"");
|
||||
first_log = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Genode::Sandbox::Library::_destroy_abandoned_parent_services()
|
||||
{
|
||||
_parent_services.for_each([&] (Parent_service &service) {
|
||||
if (service.abandoned())
|
||||
destroy(_heap, &service); });
|
||||
}
|
||||
|
||||
|
||||
void Genode::Sandbox::Library::_update_aliases_from_config(Xml_node const &config)
|
||||
{
|
||||
/* remove all known aliases */
|
||||
while (_children.any_alias()) {
|
||||
::Sandbox::Alias *alias = _children.any_alias();
|
||||
_children.remove_alias(alias);
|
||||
destroy(_heap, alias);
|
||||
}
|
||||
|
||||
/* create aliases */
|
||||
config.for_each_sub_node("alias", [&] (Xml_node alias_node) {
|
||||
|
||||
try {
|
||||
_children.insert_alias(new (_heap) Alias(alias_node)); }
|
||||
catch (Alias::Name_is_missing) {
|
||||
warning("missing 'name' attribute in '<alias>' entry"); }
|
||||
catch (Alias::Child_is_missing) {
|
||||
warning("missing 'child' attribute in '<alias>' entry"); }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Genode::Sandbox::Library::_abandon_obsolete_children(Xml_node const &config)
|
||||
{
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
|
||||
bool obsolete = true;
|
||||
config.for_each_sub_node("start", [&] (Xml_node node) {
|
||||
if (child.has_name (node.attribute_value("name", Child_policy::Name()))
|
||||
&& child.has_version(node.attribute_value("version", Child::Version())))
|
||||
obsolete = false; });
|
||||
|
||||
if (obsolete)
|
||||
child.abandon();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Genode::Sandbox::Library::_update_children_config(Xml_node const &config)
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
/*
|
||||
* Children are abandoned if any of their client sessions can no longer
|
||||
* be routed or result in a different route. As each child may be a
|
||||
* service, an avalanche effect may occur. It stops if no update causes
|
||||
* a potential side effect in one iteration over all chilren.
|
||||
*/
|
||||
bool side_effects = false;
|
||||
|
||||
config.for_each_sub_node("start", [&] (Xml_node node) {
|
||||
|
||||
Child_policy::Name const start_node_name =
|
||||
node.attribute_value("name", Child_policy::Name());
|
||||
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
if (!child.abandoned() && child.name() == start_node_name) {
|
||||
switch (child.apply_config(node)) {
|
||||
case Child::NO_SIDE_EFFECTS: break;
|
||||
case Child::MAY_HAVE_SIDE_EFFECTS: side_effects = true; break;
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!side_effects)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Genode::Sandbox::Library::apply_config(Xml_node const &config)
|
||||
{
|
||||
bool update_state_report = false;
|
||||
|
||||
_preserved_ram = _preserved_ram_from_config(config);
|
||||
_preserved_caps = _preserved_caps_from_config(config);
|
||||
|
||||
_verbose.construct(config);
|
||||
_state_reporter.apply_config(config);
|
||||
_heartbeat.apply_config(config);
|
||||
|
||||
/* determine default route for resolving service requests */
|
||||
try {
|
||||
_default_route.construct(_heap, config.sub_node("default-route")); }
|
||||
catch (...) { }
|
||||
|
||||
_default_caps = Cap_quota { 0 };
|
||||
try {
|
||||
_default_caps = Cap_quota { config.sub_node("default")
|
||||
.attribute_value("caps", 0UL) }; }
|
||||
catch (...) { }
|
||||
|
||||
Prio_levels const prio_levels = ::Sandbox::prio_levels_from_xml(config);
|
||||
Affinity::Space const affinity_space = ::Sandbox::affinity_space_from_xml(config);
|
||||
bool const space_defined = config.has_sub_node("affinity-space");
|
||||
|
||||
_update_aliases_from_config(config);
|
||||
_update_parent_services_from_config(config);
|
||||
_abandon_obsolete_children(config);
|
||||
_update_children_config(config);
|
||||
|
||||
/* kill abandoned children */
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
|
||||
if (!child.abandoned())
|
||||
return;
|
||||
|
||||
/* make the child's services unavailable */
|
||||
child.destroy_services();
|
||||
child.close_all_sessions();
|
||||
update_state_report = true;
|
||||
|
||||
/* destroy child once all environment sessions are gone */
|
||||
if (child.env_sessions_closed()) {
|
||||
_children.remove(&child);
|
||||
destroy(_heap, &child);
|
||||
}
|
||||
});
|
||||
|
||||
_destroy_abandoned_parent_services();
|
||||
|
||||
/* initial RAM and caps limit before starting new children */
|
||||
Ram_quota const avail_ram = _avail_ram();
|
||||
Cap_quota const avail_caps = _avail_caps();
|
||||
|
||||
/* variable used to track the RAM and caps taken by new started children */
|
||||
Ram_quota used_ram { 0 };
|
||||
Cap_quota used_caps { 0 };
|
||||
|
||||
/* create new children */
|
||||
try {
|
||||
config.for_each_sub_node("start", [&] (Xml_node start_node) {
|
||||
|
||||
bool exists = false;
|
||||
|
||||
unsigned num_abandoned = 0;
|
||||
|
||||
typedef Child_policy::Name Name;
|
||||
Name const child_name = start_node.attribute_value("name", Name());
|
||||
|
||||
_children.for_each_child([&] (Child const &child) {
|
||||
if (child.name() == child_name) {
|
||||
if (child.abandoned())
|
||||
num_abandoned++;
|
||||
else
|
||||
exists = true;
|
||||
}
|
||||
});
|
||||
|
||||
/* skip start node if corresponding child already exists */
|
||||
if (exists)
|
||||
return;
|
||||
|
||||
/* prevent queuing up abandoned children with the same name */
|
||||
if (num_abandoned > 1)
|
||||
return;
|
||||
|
||||
if (used_ram.value > avail_ram.value) {
|
||||
error("RAM exhausted while starting child: ", child_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (used_caps.value > avail_caps.value) {
|
||||
error("capabilities exhausted while starting child: ", child_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!space_defined && start_node.has_sub_node("affinity")) {
|
||||
warning("affinity-space configuration missing, "
|
||||
"but affinity defined for child: ", child_name);
|
||||
}
|
||||
|
||||
try {
|
||||
Child &child = *new (_heap)
|
||||
Child(_env, _heap, *_verbose,
|
||||
Child::Id { ++_child_cnt }, _state_reporter,
|
||||
start_node, *this, *this, _children,
|
||||
Ram_quota { avail_ram.value - used_ram.value },
|
||||
Cap_quota { avail_caps.value - used_caps.value },
|
||||
*this, *this, prio_levels, affinity_space,
|
||||
_parent_services, _child_services, _local_services);
|
||||
_children.insert(&child);
|
||||
|
||||
update_state_report = true;
|
||||
|
||||
/* account for the start XML node buffered in the child */
|
||||
size_t const metadata_overhead = start_node.size() + sizeof(Child);
|
||||
|
||||
/* track used memory and RAM limit */
|
||||
used_ram = Ram_quota { used_ram.value
|
||||
+ child.ram_quota().value
|
||||
+ metadata_overhead };
|
||||
|
||||
used_caps = Cap_quota { used_caps.value
|
||||
+ child.cap_quota().value };
|
||||
}
|
||||
catch (Rom_connection::Rom_connection_failed) {
|
||||
/*
|
||||
* The binary does not exist. An error message is printed
|
||||
* by the Rom_connection constructor.
|
||||
*/
|
||||
}
|
||||
catch (Out_of_ram) {
|
||||
warning("memory exhausted during child creation"); }
|
||||
catch (Out_of_caps) {
|
||||
warning("local capabilities exhausted during child creation"); }
|
||||
catch (Child::Missing_name_attribute) {
|
||||
warning("skipped startup of nameless child"); }
|
||||
catch (Region_map::Region_conflict) {
|
||||
warning("failed to attach dataspace to local address space "
|
||||
"during child construction"); }
|
||||
catch (Region_map::Invalid_dataspace) {
|
||||
warning("attempt to attach invalid dataspace to local address space "
|
||||
"during child construction"); }
|
||||
catch (Service_denied) {
|
||||
warning("failed to create session during child construction"); }
|
||||
});
|
||||
}
|
||||
catch (Xml_node::Nonexistent_sub_node) { error("no children to start"); }
|
||||
catch (Xml_node::Invalid_syntax) { error("config has invalid syntax"); }
|
||||
catch (Child_registry::Alias_name_is_not_unique) { }
|
||||
|
||||
/*
|
||||
* Initiate RAM sessions of all new children
|
||||
*/
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
if (!child.abandoned())
|
||||
child.initiate_env_pd_session(); });
|
||||
|
||||
/*
|
||||
* Initiate remaining environment sessions of all new children
|
||||
*/
|
||||
_children.for_each_child([&] (Child &child) {
|
||||
if (!child.abandoned())
|
||||
child.initiate_env_sessions(); });
|
||||
|
||||
/*
|
||||
* (Re-)distribute RAM and capability quota among the children, given their
|
||||
* resource assignments and the available slack memory. We first apply
|
||||
* possible downgrades to free as much resources as we can. These resources
|
||||
* are then incorporated in the subsequent upgrade step.
|
||||
*/
|
||||
_children.for_each_child([&] (Child &child) { child.apply_downgrade(); });
|
||||
_children.for_each_child([&] (Child &child) { child.apply_upgrade(); });
|
||||
|
||||
_server.apply_config(config);
|
||||
|
||||
if (update_state_report)
|
||||
_state_reporter.trigger_immediate_report_update();
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
** Sandbox::Local_service_base **
|
||||
*********************************/
|
||||
|
||||
void Genode::Sandbox::Local_service_base::_for_each_requested_session(Request_fn &fn)
|
||||
{
|
||||
_server_id_space.for_each<Session_state>([&] (Session_state &session) {
|
||||
|
||||
if (session.phase == Session_state::CREATE_REQUESTED) {
|
||||
|
||||
Request request(session);
|
||||
|
||||
fn.with_requested_session(request);
|
||||
|
||||
bool wakeup_client = false;
|
||||
|
||||
if (request._denied) {
|
||||
session.phase = Session_state::SERVICE_DENIED;
|
||||
wakeup_client = true;
|
||||
}
|
||||
|
||||
if (request._session_ptr) {
|
||||
session.local_ptr = request._session_ptr;
|
||||
session.cap = request._session_cap;
|
||||
session.phase = Session_state::AVAILABLE;
|
||||
wakeup_client = true;
|
||||
}
|
||||
|
||||
if (wakeup_client && session.ready_callback)
|
||||
session.ready_callback->session_ready(session);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Genode::Sandbox::Local_service_base::_for_each_upgraded_session(Upgrade_fn &fn)
|
||||
{
|
||||
_server_id_space.for_each<Session_state>([&] (Session_state &session) {
|
||||
|
||||
if (session.phase != Session_state::UPGRADE_REQUESTED)
|
||||
return;
|
||||
|
||||
if (session.local_ptr == nullptr)
|
||||
return;
|
||||
|
||||
bool wakeup_client = false;
|
||||
|
||||
Session::Resources const amount { session.ram_upgrade,
|
||||
session.cap_upgrade };
|
||||
|
||||
switch (fn.with_upgraded_session(*session.local_ptr, amount)) {
|
||||
|
||||
case Upgrade_response::CONFIRMED:
|
||||
session.phase = Session_state::CAP_HANDED_OUT;
|
||||
wakeup_client = true;
|
||||
break;
|
||||
|
||||
case Upgrade_response::DEFERRED:
|
||||
break;
|
||||
}
|
||||
|
||||
if (wakeup_client && session.ready_callback)
|
||||
session.ready_callback->session_ready(session);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Genode::Sandbox::Local_service_base::_for_each_session_to_close(Close_fn &close_fn)
|
||||
{
|
||||
/*
|
||||
* Collection of closed sessions to be destructed via callback
|
||||
*
|
||||
* For asynchronous sessions, the 'Session_state' object is destructed by
|
||||
* the 'Closed_callback'. We cannot issue the callback from within
|
||||
* '_server_id_space.for_each()' because the destruction of 'id_at_server'
|
||||
* would deadlock. Instead be collect the 'Session_state' objects to be
|
||||
* called back in the 'pending_callbacks' ID space. This is possible
|
||||
* because the parent ID space is not used for local services.
|
||||
*/
|
||||
Id_space<Parent::Client> pending_callbacks { };
|
||||
|
||||
_server_id_space.for_each<Session_state>([&] (Session_state &session) {
|
||||
|
||||
if (session.phase != Session_state::CLOSE_REQUESTED)
|
||||
return;
|
||||
|
||||
if (session.local_ptr == nullptr)
|
||||
return;
|
||||
|
||||
switch (close_fn.close_session(*session.local_ptr)) {
|
||||
|
||||
case Close_response::CLOSED:
|
||||
|
||||
session.phase = Session_state::CLOSED;
|
||||
|
||||
if (session.closed_callback)
|
||||
session.id_at_parent.construct(session, pending_callbacks);
|
||||
break;
|
||||
|
||||
case Close_response::DEFERRED:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Purge 'Session_state' objects by calling 'closed_callback'
|
||||
*/
|
||||
while (pending_callbacks.apply_any<Session_state>([&] (Session_state &session) {
|
||||
|
||||
session.id_at_parent.destruct();
|
||||
|
||||
if (session.closed_callback)
|
||||
session.closed_callback->session_closed(session);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
Genode::Sandbox::Local_service_base::Local_service_base(Sandbox &sandbox,
|
||||
Name const &name,
|
||||
Wakeup &wakeup)
|
||||
:
|
||||
Service(name),
|
||||
_element(sandbox._local_services, *this),
|
||||
_session_factory(sandbox._heap, Session_state::Factory::Batch_size{16}),
|
||||
_async_wakeup(wakeup),
|
||||
_async_service(name, _server_id_space, _session_factory, _async_wakeup)
|
||||
{ }
|
||||
|
||||
|
||||
/*************
|
||||
** Sandbox **
|
||||
*************/
|
||||
|
||||
void Genode::Sandbox::apply_config(Xml_node const &config)
|
||||
{
|
||||
_library.apply_config(config);
|
||||
}
|
||||
|
||||
|
||||
Genode::Sandbox::Sandbox(Env &env)
|
||||
:
|
||||
_heap(env.ram(), env.rm()),
|
||||
_library(*new (_heap) Library(env, _heap, _local_services))
|
||||
{ }
|
||||
|
@ -11,8 +11,8 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__NAME_REGISTRY_H_
|
||||
#define _SRC__INIT__NAME_REGISTRY_H_
|
||||
#ifndef _LIB__SANDBOX__NAME_REGISTRY_H_
|
||||
#define _LIB__SANDBOX__NAME_REGISTRY_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/child.h>
|
||||
@ -20,9 +20,9 @@
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
|
||||
namespace Init { struct Name_registry; }
|
||||
namespace Sandbox { struct Name_registry; }
|
||||
|
||||
struct Init::Name_registry
|
||||
struct Sandbox::Name_registry
|
||||
{
|
||||
virtual ~Name_registry() { }
|
||||
|
||||
@ -36,4 +36,4 @@ struct Init::Name_registry
|
||||
virtual Name deref_alias(Name const &) = 0;
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__NAME_REGISTRY_H_ */
|
||||
#endif /* _LIB__SANDBOX__NAME_REGISTRY_H_ */
|
@ -11,19 +11,19 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__REPORT_H_
|
||||
#define _SRC__INIT__REPORT_H_
|
||||
#ifndef _LIB__SANDBOX__REPORT_H_
|
||||
#define _LIB__SANDBOX__REPORT_H_
|
||||
|
||||
#include <util/noncopyable.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
namespace Init {
|
||||
namespace Sandbox {
|
||||
struct Report_update_trigger;
|
||||
struct Report_detail;
|
||||
}
|
||||
|
||||
|
||||
class Init::Report_detail : Genode::Noncopyable
|
||||
class Sandbox::Report_detail : Genode::Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
@ -66,7 +66,7 @@ class Init::Report_detail : Genode::Noncopyable
|
||||
};
|
||||
|
||||
|
||||
struct Init::Report_update_trigger : Interface
|
||||
struct Sandbox::Report_update_trigger : Interface
|
||||
{
|
||||
/**
|
||||
* Trigger regular (rate-limited) report update
|
||||
@ -84,4 +84,4 @@ struct Init::Report_update_trigger : Interface
|
||||
virtual void trigger_immediate_report_update() = 0;
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__REPORT_H_ */
|
||||
#endif /* _LIB__SANDBOX__REPORT_H_ */
|
@ -19,11 +19,11 @@
|
||||
#include "server.h"
|
||||
|
||||
|
||||
/***************************
|
||||
** Init::Server::Service **
|
||||
***************************/
|
||||
/******************************
|
||||
** Sandbox::Server::Service **
|
||||
**********...*****************/
|
||||
|
||||
struct Init::Server::Service
|
||||
struct Sandbox::Server::Service
|
||||
{
|
||||
Registry<Service>::Element _registry_element;
|
||||
|
||||
@ -62,8 +62,8 @@ struct Init::Server::Service
|
||||
};
|
||||
|
||||
|
||||
Init::Server::Route
|
||||
Init::Server::Service::resolve_session_request(Session_label const &label)
|
||||
Sandbox::Server::Route
|
||||
Sandbox::Server::Service::resolve_session_request(Session_label const &label)
|
||||
{
|
||||
try {
|
||||
Session_policy policy(label, _service_node.xml());
|
||||
@ -95,13 +95,13 @@ Init::Server::Service::resolve_session_request(Session_label const &label)
|
||||
}
|
||||
|
||||
|
||||
/******************
|
||||
** Init::Server **
|
||||
******************/
|
||||
/*********************
|
||||
** Sandbox::Server **
|
||||
*********************/
|
||||
|
||||
Init::Server::Route
|
||||
Init::Server::_resolve_session_request(Service::Name const &service_name,
|
||||
Session_label const &label)
|
||||
Sandbox::Server::Route
|
||||
Sandbox::Server::_resolve_session_request(Service::Name const &service_name,
|
||||
Session_label const &label)
|
||||
{
|
||||
Service *matching_service = nullptr;
|
||||
_services.for_each([&] (Service &service) {
|
||||
@ -123,7 +123,7 @@ static void close_session(Genode::Session_state &session)
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::session_ready(Session_state &session)
|
||||
void Sandbox::Server::session_ready(Session_state &session)
|
||||
{
|
||||
_report_update_trigger.trigger_report_update();
|
||||
|
||||
@ -154,8 +154,8 @@ void Init::Server::session_ready(Session_state &session)
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_close_session(Session_state &session,
|
||||
Parent::Session_response response)
|
||||
void Sandbox::Server::_close_session(Session_state &session,
|
||||
Parent::Session_response response)
|
||||
{
|
||||
_report_update_trigger.trigger_report_update();
|
||||
|
||||
@ -176,14 +176,14 @@ void Init::Server::_close_session(Session_state &session,
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::session_closed(Session_state &session)
|
||||
void Sandbox::Server::session_closed(Session_state &session)
|
||||
{
|
||||
_close_session(session, Parent::SESSION_CLOSED);
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_create_session_request(Xml_node request,
|
||||
Parent::Client::Id id)
|
||||
void Sandbox::Server::_handle_create_session_request(Xml_node request,
|
||||
Parent::Client::Id id)
|
||||
{
|
||||
/*
|
||||
* Ignore requests that are already successfully forwarded (by a prior call
|
||||
@ -287,8 +287,8 @@ void Init::Server::_handle_create_session_request(Xml_node request,
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_upgrade_session_request(Xml_node request,
|
||||
Parent::Client::Id id)
|
||||
void Sandbox::Server::_handle_upgrade_session_request(Xml_node request,
|
||||
Parent::Client::Id id)
|
||||
{
|
||||
_client_id_space.apply<Session_state>(id, [&] (Session_state &session) {
|
||||
|
||||
@ -321,14 +321,14 @@ void Init::Server::_handle_upgrade_session_request(Xml_node request,
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_close_session_request(Xml_node, Parent::Client::Id id)
|
||||
void Sandbox::Server::_handle_close_session_request(Xml_node, Parent::Client::Id id)
|
||||
{
|
||||
_client_id_space.apply<Session_state>(id, [&] (Session_state &session) {
|
||||
close_session(session); });
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_session_request(Xml_node request)
|
||||
void Sandbox::Server::_handle_session_request(Xml_node request)
|
||||
{
|
||||
if (!request.has_attribute("id"))
|
||||
return;
|
||||
@ -350,7 +350,7 @@ void Init::Server::_handle_session_request(Xml_node request)
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_session_requests()
|
||||
void Sandbox::Server::_handle_session_requests()
|
||||
{
|
||||
_session_requests->update();
|
||||
|
||||
@ -363,7 +363,7 @@ void Init::Server::_handle_session_requests()
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::apply_config(Xml_node config)
|
||||
void Sandbox::Server::apply_config(Xml_node config)
|
||||
{
|
||||
_services.for_each([&] (Service &service) { destroy(_alloc, &service); });
|
||||
|
@ -11,8 +11,8 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__SERVER_H_
|
||||
#define _SRC__INIT__SERVER_H_
|
||||
#ifndef _LIB__SANDBOX__SERVER_H_
|
||||
#define _LIB__SANDBOX__SERVER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
@ -23,11 +23,11 @@
|
||||
#include "service.h"
|
||||
#include "state_reporter.h"
|
||||
|
||||
namespace Init { class Server; }
|
||||
namespace Sandbox { class Server; }
|
||||
|
||||
|
||||
class Init::Server : Session_state::Ready_callback,
|
||||
Session_state::Closed_callback
|
||||
class Sandbox::Server : Session_state::Ready_callback,
|
||||
Session_state::Closed_callback
|
||||
{
|
||||
private:
|
||||
|
||||
@ -47,7 +47,7 @@ class Init::Server : Session_state::Ready_callback,
|
||||
Id_space<Parent::Server> _server_id_space { };
|
||||
|
||||
/*
|
||||
* ID space of requests issued to the children of init
|
||||
* ID space of requests issued to the children
|
||||
*/
|
||||
Id_space<Parent::Client> _client_id_space { };
|
||||
|
||||
@ -116,4 +116,4 @@ class Init::Server : Session_state::Ready_callback,
|
||||
void apply_config(Xml_node);
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__SERVER_H_ */
|
||||
#endif /* _LIB__SANDBOX__SERVER_H_ */
|
@ -11,14 +11,14 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__SERVICE_H_
|
||||
#define _SRC__INIT__SERVICE_H_
|
||||
#ifndef _LIB__SANDBOX__SERVICE_H_
|
||||
#define _LIB__SANDBOX__SERVICE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/service.h>
|
||||
#include <base/child.h>
|
||||
|
||||
namespace Init {
|
||||
namespace Sandbox {
|
||||
class Abandonable;
|
||||
class Parent_service;
|
||||
class Routed_service;
|
||||
@ -26,7 +26,7 @@ namespace Init {
|
||||
}
|
||||
|
||||
|
||||
class Init::Abandonable : Interface
|
||||
class Sandbox::Abandonable : Interface
|
||||
{
|
||||
private:
|
||||
|
||||
@ -40,7 +40,7 @@ class Init::Abandonable : Interface
|
||||
};
|
||||
|
||||
|
||||
class Init::Parent_service : public Genode::Parent_service, public Abandonable
|
||||
class Sandbox::Parent_service : public Genode::Parent_service, public Abandonable
|
||||
{
|
||||
private:
|
||||
|
||||
@ -57,9 +57,9 @@ class Init::Parent_service : public Genode::Parent_service, public Abandonable
|
||||
|
||||
|
||||
/**
|
||||
* Init-specific representation of a child service
|
||||
* Sandbox-specific representation of a child service
|
||||
*/
|
||||
class Init::Routed_service : public Async_service, public Abandonable
|
||||
class Sandbox::Routed_service : public Async_service, public Abandonable
|
||||
{
|
||||
public:
|
||||
|
||||
@ -148,4 +148,4 @@ class Init::Routed_service : public Async_service, public Abandonable
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__SERVICE_H_ */
|
||||
#endif /* _LIB__SANDBOX__SERVICE_H_ */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* \brief Init-state reporting mechanism
|
||||
* \brief State reporting mechanism
|
||||
* \author Norman Feske
|
||||
* \date 2017-03-03
|
||||
*/
|
||||
@ -11,8 +11,8 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__STATE_REPORTER_H_
|
||||
#define _SRC__INIT__STATE_REPORTER_H_
|
||||
#ifndef _LIB__SANDBOX__STATE_REPORTER_H_
|
||||
#define _LIB__SANDBOX__STATE_REPORTER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/reporter.h>
|
||||
@ -21,9 +21,9 @@
|
||||
/* local includes */
|
||||
#include "report.h"
|
||||
|
||||
namespace Init { class State_reporter; }
|
||||
namespace Sandbox { class State_reporter; }
|
||||
|
||||
class Init::State_reporter : public Report_update_trigger
|
||||
class Sandbox::State_reporter : public Report_update_trigger
|
||||
{
|
||||
public:
|
||||
|
||||
@ -149,9 +149,9 @@ class Init::State_reporter : public Report_update_trigger
|
||||
* If the report features information about child-RAM quotas, we
|
||||
* update the report periodically. Even in the absence of any other
|
||||
* report-triggering event, a child may consume/free RAM from its
|
||||
* RAM session without any interplay with init. The periodic
|
||||
* reports ensure that such changes are reflected by init's state
|
||||
* report.
|
||||
* RAM session without any interplay with the sandbox. The periodic
|
||||
* reports ensure that such changes are reflected by the sandbox'
|
||||
* state report.
|
||||
*
|
||||
* By default, the interval is one second. However, when the
|
||||
* 'delay_ms' attribute is defined with a higher value than that,
|
||||
@ -194,4 +194,4 @@ class Init::State_reporter : public Report_update_trigger
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__STATE_REPORTER_H_ */
|
||||
#endif /* _LIB__SANDBOX__STATE_REPORTER_H_ */
|
@ -11,14 +11,14 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__TYPES_H_
|
||||
#define _SRC__INIT__TYPES_H_
|
||||
#ifndef _LIB__SANDBOX__TYPES_H_
|
||||
#define _LIB__SANDBOX__TYPES_H_
|
||||
|
||||
#include <util/string.h>
|
||||
#include <util/list.h>
|
||||
#include <session/session.h>
|
||||
|
||||
namespace Init {
|
||||
namespace Sandbox {
|
||||
|
||||
class Child;
|
||||
|
||||
@ -28,8 +28,7 @@ namespace Init {
|
||||
|
||||
struct Prio_levels { long value; };
|
||||
|
||||
typedef List<List_element<Init::Child> > Child_list;
|
||||
typedef List<List_element<Sandbox::Child> > Child_list;
|
||||
}
|
||||
|
||||
#endif /* _SRC__INIT__TYPES_H_ */
|
||||
|
||||
#endif /* _LIB__SANDBOX__TYPES_H_ */
|
@ -11,10 +11,10 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__UTIL_H_
|
||||
#define _SRC__INIT__UTIL_H_
|
||||
#ifndef _LIB__SANDBOX__UTILS_H_
|
||||
#define _LIB__SANDBOX__UTILS_H_
|
||||
|
||||
namespace Init {
|
||||
namespace Sandbox {
|
||||
|
||||
static inline void warn_insuff_quota(size_t const avail)
|
||||
{
|
||||
@ -270,4 +270,4 @@ namespace Init {
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _SRC__INIT__UTIL_H_ */
|
||||
#endif /* _LIB__SANDBOX__UTILS_H_ */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* \brief Init verbosity
|
||||
* \brief Sandbox verbosity
|
||||
* \author Norman Feske
|
||||
* \date 2017-01-03
|
||||
*/
|
||||
@ -11,27 +11,33 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__VERBOSE_H_
|
||||
#define _SRC__INIT__VERBOSE_H_
|
||||
#ifndef _LIB__SANDBOX__VERBOSE_H_
|
||||
#define _LIB__SANDBOX__VERBOSE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/noncopyable.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
namespace Init { struct Verbose; }
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
|
||||
namespace Sandbox { struct Verbose; }
|
||||
|
||||
|
||||
class Init::Verbose : Genode::Noncopyable
|
||||
class Sandbox::Verbose : Genode::Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
bool _enabled;
|
||||
bool _enabled = false;
|
||||
|
||||
public:
|
||||
|
||||
Verbose() { }
|
||||
|
||||
Verbose(Genode::Xml_node config)
|
||||
: _enabled(config.attribute_value("verbose", false)) { }
|
||||
|
||||
bool enabled() const { return _enabled; }
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__VERBOSE_H_ */
|
||||
#endif /* _LIB__SANDBOX__VERBOSE_H_ */
|
147
repos/os/src/test/sandbox/main.cc
Normal file
147
repos/os/src/test/sandbox/main.cc
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* \brief Test for the sandbox API
|
||||
* \author Norman Feske
|
||||
* \date 2020-01-09
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#include <base/component.h>
|
||||
#include <log_session/log_session.h>
|
||||
#include <base/session_object.h>
|
||||
#include <os/buffered_xml.h>
|
||||
#include <os/sandbox.h>
|
||||
|
||||
namespace Test {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
struct Log_session_component;
|
||||
struct Main;
|
||||
}
|
||||
|
||||
|
||||
struct Test::Log_session_component : Session_object<Log_session>
|
||||
{
|
||||
template <typename... ARGS>
|
||||
Log_session_component(ARGS &&... args) : Session_object(args...) { }
|
||||
|
||||
size_t write(String const &msg) override
|
||||
{
|
||||
/* omit line break and zero termination supplied by 'msg' */
|
||||
if (msg.size() > 1)
|
||||
log("local LOG service: ", Cstring(msg.string(), msg.size() - 2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Test::Main : Sandbox::Local_service_base::Wakeup
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
Heap _heap { _env.ram(), _env.rm() };
|
||||
|
||||
Sandbox _sandbox { _env };
|
||||
|
||||
typedef Sandbox::Local_service<Log_session_component> Log_service;
|
||||
|
||||
Log_service _log_service { _sandbox, *this };
|
||||
|
||||
void _generate_sandbox_config(Xml_generator &xml) const
|
||||
{
|
||||
xml.node("parent-provides", [&] () {
|
||||
|
||||
auto service_node = [&] (char const *name) {
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", name); }); };
|
||||
|
||||
service_node("ROM");
|
||||
service_node("CPU");
|
||||
service_node("PD");
|
||||
service_node("LOG");
|
||||
});
|
||||
|
||||
xml.node("start", [&] () {
|
||||
xml.attribute("name", "dummy");
|
||||
xml.attribute("caps", 100);
|
||||
xml.node("resource", [&] () {
|
||||
xml.attribute("name", "RAM");
|
||||
xml.attribute("quantum", "2M");
|
||||
});
|
||||
|
||||
xml.node("config", [&] () {
|
||||
xml.node("log", [&] () {
|
||||
xml.attribute("string", "started"); });
|
||||
xml.node("create_log_connections", [&] () {
|
||||
xml.attribute("ram_upgrade", "100K");
|
||||
xml.attribute("count", "1"); });
|
||||
xml.node("destroy_log_connections", [&] () { });
|
||||
xml.node("log", [&] () {
|
||||
xml.attribute("string", "done"); });
|
||||
xml.node("exit", [&] () { });
|
||||
});
|
||||
|
||||
xml.node("route", [&] () {
|
||||
|
||||
xml.node("service", [&] () {
|
||||
xml.attribute("name", "LOG");
|
||||
xml.node("local", [&] () { }); });
|
||||
|
||||
xml.node("any-service", [&] () {
|
||||
xml.node("parent", [&] () { }); });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sandbox::Local_service_base::Wakeup interface
|
||||
*/
|
||||
void wakeup_local_service() override
|
||||
{
|
||||
_log_service.for_each_requested_session([&] (Log_service::Request &request) {
|
||||
|
||||
Log_session_component &session = *new (_heap)
|
||||
Log_session_component(_env.ep(),
|
||||
request.resources,
|
||||
request.label,
|
||||
request.diag);
|
||||
|
||||
request.deliver_session(session);
|
||||
});
|
||||
|
||||
_log_service.for_each_upgraded_session([&] (Log_session_component &,
|
||||
Session::Resources const &amount) {
|
||||
log("received RAM upgrade of ", amount.ram_quota);
|
||||
return Log_service::Upgrade_response::CONFIRMED;
|
||||
});
|
||||
|
||||
_log_service.for_each_session_to_close([&] (Log_session_component &session) {
|
||||
destroy(_heap, &session);
|
||||
return Log_service::Close_response::CLOSED;
|
||||
});
|
||||
}
|
||||
|
||||
Main(Env &env) : _env(env)
|
||||
{
|
||||
Buffered_xml const config { _heap, "config", [&] (Xml_generator &xml) {
|
||||
_generate_sandbox_config(xml); } };
|
||||
|
||||
config.with_xml_node([&] (Xml_node const &config) {
|
||||
|
||||
log("generated config: ", config);
|
||||
|
||||
_sandbox.apply_config(config);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Component::construct(Genode::Env &env) { static Test::Main main(env); }
|
||||
|
3
repos/os/src/test/sandbox/target.mk
Normal file
3
repos/os/src/test/sandbox/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-sandbox
|
||||
SRC_CC = main.cc
|
||||
LIBS += base sandbox
|
@ -21,8 +21,8 @@
|
||||
#include <os/session_requester.h>
|
||||
#include <util/arg_string.h>
|
||||
|
||||
/* init private includes */
|
||||
#include <init/server.h>
|
||||
/* sandbox library private includes */
|
||||
#include <sandbox/server.h>
|
||||
|
||||
/* GDB monitor includes */
|
||||
#include "genode_child_resources.h"
|
||||
@ -39,16 +39,16 @@ namespace Gdb_monitor {
|
||||
|
||||
class Gdb_monitor::App_child : public Child_policy,
|
||||
public Async_service::Wakeup,
|
||||
public Init::Report_update_trigger,
|
||||
public Init::Routed_service::Pd_accessor,
|
||||
public Init::Routed_service::Ram_accessor
|
||||
public Sandbox::Report_update_trigger,
|
||||
public Sandbox::Routed_service::Pd_accessor,
|
||||
public Sandbox::Routed_service::Ram_accessor
|
||||
{
|
||||
private:
|
||||
|
||||
typedef Registered<Genode::Parent_service> Parent_service;
|
||||
|
||||
typedef Registry<Parent_service> Parent_services;
|
||||
typedef Registry<Init::Routed_service> Child_services;
|
||||
typedef Registry<Parent_service> Parent_services;
|
||||
typedef Registry<Sandbox::Routed_service> Child_services;
|
||||
|
||||
/**
|
||||
* gdbserver blocks in 'select()', so a separate entrypoint is used.
|
||||
@ -144,7 +144,7 @@ class Gdb_monitor::App_child : public Child_policy,
|
||||
_env.ram(),
|
||||
_env.rm() };
|
||||
|
||||
Init::Server _server { _env, _alloc, _child_services, *this };
|
||||
Sandbox::Server _server { _env, _alloc, _child_services, *this };
|
||||
|
||||
Child *_child;
|
||||
|
||||
@ -173,19 +173,19 @@ class Gdb_monitor::App_child : public Child_policy,
|
||||
}
|
||||
|
||||
/**
|
||||
* Init::Report_update_trigger callbacks
|
||||
* Sandbox::Report_update_trigger callbacks
|
||||
*/
|
||||
void trigger_report_update() override { }
|
||||
void trigger_immediate_report_update() override { }
|
||||
|
||||
/**
|
||||
* Init::Routed_service::Pd_accessor interface
|
||||
* Sandbox::Routed_service::Pd_accessor interface
|
||||
*/
|
||||
Pd_session &pd() override { return _child->pd(); }
|
||||
Pd_session_capability pd_cap() const override { return _child->pd_session_cap(); }
|
||||
|
||||
/**
|
||||
* Init::Routed_service::Ram_accessor interface
|
||||
* Sandbox::Routed_service::Ram_accessor interface
|
||||
*/
|
||||
Pd_session &ram() override { return _child->pd(); }
|
||||
Pd_session_capability ram_cap() const override { return _child->pd_session_cap(); }
|
||||
@ -260,7 +260,7 @@ class Gdb_monitor::App_child : public Child_policy,
|
||||
|
||||
~App_child()
|
||||
{
|
||||
_child_services.for_each([&] (Init::Routed_service &service) {
|
||||
_child_services.for_each([&] (Sandbox::Routed_service &service) {
|
||||
destroy(_alloc, &service);
|
||||
});
|
||||
|
||||
@ -320,13 +320,13 @@ class Gdb_monitor::App_child : public Child_policy,
|
||||
return;
|
||||
}
|
||||
|
||||
new (_alloc) Init::Routed_service(_child_services,
|
||||
"target",
|
||||
*this, *this,
|
||||
_session_requester.id_space(),
|
||||
_child->session_factory(),
|
||||
service_name,
|
||||
*this);
|
||||
new (_alloc) Sandbox::Routed_service(_child_services,
|
||||
"target",
|
||||
*this, *this,
|
||||
_session_requester.id_space(),
|
||||
_child->session_factory(),
|
||||
service_name,
|
||||
*this);
|
||||
|
||||
char server_config[4096];
|
||||
|
||||
|
@ -97,12 +97,12 @@ vpath %.cc $(PRG_DIR)/gdbserver
|
||||
# parent directory of the init source is used as reference.
|
||||
#
|
||||
|
||||
INIT_PARENT_DIR = $(abspath $(dir $(call select_from_repositories,src/init/server.cc))/..)
|
||||
SANDBOX_PARENT_DIR = $(abspath $(dir $(call select_from_repositories,src/lib/sandbox/server.cc))/..)
|
||||
|
||||
INC_DIR += $(INIT_PARENT_DIR)
|
||||
INC_DIR += $(SANDBOX_PARENT_DIR)
|
||||
|
||||
SRC_CC += init/server.cc
|
||||
SRC_CC += sandbox/server.cc
|
||||
|
||||
vpath init/%.cc $(INIT_PARENT_DIR)
|
||||
vpath sandbox/%.cc $(SANDBOX_PARENT_DIR)
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
|
Loading…
Reference in New Issue
Block a user