mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
Merged refactored sandbox library with upstream.
This commit is contained in:
@@ -31,65 +31,42 @@
|
||||
#include <sandbox/utils.h>
|
||||
#include <sandbox/route_model.h>
|
||||
|
||||
namespace Sandbox { class Child; }
|
||||
namespace Sandbox
|
||||
{
|
||||
class Child;
|
||||
}
|
||||
|
||||
class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Resources assigned to the child
|
||||
*/
|
||||
struct Resources
|
||||
{
|
||||
long prio_levels_log2;
|
||||
long priority;
|
||||
Affinity affinity;
|
||||
Ram_quota assigned_ram_quota;
|
||||
Cap_quota assigned_cap_quota;
|
||||
Cpu_quota assigned_cpu_quota;
|
||||
|
||||
Ram_quota effective_ram_quota() const
|
||||
{
|
||||
return Genode::Child::effective_quota(assigned_ram_quota);
|
||||
}
|
||||
|
||||
Cap_quota effective_cap_quota() const
|
||||
{
|
||||
/* capabilities consumed by 'Genode::Child' */
|
||||
Cap_quota const effective =
|
||||
Genode::Child::effective_quota(assigned_cap_quota);
|
||||
|
||||
/* capabilities additionally consumed by init */
|
||||
enum {
|
||||
STATIC_COSTS = 1 /* possible heap backing-store
|
||||
allocation for session object */
|
||||
+ 1 /* buffered XML start node */
|
||||
+ 2 /* dynamic ROM for config */
|
||||
+ 2 /* dynamic ROM for session requester */
|
||||
};
|
||||
|
||||
if (effective.value < STATIC_COSTS)
|
||||
return Cap_quota{0};
|
||||
|
||||
return Cap_quota{effective.value - STATIC_COSTS};
|
||||
}
|
||||
};
|
||||
|
||||
typedef String<80> Version;
|
||||
public:
|
||||
using Version = String<80>;
|
||||
|
||||
/**
|
||||
* Exception types
|
||||
*/
|
||||
struct Child_name_is_not_unique : Exception { };
|
||||
struct Missing_name_attribute : Exception { };
|
||||
struct Child_name_is_not_unique : Exception
|
||||
{
|
||||
};
|
||||
struct Missing_name_attribute : Exception
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Unique ID of the child, solely used for diagnostic purposes
|
||||
*/
|
||||
struct Id { unsigned value; };
|
||||
struct Id
|
||||
{
|
||||
unsigned value;
|
||||
};
|
||||
|
||||
struct Default_route_accessor : Interface { virtual Xml_node default_route() = 0; };
|
||||
struct Default_caps_accessor : Interface { virtual Cap_quota default_caps() = 0; };
|
||||
struct Default_route_accessor : Interface
|
||||
{
|
||||
virtual Xml_node default_route() = 0;
|
||||
};
|
||||
struct Default_caps_accessor : Interface
|
||||
{
|
||||
virtual Cap_quota default_caps() = 0;
|
||||
};
|
||||
|
||||
template <typename QUOTA>
|
||||
struct Resource_limit_accessor : Interface
|
||||
@@ -100,19 +77,46 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
virtual QUOTA resource_limit(QUOTA const &) const = 0;
|
||||
};
|
||||
|
||||
typedef Resource_limit_accessor<Ram_quota> Ram_limit_accessor;
|
||||
typedef Resource_limit_accessor<Cap_quota> Cap_limit_accessor;
|
||||
typedef Resource_limit_accessor<Cpu_quota> Cpu_limit_accessor;
|
||||
using Ram_limit_accessor = Resource_limit_accessor<Ram_quota>;
|
||||
using Cap_limit_accessor = Resource_limit_accessor<Cap_quota>;
|
||||
using Cpu_limit_accessor = Resource_limit_accessor<Cpu_quota>;
|
||||
|
||||
struct Cpu_quota_transfer : Interface
|
||||
{
|
||||
virtual void transfer_cpu_quota(Cpu_session_capability, Cpu_quota) = 0;
|
||||
virtual void transfer_cpu_quota(Capability<Pd_session>, Pd_session &,
|
||||
Capability<Cpu_session>, Cpu_quota) = 0;
|
||||
};
|
||||
|
||||
enum class Sample_state_result { CHANGED, UNCHANGED };
|
||||
enum class Sample_state_result
|
||||
{
|
||||
CHANGED,
|
||||
UNCHANGED
|
||||
};
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Helper for passing lambda functions as 'Pd_intrinsics::Fn'
|
||||
*/
|
||||
|
||||
using Pd_intrinsics = Genode::Sandbox::Pd_intrinsics;
|
||||
|
||||
template <typename PD_SESSION, typename FN>
|
||||
static void with_pd_intrinsics(Pd_intrinsics &pd_intrinsics,
|
||||
Capability<Pd_session> cap, PD_SESSION &pd,
|
||||
FN const &fn)
|
||||
{
|
||||
struct Impl : Pd_intrinsics::Fn
|
||||
{
|
||||
using Intrinsics = Pd_intrinsics::Intrinsics;
|
||||
|
||||
FN const &_fn;
|
||||
Impl(FN const &fn) : _fn(fn) {}
|
||||
void call(Intrinsics &intrinsics) const override { _fn(intrinsics); }
|
||||
};
|
||||
|
||||
pd_intrinsics.with_intrinsics(cap, pd, Impl{fn});
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Child_registry;
|
||||
|
||||
Env &_env;
|
||||
@@ -123,12 +127,15 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
Id const _id;
|
||||
|
||||
enum class State {
|
||||
enum class State
|
||||
{
|
||||
|
||||
/*
|
||||
* States modelling the child's boostrap phase
|
||||
*/
|
||||
INITIAL, RAM_INITIALIZED, ALIVE,
|
||||
INITIAL,
|
||||
RAM_INITIALIZED,
|
||||
ALIVE,
|
||||
|
||||
/*
|
||||
* The child is present in the config model but its bootstrapping
|
||||
@@ -147,8 +154,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
* The child is no longer referenced by config model and can
|
||||
* safely be destructed.
|
||||
*/
|
||||
ABANDONED,
|
||||
|
||||
ABANDONED
|
||||
};
|
||||
|
||||
State _state = State::INITIAL;
|
||||
@@ -159,23 +165,24 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
Reconstructible<Buffered_xml> _start_node;
|
||||
|
||||
Constructible<Route_model> _route_model { };
|
||||
Constructible<Route_model> _route_model{};
|
||||
|
||||
void _construct_route_model_from_start_node(Xml_node const &start)
|
||||
{
|
||||
_route_model.destruct();
|
||||
|
||||
start.with_sub_node("route",
|
||||
[&] (Xml_node const &route) {
|
||||
_route_model.construct(_alloc, route); },
|
||||
[&] () {
|
||||
_route_model.construct(_alloc, _default_route_accessor.default_route()); });
|
||||
start.with_sub_node(
|
||||
"route",
|
||||
[&](Xml_node const &route)
|
||||
{ _route_model.construct(_alloc, route); },
|
||||
[&]()
|
||||
{ _route_model.construct(_alloc, _default_route_accessor.default_route()); });
|
||||
}
|
||||
|
||||
/*
|
||||
* Version attribute of the start node, used to force child restarts.
|
||||
*/
|
||||
Version _version { _start_node->xml().attribute_value("version", Version()) };
|
||||
Version _version{_start_node->xml().attribute_value("version", Version())};
|
||||
|
||||
bool _uncertain_dependencies = false;
|
||||
|
||||
@@ -208,8 +215,8 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
throw Missing_name_attribute();
|
||||
}
|
||||
|
||||
typedef String<64> Name;
|
||||
Name const _unique_name { _name_from_xml(_start_node->xml()) };
|
||||
using Name = String<64>;
|
||||
Name const _unique_name{_name_from_xml(_start_node->xml())};
|
||||
|
||||
static Binary_name _binary_from_xml(Xml_node start_node,
|
||||
Name const &unique_name)
|
||||
@@ -221,7 +228,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
}
|
||||
|
||||
/* updated on configuration update */
|
||||
Binary_name _binary_name { _binary_from_xml(_start_node->xml(), _unique_name) };
|
||||
Binary_name _binary_name{_binary_from_xml(_start_node->xml(), _unique_name)};
|
||||
|
||||
/* initialized in constructor, updated by 'apply_config' */
|
||||
bool _heartbeat_enabled;
|
||||
@@ -241,11 +248,48 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
return _heartbeat_enabled && (_state == State::ALIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resources assigned to the child
|
||||
*/
|
||||
struct Resources
|
||||
{
|
||||
long prio_levels_log2;
|
||||
long priority;
|
||||
Genode::Affinity affinity;
|
||||
Ram_quota assigned_ram_quota;
|
||||
Cap_quota assigned_cap_quota;
|
||||
Cpu_quota assigned_cpu_quota;
|
||||
|
||||
static
|
||||
Resources _resources_from_start_node(Xml_node start_node, Prio_levels prio_levels,
|
||||
Ram_quota effective_ram_quota() const
|
||||
{
|
||||
return Genode::Child::effective_quota(assigned_ram_quota);
|
||||
}
|
||||
|
||||
Cap_quota effective_cap_quota() const
|
||||
{
|
||||
/* capabilities consumed by 'Genode::Child' */
|
||||
Cap_quota const effective =
|
||||
Genode::Child::effective_quota(assigned_cap_quota);
|
||||
|
||||
/* capabilities additionally consumed by init */
|
||||
enum
|
||||
{
|
||||
STATIC_COSTS = 1 /* possible heap backing-store
|
||||
allocation for session object */
|
||||
+ 1 /* buffered XML start node */
|
||||
+ 2 /* dynamic ROM for config */
|
||||
+ 2 /* dynamic ROM for session requester */
|
||||
};
|
||||
|
||||
if (effective.value < STATIC_COSTS)
|
||||
return Cap_quota{0};
|
||||
|
||||
return Cap_quota{effective.value - STATIC_COSTS};
|
||||
}
|
||||
};
|
||||
|
||||
static Resources _resources_from_start_node(Xml_node start_node, Prio_levels prio_levels,
|
||||
Affinity::Space const &affinity_space,
|
||||
Affinity::Location const &location,
|
||||
Cap_quota default_cap_quota)
|
||||
{
|
||||
unsigned cpu_percent = 0;
|
||||
@@ -253,9 +297,10 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
size_t caps = start_node.attribute_value("caps", default_cap_quota.value);
|
||||
|
||||
start_node.for_each_sub_node("resource", [&] (Xml_node rsc) {
|
||||
start_node.for_each_sub_node("resource", [&](Xml_node rsc)
|
||||
{
|
||||
|
||||
typedef String<8> Name;
|
||||
using Name = String<8>;
|
||||
Name const name = rsc.attribute_value("name", Name());
|
||||
|
||||
if (name == "RAM")
|
||||
@@ -265,17 +310,15 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
cpu_percent = rsc.attribute_value("quantum", 0U);
|
||||
|
||||
if (name == "CAP")
|
||||
caps = rsc.attribute_value("quantum", 0UL);
|
||||
});
|
||||
caps = rsc.attribute_value("quantum", 0UL); });
|
||||
|
||||
return Resources { log2(prio_levels.value),
|
||||
return Resources{log2(prio_levels.value),
|
||||
priority_from_xml(start_node, prio_levels),
|
||||
Affinity(affinity_space,
|
||||
(location.xpos() == -1 ? affinity_location_from_xml(affinity_space, start_node) : location)),
|
||||
//affinity_location_from_xml(affinity_space, start_node)),
|
||||
Ram_quota { ram_bytes },
|
||||
Cap_quota { caps },
|
||||
Cpu_quota { cpu_percent } };
|
||||
Genode::Affinity(affinity_space,
|
||||
affinity_location_from_xml(affinity_space, start_node)),
|
||||
Ram_quota{ram_bytes},
|
||||
Cap_quota{caps},
|
||||
Cpu_quota{cpu_percent}};
|
||||
}
|
||||
|
||||
Resources _resources;
|
||||
@@ -283,6 +326,16 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
Ram_quota _configured_ram_quota() const;
|
||||
Cap_quota _configured_cap_quota() const;
|
||||
|
||||
Pd_intrinsics &_pd_intrinsics;
|
||||
|
||||
template <typename FN>
|
||||
void _with_pd_intrinsics(FN const &fn)
|
||||
{
|
||||
with_pd_intrinsics(_pd_intrinsics, _child.pd_session_cap(), _child.pd(), fn);
|
||||
}
|
||||
|
||||
Capability<Pd_session> _ref_pd_cap{}; /* defined by 'init' */
|
||||
|
||||
using Local_service = Genode::Sandbox::Local_service_base;
|
||||
|
||||
Registry<Parent_service> &_parent_services;
|
||||
@@ -291,18 +344,18 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
struct Inline_config_rom_service : Abandonable, Dynamic_rom_session::Content_producer
|
||||
{
|
||||
typedef Genode::Local_service<Dynamic_rom_session> Service;
|
||||
using Service = Genode::Local_service<Dynamic_rom_session>;
|
||||
|
||||
Child &_child;
|
||||
|
||||
Dynamic_rom_session _session { _child._env.ep().rpc_ep(),
|
||||
_child.ref_pd(), _child._env.rm(),
|
||||
*this };
|
||||
Dynamic_rom_session _session{_child._env.ep().rpc_ep(),
|
||||
_child._env.ram(), _child._env.rm(),
|
||||
*this};
|
||||
|
||||
Service::Single_session_factory _factory { _session };
|
||||
Service _service { _factory };
|
||||
Service::Single_session_factory _factory{_session};
|
||||
Service _service{_factory};
|
||||
|
||||
Inline_config_rom_service(Child &child) : _child(child) { }
|
||||
Inline_config_rom_service(Child &child) : _child(child) {}
|
||||
|
||||
/**
|
||||
* Dynamic_rom_session::Content_producer interface
|
||||
@@ -318,7 +371,8 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
if (config_len + 1 /* null termination */ >= dst_len)
|
||||
throw Buffer_capacity_exceeded();
|
||||
|
||||
config.with_raw_node([&] (char const *start, size_t length) {
|
||||
config.with_raw_node([&](char const *start, size_t length)
|
||||
{
|
||||
|
||||
/*
|
||||
* The 'length' is the number of bytes of the config-node
|
||||
@@ -329,8 +383,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
* thereby include the last actual config-content character
|
||||
* in the result.
|
||||
*/
|
||||
copy_cstring(dst, start, length + 1);
|
||||
});
|
||||
copy_cstring(dst, start, length + 1); });
|
||||
}
|
||||
|
||||
void trigger_update() { _session.trigger_update(); }
|
||||
@@ -338,26 +391,26 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
Service &service() { return _service; }
|
||||
};
|
||||
|
||||
Constructible<Inline_config_rom_service> _config_rom_service { };
|
||||
Constructible<Inline_config_rom_service> _config_rom_service{};
|
||||
|
||||
Session_requester _session_requester;
|
||||
|
||||
/**
|
||||
* CPU-session priority parameters
|
||||
*/
|
||||
long const _prio_levels_log2 { _resources.prio_levels_log2 };
|
||||
long const _priority { _resources.priority };
|
||||
long const _prio_levels_log2{_resources.prio_levels_log2};
|
||||
long const _priority{_resources.priority};
|
||||
|
||||
Cpu_quota const _effective_cpu_quota {
|
||||
Cpu_quota const _effective_cpu_quota{
|
||||
min(_cpu_limit_accessor.resource_limit(Cpu_quota{}).percent,
|
||||
_resources.assigned_cpu_quota.percent) };
|
||||
_resources.assigned_cpu_quota.percent)};
|
||||
|
||||
/**
|
||||
* If set to true, the child is allowed to do system management,
|
||||
* e.g., constrain physical RAM allocations.
|
||||
*/
|
||||
bool const _managing_system {
|
||||
_start_node->xml().attribute_value("managing_system", false) };
|
||||
bool const _managing_system{
|
||||
_start_node->xml().attribute_value("managing_system", false)};
|
||||
|
||||
/**
|
||||
* Resource request initiated by the child
|
||||
@@ -368,37 +421,37 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
Cap_quota const caps;
|
||||
|
||||
Requested_resources(Parent::Resource_args const &args)
|
||||
:
|
||||
ram (ram_quota_from_args(args.string())),
|
||||
: ram(ram_quota_from_args(args.string())),
|
||||
caps(cap_quota_from_args(args.string()))
|
||||
{ }
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Constructible<Requested_resources> _requested_resources { };
|
||||
Constructible<Requested_resources> _requested_resources{};
|
||||
|
||||
Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
|
||||
Genode::Child _child{_env.rm(), _env.ep().rpc_ep(), *this};
|
||||
|
||||
struct Pd_accessor : Routed_service::Pd_accessor
|
||||
{
|
||||
Genode::Child &_child;
|
||||
|
||||
Pd_accessor(Genode::Child &child) : _child(child) { }
|
||||
Pd_accessor(Genode::Child &child) : _child(child) {}
|
||||
|
||||
Pd_session &pd() override { return _child.pd(); }
|
||||
Pd_session_capability pd_cap() const override { return _child.pd_session_cap(); }
|
||||
|
||||
} _pd_accessor { _child };
|
||||
} _pd_accessor{_child};
|
||||
|
||||
struct Ram_accessor : Routed_service::Ram_accessor
|
||||
{
|
||||
Genode::Child &_child;
|
||||
|
||||
Ram_accessor(Genode::Child &child) : _child(child) { }
|
||||
Ram_accessor(Genode::Child &child) : _child(child) {}
|
||||
|
||||
Pd_session &ram() override { return _child.pd(); }
|
||||
Pd_session_capability ram_cap() const override { return _child.pd_session_cap(); }
|
||||
|
||||
} _ram_accessor { _child };
|
||||
} _ram_accessor{_child};
|
||||
|
||||
/**
|
||||
* Async_service::Wakeup callback
|
||||
@@ -408,7 +461,12 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
_session_requester.trigger_update();
|
||||
}
|
||||
|
||||
enum class Route_state { VALID, MISMATCH, UNAVAILABLE };
|
||||
enum class Route_state
|
||||
{
|
||||
VALID,
|
||||
MISMATCH,
|
||||
UNAVAILABLE
|
||||
};
|
||||
|
||||
/**
|
||||
* Return true if the policy results in the current route of the session
|
||||
@@ -419,24 +477,28 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
*/
|
||||
Route_state _route_valid(Session_state const &session)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
Route const route =
|
||||
resolve_session_request(session.service().name(),
|
||||
session.client_label(),
|
||||
session.diag());
|
||||
|
||||
bool const valid = (session.service() == route.service)
|
||||
&& (route.label == session.label());
|
||||
bool const valid = (session.service() == route.service) && (route.label == session.label());
|
||||
|
||||
return valid ? Route_state::VALID : Route_state::MISMATCH;
|
||||
}
|
||||
catch (Service_denied) { return Route_state::UNAVAILABLE; }
|
||||
catch (Service_denied)
|
||||
{
|
||||
return Route_state::UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
static Xml_node _provides_sub_node(Xml_node start_node)
|
||||
{
|
||||
return start_node.has_sub_node("provides")
|
||||
? start_node.sub_node("provides") : Xml_node("<provides/>");
|
||||
? start_node.sub_node("provides")
|
||||
: Xml_node("<provides/>");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -453,7 +515,8 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
bool _service_exists(Xml_node node) const
|
||||
{
|
||||
bool exists = false;
|
||||
_child_services.for_each([&] (Routed_service const &service) {
|
||||
_child_services.for_each([&](Routed_service const &service)
|
||||
{
|
||||
if (_provided_by_this(service) &&
|
||||
service.name() == node.attribute_value("name", Service::Name()))
|
||||
exists = true; });
|
||||
@@ -482,8 +545,8 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
* and reported afterwards through the state report.
|
||||
*/
|
||||
|
||||
bool _exited { false };
|
||||
int _exit_value { -1 };
|
||||
bool _exited{false};
|
||||
int _exit_value{-1};
|
||||
|
||||
/**
|
||||
* Return true if it's safe to call the PD for requesting resource
|
||||
@@ -503,20 +566,21 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
static Sampled_state from_pd(Pd_session &pd)
|
||||
{
|
||||
return { .ram = Ram_info::from_pd(pd),
|
||||
.caps = Cap_info::from_pd(pd) };
|
||||
return {.ram = Ram_info::from_pd(pd),
|
||||
.caps = Cap_info::from_pd(pd)};
|
||||
}
|
||||
|
||||
bool operator != (Sampled_state const &other) const
|
||||
bool operator!=(Sampled_state const &other) const
|
||||
{
|
||||
return (ram != other.ram) || (caps != other.caps);
|
||||
}
|
||||
|
||||
} _sampled_state { };
|
||||
} _sampled_state{};
|
||||
|
||||
void _abandon_services()
|
||||
{
|
||||
_child_services.for_each([&] (Routed_service &service) {
|
||||
_child_services.for_each([&](Routed_service &service)
|
||||
{
|
||||
if (service.has_id_space(_session_requester.id_space()))
|
||||
service.abandon(); });
|
||||
}
|
||||
@@ -527,8 +591,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
_abandon_services();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -558,10 +621,10 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
Cpu_quota_transfer &cpu_quota_transfer,
|
||||
Prio_levels prio_levels,
|
||||
Affinity::Space const &affinity_space,
|
||||
Affinity::Location const &location,
|
||||
Registry<Parent_service> &parent_services,
|
||||
Registry<Routed_service> &child_services,
|
||||
Registry<Local_service> &local_services);
|
||||
Registry<Local_service> &local_services,
|
||||
Pd_intrinsics &pd_intrinsics);
|
||||
|
||||
virtual ~Child();
|
||||
|
||||
@@ -576,9 +639,10 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
Cap_quota cap_quota() const { return _resources.assigned_cap_quota; }
|
||||
Cpu_quota cpu_quota() const { return _effective_cpu_quota; }
|
||||
|
||||
virtual void try_start()
|
||||
void try_start()
|
||||
{
|
||||
if (_state == State::INITIAL)
|
||||
{
|
||||
if (_state == State::INITIAL) {
|
||||
_child.initiate_env_pd_session();
|
||||
_state = State::RAM_INITIALIZED;
|
||||
}
|
||||
@@ -591,7 +655,8 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
if (_state == State::RAM_INITIALIZED && _child.active())
|
||||
_state = State::ALIVE;
|
||||
|
||||
if (_state == State::RAM_INITIALIZED) {
|
||||
if (_state == State::RAM_INITIALIZED)
|
||||
{
|
||||
_child.initiate_env_sessions();
|
||||
|
||||
if (_child.active())
|
||||
@@ -624,7 +689,11 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
bool env_sessions_closed() const { return _child.env_sessions_closed(); }
|
||||
|
||||
enum Apply_config_result { PROVIDED_SERVICES_CHANGED, NO_SIDE_EFFECTS };
|
||||
enum Apply_config_result
|
||||
{
|
||||
PROVIDED_SERVICES_CHANGED,
|
||||
NO_SIDE_EFFECTS
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply new configuration to child
|
||||
@@ -665,7 +734,6 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
_report_update_trigger.trigger_report_update();
|
||||
|
||||
_last_skipped_heartbeats = skipped_heartbeats;
|
||||
|
||||
}
|
||||
|
||||
unsigned skipped_heartbeats() const
|
||||
@@ -677,22 +745,31 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
Sample_state_result sample_state();
|
||||
|
||||
|
||||
|
||||
/****************************
|
||||
** Child-policy interface **
|
||||
****************************/
|
||||
|
||||
Child_policy::Name name() const override { return _unique_name; }
|
||||
|
||||
Pd_session &ref_pd() override { return _env.pd(); }
|
||||
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
|
||||
Pd_session &ref_pd() override
|
||||
{
|
||||
Pd_session *_ref_pd_ptr = nullptr;
|
||||
_with_pd_intrinsics([&](Pd_intrinsics::Intrinsics &intrinsics)
|
||||
{ _ref_pd_ptr = &intrinsics.ref_pd; });
|
||||
return *_ref_pd_ptr;
|
||||
}
|
||||
|
||||
Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; }
|
||||
|
||||
Ram_allocator &session_md_ram() override { return _env.ram(); }
|
||||
|
||||
void init(Pd_session &, Pd_session_capability) override;
|
||||
void init(Cpu_session &, Cpu_session_capability) override;
|
||||
|
||||
Id_space<Parent::Server> &server_id_space() override {
|
||||
return _session_requester.id_space(); }
|
||||
Id_space<Parent::Server> &server_id_space() override
|
||||
{
|
||||
return _session_requester.id_space();
|
||||
}
|
||||
|
||||
Route resolve_session_request(Service::Name const &,
|
||||
Session_label const &, Session::Diag) override;
|
||||
@@ -704,12 +781,17 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
void exit(int exit_value) override
|
||||
{
|
||||
try {
|
||||
if (_start_node->xml().sub_node("exit").attribute_value("propagate", false)) {
|
||||
try
|
||||
{
|
||||
if (_start_node->xml().sub_node("exit").attribute_value("propagate", false))
|
||||
{
|
||||
_env.parent().exit(exit_value);
|
||||
return;
|
||||
}
|
||||
} catch (...) { }
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger a new report for exited children so that any management
|
||||
@@ -720,7 +802,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
_child.close_all_sessions();
|
||||
|
||||
_report_update_trigger.trigger_report_update();
|
||||
_report_update_trigger.trigger_immediate_report_update();
|
||||
|
||||
/*
|
||||
* Print a message as the exit is not handled otherwise. There are
|
||||
@@ -737,6 +819,17 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
|
||||
bool initiate_env_sessions() const override { return false; }
|
||||
|
||||
void _with_address_space(Pd_session &, With_address_space_fn const &fn) override
|
||||
{
|
||||
_with_pd_intrinsics([&](Pd_intrinsics::Intrinsics &intrinsics)
|
||||
{ fn.call(intrinsics.address_space); });
|
||||
}
|
||||
|
||||
void start_initial_thread(Capability<Cpu_thread> cap, addr_t ip) override
|
||||
{
|
||||
_pd_intrinsics.start_initial_thread(cap, ip);
|
||||
}
|
||||
|
||||
void yield_response() override
|
||||
{
|
||||
apply_downgrade();
|
||||
@@ -745,3 +838,4 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
|
||||
};
|
||||
|
||||
#endif /* _LIB__SANDBOX__CHILD_H_ */
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <sandbox/server.h>
|
||||
#include <sandbox/heartbeat.h>
|
||||
#include <sandbox/config_model.h>
|
||||
#include <sandbox/sandbox.h>
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/heap.h>
|
||||
@@ -21,7 +22,6 @@ namespace Sandbox {
|
||||
namespace Genode {
|
||||
class Sandbox;
|
||||
}
|
||||
|
||||
struct Sandbox::Library : ::Sandbox::State_reporter::Producer,
|
||||
::Sandbox::Child::Default_route_accessor,
|
||||
::Sandbox::Child::Default_caps_accessor,
|
||||
@@ -50,41 +50,45 @@ struct Sandbox::Library : ::Sandbox::State_reporter::Producer,
|
||||
using Config_model = ::Sandbox::Config_model;
|
||||
using Start_model = ::Sandbox::Start_model;
|
||||
using Preservation = ::Sandbox::Preservation;
|
||||
using Pd_intrinsics = Genode::Sandbox::Pd_intrinsics;
|
||||
|
||||
using State_handler = Genode::Sandbox::State_handler;
|
||||
|
||||
public:
|
||||
Env &_env;
|
||||
Heap &_heap;
|
||||
|
||||
Registry<Parent_service> _parent_services { };
|
||||
Registry<Routed_service> _child_services { };
|
||||
Pd_intrinsics &_pd_intrinsics;
|
||||
|
||||
Registry<Parent_service> _parent_services{};
|
||||
Registry<Routed_service> _child_services{};
|
||||
Registry<Local_service> &_local_services;
|
||||
Child_registry _children { };
|
||||
Child_registry _children{};
|
||||
|
||||
/*
|
||||
* Global parameters obtained from config
|
||||
*/
|
||||
Reconstructible<Verbose> _verbose { };
|
||||
Config_model::Version _version { };
|
||||
Constructible<Buffered_xml> _default_route { };
|
||||
Cap_quota _default_caps { 0 };
|
||||
Prio_levels _prio_levels { };
|
||||
Constructible<Affinity::Space> _affinity_space { };
|
||||
Preservation _preservation { };
|
||||
Reconstructible<Verbose> _verbose{};
|
||||
Config_model::Version _version{};
|
||||
Constructible<Buffered_xml> _default_route{};
|
||||
Cap_quota _default_caps{0};
|
||||
Prio_levels _prio_levels{};
|
||||
Constructible<Affinity::Space> _affinity_space{};
|
||||
Preservation _preservation{};
|
||||
|
||||
Affinity::Space _effective_affinity_space() const
|
||||
{
|
||||
return _affinity_space.constructed() ? *_affinity_space
|
||||
: Affinity::Space { 1, 1 };
|
||||
: Affinity::Space{1, 1};
|
||||
}
|
||||
|
||||
State_reporter _state_reporter;
|
||||
|
||||
Heartbeat _heartbeat { _env, _children, _state_reporter };
|
||||
Heartbeat _heartbeat{_env, _children, _state_reporter};
|
||||
|
||||
/*
|
||||
* Internal representation of the XML configuration
|
||||
*/
|
||||
Config_model _config_model { };
|
||||
Config_model _config_model{};
|
||||
|
||||
/*
|
||||
* Variables for tracking the side effects of updating the config model
|
||||
@@ -94,33 +98,35 @@ public:
|
||||
|
||||
unsigned _child_cnt = 0;
|
||||
|
||||
Cpu_quota _avail_cpu { .percent = 100 };
|
||||
Cpu_quota _transferred_cpu { .percent = 0 };
|
||||
Cpu_quota _avail_cpu{.percent = 100};
|
||||
Cpu_quota _transferred_cpu{.percent = 0};
|
||||
|
||||
Ram_quota _avail_ram() const
|
||||
{
|
||||
Ram_quota avail_ram = _env.pd().avail_ram();
|
||||
|
||||
if (_preservation.ram.value > avail_ram.value) {
|
||||
if (_preservation.ram.value > avail_ram.value)
|
||||
{
|
||||
error("RAM preservation exceeds available memory");
|
||||
return Ram_quota { 0 };
|
||||
return Ram_quota{0};
|
||||
}
|
||||
|
||||
/* deduce preserved quota from available quota */
|
||||
return Ram_quota { avail_ram.value - _preservation.ram.value };
|
||||
return Ram_quota{avail_ram.value - _preservation.ram.value};
|
||||
}
|
||||
|
||||
Cap_quota _avail_caps() const
|
||||
{
|
||||
Cap_quota avail_caps { _env.pd().avail_caps().value };
|
||||
Cap_quota avail_caps{_env.pd().avail_caps().value};
|
||||
|
||||
if (_preservation.caps.value > avail_caps.value) {
|
||||
if (_preservation.caps.value > avail_caps.value)
|
||||
{
|
||||
error("Capability preservation exceeds available capabilities");
|
||||
return Cap_quota { 0 };
|
||||
return Cap_quota{0};
|
||||
}
|
||||
|
||||
/* deduce preserved quota from available quota */
|
||||
return Cap_quota { avail_caps.value - _preservation.caps.value };
|
||||
return Cap_quota{avail_caps.value - _preservation.caps.value};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,9 +150,10 @@ public:
|
||||
/**
|
||||
* Child::Cpu_quota_transfer interface
|
||||
*/
|
||||
void transfer_cpu_quota(Cpu_session_capability cap, Cpu_quota quota) override
|
||||
void transfer_cpu_quota(Capability<Pd_session> pd_cap, Pd_session &pd,
|
||||
Capability<Cpu_session> cpu, Cpu_quota quota) override
|
||||
{
|
||||
Cpu_quota const remaining { 100 - min(100u, _transferred_cpu.percent) };
|
||||
Cpu_quota const remaining{100 - min(100u, _transferred_cpu.percent)};
|
||||
|
||||
/* prevent division by zero in 'quota_lim_upscale' */
|
||||
if (remaining.percent == 0)
|
||||
@@ -155,7 +162,8 @@ public:
|
||||
size_t const fraction =
|
||||
Cpu_session::quota_lim_upscale(quota.percent, remaining.percent);
|
||||
|
||||
_env.cpu().transfer_quota(cap, fraction);
|
||||
Child::with_pd_intrinsics(_pd_intrinsics, pd_cap, pd, [&](auto &intrinsics)
|
||||
{ intrinsics.ref_cpu.transfer_quota(cpu, fraction); });
|
||||
|
||||
_transferred_cpu.percent += quota.percent;
|
||||
}
|
||||
@@ -166,10 +174,12 @@ public:
|
||||
void produce_state_report(Xml_generator &xml, Report_detail const &detail) const override
|
||||
{
|
||||
if (detail.init_ram())
|
||||
xml.node("ram", [&] () { Ram_info::from_pd(_env.pd()).generate(xml); });
|
||||
xml.node("ram", [&]()
|
||||
{ Ram_info::from_pd(_env.pd()).generate(xml); });
|
||||
|
||||
if (detail.init_caps())
|
||||
xml.node("caps", [&] () { Cap_info::from_pd(_env.pd()).generate(xml); });
|
||||
xml.node("caps", [&]()
|
||||
{ Cap_info::from_pd(_env.pd()).generate(xml); });
|
||||
|
||||
if (detail.children())
|
||||
_children.report_state(xml, detail);
|
||||
@@ -201,19 +211,19 @@ public:
|
||||
void _update_parent_services_from_config(Xml_node const &);
|
||||
void _update_children_config(Xml_node const &);
|
||||
void _destroy_abandoned_parent_services();
|
||||
virtual void _destroy_abandoned_children();
|
||||
void _destroy_abandoned_children();
|
||||
|
||||
Server _server { _env, _heap, _child_services, _state_reporter };
|
||||
Server _server{_env, _heap, _child_services, _state_reporter};
|
||||
|
||||
/**
|
||||
* Sandbox::Start_model::Factory
|
||||
*/
|
||||
virtual Child &create_child(Xml_node const &) override;
|
||||
Child &create_child(Xml_node const &) override;
|
||||
|
||||
/**
|
||||
* Sandbox::Start_model::Factory
|
||||
*/
|
||||
virtual void update_child(Child &, Xml_node const &) override;
|
||||
void update_child(Child &, Xml_node const &) override;
|
||||
|
||||
/**
|
||||
* Sandbox::Start_model::Factory
|
||||
@@ -248,16 +258,48 @@ public:
|
||||
return *new (_heap) Parent_service(_parent_services, _env, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default way of using the 'Env::pd' as the child's 'ref_pd' and accessing
|
||||
* the child's address space via RPC.
|
||||
*/
|
||||
struct Default_pd_intrinsics : Pd_intrinsics
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
void with_intrinsics(Capability<Pd_session>, Pd_session &pd, Fn const &fn) override
|
||||
{
|
||||
Region_map_client region_map(pd.address_space());
|
||||
|
||||
Intrinsics intrinsics{_env.pd(), _env.pd_session_cap(),
|
||||
_env.cpu(), _env.cpu_session_cap(), region_map};
|
||||
fn.call(intrinsics);
|
||||
}
|
||||
|
||||
void start_initial_thread(Capability<Cpu_thread> cap, addr_t ip) override
|
||||
{
|
||||
Cpu_thread_client(cap).start(ip, 0);
|
||||
}
|
||||
|
||||
Default_pd_intrinsics(Env &env) : _env(env) {}
|
||||
|
||||
} _default_pd_intrinsics{_env};
|
||||
|
||||
Library(Env &env, Heap &heap, Registry<Local_service> &local_services,
|
||||
Genode::Sandbox::State_handler &state_handler)
|
||||
:
|
||||
_env(env), _heap(heap), _local_services(local_services),
|
||||
_state_reporter(_env, *this, state_handler)
|
||||
{ }
|
||||
State_handler &state_handler, Pd_intrinsics &pd_intrinsics)
|
||||
: _env(env), _heap(heap), _pd_intrinsics(pd_intrinsics),
|
||||
_local_services(local_services), _state_reporter(_env, *this, state_handler)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void apply_config(Xml_node const &);
|
||||
Library(Env &env, Heap &heap, Registry<Local_service> &local_services,
|
||||
State_handler &state_handler)
|
||||
: Library(env, heap, local_services, state_handler, _default_pd_intrinsics)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void generate_state_report(Xml_generator &xml) const
|
||||
void apply_config(Xml_node const &);
|
||||
|
||||
void generate_state_report(Xml_generator &xml) const
|
||||
{
|
||||
_state_reporter.generate(xml);
|
||||
}
|
||||
|
||||
@@ -15,17 +15,16 @@
|
||||
#include <vm_session/vm_session.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sandbox/child.h>
|
||||
|
||||
#include <child.h>
|
||||
|
||||
void Sandbox::Child::destroy_services()
|
||||
{
|
||||
_child_services.for_each([&] (Routed_service &service) {
|
||||
_child_services.for_each([&](Routed_service &service)
|
||||
{
|
||||
if (service.has_id_space(_session_requester.id_space()))
|
||||
destroy(_alloc, &service); });
|
||||
}
|
||||
|
||||
|
||||
Sandbox::Child::Apply_config_result
|
||||
Sandbox::Child::apply_config(Xml_node start_node)
|
||||
{
|
||||
@@ -36,15 +35,17 @@ Sandbox::Child::apply_config(Xml_node start_node)
|
||||
* If the child was started but its environment is incomplete, mark it as
|
||||
* being stuck in order to restart it once the environment changes.
|
||||
*/
|
||||
if (_state != State::INITIAL) {
|
||||
if (_state != State::INITIAL)
|
||||
{
|
||||
bool env_log_exists = false, env_binary_exists = false;
|
||||
_child.for_each_session([&] (Session_state const &session) {
|
||||
_child.for_each_session([&](Session_state const &session)
|
||||
{
|
||||
Parent::Client::Id const id = session.id_at_client();
|
||||
env_log_exists |= (id == Parent::Env::log());
|
||||
env_binary_exists |= (id == Parent::Env::binary());
|
||||
});
|
||||
env_binary_exists |= (id == Parent::Env::binary()); });
|
||||
|
||||
if (!env_binary_exists || !env_log_exists) {
|
||||
if (!env_binary_exists || !env_log_exists)
|
||||
{
|
||||
_state = State::STUCK;
|
||||
return NO_SIDE_EFFECTS;
|
||||
}
|
||||
@@ -52,22 +53,29 @@ Sandbox::Child::apply_config(Xml_node start_node)
|
||||
|
||||
bool provided_services_changed = false;
|
||||
|
||||
enum Config_update { CONFIG_APPEARED, CONFIG_VANISHED,
|
||||
CONFIG_CHANGED, CONFIG_UNCHANGED };
|
||||
enum Config_update
|
||||
{
|
||||
CONFIG_APPEARED,
|
||||
CONFIG_VANISHED,
|
||||
CONFIG_CHANGED,
|
||||
CONFIG_UNCHANGED
|
||||
};
|
||||
|
||||
Config_update config_update = CONFIG_UNCHANGED;
|
||||
|
||||
/*
|
||||
* Import new start node if it differs
|
||||
*/
|
||||
if (start_node.differs_from(_start_node->xml())) {
|
||||
if (start_node.differs_from(_start_node->xml()))
|
||||
{
|
||||
|
||||
/*
|
||||
* The <route> node may affect the availability or unavailability
|
||||
* of dependencies.
|
||||
*/
|
||||
start_node.with_optional_sub_node("route", [&] (Xml_node const &route) {
|
||||
_start_node->xml().with_optional_sub_node("route", [&] (Xml_node const &orig) {
|
||||
start_node.with_optional_sub_node("route", [&](Xml_node const &route)
|
||||
{ _start_node->xml().with_optional_sub_node("route", [&](Xml_node const &orig)
|
||||
{
|
||||
if (route.differs_from(orig)) {
|
||||
_construct_route_model_from_start_node(start_node);
|
||||
_uncertain_dependencies = true; } }); });
|
||||
@@ -75,7 +83,7 @@ Sandbox::Child::apply_config(Xml_node start_node)
|
||||
/*
|
||||
* Determine how the inline config is affected.
|
||||
*/
|
||||
char const * const tag = "config";
|
||||
char const *const tag = "config";
|
||||
bool const config_was_present = _start_node->xml().has_sub_node(tag);
|
||||
bool const config_is_present = start_node.has_sub_node(tag);
|
||||
|
||||
@@ -88,7 +96,8 @@ Sandbox::Child::apply_config(Xml_node start_node)
|
||||
if (!config_was_present && config_is_present)
|
||||
config_update = CONFIG_APPEARED;
|
||||
|
||||
if (config_was_present && config_is_present) {
|
||||
if (config_was_present && config_is_present)
|
||||
{
|
||||
|
||||
Xml_node const old_config = _start_node->xml().sub_node(tag);
|
||||
Xml_node const new_config = start_node.sub_node(tag);
|
||||
@@ -103,7 +112,8 @@ Sandbox::Child::apply_config(Xml_node start_node)
|
||||
* First abandon services that are no longer present in the
|
||||
* <provides> node. Then add services that have newly appeared.
|
||||
*/
|
||||
_child_services.for_each([&] (Routed_service &service) {
|
||||
_child_services.for_each([&](Routed_service &service)
|
||||
{
|
||||
|
||||
if (!_provided_by_this(service))
|
||||
return;
|
||||
@@ -120,17 +130,15 @@ Sandbox::Child::apply_config(Xml_node start_node)
|
||||
if (!still_provided) {
|
||||
service.abandon();
|
||||
provided_services_changed = true;
|
||||
}
|
||||
});
|
||||
} });
|
||||
|
||||
_provides_sub_node(start_node).for_each_sub_node("service",
|
||||
[&] (Xml_node node) {
|
||||
_provides_sub_node(start_node).for_each_sub_node("service", [&](Xml_node node)
|
||||
{
|
||||
if (_service_exists(node))
|
||||
return;
|
||||
|
||||
_add_service(node);
|
||||
provided_services_changed = true;
|
||||
});
|
||||
provided_services_changed = true; });
|
||||
|
||||
/*
|
||||
* Import new binary name. A change may affect the route for
|
||||
@@ -154,11 +162,19 @@ Sandbox::Child::apply_config(Xml_node start_node)
|
||||
* may in turn prompt the routing-check by 'evaluate_dependencies'
|
||||
* to restart the child.
|
||||
*/
|
||||
switch (config_update) {
|
||||
case CONFIG_UNCHANGED: break;
|
||||
case CONFIG_CHANGED: _config_rom_service->trigger_update(); break;
|
||||
case CONFIG_APPEARED: _config_rom_service.construct(*this); break;
|
||||
case CONFIG_VANISHED: _config_rom_service->abandon(); break;
|
||||
switch (config_update)
|
||||
{
|
||||
case CONFIG_UNCHANGED:
|
||||
break;
|
||||
case CONFIG_CHANGED:
|
||||
_config_rom_service->trigger_update();
|
||||
break;
|
||||
case CONFIG_APPEARED:
|
||||
_config_rom_service.construct(*this);
|
||||
break;
|
||||
case CONFIG_VANISHED:
|
||||
_config_rom_service->abandon();
|
||||
break;
|
||||
}
|
||||
|
||||
if (provided_services_changed)
|
||||
@@ -167,24 +183,24 @@ Sandbox::Child::apply_config(Xml_node start_node)
|
||||
return NO_SIDE_EFFECTS;
|
||||
}
|
||||
|
||||
|
||||
void Sandbox::Child::evaluate_dependencies()
|
||||
{
|
||||
bool any_route_changed = false;
|
||||
bool any_route_unavailable = false;
|
||||
|
||||
_child.for_each_session([&] (Session_state const &session) {
|
||||
_child.for_each_session([&](Session_state const &session)
|
||||
{
|
||||
|
||||
switch (_route_valid(session)) {
|
||||
case Route_state::VALID: break;
|
||||
case Route_state::UNAVAILABLE: any_route_unavailable = true; break;
|
||||
case Route_state::MISMATCH: any_route_changed = true; break;
|
||||
}
|
||||
});
|
||||
} });
|
||||
|
||||
_uncertain_dependencies = false;
|
||||
|
||||
if (any_route_unavailable) {
|
||||
if (any_route_unavailable)
|
||||
{
|
||||
_state = State::STUCK;
|
||||
return;
|
||||
}
|
||||
@@ -193,27 +209,25 @@ void Sandbox::Child::evaluate_dependencies()
|
||||
_schedule_restart();
|
||||
}
|
||||
|
||||
|
||||
Sandbox::Ram_quota Sandbox::Child::_configured_ram_quota() const
|
||||
{
|
||||
size_t assigned = 0;
|
||||
|
||||
_start_node->xml().for_each_sub_node("resource", [&] (Xml_node resource) {
|
||||
_start_node->xml().for_each_sub_node("resource", [&](Xml_node resource)
|
||||
{
|
||||
if (resource.attribute_value("name", String<8>()) == "RAM")
|
||||
assigned = resource.attribute_value("quantum", Number_of_bytes()); });
|
||||
|
||||
return Ram_quota { assigned };
|
||||
return Ram_quota{assigned};
|
||||
}
|
||||
|
||||
|
||||
Sandbox::Cap_quota Sandbox::Child::_configured_cap_quota() const
|
||||
{
|
||||
size_t const default_caps = _default_caps_accessor.default_caps().value;
|
||||
|
||||
return Cap_quota { _start_node->xml().attribute_value("caps", default_caps) };
|
||||
return Cap_quota{_start_node->xml().attribute_value("caps", default_caps)};
|
||||
}
|
||||
|
||||
|
||||
template <typename QUOTA, typename LIMIT_ACCESSOR>
|
||||
void Sandbox::Child::_apply_resource_upgrade(QUOTA &assigned, QUOTA const configured,
|
||||
LIMIT_ACCESSOR const &limit_accessor)
|
||||
@@ -232,7 +246,7 @@ void Sandbox::Child::_apply_resource_upgrade(QUOTA &assigned, QUOTA const config
|
||||
if (_verbose.enabled())
|
||||
warn_insuff_quota(limit.value);
|
||||
|
||||
QUOTA const transfer { min(increment, limit.value) };
|
||||
QUOTA const transfer{min(increment, limit.value)};
|
||||
|
||||
/*
|
||||
* Remember assignment and apply upgrade to child
|
||||
@@ -243,21 +257,22 @@ void Sandbox::Child::_apply_resource_upgrade(QUOTA &assigned, QUOTA const config
|
||||
* This way, a future config update will attempt the completion of the
|
||||
* upgrade if memory become available.
|
||||
*/
|
||||
if (transfer.value) {
|
||||
if (transfer.value)
|
||||
{
|
||||
|
||||
assigned.value += transfer.value;
|
||||
|
||||
ref_pd().transfer_quota(_child.pd_session_cap(), transfer);
|
||||
|
||||
/* wake up child that blocks on a resource request */
|
||||
if (_requested_resources.constructed()) {
|
||||
if (_requested_resources.constructed())
|
||||
{
|
||||
_child.notify_resource_avail();
|
||||
_requested_resources.destruct();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Sandbox::Child::apply_upgrade()
|
||||
{
|
||||
/* pd_session_cap of exited child is invalid and unusable for transfers */
|
||||
@@ -277,7 +292,6 @@ void Sandbox::Child::apply_upgrade()
|
||||
_configured_cap_quota(), _cap_limit_accessor);
|
||||
}
|
||||
|
||||
|
||||
template <typename QUOTA, typename CHILD_AVAIL_QUOTA_FN>
|
||||
void Sandbox::Child::_apply_resource_downgrade(QUOTA &assigned, QUOTA const configured,
|
||||
QUOTA const preserved,
|
||||
@@ -286,7 +300,7 @@ void Sandbox::Child::_apply_resource_downgrade(QUOTA &assigned, QUOTA const conf
|
||||
if (configured.value >= assigned.value)
|
||||
return;
|
||||
|
||||
QUOTA const decrement { assigned.value - configured.value };
|
||||
QUOTA const decrement{assigned.value - configured.value};
|
||||
|
||||
/*
|
||||
* The child may concurrently consume quota from its PD session,
|
||||
@@ -294,39 +308,45 @@ void Sandbox::Child::_apply_resource_downgrade(QUOTA &assigned, QUOTA const conf
|
||||
* attempt the transfer.
|
||||
*/
|
||||
unsigned max_attempts = 4, attempts = 0;
|
||||
for (; attempts < max_attempts; attempts++) {
|
||||
for (; attempts < max_attempts; attempts++)
|
||||
{
|
||||
|
||||
/* give up if the child's available quota is exhausted */
|
||||
size_t const avail = child_avail_quota_fn().value;
|
||||
if (avail < preserved.value)
|
||||
break;
|
||||
|
||||
QUOTA const transfer { min(avail - preserved.value, decrement.value) };
|
||||
QUOTA const transfer{min(avail - preserved.value, decrement.value)};
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
_child.pd().transfer_quota(ref_pd_cap(), transfer);
|
||||
assigned.value -= transfer.value;
|
||||
break;
|
||||
} catch (...) { }
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (attempts == max_attempts)
|
||||
warning(name(), ": downgrade failed after ", max_attempts, " attempts");
|
||||
}
|
||||
|
||||
|
||||
void Sandbox::Child::apply_downgrade()
|
||||
{
|
||||
Ram_quota const configured_ram_quota = _configured_ram_quota();
|
||||
Cap_quota const configured_cap_quota = _configured_cap_quota();
|
||||
|
||||
_apply_resource_downgrade(_resources.assigned_ram_quota,
|
||||
configured_ram_quota, Ram_quota{16*1024},
|
||||
[&] () { return _child.pd().avail_ram(); });
|
||||
configured_ram_quota, Ram_quota{16 * 1024},
|
||||
[&]()
|
||||
{ return _child.pd().avail_ram(); });
|
||||
|
||||
_apply_resource_downgrade(_resources.assigned_cap_quota,
|
||||
configured_cap_quota, Cap_quota{5},
|
||||
[&] () { return _child.pd().avail_caps(); });
|
||||
[&]()
|
||||
{ return _child.pd().avail_caps(); });
|
||||
|
||||
/*
|
||||
* If designated resource quota is lower than the child's consumed quota,
|
||||
@@ -341,21 +361,22 @@ void Sandbox::Child::apply_downgrade()
|
||||
if (configured_cap_quota.value < _resources.assigned_cap_quota.value)
|
||||
demanded_cap_quota = _resources.assigned_cap_quota.value - configured_cap_quota.value;
|
||||
|
||||
if (demanded_ram_quota || demanded_cap_quota) {
|
||||
if (demanded_ram_quota || demanded_cap_quota)
|
||||
{
|
||||
Parent::Resource_args const
|
||||
args { "ram_quota=", Number_of_bytes(demanded_ram_quota), ", ",
|
||||
args{"ram_quota=", Number_of_bytes(demanded_ram_quota), ", ",
|
||||
"cap_quota=", demanded_cap_quota};
|
||||
_child.yield(args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Sandbox::Child::report_state(Xml_generator &xml, Report_detail const &detail) const
|
||||
{
|
||||
if (abandoned())
|
||||
return;
|
||||
|
||||
xml.node("child", [&] () {
|
||||
xml.node("child", [&]()
|
||||
{
|
||||
|
||||
xml.attribute("name", _unique_name);
|
||||
xml.attribute("binary", _binary_name);
|
||||
@@ -422,11 +443,9 @@ void Sandbox::Child::report_state(Xml_generator &xml, Report_detail const &detai
|
||||
|
||||
_session_requester.id_space().for_each<Session_state const>(fn);
|
||||
});
|
||||
}
|
||||
});
|
||||
} });
|
||||
}
|
||||
|
||||
|
||||
Sandbox::Child::Sample_state_result Sandbox::Child::sample_state()
|
||||
{
|
||||
if (!_pd_alive())
|
||||
@@ -440,37 +459,39 @@ Sandbox::Child::Sample_state_result Sandbox::Child::sample_state()
|
||||
: Sample_state_result::UNCHANGED;
|
||||
}
|
||||
|
||||
|
||||
void Sandbox::Child::init(Pd_session &session, Pd_session_capability cap)
|
||||
{
|
||||
size_t const initial_session_costs =
|
||||
session_alloc_batch_size()*_child.session_factory().session_costs();
|
||||
session_alloc_batch_size() * _child.session_factory().session_costs();
|
||||
|
||||
Ram_quota ram_quota { _resources.effective_ram_quota().value > initial_session_costs
|
||||
Ram_quota ram_quota{_resources.effective_ram_quota().value > initial_session_costs
|
||||
? _resources.effective_ram_quota().value - initial_session_costs
|
||||
: 0 };
|
||||
: 0};
|
||||
|
||||
Ram_quota avail_ram = _ram_limit_accessor.resource_limit(Ram_quota());
|
||||
|
||||
avail_ram = Genode::Child::effective_quota(avail_ram);
|
||||
|
||||
if (ram_quota.value > avail_ram.value) {
|
||||
if (ram_quota.value > avail_ram.value)
|
||||
{
|
||||
warning(name(), ": configured RAM exceeds available RAM, proceed with ", avail_ram);
|
||||
ram_quota = avail_ram;
|
||||
}
|
||||
|
||||
Cap_quota cap_quota { _resources.effective_cap_quota().value };
|
||||
Cap_quota cap_quota{_resources.effective_cap_quota().value};
|
||||
|
||||
Cap_quota avail_caps = _cap_limit_accessor.resource_limit(avail_caps);
|
||||
|
||||
avail_caps = Genode::Child::effective_quota(avail_caps);
|
||||
|
||||
if (cap_quota.value > avail_caps.value) {
|
||||
if (cap_quota.value > avail_caps.value)
|
||||
{
|
||||
warning(name(), ": configured caps exceed available caps, proceed with ", avail_caps);
|
||||
cap_quota = avail_caps;
|
||||
}
|
||||
|
||||
_with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) {
|
||||
_with_pd_intrinsics([&](Pd_intrinsics::Intrinsics &intrinsics)
|
||||
{
|
||||
|
||||
_ref_pd_cap = intrinsics.ref_pd_cap;
|
||||
|
||||
@@ -482,11 +503,9 @@ void Sandbox::Child::init(Pd_session &session, Pd_session_capability cap)
|
||||
|
||||
try { intrinsics.ref_pd.transfer_quota(cap, ram_quota); }
|
||||
catch (Out_of_ram) {
|
||||
error(name(), ": unable to initialize RAM quota of PD"); }
|
||||
});
|
||||
error(name(), ": unable to initialize RAM quota of PD"); } });
|
||||
}
|
||||
|
||||
|
||||
void Sandbox::Child::init(Cpu_session &session, Cpu_session_capability cap)
|
||||
{
|
||||
Cpu_quota const assigned = _resources.assigned_cpu_quota;
|
||||
@@ -494,16 +513,16 @@ void Sandbox::Child::init(Cpu_session &session, Cpu_session_capability cap)
|
||||
|
||||
if (assigned.percent > effective.percent)
|
||||
warning(name(), ": configured CPU quota of ", assigned, " exceeds "
|
||||
"available quota, proceeding with a quota of ", effective);
|
||||
"available quota, proceeding with a quota of ",
|
||||
effective);
|
||||
|
||||
_with_pd_intrinsics([&] (Pd_intrinsics::Intrinsics &intrinsics) {
|
||||
session.ref_account(intrinsics.ref_cpu_cap); });
|
||||
_with_pd_intrinsics([&](Pd_intrinsics::Intrinsics &intrinsics)
|
||||
{ session.ref_account(intrinsics.ref_cpu_cap); });
|
||||
|
||||
_cpu_quota_transfer.transfer_cpu_quota(_child.pd_session_cap(), _child.pd(),
|
||||
cap, effective);
|
||||
}
|
||||
|
||||
|
||||
Sandbox::Child::Route
|
||||
Sandbox::Child::resolve_session_request(Service::Name const &service_name,
|
||||
Session_label const &label,
|
||||
@@ -512,12 +531,13 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name,
|
||||
bool const rom_service = (service_name == Rom_session::service_name());
|
||||
|
||||
/* check for "config" ROM request */
|
||||
if (rom_service && label.last_element() == "config") {
|
||||
if (rom_service && label.last_element() == "config")
|
||||
{
|
||||
|
||||
if (_config_rom_service.constructed() &&
|
||||
!_config_rom_service->abandoned())
|
||||
return Route { _config_rom_service->service(), label,
|
||||
Session::Diag{false} };
|
||||
return Route{_config_rom_service->service(), label,
|
||||
Session::Diag{false}};
|
||||
|
||||
/*
|
||||
* If there is no inline '<config>', we apply the regular session
|
||||
@@ -543,9 +563,9 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name,
|
||||
|
||||
/* check for "session_requests" ROM request */
|
||||
if (rom_service && label.last_element() == Session_requester::rom_name())
|
||||
return Route { _session_requester.service(), Session::Label(), diag };
|
||||
return Route{_session_requester.service(), Session::Label(), diag};
|
||||
|
||||
auto resolve_at_target = [&] (Xml_node const &target) -> Route
|
||||
auto resolve_at_target = [&](Xml_node const &target) -> Route
|
||||
{
|
||||
/*
|
||||
* Determine session label to be provided to the server
|
||||
@@ -561,54 +581,77 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name,
|
||||
target.attribute_value("label", Label(label.string()));
|
||||
|
||||
Session::Diag const
|
||||
target_diag { target.attribute_value("diag", diag.enabled) };
|
||||
target_diag{target.attribute_value("diag", diag.enabled)};
|
||||
|
||||
auto no_filter = [] (Service &) -> bool { return false; };
|
||||
auto no_filter = [](Service &) -> bool
|
||||
{ return false; };
|
||||
|
||||
if (target.has_type("parent")) {
|
||||
if (target.has_type("parent"))
|
||||
{
|
||||
|
||||
try {
|
||||
return Route { find_service(_parent_services, service_name, no_filter),
|
||||
target_label, target_diag };
|
||||
} catch (Service_denied) { }
|
||||
try
|
||||
{
|
||||
return Route{find_service(_parent_services, service_name, no_filter),
|
||||
target_label, target_diag};
|
||||
}
|
||||
catch (Service_denied)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (target.has_type("local")) {
|
||||
if (target.has_type("local"))
|
||||
{
|
||||
|
||||
try {
|
||||
return Route { find_service(_local_services, service_name, no_filter),
|
||||
target_label, target_diag };
|
||||
} catch (Service_denied) { }
|
||||
try
|
||||
{
|
||||
return Route{find_service(_local_services, service_name, no_filter),
|
||||
target_label, target_diag};
|
||||
}
|
||||
catch (Service_denied)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (target.has_type("child")) {
|
||||
if (target.has_type("child"))
|
||||
{
|
||||
|
||||
using Name = Name_registry::Name;
|
||||
Name server_name = target.attribute_value("name", Name());
|
||||
server_name = _name_registry.deref_alias(server_name);
|
||||
|
||||
auto filter_server_name = [&] (Routed_service &s) -> bool {
|
||||
return s.child_name() != server_name; };
|
||||
auto filter_server_name = [&](Routed_service &s) -> bool
|
||||
{ return s.child_name() != server_name; };
|
||||
|
||||
try {
|
||||
return Route { find_service(_child_services, service_name,
|
||||
filter_server_name), target_label, target_diag };
|
||||
|
||||
} catch (Service_denied) { }
|
||||
try
|
||||
{
|
||||
return Route{find_service(_child_services, service_name,
|
||||
filter_server_name),
|
||||
target_label, target_diag};
|
||||
}
|
||||
catch (Service_denied)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (target.has_type("any-child")) {
|
||||
if (target.has_type("any-child"))
|
||||
{
|
||||
|
||||
if (is_ambiguous(_child_services, service_name)) {
|
||||
if (is_ambiguous(_child_services, service_name))
|
||||
{
|
||||
error(name(), ": ambiguous routes to "
|
||||
"service \"", service_name, "\"");
|
||||
"service \"",
|
||||
service_name, "\"");
|
||||
throw Service_denied();
|
||||
}
|
||||
try {
|
||||
return Route { find_service(_child_services, service_name,
|
||||
no_filter), target_label, target_diag };
|
||||
|
||||
} catch (Service_denied) { }
|
||||
try
|
||||
{
|
||||
return Route{find_service(_child_services, service_name,
|
||||
no_filter),
|
||||
target_label, target_diag};
|
||||
}
|
||||
catch (Service_denied)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
throw Service_denied();
|
||||
@@ -619,7 +662,6 @@ Sandbox::Child::resolve_session_request(Service::Name const &service_name,
|
||||
return _route_model->resolve(query, resolve_at_target);
|
||||
}
|
||||
|
||||
|
||||
void Sandbox::Child::filter_session_args(Service::Name const &service,
|
||||
char *args, size_t args_len)
|
||||
{
|
||||
@@ -627,8 +669,9 @@ void Sandbox::Child::filter_session_args(Service::Name const &service,
|
||||
* Intercept CPU session requests to scale priorities
|
||||
*/
|
||||
if ((service == Cpu_session::service_name() ||
|
||||
service == Vm_session::service_name())
|
||||
&& _prio_levels_log2 > 0) {
|
||||
service == Vm_session::service_name()) &&
|
||||
_prio_levels_log2 > 0)
|
||||
{
|
||||
|
||||
unsigned priority = (unsigned)Arg_string::find_arg(args, "priority").ulong_value(0);
|
||||
|
||||
@@ -642,11 +685,10 @@ void Sandbox::Child::filter_session_args(Service::Name const &service,
|
||||
priority >>= _prio_levels_log2;
|
||||
|
||||
/* assign child priority to the most significant priority bits */
|
||||
priority = priority
|
||||
| (unsigned)(_priority*(Cpu_session::PRIORITY_LIMIT >> _prio_levels_log2));
|
||||
priority = priority | (unsigned)(_priority * (Cpu_session::PRIORITY_LIMIT >> _prio_levels_log2));
|
||||
|
||||
/* override priority when delegating the session request to the parent */
|
||||
String<64> value { Hex(priority) };
|
||||
String<64> value{Hex(priority)};
|
||||
Arg_string::set_arg(args, args_len, "priority", value.string());
|
||||
}
|
||||
|
||||
@@ -654,7 +696,8 @@ void Sandbox::Child::filter_session_args(Service::Name const &service,
|
||||
* Unset the 'managing_system' argument unless explicitly permitted by the
|
||||
* child configuration.
|
||||
*/
|
||||
if (service == Pd_session::service_name()) {
|
||||
if (service == Pd_session::service_name())
|
||||
{
|
||||
|
||||
/*
|
||||
* For an environment PD session created by us for a direct child, the
|
||||
@@ -680,7 +723,6 @@ void Sandbox::Child::filter_session_args(Service::Name const &service,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Genode::Affinity Sandbox::Child::filter_session_affinity(Affinity const &session_affinity)
|
||||
{
|
||||
Affinity::Space const &child_space = _resources.affinity.space();
|
||||
@@ -693,7 +735,6 @@ Genode::Affinity Sandbox::Child::filter_session_affinity(Affinity const &session
|
||||
Affinity::Space const &session_space = session_affinity.space();
|
||||
Affinity::Location const &session_location = session_affinity.location();
|
||||
|
||||
|
||||
/* scale resolution of resulting space */
|
||||
Affinity::Space space(child_space.multiply(session_space));
|
||||
Affinity::Location child_session(child_location.xpos(), child_location.ypos(),
|
||||
@@ -709,24 +750,24 @@ Genode::Affinity Sandbox::Child::filter_session_affinity(Affinity const &session
|
||||
return Affinity(space, location);
|
||||
}
|
||||
|
||||
|
||||
void Sandbox::Child::announce_service(Service::Name const &service_name)
|
||||
{
|
||||
if (_verbose.enabled())
|
||||
log("child \"", name(), "\" announces service \"", service_name, "\"");
|
||||
|
||||
bool found = false;
|
||||
_child_services.for_each([&] (Routed_service &service) {
|
||||
_child_services.for_each([&](Routed_service &service)
|
||||
{
|
||||
if (service.has_id_space(_session_requester.id_space())
|
||||
&& service.name() == service_name)
|
||||
found = true; });
|
||||
|
||||
if (!found)
|
||||
error(name(), ": illegal announcement of "
|
||||
"service \"", service_name, "\"");
|
||||
"service \"",
|
||||
service_name, "\"");
|
||||
}
|
||||
|
||||
|
||||
void Sandbox::Child::resource_request(Parent::Resource_args const &args)
|
||||
{
|
||||
log("child \"", name(), "\" requests resources: ", args);
|
||||
@@ -735,7 +776,6 @@ void Sandbox::Child::resource_request(Parent::Resource_args const &args)
|
||||
_report_update_trigger.trigger_immediate_report_update();
|
||||
}
|
||||
|
||||
|
||||
Sandbox::Child::Child(Env &env,
|
||||
Allocator &alloc,
|
||||
Verbose const &verbose,
|
||||
@@ -751,13 +791,11 @@ Sandbox::Child::Child(Env &env,
|
||||
Cpu_quota_transfer &cpu_quota_transfer,
|
||||
Prio_levels prio_levels,
|
||||
Affinity::Space const &affinity_space,
|
||||
Affinity::Location const &location,
|
||||
Registry<Parent_service> &parent_services,
|
||||
Registry<Routed_service> &child_services,
|
||||
Registry<Local_service> &local_services,
|
||||
Pd_intrinsics &pd_intrinsics)
|
||||
:
|
||||
_env(env), _alloc(alloc), _verbose(verbose), _id(id),
|
||||
: _env(env), _alloc(alloc), _verbose(verbose), _id(id),
|
||||
_report_update_trigger(report_update_trigger),
|
||||
_list_element(this),
|
||||
_start_node(_alloc, start_node),
|
||||
@@ -769,7 +807,7 @@ Sandbox::Child::Child(Env &env,
|
||||
_cpu_quota_transfer(cpu_quota_transfer),
|
||||
_name_registry(name_registry),
|
||||
_heartbeat_enabled(start_node.has_sub_node("heartbeat")),
|
||||
_resources(_resources_from_start_node(start_node, prio_levels, affinity_space, location,
|
||||
_resources(_resources_from_start_node(start_node, prio_levels, affinity_space,
|
||||
default_caps_accessor.default_caps())),
|
||||
_pd_intrinsics(pd_intrinsics),
|
||||
_parent_services(parent_services),
|
||||
@@ -777,7 +815,8 @@ Sandbox::Child::Child(Env &env,
|
||||
_local_services(local_services),
|
||||
_session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm())
|
||||
{
|
||||
if (_verbose.enabled()) {
|
||||
if (_verbose.enabled())
|
||||
{
|
||||
log("child \"", _unique_name, "\"");
|
||||
log(" RAM quota: ", _resources.effective_ram_quota());
|
||||
log(" cap quota: ", _resources.effective_cap_quota());
|
||||
@@ -792,7 +831,8 @@ Sandbox::Child::Child(Env &env,
|
||||
*/
|
||||
_provides_sub_node(start_node)
|
||||
.for_each_sub_node("service",
|
||||
[&] (Xml_node node) { _add_service(node); });
|
||||
[&](Xml_node node)
|
||||
{ _add_service(node); });
|
||||
|
||||
/*
|
||||
* Construct inline config ROM service if "config" node is present.
|
||||
@@ -801,5 +841,4 @@ Sandbox::Child::Child(Env &env,
|
||||
_config_rom_service.construct(*this);
|
||||
}
|
||||
|
||||
|
||||
Sandbox::Child::~Child() { }
|
||||
Sandbox::Child::~Child() {}
|
||||
@@ -385,7 +385,7 @@ void Genode::Sandbox::generate_state_report(Xml_generator &xml) const
|
||||
Genode::Sandbox::Sandbox(Env &env, State_handler &state_handler, Pd_intrinsics &pd_intrinsics)
|
||||
:
|
||||
_heap(env.ram(), env.rm()),
|
||||
_library(*new (_heap) Library(env, _heap, _local_services, state_handler, pd_intrinsics))
|
||||
_library(*new (_heap) ::Sandbox::Library(env, _heap, _local_services, state_handler, pd_intrinsics))
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user