Capability quota accounting and trading

This patch mirrors the accounting and trading scheme that Genode employs
for physical memory to the accounting of capability allocations.

Capability quotas must now be explicitly assigned to subsystems by
specifying a 'caps=<amount>' attribute to init's start nodes.
Analogously to RAM quotas, cap quotas can be traded between clients and
servers as part of the session protocol. The capability budget of each
component is maintained by the component's corresponding PD session at
core.

At the current stage, the accounting is applied to RPC capabilities,
signal-context capabilities, and dataspace capabilities. Capabilities
that are dynamically allocated via core's CPU and TRACE service are not
yet covered. Also, the capabilities allocated by resource multiplexers
outside of core (like nitpicker) must be accounted by the respective
servers, which is not covered yet.

If a component runs out of capabilities, core's PD service prints a
warning to the log. To observe the consumption of capabilities per
component in detail, the PD service is equipped with a diagnostic
mode, which can be enabled via the 'diag' attribute in the target
node of init's routing rules. E.g., the following route enables the
diagnostic mode for the PD session of the "timer" component:

  <default-route>
    <service name="PD" unscoped_label="timer">
      <parent diag="yes"/>
    </service>
    ...
  </default-route>

For subsystems based on a sub-init instance, init can be configured
to report the capability-quota information of its subsystems by
adding the attribute 'child_caps="yes"' to init's '<report>'
config node. Init's own capability quota can be reported by adding
the attribute 'init_caps="yes"'.

Fixes #2398
This commit is contained in:
Norman Feske 2017-05-08 21:35:43 +02:00 committed by Christian Helmuth
parent 773e08976d
commit 1f4f119b1e
105 changed files with 1494 additions and 405 deletions

View File

@ -28,13 +28,13 @@ Native_pd_component::Native_pd_component(Pd_session_component &pd_session,
:
_pd_session(pd_session)
{
_pd_session._thread_ep.manage(this);
_pd_session._ep.manage(this);
}
Native_pd_component::~Native_pd_component()
{
_pd_session._thread_ep.dissolve(this);
_pd_session._ep.dissolve(this);
}

View File

@ -14,5 +14,6 @@
#include <base/internal/native_env.h>
#include <assertion.h>
void Genode::upgrade_pd_quota_non_blocking(Genode::size_t quota) {
ASSERT_NEVER_CALLED; }
using namespace Genode;
void Genode::upgrade_pd_quota_non_blocking(Ram_quota, Cap_quota) { ASSERT_NEVER_CALLED; }

View File

@ -17,9 +17,8 @@
using namespace Genode;
void Pd_session_component::upgrade_ram_quota(size_t ram_quota)
void Pd_session_component::session_quota_upgraded()
{
_md_alloc.upgrade(ram_quota);
_pd.upgrade_slab(_md_alloc);
_pd.upgrade_slab(_sliced_heap);
}

View File

@ -16,6 +16,7 @@
/* Genode includes */
#include <base/stdint.h>
#include <base/quota_guard.h>
namespace Genode
{
@ -26,7 +27,7 @@ namespace Genode
* needed when doing upgrades in situations where the environment is
* already locked due to the operation that triggered the upgrade.
*/
void upgrade_pd_quota_non_blocking(size_t);
void upgrade_pd_quota_non_blocking(Ram_quota, Cap_quota);
};
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_ENV_H_ */

View File

@ -18,8 +18,9 @@
#include <base/internal/globals.h>
#include <base/internal/native_env.h>
void Genode::upgrade_pd_quota_non_blocking(size_t quota)
void Genode::upgrade_pd_quota_non_blocking(Ram_quota ram, Cap_quota caps)
{
internal_env().parent().upgrade(Parent::Env::pd(),
String<64>("ram_quota=", quota).string());
String<100>("ram_quota=", ram, ", "
"cap_quota=", caps).string());
}

View File

@ -109,7 +109,8 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
}
},
[&] () { upgrade_pd_quota_non_blocking(3 * 1024 * sizeof(addr_t)); });
[&] () { upgrade_pd_quota_non_blocking(Ram_quota{3 * 1024 * sizeof(addr_t)},
Cap_quota{0}); });
return Rpc_exception_code(utcb.exception_code());
}
@ -154,7 +155,8 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
default: break;
}
},
[&] () { upgrade_pd_quota_non_blocking(3 * 1024 * sizeof(addr_t)); });
[&] () { upgrade_pd_quota_non_blocking(Ram_quota{3 * 1024 * sizeof(addr_t)},
Cap_quota{0}); });
copy_utcb_to_msg(utcb, request_msg);

View File

@ -66,13 +66,22 @@ void Signal_transmitter::submit(unsigned cnt)
Signal_receiver::Signal_receiver()
{
retry<Pd_session::Out_of_metadata>(
[&] () { _cap = internal_env().pd().alloc_signal_source(); },
[&] () {
log("upgrading quota donation for PD session");
internal_env().upgrade(Parent::Env::pd(), "ram_quota=8K");
for (;;) {
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try {
_cap = internal_env().pd().alloc_signal_source();
break;
}
);
catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
internal_env().upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
}
}
@ -98,17 +107,23 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
Lock::Guard context_guard(c->_lock);
if (c->_receiver) { throw Context_already_in_use(); }
retry<Pd_session::Out_of_metadata>(
[&] () {
for (;;) {
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try {
/* use signal context as imprint */
c->_cap = env_deprecated()->pd_session()->alloc_context(_cap, (unsigned long)c);
c->_receiver = this;
_contexts.insert(&c->_receiver_le);
return c->_cap;
},
[&] () { upgrade_pd_quota_non_blocking(1024 * sizeof(addr_t)); });
}
catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
return c->_cap;
upgrade_pd_quota_non_blocking(ram_upgrade, cap_upgrade);
}
}

View File

@ -52,7 +52,7 @@ struct Sync_root : public Root_component<Session_component>
Session_component *_create_session(char const *args) override
{
try { return new (md_alloc()) Session_component(*this); }
catch (...) { throw Root::Exception(); }
catch (...) { throw Root::Invalid_args(); }
}
Sync_root(Entrypoint &ep, Allocator &md_alloc)

View File

@ -122,8 +122,8 @@ namespace Genode {
* method to issue out-of-order replies to
* 'Signal_source::wait_for_signal' calls.
*/
Core_pd_session_component _pd_session_component;
Pd_session_client _pd_session_client;
Core_pd_session_component _pd_session_component { _entrypoint };
Pd_session_client _pd_session_client { _pd_session_component.cap() };
Registry<Service> _services;
@ -155,9 +155,7 @@ namespace Genode {
Session::Diag{false},
*platform()->ram_alloc(),
*Platform_env_base::rm_session(),
Ram_session_component::any_phys_range()),
_pd_session_component(_entrypoint),
_pd_session_client(_entrypoint.manage(&_pd_session_component))
Ram_session_component::any_phys_range())
{
_ram_session.init_ram_account();
}

View File

@ -143,7 +143,7 @@ void Native_pd_component::_start(Dataspace_component &ds)
/* prefix name of Linux program (helps killing some zombies) */
char const *prefix = "[Genode] ";
char pname_buf[sizeof(_pd_session._label) + sizeof(prefix)];
snprintf(pname_buf, sizeof(pname_buf), "%s%s", prefix, _pd_session._label.string);
snprintf(pname_buf, sizeof(pname_buf), "%s%s", prefix, _pd_session._label.string());
char *argv_buf[2];
argv_buf[0] = pname_buf;
argv_buf[1] = 0;
@ -184,7 +184,7 @@ Native_pd_component::Native_pd_component(Pd_session_component &pd_session,
:
_pd_session(pd_session)
{
_pd_session._thread_ep.manage(this);
_pd_session._ep.manage(this);
}
@ -193,14 +193,14 @@ Native_pd_component::~Native_pd_component()
if (_pid)
lx_kill(_pid, 9);
_pd_session._thread_ep.dissolve(this);
_pd_session._ep.dissolve(this);
}
void Native_pd_component::start(Capability<Dataspace> binary)
{
/* lookup binary dataspace */
_pd_session._thread_ep.apply(binary, [&] (Dataspace_component *ds) {
_pd_session._ep.apply(binary, [&] (Dataspace_component *ds) {
if (ds)
_start(*ds);

View File

@ -28,7 +28,8 @@ struct Genode::Nova_native_pd : Pd_session::Native_pd
* \param entry server-side instruction pointer of the RPC handler
* \param mtd NOVA message transfer descriptor
*
* \throw Pd_session::Out_of_metadata
* \throw Out_of_ram
* \throw Out_of_caps
*
* \return new RPC object capability
*/
@ -41,7 +42,7 @@ struct Genode::Nova_native_pd : Pd_session::Native_pd
virtual void imprint_rpc_cap(Native_capability cap, unsigned long badge) = 0;
GENODE_RPC_THROW(Rpc_alloc_rpc_cap, Native_capability, alloc_rpc_cap,
GENODE_TYPE_LIST(Pd_session::Out_of_metadata),
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
Native_capability, addr_t, addr_t);
GENODE_RPC(Rpc_imprint_rpc_cap, void, imprint_rpc_cap,
Native_capability, unsigned long);

View File

@ -24,6 +24,7 @@ Native_capability Native_pd_component::alloc_rpc_cap(Native_capability ep,
addr_t entry, addr_t mtd)
{
try {
_pd_session._consume_cap(Pd_session_component::RPC_CAP);
return _pd_session._rpc_cap_factory.alloc(ep, entry, mtd); }
catch (Allocator::Out_of_memory) { throw Out_of_ram(); }
@ -42,13 +43,13 @@ Native_pd_component::Native_pd_component(Pd_session_component &pd_session,
:
_pd_session(pd_session)
{
_pd_session._thread_ep.manage(this);
_pd_session._ep.manage(this);
}
Native_pd_component::~Native_pd_component()
{
_pd_session._thread_ep.dissolve(this);
_pd_session._ep.dissolve(this);
}

View File

@ -34,18 +34,23 @@ Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd, Native_capabili
Nova_native_pd_client native_pd(_native_pd_cap);
Untyped_capability new_obj_cap =
retry<Genode::Pd_session::Out_of_metadata>(
[&] () {
return native_pd.alloc_rpc_cap(ep, entry, 0);
},
[&] () {
internal_env().upgrade(Parent::Env::pd(), "ram_quota=16K");
});
for (;;) {
native_pd.imprint_rpc_cap(new_obj_cap, new_obj_cap.local_name());
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
return new_obj_cap;
try {
Untyped_capability new_obj_cap = native_pd.alloc_rpc_cap(ep, entry, 0);
native_pd.imprint_rpc_cap(new_obj_cap, new_obj_cap.local_name());
return new_obj_cap;
}
catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
env_deprecated()->parent()->upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
}
}

View File

@ -75,6 +75,7 @@ struct Genode::Allocator : Deallocator
* undefined in the error case
*
* \throw Out_of_ram
* \throw Out_of_caps
*
* \return true on success
*/
@ -89,6 +90,7 @@ struct Genode::Allocator : Deallocator
* pointer will break strict-aliasing rules".
*
* \throw Out_of_ram
* \throw Out_of_caps
*/
template <typename T> bool alloc(size_t size, T **out_addr)
{
@ -114,6 +116,7 @@ struct Genode::Allocator : Deallocator
* \param size block size to allocate
*
* \throw Out_of_ram
* \throw Out_of_caps
*
* \return pointer to the new block
*/

View File

@ -47,8 +47,10 @@ class Genode::Attached_io_mem_dataspace
*
* \throw Parent::Service_denied
* \throw Insufficient_ram_quota
* \throw Insufficient_cap_quota
* \throw Parent::Unavailable
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Rm_session::Attach_failed
*/
Attached_io_mem_dataspace(Env &env, Genode::addr_t base, Genode::size_t size,

View File

@ -91,6 +91,7 @@ class Genode::Attached_ram_dataspace
* Constructor
*
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Rm_session::Attach_failed
*/
Attached_ram_dataspace(Ram_session &ram, Region_map &rm,

View File

@ -134,6 +134,15 @@ struct Genode::Child_policy
log("child \"", name(), "\" exited with exit value ", exit_value);
}
/**
* Reference PD session
*
* The PD session returned by this method is used for session cap-quota
* transfers.
*/
virtual Pd_session &ref_pd() = 0;
virtual Pd_session_capability ref_pd_cap() const = 0;
/**
* Reference RAM session
*
@ -393,6 +402,7 @@ class Genode::Child : protected Rpc_object<Parent>,
* \throw Invalid_executable
* \throw Region_map::Attach_failed
* \throw Out_of_ram
* \throw Out_of_caps
*
* The other arguments correspond to those of 'Child::Child'.
*
@ -487,6 +497,25 @@ class Genode::Child : protected Rpc_object<Parent>,
Ram_transfer::Account &to = _service;
return to.cap(Ram_quota());
}
/**
* Service (Cap_transfer::Account) interface
*/
void transfer(Pd_session_capability to, Cap_quota amount) override
{
Cap_transfer::Account &from = _service;
from.transfer(to, amount);
}
/**
* Service (Cap_transfer::Account) interface
*/
Pd_session_capability cap(Cap_quota) const override
{
Cap_transfer::Account &to = _service;
return to.cap(Cap_quota());
}
void wakeup() override { _service.wakeup(); }
bool operator == (Service const &other) const override
@ -662,6 +691,13 @@ class Genode::Child : protected Rpc_object<Parent>,
2*Rom_connection::RAM_QUOTA };
}
static Cap_quota env_cap_quota()
{
return { Cpu_connection::CAP_QUOTA + Ram_connection::CAP_QUOTA +
Pd_connection::CAP_QUOTA + Log_connection::CAP_QUOTA +
2*Rom_connection::CAP_QUOTA + 1 /* parent cap */ };
}
template <typename FN>
void for_each_session(FN const &fn) const
{
@ -676,7 +712,16 @@ class Genode::Child : protected Rpc_object<Parent>,
return _effective_quota(quota, env_ram_quota());
}
/**
* Deduce env session costs from usable cap quota
*/
static Cap_quota effective_quota(Cap_quota quota)
{
return _effective_quota(quota, env_cap_quota());
}
Ram_session_capability ram_session_cap() const { return _ram.cap(); }
Pd_session_capability pd_session_cap() const { return _pd.cap(); }
Parent_capability parent_cap() const { return cap(); }
@ -684,6 +729,7 @@ class Genode::Child : protected Rpc_object<Parent>,
Ram_session const &ram() const { return _ram.session(); }
Cpu_session &cpu() { return _cpu.session(); }
Pd_session &pd() { return _pd .session(); }
Pd_session const &pd() const { return _pd .session(); }
/**
* Request factory for creating session-state objects

View File

@ -52,10 +52,17 @@ class Genode::Connection_base : public Noncopyable
*/
Connection_base();
void upgrade(Session::Resources resources)
{
String<80> const args("ram_quota=", resources.ram_quota, ", "
"cap_quota=", resources.cap_quota);
_env.upgrade(_id_space_element.id(), args.string());
}
void upgrade_ram(size_t bytes)
{
String<64> const args("ram_quota=", Ram_quota{bytes});
_env.upgrade(_id_space_element.id(), args.string());
upgrade(Session::Resources { Ram_quota{bytes}, Cap_quota{0} });
}
};

View File

@ -93,8 +93,12 @@ struct Genode::Env
* \param affinity preferred CPU affinity for the session
*
* \throw Service_denied
* \throw Insufficient_cap_quota
* \throw Insufficient_ram_quota
* \throw Unavailable
* \throw Out_of_caps
* \throw Out_of_ram
*
* See the documentation of 'Parent::session'.
*
* This method blocks until the session is available or an error
* occurred.
@ -116,6 +120,9 @@ struct Genode::Env
* \param args description of the amount of quota to transfer
*
* \throw Out_of_ram
* \throw Out_of_caps
*
* See the documentation of 'Parent::upgrade'.
*
* The 'args' argument has the same principle format as the 'args'
* argument of the 'session' operation.

View File

@ -39,7 +39,7 @@ struct Genode::Local_connection_base : Noncopyable
private:
static Args _init_args(Args const &args, size_t const &ram_quota,
static Args _init_args(Args const &args, Session::Resources resources,
Session::Diag diag)
{
/* copy original arguments into modifiable buffer */
@ -47,7 +47,9 @@ struct Genode::Local_connection_base : Noncopyable
strncpy(buf, args.string(), sizeof(buf));
Arg_string::set_arg(buf, sizeof(buf), "ram_quota",
String<64>(ram_quota).string());
String<64>(resources.ram_quota.value).string());
Arg_string::set_arg(buf, sizeof(buf), "cap_quota",
String<64>(resources.cap_quota.value).string());
Arg_string::set_arg(buf, sizeof(buf), "diag", diag.enabled);
/* return result as a copy */
@ -62,23 +64,35 @@ struct Genode::Local_connection_base : Noncopyable
Args const &args, Affinity const &affinity,
Session::Label const &label,
Session::Diag diag,
size_t ram_quota)
Session::Resources resources)
{
enum { NUM_ATTEMPTS = 10 };
for (unsigned i = 0; i < NUM_ATTEMPTS; i++) {
_session_state.construct(service, id_space, id, label,
_init_args(args, ram_quota, diag),
_init_args(args, resources, diag),
affinity);
_session_state->service().initiate_request(*_session_state);
if (_session_state->phase == Session_state::INSUFFICIENT_RAM_QUOTA)
ram_quota += 4096;
else
if (_session_state->alive())
break;
switch (_session_state->phase) {
case Session_state::INSUFFICIENT_RAM_QUOTA:
resources.ram_quota.value += 4096;
break;
case Session_state::INSUFFICIENT_CAP_QUOTA:
resources.cap_quota.value += 1;
break;
default: break;
}
}
if (_session_state->phase == Session_state::INSUFFICIENT_RAM_QUOTA)
if (_session_state->phase == Session_state::INSUFFICIENT_RAM_QUOTA
|| _session_state->phase == Session_state::INSUFFICIENT_CAP_QUOTA)
warning("giving up to increase session quota for ", service.name(), " session "
"after ", (int)NUM_ATTEMPTS, " attempts");
}
@ -153,7 +167,8 @@ class Genode::Local_connection : Local_connection_base
Local_connection_base(service, id_space, id, args, affinity,
label.valid() ? label : label_from_args(args.string()),
diag,
CONNECTION::RAM_QUOTA)
Session::Resources { Ram_quota { CONNECTION::RAM_QUOTA },
Cap_quota { CONNECTION::CAP_QUOTA } })
{
service.wakeup();
}

View File

@ -16,6 +16,7 @@
#include <util/list.h>
#include <ram_session/client.h>
#include <pd_session/client.h>
#include <base/env.h>
#include <base/session_state.h>
#include <base/log.h>
@ -33,7 +34,8 @@ namespace Genode {
}
class Genode::Service : public Ram_transfer::Account
class Genode::Service : public Ram_transfer::Account,
public Cap_transfer::Account
{
public:
@ -126,6 +128,7 @@ class Genode::Local_service : public Service
*
* \throw Denied
* \throw Insufficient_ram_quota
* \throw Insufficient_cap_quota
*/
virtual SESSION &create(Args const &, Affinity) = 0;
@ -192,6 +195,8 @@ class Genode::Local_service : public Service
}
catch (typename Factory::Denied) {
session.phase = Session_state::INVALID_ARGS; }
catch (Insufficient_cap_quota) {
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA; }
catch (Insufficient_ram_quota) {
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; }
@ -199,7 +204,8 @@ class Genode::Local_service : public Service
case Session_state::UPGRADE_REQUESTED:
{
String<64> const args("ram_quota=", session.ram_upgrade);
String<100> const args("ram_quota=", session.ram_upgrade, ", "
"cap_quota=", session.cap_upgrade);
_apply_to_rpc_obj(session, [&] (SESSION &rpc_obj) {
_factory.upgrade(rpc_obj, args.string()); });
@ -220,6 +226,7 @@ class Genode::Local_service : public Service
case Session_state::INVALID_ARGS:
case Session_state::INSUFFICIENT_RAM_QUOTA:
case Session_state::INSUFFICIENT_CAP_QUOTA:
case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED:
@ -279,10 +286,19 @@ class Genode::Parent_service : public Service
catch (Out_of_ram) {
session.id_at_parent.destruct();
session.phase = Session_state::INVALID_ARGS; }
catch (Out_of_caps) {
session.id_at_parent.destruct();
session.phase = Session_state::INVALID_ARGS; }
catch (Insufficient_ram_quota) {
session.id_at_parent.destruct();
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA; }
catch (Insufficient_cap_quota) {
session.id_at_parent.destruct();
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA; }
catch (Parent::Service_denied) {
session.id_at_parent.destruct();
session.phase = Session_state::INVALID_ARGS; }
@ -291,7 +307,8 @@ class Genode::Parent_service : public Service
case Session_state::UPGRADE_REQUESTED:
{
String<64> const args("ram_quota=", session.ram_upgrade);
String<100> const args("ram_quota=", session.ram_upgrade, ", "
"cap_quota=", session.cap_upgrade);
if (!session.id_at_parent.constructed())
error("invalid parent-session state: ", session);
@ -300,6 +317,8 @@ class Genode::Parent_service : public Service
_env.upgrade(session.id_at_parent->id(), args.string()); }
catch (Out_of_ram) {
warning("RAM quota exceeded while upgrading parent session"); }
catch (Out_of_caps) {
warning("cap quota exceeded while upgrading parent session"); }
session.confirm_ram_upgrade();
session.phase = Session_state::CAP_HANDED_OUT;
@ -317,6 +336,7 @@ class Genode::Parent_service : public Service
case Session_state::INVALID_ARGS:
case Session_state::INSUFFICIENT_RAM_QUOTA:
case Session_state::INSUFFICIENT_CAP_QUOTA:
case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED:
@ -398,6 +418,7 @@ class Genode::Child_service : public Async_service
private:
Ram_session_client _ram;
Pd_session_client _pd;
public:
@ -408,10 +429,11 @@ class Genode::Child_service : public Async_service
Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory,
Wakeup &wakeup,
Ram_session_capability ram)
Ram_session_capability ram,
Pd_session_capability pd)
:
Async_service(name, server_id_space, factory, wakeup),
_ram(ram)
_ram(ram), _pd(pd)
{ }
/**
@ -426,6 +448,19 @@ class Genode::Child_service : public Async_service
* Ram_transfer::Account interface
*/
Ram_session_capability cap(Ram_quota) const override { return _ram; }
/**
* Cap_transfer::Account interface
*/
void transfer(Pd_session_capability to, Cap_quota amount) override
{
if (to.valid()) _pd.transfer_quota(to, amount);
}
/**
* Cap_transfer::Account interface
*/
Pd_session_capability cap(Cap_quota) const override { return _pd; }
};
#endif /* _INCLUDE__BASE__SERVICE_H_ */

View File

@ -65,12 +65,14 @@ class Genode::Session_object : public Ram_quota_guard,
Cap_quota_guard(resources.cap_quota),
_ep(ep), _diag(diag), _label(label)
{
Cap_quota_guard::withdraw(Cap_quota{1});
_ep.manage(this);
}
~Session_object()
{
_ep.dissolve(this);
Cap_quota_guard::replenish(Cap_quota{1});
}
/**

View File

@ -59,6 +59,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
* Total of quota associated with this session
*/
Ram_quota _donated_ram_quota { 0 };
Cap_quota _donated_cap_quota { 0 };
Factory *_factory = nullptr;
@ -80,6 +81,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
enum Phase { CREATE_REQUESTED,
INVALID_ARGS,
INSUFFICIENT_RAM_QUOTA,
INSUFFICIENT_CAP_QUOTA,
AVAILABLE,
CAP_HANDED_OUT,
UPGRADE_REQUESTED,
@ -107,6 +109,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
Session_capability cap;
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
void print(Output &out) const;
@ -150,10 +153,13 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
ram_upgrade = Ram_quota { 0 };
}
void increase_donated_quota(Ram_quota added_ram_quota)
void increase_donated_quota(Ram_quota added_ram_quota,
Cap_quota added_cap_quota)
{
_donated_ram_quota.value += added_ram_quota.value;
_donated_cap_quota.value += added_cap_quota.value;
ram_upgrade = added_ram_quota;
cap_upgrade = added_cap_quota;
}
Parent::Client::Id id_at_client() const
@ -178,6 +184,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
void generate_server_side_info(Xml_generator &, Detail detail) const;
Ram_quota donated_ram_quota() const { return _donated_ram_quota; }
Cap_quota donated_cap_quota() const { return _donated_cap_quota; }
bool alive() const
{
@ -186,6 +193,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
case CREATE_REQUESTED:
case INVALID_ARGS:
case INSUFFICIENT_RAM_QUOTA:
case INSUFFICIENT_CAP_QUOTA:
case CLOSED:
return false;

View File

@ -57,9 +57,8 @@ class Genode::Parent
** Exception types **
*********************/
class Exception : public ::Genode::Exception { };
class Service_denied : public Exception { };
class Unavailable : public Exception { };
struct Service_denied : Exception { };
struct Unavailable : Exception { };
typedef Rpc_in_buffer<64> Service_name;
typedef Rpc_in_buffer<160> Session_args;
@ -160,7 +159,9 @@ class Genode::Parent
* \param affinity preferred CPU affinity for the session
*
* \throw Service_denied parent denies session request
* \throw Insufficient_cap_quota donated cap quota does not suffice
* \throw Insufficient_ram_quota donated RAM quota does not suffice
* \throw Out_of_caps session CAP quota exceeds our resources
* \throw Out_of_ram session RAM quota exceeds our resources
*
* \return session capability of the new session is immediately
@ -182,8 +183,11 @@ class Genode::Parent
* Request session capability
*
* \throw Service_denied
* \throw Insufficient_cap_quota
* \throw Insufficient_ram_quota
*
* See 'session' for more documentation.
*
* In the exception case, the parent implicitly closes the session.
*/
virtual Session_capability session_cap(Client::Id id) = 0;
@ -196,6 +200,7 @@ class Genode::Parent
* \param id ID of recipient session
* \param args description of the amount of quota to transfer
*
* \throw Out_of_caps
* \throw Out_of_ram
*
* The 'args' argument has the same principle format as the 'args'
@ -216,7 +221,7 @@ class Genode::Parent
*/
enum Session_response { SESSION_OK, SESSION_CLOSED, INVALID_ARGS,
INSUFFICIENT_RAM_QUOTA };
INSUFFICIENT_RAM_QUOTA, INSUFFICIENT_CAP_QUOTA };
/**
* Set state of a session provided by the child service
@ -294,16 +299,17 @@ class Genode::Parent
Service_name const &);
GENODE_RPC(Rpc_session_sigh, void, session_sigh, Signal_context_capability);
GENODE_RPC_THROW(Rpc_session, Session_capability, session,
GENODE_TYPE_LIST(Service_denied, Out_of_ram,
GENODE_TYPE_LIST(Service_denied, Out_of_caps,
Out_of_ram, Insufficient_cap_quota,
Insufficient_ram_quota, Unavailable),
Client::Id, Service_name const &, Session_args const &,
Affinity const &);
GENODE_RPC_THROW(Rpc_session_cap, Session_capability, session_cap,
GENODE_TYPE_LIST(Service_denied,
GENODE_TYPE_LIST(Service_denied, Insufficient_cap_quota,
Insufficient_ram_quota, Unavailable),
Client::Id);
GENODE_RPC_THROW(Rpc_upgrade, Upgrade_result, upgrade,
GENODE_TYPE_LIST(Out_of_ram),
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
Client::Id, Upgrade_args const &);
GENODE_RPC(Rpc_close, Close_result, close, Client::Id);
GENODE_RPC(Rpc_session_response, void, session_response,

View File

@ -62,6 +62,15 @@ struct Genode::Pd_session_client : Rpc_client<Pd_session>
Capability<Region_map> linker_area() override {
return call<Rpc_linker_area>(); }
void ref_account(Capability<Pd_session> pd) override {
call<Rpc_ref_account>(pd); }
void transfer_quota(Capability<Pd_session> pd, Cap_quota amount) override {
call<Rpc_transfer_cap_quota>(pd, amount); }
Cap_quota cap_quota() const { return call<Rpc_cap_quota>(); }
Cap_quota used_caps() const { return call<Rpc_used_caps>(); }
Capability<Native_pd> native_pd() override { return call<Rpc_native_pd>(); }
};

View File

@ -71,7 +71,8 @@ struct Genode::Pd_session : Session
typedef Capability<Signal_source> Signal_source_capability;
class Out_of_metadata : public Exception { };
class Invalid_session : public Exception { };
class Undefined_ref_account : public Exception { };
class Invalid_signal_source : public Exception { };
/**
@ -81,7 +82,8 @@ struct Genode::Pd_session : Session
*
* The signal source provides an interface to wait for incoming signals.
*
* \throw Out_of_metadata
* \throw Out_of_ram
* \throw Out_of_caps
*/
virtual Signal_source_capability alloc_signal_source() = 0;
@ -102,7 +104,8 @@ struct Genode::Pd_session : Session
* originating from the allocated signal-context capability
* \return new signal-context capability
*
* \throw Out_of_metadata
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Invalid_signal_source
*/
virtual Capability<Signal_context>
@ -141,7 +144,8 @@ struct Genode::Pd_session : Session
*
* \param ep entry point that will use this capability
*
* \throw Out_of_metadata if meta-data backing store is exhausted
* \throw Out_of_ram if meta-data backing store is exhausted
* \throw Out_of_caps if 'cap_quota' is exceeded
*
* \return new RPC capability
*/
@ -177,6 +181,49 @@ struct Genode::Pd_session : Session
virtual Capability<Region_map> linker_area() = 0;
/*******************************************
** Accounting for capability allocations **
*******************************************/
/**
* Define reference account for the PD session
*
* \throw Invalid_session
*/
virtual void ref_account(Capability<Pd_session>) = 0;
/**
* Transfer capability quota to another PD session
*
* \param pd_session receiver of quota donation
* \param amount amount of quota to donate
*
* \throw Out_of_caps
* \throw Invalid_session
* \throw Undefined_ref_account
*
* Quota can only be transfered if the specified PD session is either the
* reference account for this session or vice versa.
*/
virtual void transfer_quota(Capability<Pd_session> pd_session,
Cap_quota amount) = 0;
/**
* Return current capability-quota limit
*/
virtual Cap_quota cap_quota() const = 0;
/**
* Return number of capabilities allocated from the session
*/
virtual Cap_quota used_caps() const = 0;
Cap_quota avail_caps() const
{
return Cap_quota { cap_quota().value - used_caps().value };
}
/*****************************************
** Access to kernel-specific interface **
*****************************************/
@ -200,30 +247,41 @@ struct Genode::Pd_session : Session
GENODE_RPC(Rpc_assign_pci, bool, assign_pci, addr_t, uint16_t);
GENODE_RPC_THROW(Rpc_alloc_signal_source, Signal_source_capability,
alloc_signal_source, GENODE_TYPE_LIST(Out_of_metadata));
alloc_signal_source,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps));
GENODE_RPC(Rpc_free_signal_source, void, free_signal_source, Signal_source_capability);
GENODE_RPC_THROW(Rpc_alloc_context, Capability<Signal_context>, alloc_context,
GENODE_TYPE_LIST(Out_of_metadata, Invalid_signal_source),
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Invalid_signal_source),
Signal_source_capability, unsigned long);
GENODE_RPC(Rpc_free_context, void, free_context,
Capability<Signal_context>);
GENODE_RPC(Rpc_submit, void, submit, Capability<Signal_context>, unsigned);
GENODE_RPC_THROW(Rpc_alloc_rpc_cap, Native_capability, alloc_rpc_cap,
GENODE_TYPE_LIST(Out_of_metadata), Native_capability);
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), Native_capability);
GENODE_RPC(Rpc_free_rpc_cap, void, free_rpc_cap, Native_capability);
GENODE_RPC(Rpc_address_space, Capability<Region_map>, address_space);
GENODE_RPC(Rpc_stack_area, Capability<Region_map>, stack_area);
GENODE_RPC(Rpc_linker_area, Capability<Region_map>, linker_area);
GENODE_RPC_THROW(Rpc_ref_account, void, ref_account,
GENODE_TYPE_LIST(Invalid_session), Capability<Pd_session>);
GENODE_RPC_THROW(Rpc_transfer_cap_quota, void, transfer_quota,
GENODE_TYPE_LIST(Out_of_caps, Invalid_session, Undefined_ref_account),
Capability<Pd_session>, Cap_quota);
GENODE_RPC(Rpc_cap_quota, Cap_quota, cap_quota);
GENODE_RPC(Rpc_used_caps, Cap_quota, used_caps);
GENODE_RPC(Rpc_native_pd, Capability<Native_pd>, native_pd);
GENODE_RPC_INTERFACE(Rpc_assign_parent, Rpc_assign_pci,
Rpc_alloc_signal_source, Rpc_free_signal_source,
Rpc_alloc_context, Rpc_free_context, Rpc_submit,
Rpc_alloc_rpc_cap, Rpc_free_rpc_cap, Rpc_address_space,
Rpc_stack_area, Rpc_linker_area, Rpc_native_pd);
Rpc_stack_area, Rpc_linker_area, Rpc_ref_account,
Rpc_transfer_cap_quota, Rpc_cap_quota, Rpc_used_caps,
Rpc_native_pd);
};
#endif /* _INCLUDE__PD_SESSION__PD_SESSION_H_ */

View File

@ -26,7 +26,7 @@ class Genode::Rom_connection : public Connection<Rom_session>,
{
public:
class Rom_connection_failed : public Parent::Exception { };
class Rom_connection_failed : public Parent::Service_denied { };
enum { RAM_QUOTA = 6*1024UL };

View File

@ -151,6 +151,24 @@ class Genode::Root_component : public Rpc_object<Typed_root<SESSION_TYPE> >,
Ram_quota const remaining_ram_quota { ram_quota.value - needed };
/*
* Validate that the client provided the amount of caps as mandated
* for the session interface.
*/
Cap_quota const cap_quota = cap_quota_from_args(args.string());
if (cap_quota.value < SESSION_TYPE::CAP_QUOTA)
throw Insufficient_cap_quota();
/*
* Account for the dataspace capability needed for allocating the
* session object from the sliced heap.
*/
if (cap_quota.value < 1)
throw Insufficient_cap_quota();
Cap_quota const remaining_cap_quota { cap_quota.value - 1 };
/*
* Deduce ram quota needed for allocating the session object from the
* donated ram quota.
@ -162,9 +180,13 @@ class Genode::Root_component : public Rpc_object<Typed_root<SESSION_TYPE> >,
Arg_string::set_arg(adjusted_args, sizeof(adjusted_args),
"ram_quota", String<64>(remaining_ram_quota).string());
Arg_string::set_arg(adjusted_args, sizeof(adjusted_args),
"cap_quota", String<64>(remaining_cap_quota).string());
SESSION_TYPE *s = 0;
try { s = _create_session(adjusted_args, affinity); }
catch (Out_of_ram) { throw Insufficient_ram_quota(); }
catch (Out_of_caps) { throw Insufficient_cap_quota(); }
/*
* Consider that the session-object constructor may already have
@ -281,7 +303,9 @@ class Genode::Root_component : public Rpc_object<Typed_root<SESSION_TYPE> >,
{
try {
return _create(args, affinity); }
catch (Insufficient_ram_quota) { throw; }
catch (Insufficient_cap_quota) { throw; }
catch (...) {
throw typename Local_service<SESSION_TYPE>::Factory::Denied(); }
}

View File

@ -33,10 +33,8 @@ struct Genode::Root
** Exception types **
*********************/
class Exception : public ::Genode::Exception { };
class Unavailable : public Exception { };
class Quota_exceeded : public Exception { };
class Invalid_args : public Exception { };
class Unavailable : public Exception { };
class Invalid_args : public Exception { };
typedef Rpc_in_buffer<160> Session_args;
typedef Rpc_in_buffer<160> Upgrade_args;
@ -48,6 +46,7 @@ struct Genode::Root
*
* \throw Unavailable
* \throw Insufficient_ram_quota
* \throw Insufficient_cap_quota
* \throw Invalid_args
*
* \return capability to new session
@ -72,7 +71,7 @@ struct Genode::Root
GENODE_RPC_THROW(Rpc_session, Session_capability, session,
GENODE_TYPE_LIST(Unavailable, Insufficient_ram_quota,
Invalid_args),
Insufficient_cap_quota, Invalid_args),
Session_args const &, Affinity const &);
GENODE_RPC_THROW(Rpc_upgrade, void, upgrade,
GENODE_TYPE_LIST(Invalid_args),

View File

@ -188,7 +188,7 @@ _ZN6Genode18server_socket_pairEv T
_ZN6Genode20env_session_id_spaceEv T
_ZN6Genode25env_stack_area_region_mapE B 4
_ZN6Genode26env_stack_area_ram_sessionE B 4
_ZN6Genode29upgrade_pd_quota_non_blockingEm T
_ZN6Genode29upgrade_pd_quota_non_blockingENS_9Ram_quotaENS_9Cap_quotaE T
_ZN6Genode3Log3logEv T
_ZN6Genode3Log8_acquireENS0_4TypeE T
_ZN6Genode3Log8_releaseEv T

View File

@ -112,11 +112,10 @@ namespace Genode {
bool _init_stack_area() { init_stack_area(); return true; }
bool _stack_area_initialized = _init_stack_area();
Rpc_entrypoint _entrypoint;
Core_region_map _region_map;
Ram_session_component _ram_session;
Ram_session_capability _ram_session_cap;
Synced_ram_session _synced_ram_session { _ram_session };
Rpc_entrypoint _entrypoint;
Core_region_map _region_map;
Ram_session_component _ram_session;
Synced_ram_session _synced_ram_session { _ram_session };
/*
* The core-local PD session is provided by a real RPC object
@ -159,7 +158,8 @@ namespace Genode {
_region_map,
Ram_session_component::any_phys_range()),
_pd_session_component(_entrypoint),
_pd_session_client(_entrypoint.manage(&_pd_session_component))
_pd_session_client(_pd_session_component.cap()),
_heap(_ram_session, _region_map)
{
_ram_session.init_ram_account();
}
@ -192,7 +192,7 @@ namespace Genode {
Cpu_session_capability cpu_session_cap() override
{
warning(__func__, " not implemented");
warning(__FILE__, ":", __LINE__, " not implemented");
return Cpu_session_capability();
}

View File

@ -30,20 +30,17 @@ class Genode::Core_pd_session_component : public Rpc_object<Pd_session>
{
private:
Rpc_entrypoint &_signal_source_ep;
Rpc_entrypoint &_ep;
public:
/**
* Constructor
*
* \param context_ep entrypoint that serves the signal-source
* components
*/
Core_pd_session_component(Rpc_entrypoint &signal_source_ep)
:
_signal_source_ep(signal_source_ep)
{ }
Core_pd_session_component(Rpc_entrypoint &ep) : _ep(ep)
{
ep.manage(this);
}
void assign_parent(Capability<Parent> parent) override
{
@ -83,7 +80,7 @@ class Genode::Core_pd_session_component : public Rpc_object<Pd_session>
void submit(Capability<Signal_context> cap, unsigned cnt = 1) override
{
_signal_source_ep.apply(cap, [&] (Signal_context_component *context) {
_ep.apply(cap, [&] (Signal_context_component *context) {
if (!context) {
warning("invalid signal-context capability");
return;
@ -103,11 +100,17 @@ class Genode::Core_pd_session_component : public Rpc_object<Pd_session>
ASSERT_NEVER_CALLED;
}
Capability<Region_map> address_space() { ASSERT_NEVER_CALLED; }
Capability<Region_map> address_space() override { ASSERT_NEVER_CALLED; }
Capability<Region_map> stack_area() override { ASSERT_NEVER_CALLED; }
Capability<Region_map> linker_area() override { ASSERT_NEVER_CALLED; }
Capability<Region_map> stack_area() { ASSERT_NEVER_CALLED; }
void ref_account(Capability<Pd_session>) override { ASSERT_NEVER_CALLED; }
Capability<Region_map> linker_area() { ASSERT_NEVER_CALLED; }
void transfer_quota(Capability<Pd_session>, Cap_quota) override {
ASSERT_NEVER_CALLED; }
Cap_quota cap_quota() const { ASSERT_NEVER_CALLED; }
Cap_quota used_caps() const { ASSERT_NEVER_CALLED; }
Capability<Native_pd> native_pd() override { ASSERT_NEVER_CALLED; }
};

View File

@ -29,27 +29,29 @@ class Genode::Pd_root : public Genode::Root_component<Genode::Pd_session_compone
{
private:
Rpc_entrypoint &_thread_ep;
Rpc_entrypoint &_ep;
Pager_entrypoint &_pager_ep;
Allocator &_md_alloc;
Ram_allocator &_ram_alloc;
Region_map &_local_rm;
protected:
Pd_session_component *_create_session(const char *args)
{
/* XXX use separate entrypoint for PD sessions */
return new (md_alloc()) Pd_session_component(_thread_ep,
_thread_ep,
_thread_ep,
_md_alloc,
_pager_ep, args);
Pd_session_component *result = new (md_alloc())
Pd_session_component(_ep,
session_resources_from_args(args),
session_label_from_args(args),
session_diag_from_args(args),
_ram_alloc, _local_rm, _pager_ep, args);
return result;
}
void _upgrade_session(Pd_session_component *p, const char *args)
void _upgrade_session(Pd_session_component *pd, const char *args)
{
size_t ram_quota =
Arg_string::find_arg(args, "ram_quota").ulong_value(0);
p->upgrade_ram_quota(ram_quota);
pd->Ram_quota_guard::upgrade(ram_quota_from_args(args));
pd->Cap_quota_guard::upgrade(cap_quota_from_args(args));
pd->session_quota_upgraded();
}
public:
@ -57,16 +59,20 @@ class Genode::Pd_root : public Genode::Root_component<Genode::Pd_session_compone
/**
* Constructor
*
* \param session_ep entry point for managing pd session objects
* \param thread_ep entry point for managing threads
* \param md_alloc meta-data allocator to be used by root component
* \param ep entry point for managing pd session objects,
* threads, and signal contexts
* \param ram_alloc allocator used for session-local allocations
* \param md_alloc meta-data allocator to be used by root component
*/
Pd_root(Rpc_entrypoint *session_ep,
Rpc_entrypoint *thread_ep,
Pd_root(Rpc_entrypoint &ep,
Pager_entrypoint &pager_ep,
Allocator *md_alloc)
: Root_component<Pd_session_component>(session_ep, md_alloc),
_thread_ep(*thread_ep), _pager_ep(pager_ep), _md_alloc(*md_alloc) { }
Ram_allocator &ram_alloc,
Region_map &local_rm,
Allocator &md_alloc)
:
Root_component<Pd_session_component>(&ep, &md_alloc),
_ep(ep), _pager_ep(pager_ep), _ram_alloc(ram_alloc), _local_rm(local_rm)
{ }
};
#endif /* _CORE__INCLUDE__PD_ROOT_H_ */

View File

@ -17,9 +17,11 @@
#define _CORE__INCLUDE__PD_SESSION_COMPONENT_H_
/* Genode includes */
#include <util/reconstructible.h>
#include <base/allocator_guard.h>
#include <base/session_label.h>
#include <base/rpc_server.h>
#include <base/session_object.h>
#include <base/registry.h>
#include <base/heap.h>
#include <pd_session/pd_session.h>
#include <util/arg_string.h>
@ -33,88 +35,111 @@
#include <native_pd_component.h>
#include <region_map_component.h>
#include <platform_generic.h>
#include <account.h>
namespace Genode { class Pd_session_component; }
class Genode::Pd_session_component : public Rpc_object<Pd_session>
class Genode::Pd_session_component : public Session_object<Pd_session>
{
private:
/**
* Read and store the PD label
*/
struct Label {
enum { MAX_LEN = 64 };
char string[MAX_LEN];
Label(char const *args)
{
Arg_string::find_arg(args, "label").string(string,
sizeof(string), "");
}
} const _label;
Allocator_guard _md_alloc; /* guarded meta-data allocator */
Platform_pd _pd;
Capability<Parent> _parent;
Rpc_entrypoint &_thread_ep;
Pager_entrypoint &_pager_ep;
Signal_broker _signal_broker;
Rpc_cap_factory _rpc_cap_factory;
Native_pd_component _native_pd;
Constrained_ram_allocator _constrained_md_ram_alloc;
Sliced_heap _sliced_heap;
Platform_pd _pd { &_sliced_heap, _label.string() };
Capability<Parent> _parent;
Rpc_entrypoint &_ep;
Pager_entrypoint &_pager_ep;
Signal_broker _signal_broker { _sliced_heap, _ep, _ep };
Rpc_cap_factory _rpc_cap_factory { _sliced_heap };
Native_pd_component _native_pd;
Region_map_component _address_space;
Region_map_component _stack_area;
Region_map_component _linker_area;
size_t _ram_quota(char const * args) {
return Arg_string::find_arg(args, "ram_quota").long_value(0); }
Constructible<Account<Cap_quota> > _cap_account;
friend class Native_pd_component;
enum Cap_type { RPC_CAP, SIG_SOURCE_CAP, SIG_CONTEXT_CAP, IGN_CAP };
char const *_name(Cap_type type)
{
switch (type) {
case RPC_CAP: return "RPC";
case SIG_SOURCE_CAP: return "signal-source";
case SIG_CONTEXT_CAP: return "signal-context";
default: return "";
}
}
/*
* \throw Out_of_caps
*/
void _consume_cap(Cap_type type)
{
try { Cap_quota_guard::withdraw(Cap_quota{1}); }
catch (Out_of_caps) {
diag("out of caps while consuming ", _name(type), " cap "
"(", _cap_account, ")");
throw;
}
diag("consumed ", _name(type), " cap (", _cap_account, ")");
}
void _released_cap_silent() { Cap_quota_guard::replenish(Cap_quota{1}); }
void _released_cap(Cap_type type)
{
_released_cap_silent();
diag("released ", _name(type), " cap (", _cap_account, ")");
}
public:
/**
* Constructor
*
* \param receiver_ep entrypoint holding signal-receiver component
* objects
* \param context_ep global pool of all signal contexts
* \param md_alloc backing-store allocator for
* signal-context component objects
*
* To maintain proper synchronization, 'receiver_ep' must be
* the same entrypoint as used for the signal-session component.
* The 'signal_context_ep' is only used for associative array
* to map signal-context capabilities to 'Signal_context_component'
* objects and as capability allocator for such objects.
* \param ep entrypoint holding signal-receiver component
* objects, signal contexts, thread objects
* \param ram_alloc backing store for dynamically allocated
* session meta data
*/
Pd_session_component(Rpc_entrypoint &thread_ep,
Rpc_entrypoint &receiver_ep,
Rpc_entrypoint &context_ep,
Allocator &md_alloc,
Pd_session_component(Rpc_entrypoint &ep,
Resources resources,
Label const &label,
Diag diag,
Ram_allocator &ram_alloc,
Region_map &local_rm,
Pager_entrypoint &pager_ep,
char const *args)
:
_label(args),
_md_alloc(&md_alloc, _ram_quota(args)),
_pd(&_md_alloc, _label.string),
_thread_ep(thread_ep), _pager_ep(pager_ep),
_signal_broker(_md_alloc, receiver_ep, context_ep),
_rpc_cap_factory(_md_alloc),
Session_object(ep, resources, label, diag),
_constrained_md_ram_alloc(ram_alloc, *this, *this),
_sliced_heap(_constrained_md_ram_alloc, local_rm),
_ep(ep), _pager_ep(pager_ep),
_rpc_cap_factory(_sliced_heap),
_native_pd(*this, args),
_address_space(thread_ep, _md_alloc, pager_ep,
_address_space(ep, _sliced_heap, pager_ep,
platform()->vm_start(), platform()->vm_size()),
_stack_area(thread_ep, _md_alloc, pager_ep, 0, stack_area_virtual_size()),
_linker_area(thread_ep, _md_alloc, pager_ep, 0, LINKER_AREA_SIZE)
_stack_area (_ep, _sliced_heap, pager_ep, 0, stack_area_virtual_size()),
_linker_area(_ep, _sliced_heap, pager_ep, 0, LINKER_AREA_SIZE)
{ }
/**
* Register quota donation at allocator guard
* Initialize cap account without providing a reference account
*
* This method is solely used to set up the initial PD session within
* core. The cap accounts of regular PD session are initialized via
* 'ref_account'.
*/
void upgrade_ram_quota(size_t ram_quota);
void init_cap_account() { _cap_account.construct(*this, _label); }
/**
* Session_object interface
*/
void session_quota_upgraded() override;
/**
* Associate thread with PD
@ -135,8 +160,6 @@ class Genode::Pd_session_component : public Rpc_object<Pd_session>
return _address_space;
}
Session_label label() { return Session_label(_label.string); }
/**************************
** PD session interface **
@ -147,42 +170,62 @@ class Genode::Pd_session_component : public Rpc_object<Pd_session>
Signal_source_capability alloc_signal_source() override
{
try {
return _signal_broker.alloc_signal_source(); }
_consume_cap(SIG_SOURCE_CAP);
try { return _signal_broker.alloc_signal_source(); }
catch (Genode::Allocator::Out_of_memory) {
throw Pd_session::Out_of_metadata(); }
_released_cap_silent();
throw Out_of_ram();
}
}
void free_signal_source(Signal_source_capability sig_rec_cap) override {
_signal_broker.free_signal_source(sig_rec_cap); }
void free_signal_source(Signal_source_capability sig_rec_cap) override
{
_signal_broker.free_signal_source(sig_rec_cap);
_released_cap(SIG_SOURCE_CAP);
}
Signal_context_capability
alloc_context(Signal_source_capability sig_rec_cap, unsigned long imprint) override
{
Cap_quota_guard::Reservation cap_costs(*this, Cap_quota{1});
try {
return _signal_broker.alloc_context(sig_rec_cap, imprint); }
Signal_context_capability cap =
_signal_broker.alloc_context(sig_rec_cap, imprint);
cap_costs.acknowledge();
diag("consumed signal-context cap (", _cap_account, ")");
return cap;
}
catch (Genode::Allocator::Out_of_memory) {
throw Pd_session::Out_of_metadata(); }
throw Out_of_ram(); }
catch (Signal_broker::Invalid_signal_source) {
throw Pd_session::Invalid_signal_source(); }
}
void free_context(Signal_context_capability cap) override {
_signal_broker.free_context(cap); }
void free_context(Signal_context_capability cap) override
{
_signal_broker.free_context(cap);
_released_cap(SIG_CONTEXT_CAP);
}
void submit(Signal_context_capability cap, unsigned n) override {
_signal_broker.submit(cap, n); }
/*
* \throw Out_of_caps by '_consume_cap'
* \throw Out_of_ram by '_rpc_cap_factory.alloc'
*/
Native_capability alloc_rpc_cap(Native_capability ep) override
{
try {
return _rpc_cap_factory.alloc(ep); }
catch (Genode::Allocator::Out_of_memory) {
throw Pd_session::Out_of_metadata(); }
_consume_cap(RPC_CAP);
return _rpc_cap_factory.alloc(ep);
}
void free_rpc_cap(Native_capability cap) override {
_rpc_cap_factory.free(cap); }
void free_rpc_cap(Native_capability cap) override
{
_rpc_cap_factory.free(cap);
_released_cap(RPC_CAP);
}
Capability<Region_map> address_space() {
return _address_space.cap(); }
@ -193,6 +236,65 @@ class Genode::Pd_session_component : public Rpc_object<Pd_session>
Capability<Region_map> linker_area() {
return _linker_area.cap(); }
void ref_account(Capability<Pd_session> pd_cap) override
{
/* the reference account can be defined only once */
if (_cap_account.constructed())
return;
if (this->cap() == pd_cap)
return;
_ep.apply(pd_cap, [&] (Pd_session_component *pd) {
if (!pd || !pd->_cap_account.constructed()) {
error("invalid PD session specified as ref account");
throw Invalid_session();
}
_cap_account.construct(*this, _label, *pd->_cap_account);
});
}
void transfer_quota(Capability<Pd_session> pd_cap, Cap_quota amount) override
{
/* the reference account can be defined only once */
if (!_cap_account.constructed())
throw Undefined_ref_account();
if (this->cap() == pd_cap)
return;
_ep.apply(pd_cap, [&] (Pd_session_component *pd) {
if (!pd || !pd->_cap_account.constructed())
throw Invalid_session();
try {
_cap_account->transfer_quota(*pd->_cap_account, amount);
diag("transferred ", amount, " caps "
"to '", pd->_cap_account->label(), "' (", _cap_account, ")");
}
catch (Account<Cap_quota>::Unrelated_account) {
warning("attempt to transfer cap quota to unrelated PD session");
throw Invalid_session(); }
catch (Account<Cap_quota>::Limit_exceeded) {
warning("cap limit (", *_cap_account, ") exceeded "
"during transfer_quota(", amount, ")");
throw Out_of_caps(); }
});
}
Cap_quota cap_quota() const
{
return _cap_account.constructed() ? _cap_account->limit() : Cap_quota { 0 };
}
Cap_quota used_caps() const
{
return _cap_account.constructed() ? _cap_account->used() : Cap_quota { 0 };
}
Capability<Native_pd> native_pd() { return _native_pd.cap(); }
};

View File

@ -387,7 +387,7 @@ class Genode::Trace::Subject_registry
}
/**
* \throw Ram_session::Quota_exceeded
* \throw Out_of_ram
*/
void import_new_sources(Source_registry &sources)
{

View File

@ -125,12 +125,16 @@ class Core_child : public Child_policy
Registry<Service> &_services;
Capability<Pd_session> _core_pd_cap;
Pd_session &_core_pd;
Capability<Ram_session> _core_ram_cap;
Ram_session &_core_ram;
Capability<Cpu_session> _core_cpu_cap;
Cpu_session &_core_cpu;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota;
Child _child;
@ -141,14 +145,17 @@ class Core_child : public Child_policy
* Constructor
*/
Core_child(Registry<Service> &services,
Pd_session &core_pd, Capability<Pd_session> core_pd_cap,
Ram_session &core_ram, Capability<Ram_session> core_ram_cap,
Cpu_session &core_cpu, Capability<Cpu_session> core_cpu_cap,
Ram_quota ram_quota)
Cap_quota cap_quota, Ram_quota ram_quota)
:
_entrypoint(nullptr, STACK_SIZE, "init_child", false),
_services(services),
_core_pd_cap (core_pd_cap), _core_pd (core_pd),
_core_ram_cap(core_ram_cap), _core_ram(core_ram),
_core_cpu_cap(core_cpu_cap), _core_cpu(core_cpu),
_cap_quota(Child::effective_quota(cap_quota)),
_ram_quota(Child::effective_quota(ram_quota)),
_child(*env_deprecated()->rm_session(), _entrypoint, *this)
{
@ -176,6 +183,12 @@ class Core_child : public Child_policy
return *service;
}
void init(Pd_session &session, Capability<Pd_session> cap) override
{
session.ref_account(_core_pd_cap);
_core_pd.transfer_quota(cap, _cap_quota);
}
void init(Ram_session &session, Capability<Ram_session> cap) override
{
session.ref_account(_core_ram_cap);
@ -188,6 +201,9 @@ class Core_child : public Child_policy
_core_cpu.transfer_quota(cap, Cpu_session::quota_lim_upscale(100, 100));
}
Pd_session &ref_pd() { return _core_pd; }
Pd_session_capability ref_pd_cap() const { return _core_pd_cap; }
Ram_session &ref_ram() { return _core_ram; }
Ram_session_capability ref_ram_cap() const { return _core_ram_cap; }
@ -271,7 +287,7 @@ int main()
static Rm_root rm_root (e, &sliced_heap, pager_ep);
static Cpu_root cpu_root (e, e, &pager_ep, &sliced_heap,
Trace::sources());
static Pd_root pd_root (e, e, pager_ep, &sliced_heap);
static Pd_root pd_root (*e, pager_ep, core_ram_alloc, local_rm, sliced_heap);
static Log_root log_root (e, &sliced_heap);
static Io_mem_root io_mem_root (e, e, platform()->io_mem_alloc(),
platform()->ram_alloc(), &sliced_heap);
@ -292,7 +308,27 @@ int main()
/* make platform-specific services known to service pool */
platform_add_local_services(e, &sliced_heap, &services);
/* create CPU session representing core */
/* calculate number of capabilities to be assigned to init */
size_t const preservered_cap_quota = 1000;
if (platform()->max_caps() < preservered_cap_quota) {
error("platform cap limit lower than preservation for core");
return -1;
}
size_t const avail_cap_quota = platform()->max_caps() - preservered_cap_quota;
/* PD session representing core */
static Pd_session_component
core_pd(*e,
Session::Resources { Ram_quota { 16*1024 },
Cap_quota { avail_cap_quota } },
Session::Label("core"), Session::Diag{false},
core_ram_alloc, local_rm, pager_ep, "");
core_pd.init_cap_account();
/* CPU session representing core */
static Cpu_session_component
core_cpu(e, e, &pager_ep, &sliced_heap, Trace::sources(),
"label=\"core\"", Affinity(), Cpu_session::QUOTA_LIMIT);
@ -309,14 +345,15 @@ int main()
size_t const avail_ram_quota = platform_ram_limit - preserved_ram_quota;
log("", avail_ram_quota / (1024*1024), " MiB RAM "
log("", avail_ram_quota / (1024*1024), " MiB RAM and ", avail_cap_quota, " caps "
"assigned to init");
static Reconstructible<Core_child>
init(services,
core_pd, core_pd.cap(),
*env_deprecated()->ram_session(), env_deprecated()->ram_session_cap(),
core_cpu, core_cpu_cap,
Ram_quota{avail_ram_quota});
core_pd.cap_quota(), Ram_quota{avail_ram_quota});
platform()->wait_for_exit();

View File

@ -17,8 +17,5 @@
using namespace Genode;
void Pd_session_component::upgrade_ram_quota(size_t ram_quota)
{
_md_alloc.upgrade(ram_quota);
}
void Pd_session_component::session_quota_upgraded() { }

View File

@ -60,8 +60,10 @@ void Ram_session_component::_free_ds(Dataspace_capability ds_cap)
});
/* call dataspace destructors and free memory */
if (ds)
if (ds) {
destroy(*_ds_slab, ds);
Cap_quota_guard::replenish(Cap_quota{1});
}
}
@ -92,6 +94,11 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr
Ram_quota_guard::Reservation sbs_ram_costs(*this, Ram_quota{SBS});
}
/*
* Each dataspace is an RPC object and thereby consumes a capability.
*/
Cap_quota_guard::Reservation dataspace_cap_costs(*this, Cap_quota{1});
/*
* Allocate physical backing store
*
@ -191,6 +198,7 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr
Dataspace_capability result = _ep.manage(ds);
dataspace_ram_costs.acknowledge();
dataspace_cap_costs.acknowledge();
phys_alloc_guard.ack = true;
return static_cap_cast<Ram_dataspace>(result);

View File

@ -43,11 +43,6 @@ Io_port_session_component::Io_port_session_component(Range_allocator *io_port_al
case Range_allocator::Alloc_return::OUT_OF_METADATA:
error("I/O port allocator ran out of meta data");
/*
* Do not throw 'Quota_exceeded' because the client cannot do
* anything about the meta data allocator of I/O ports.
*/
throw Root::Invalid_args();
case Range_allocator::Alloc_return::OK: break;

View File

@ -31,8 +31,17 @@ struct Genode::Expanding_ram_session_client : Upgradeable_client<Genode::Ram_ses
Parent &parent = *env_deprecated()->parent();
parent.resource_request(String<128>("ram_quota=", amount).string());
}
void _request_caps_from_parent(size_t amount)
{
Parent &parent = *env_deprecated()->parent();
parent.resource_request(String<128>("cap_quota=", amount).string());
}
Expanding_ram_session_client(Ram_session_capability cap, Parent::Client::Id id)
: Upgradeable_client<Genode::Ram_session_client>(cap, id) { }
:
Upgradeable_client<Genode::Ram_session_client>(cap, id)
{ }
Ram_dataspace_capability alloc(size_t size, Cache_attribute cached = UNCACHED) override
{
@ -41,8 +50,20 @@ struct Genode::Expanding_ram_session_client : Upgradeable_client<Genode::Ram_ses
* to the parent and retry.
*/
enum { NUM_ATTEMPTS = 2 };
enum { UPGRADE_CAPS = 4 };
return retry<Out_of_ram>(
[&] () { return Ram_session_client::alloc(size, cached); },
[&] () {
return retry<Out_of_caps>(
[&] () { return Ram_session_client::alloc(size, cached); },
[&] () {
try { upgrade_caps(UPGRADE_CAPS); }
catch (Out_of_caps) {
warning("cap quota exhausted, issuing resource request to parent");
_request_caps_from_parent(UPGRADE_CAPS);
}
},
NUM_ATTEMPTS);
},
[&] () {
/*
* The RAM service withdraws the meta data for the allocator

View File

@ -115,8 +115,8 @@ class Genode::Platform_env : public Env_deprecated,
** Emergency_ram_reserve interface **
*************************************/
void release() {
void release()
{
log("used before freeing emergency=", _resources.ram.used_ram());
_resources.ram.free(_emergency_ram_ds);
log("used after freeing emergency=", _resources.ram.used_ram());

View File

@ -35,10 +35,12 @@ struct Genode::Upgradeable_client : CLIENT
void upgrade_ram(size_t quota)
{
char buf[128];
snprintf(buf, sizeof(buf), "ram_quota=%lu", quota);
env_deprecated()->parent()->upgrade(_id, String<64>("ram_quota=", quota).string());
}
env_deprecated()->parent()->upgrade(_id, buf);
void upgrade_caps(size_t quota)
{
env_deprecated()->parent()->upgrade(_id, String<64>("cap_quota=", quota).string());
}
};

View File

@ -75,6 +75,7 @@ void Child::session_sigh(Signal_context_capability sigh)
if (session.phase == Session_state::AVAILABLE ||
session.phase == Session_state::INSUFFICIENT_RAM_QUOTA ||
session.phase == Session_state::INSUFFICIENT_CAP_QUOTA ||
session.phase == Session_state::INVALID_ARGS) {
if (sigh.valid() && session.async_client_notify)
@ -88,6 +89,7 @@ void Child::session_sigh(Signal_context_capability sigh)
* Create session-state object for a dynamically created session
*
* \throw Out_of_ram
* \throw Insufficient_cap_quota
* \throw Insufficient_ram_quota
* \throw Parent::Service_denied
*/
@ -104,6 +106,11 @@ create_session(Child_policy::Name const &child_name, Service &service,
catch (Insufficient_ram_quota) {
error(child_name, " requested session with insufficient RAM quota");
throw; }
catch (Insufficient_cap_quota) {
error(child_name, " requested session with insufficient cap quota");
throw; }
catch (Allocator::Out_of_memory) {
error(child_name, " session meta data could not be allocated");
throw Out_of_ram(); }
@ -170,6 +177,7 @@ Session_capability Child::session(Parent::Client::Id id,
/* filter session affinity */
Affinity const filtered_affinity = _policy.filter_session_affinity(affinity);
Cap_quota const cap_quota = cap_quota_from_args(argbuf);
Ram_quota const ram_quota = ram_quota_from_args(argbuf);
/* portion of quota to keep for ourself to maintain the session meta data */
@ -202,13 +210,18 @@ Session_capability Child::session(Parent::Client::Id id,
try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_ram(), _policy.ref_ram_cap() };
Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() };
Ram_transfer::Remote_account ram_account { ram(), ram_session_cap() };
Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() };
/* transfer the quota donation from the child's account to ourself */
Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account);
/* transfer session quota from ourself to the service provider */
Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service);
Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, service);
/* try to dispatch session request synchronously */
service.initiate_request(session);
@ -223,9 +236,16 @@ Session_capability Child::session(Parent::Client::Id id,
throw Insufficient_ram_quota();
}
if (session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
_revert_quota_and_destroy(session);
throw Insufficient_cap_quota();
}
/* finish transaction */
ram_donation_from_child.acknowledge();
cap_donation_from_child.acknowledge();
ram_donation_to_service.acknowledge();
cap_donation_to_service.acknowledge();
}
/*
* Release session meta data if one of the quota transfers went wrong.
@ -234,6 +254,10 @@ Session_capability Child::session(Parent::Client::Id id,
session.destroy();
throw Out_of_ram();
}
catch (Cap_transfer::Quota_exceeded) {
session.destroy();
throw Out_of_caps();
}
/*
* Copy out the session cap before we are potentially kicking off the
@ -261,7 +285,8 @@ Session_capability Child::session_cap(Client::Id id)
auto lamda = [&] (Session_state &session) {
if (session.phase == Session_state::INVALID_ARGS
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) {
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA
|| session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
Session_state::Phase const phase = session.phase;
@ -275,6 +300,7 @@ Session_capability Child::session_cap(Client::Id id)
switch (phase) {
case Session_state::INVALID_ARGS: throw Parent::Service_denied();
case Session_state::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota();
case Session_state::INSUFFICIENT_CAP_QUOTA: throw Insufficient_cap_quota();
default: break;
}
}
@ -318,29 +344,43 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const
Ram_quota const ram_quota {
Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0) };
Cap_quota const cap_quota {
Arg_string::find_arg(args.string(), "cap_quota").ulong_value(0) };
try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_ram(), _policy.ref_ram_cap() };
Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() };
Ram_transfer::Remote_account ram_account { ram(), ram_session_cap() };
Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() };
/* transfer quota from client to ourself */
Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account);
/* transfer session quota from ourself to the service provider */
Ram_transfer ram_donation_to_service(ram_quota, ref_ram_account, session.service());
Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, session.service());
session.increase_donated_quota(ram_quota);
session.increase_donated_quota(ram_quota, cap_quota);
session.phase = Session_state::UPGRADE_REQUESTED;
session.service().initiate_request(session);
/* finish transaction */
ram_donation_from_child.acknowledge();
cap_donation_from_child.acknowledge();
ram_donation_to_service.acknowledge();
cap_donation_to_service.acknowledge();
}
catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), ": RAM upgrade of ", session.service().name(), " failed");
throw Out_of_ram();
}
catch (Cap_transfer::Quota_exceeded) {
warning(_policy.name(), ": cap upgrade of ", session.service().name(), " failed");
throw Out_of_caps();
}
if (session.phase == Session_state::CAP_HANDED_OUT) {
result = UPGRADE_DONE;
@ -361,11 +401,18 @@ void Child::_revert_quota_and_destroy(Session_state &session)
Ram_transfer::Account &service_ram_account = session.service();
Ram_transfer::Remote_account child_ram_account(ram(), ram_session_cap());
Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap());
Cap_transfer::Account &service_cap_account = session.service();
Cap_transfer::Remote_account child_cap_account(pd(), pd_session_cap());
try {
/* transfer session quota from the service to ourself */
Ram_transfer ram_donation_from_service(session.donated_ram_quota(),
service_ram_account, ref_ram_account);
Cap_transfer cap_donation_from_service(session.donated_cap_quota(),
service_cap_account, ref_cap_account);
/*
* Transfer session quota from ourself to the client (our child). In
* addition to the quota returned from the server, we also return the
@ -377,9 +424,14 @@ void Child::_revert_quota_and_destroy(Session_state &session)
Ram_transfer ram_donation_to_client(returned_ram,
ref_ram_account, child_ram_account);
Cap_transfer cap_donation_to_client(session.donated_cap_quota(),
ref_cap_account, child_cap_account);
/* finish transaction */
ram_donation_from_service.acknowledge();
cap_donation_from_service.acknowledge();
ram_donation_to_client.acknowledge();
cap_donation_to_client.acknowledge();
}
catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), ": could not revert session RAM quota (", session, ")"); }
@ -398,7 +450,8 @@ Child::Close_result Child::_close(Session_state &session)
* without involving the server
*/
if (session.phase == Session_state::INVALID_ARGS
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) {
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA
|| session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
_revert_quota_and_destroy(session);
return CLOSE_DONE;
}
@ -503,6 +556,12 @@ void Child::session_response(Server::Id id, Session_response response)
session.ready_callback->session_ready(session);
break;
case Parent::INSUFFICIENT_CAP_QUOTA:
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA;
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
case Parent::SESSION_OK:
if (session.phase == Session_state::UPGRADE_REQUESTED) {
session.phase = Session_state::CAP_HANDED_OUT;
@ -649,6 +708,7 @@ void Child::_try_construct_env_dependent_members()
_parent_cap);
}
catch (Out_of_ram) { _error("out of RAM during ELF loading"); }
catch (Out_of_caps) { _error("out of caps during ELF loading"); }
catch (Cpu_session::Thread_creation_failed) { _error("unable to create initial thread"); }
catch (Cpu_session::Out_of_metadata) { _error("CPU session quota exhausted"); }
catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); }

View File

@ -123,24 +123,27 @@ namespace {
* the route between client and server, the session quota provided
* by the client may become successively diminished by intermediate
* components, prompting the server to deny the session request.
*
* If the session creation failed due to insufficient session
* quota, we try to repeatedly increase the quota up to
* 'NUM_ATTEMPTS'.
*/
enum { NUM_ATTEMPTS = 10 };
/* extract session quota as specified by the 'Connection' */
char argbuf[Parent::Session_args::MAX_SIZE];
strncpy(argbuf, args.string(), sizeof(argbuf));
Ram_quota ram_quota = ram_quota_from_args(argbuf);
return retry<Insufficient_ram_quota>(
[&] () {
Ram_quota ram_quota = ram_quota_from_args(argbuf);
Cap_quota cap_quota = cap_quota_from_args(argbuf);
unsigned warn_after_attempts = 2;
for (unsigned cnt = 0;; cnt++) {
try {
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota",
String<32>(ram_quota).string());
Arg_string::set_arg(argbuf, sizeof(argbuf), "cap_quota",
String<32>(cap_quota).string());
Session_capability cap =
_parent.session(id, name, Parent::Session_args(argbuf), affinity);
@ -149,30 +152,34 @@ namespace {
_block_for_session();
return _parent.session_cap(id);
},
[&] () {
/*
* If our RAM session has less quota available than the
* session quota, the session-quota transfer failed. In
* this case, we try to recover by issuing a resource
* request to the parent.
*
* Otherwise, the session-quota transfer succeeded but
* the request was denied by the server.
*/
}
catch (Insufficient_ram_quota) {
ram_quota = Ram_quota { ram_quota.value + 4096 }; }
catch (Insufficient_cap_quota) {
cap_quota = Cap_quota { cap_quota.value + 4 }; }
catch (Out_of_ram) {
if (ram_quota.value > ram().avail_ram().value) {
Parent::Resource_args args(String<64>("ram_quota=", ram_quota));
_parent.resource_request(args);
} else {
ram_quota = Ram_quota { ram_quota.value + 4096 };
}
},
NUM_ATTEMPTS);
}
warning("giving up to increase session quota for ", name.string(), " session "
"after ", (int)NUM_ATTEMPTS, " attempts");
catch (Out_of_caps) {
if (cap_quota.value > pd().avail_caps().value) {
Parent::Resource_args args(String<64>("cap_quota=", cap_quota));
_parent.resource_request(args);
}
}
throw Insufficient_ram_quota();
if (cnt == warn_after_attempts) {
warning("re-attempted ", name.string(), " session request ",
cnt, " times (args: ", Cstring(argbuf), ")");
warn_after_attempts *= 2;
}
}
}
void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override

View File

@ -187,6 +187,8 @@ void Root_proxy::_handle_session_request(Xml_node request)
_env.parent().session_response(id, Parent::INVALID_ARGS); }
catch (Insufficient_ram_quota) {
_env.parent().session_response(id, Parent::INSUFFICIENT_RAM_QUOTA); }
catch (Insufficient_cap_quota) {
_env.parent().session_response(id, Parent::INSUFFICIENT_CAP_QUOTA); }
catch (Root::Unavailable) {
_env.parent().session_response(id, Parent::INVALID_ARGS); }
}
@ -196,8 +198,9 @@ void Root_proxy::_handle_session_request(Xml_node request)
_id_space.apply<Session>(id, [&] (Session &session) {
Ram_quota const ram_quota { request.attribute_value("ram_quota", 0UL) };
Cap_quota const cap_quota { request.attribute_value("cap_quota", 0UL) };
String<80> const args("ram_quota=", ram_quota);
String<80> const args("ram_quota=", ram_quota, ", cap_quota=", cap_quota);
Root_client(session.service.root).upgrade(session.cap, args.string());

View File

@ -23,13 +23,19 @@ using namespace Genode;
Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd,
Native_capability ep, addr_t)
{
Untyped_capability new_obj_cap =
retry<Genode::Pd_session::Out_of_metadata>(
[&] () { return pd.alloc_rpc_cap(_cap); },
[&] () { env_deprecated()->parent()->upgrade(Parent::Env::pd(),
"ram_quota=16K"); });
for (;;) {
return new_obj_cap;
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try { return pd.alloc_rpc_cap(_cap); }
catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
env_deprecated()->parent()->upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
}
}

View File

@ -33,6 +33,7 @@ struct Formatted_phase
case State::CREATE_REQUESTED: print(output, "CREATE_REQUESTED"); break;
case State::INVALID_ARGS: print(output, "INVALID_ARGS"); break;
case State::INSUFFICIENT_RAM_QUOTA: print(output, "INSUFFICIENT_RAM_QUOTA"); break;
case State::INSUFFICIENT_CAP_QUOTA: print(output, "INSUFFICIENT_CAP_QUOTA"); break;
case State::AVAILABLE: print(output, "AVAILABLE"); break;
case State::CAP_HANDED_OUT: print(output, "CAP_HANDED_OUT"); break;
case State::UPGRADE_REQUESTED: print(output, "UPGRADE_REQUESTED"); break;
@ -49,7 +50,7 @@ void Session_state::print(Output &out) const
print(out, "service=", _service.name(), " cid=", _id_at_client, " "
"args='", _args, "' state=", Formatted_phase(phase), " "
"ram_quota=", _donated_ram_quota);
"ram_quota=", _donated_ram_quota, ", cap_quota=", _donated_cap_quota);
}
@ -77,6 +78,7 @@ void Session_state::generate_session_request(Xml_generator &xml) const
xml.node("upgrade", [&] () {
xml.attribute("id", id_at_server->id().value);
xml.attribute("ram_quota", ram_upgrade.value);
xml.attribute("cap_quota", cap_upgrade.value);
});
break;
@ -88,6 +90,7 @@ void Session_state::generate_session_request(Xml_generator &xml) const
case INVALID_ARGS:
case INSUFFICIENT_RAM_QUOTA:
case INSUFFICIENT_CAP_QUOTA:
case AVAILABLE:
case CAP_HANDED_OUT:
case CLOSED:
@ -102,6 +105,7 @@ void Session_state::generate_client_side_info(Xml_generator &xml, Detail detail)
xml.attribute("label", _label);
xml.attribute("state", String<32>(Formatted_phase(phase)));
xml.attribute("ram", String<32>(_donated_ram_quota));
xml.attribute("caps", String<32>(_donated_cap_quota));
if (detail.args == Detail::ARGS)
xml.node("args", [&] () { xml.append_sanitized(_args.string()); });
@ -161,6 +165,7 @@ Session_state::Session_state(Service &service,
:
_service(service),
_donated_ram_quota(ram_quota_from_args(args.string())),
_donated_cap_quota(cap_quota_from_args(args.string())),
_id_at_client(*this, client_id_space, client_id),
_label(label), _args(args), _affinity(affinity)
{ }

View File

@ -229,21 +229,26 @@ Signal_context_capability Signal_receiver::manage(Signal_context *context)
/* register context at process-wide registry */
signal_context_registry()->insert(&context->_registry_le);
retry<Pd_session::Out_of_metadata>(
[&] () {
for (;;) {
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try {
/* use signal context as imprint */
context->_cap = env_deprecated()->pd_session()->alloc_context(_cap, (long)context);
},
[&] () {
size_t const quota = 1024*sizeof(long);
char buf[64];
snprintf(buf, sizeof(buf), "ram_quota=%ld", quota);
log("upgrading quota donation for PD session (", quota, " bytes)");
env_deprecated()->parent()->upgrade(Parent::Env::pd(), buf);
break;
}
);
catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
log("upgrading quota donation for PD session "
"(", ram_upgrade, " bytes, ", cap_upgrade, " caps)");
env_deprecated()->parent()->upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
}
return context->_cap;
}

View File

@ -319,7 +319,6 @@ void Slab::insert_sb(void *ptr)
bool Slab::alloc(size_t size, void **out_addr)
{
/* too large for us ? */
if (size > _slab_size) {
error("requested size ", size, " is larger then slab size ",

View File

@ -98,8 +98,10 @@ class Test_child_policy : public Child_policy
Binary_name binary_name() const override { return "test-rm_fault"; }
Ram_session &ref_ram() override { return _env.ram(); }
Pd_session &ref_pd() override { return _env.pd(); }
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void init(Ram_session &session, Ram_session_capability cap) override
@ -111,6 +113,9 @@ class Test_child_policy : public Child_policy
void init(Pd_session &session, Pd_session_capability cap) override
{
session.ref_account(_env.pd_session_cap());
_env.pd().transfer_quota(cap, Cap_quota{20});
Region_map_client address_space(session.address_space());
address_space.fault_handler(_fault_handler_sigh);
}

View File

@ -59,6 +59,7 @@ class Launchpad_child : public Genode::Child_policy,
Genode::Ram_session_capability _ref_ram_cap;
Genode::Ram_session_client _ref_ram { _ref_ram_cap };
Genode::Cap_quota const _cap_quota;
Genode::Ram_quota const _ram_quota;
Parent_services &_parent_services;
@ -97,6 +98,7 @@ class Launchpad_child : public Genode::Child_policy,
Genode::Allocator &alloc,
Genode::Session_label const &label,
Binary_name const &elf_name,
Genode::Cap_quota cap_quota,
Genode::Ram_quota ram_quota,
Parent_services &parent_services,
Child_services &child_services,
@ -105,6 +107,7 @@ class Launchpad_child : public Genode::Child_policy,
_name(label), _elf_name(elf_name),
_env(env), _alloc(alloc),
_ref_ram_cap(env.ram_session_cap()),
_cap_quota(Genode::Child::effective_quota(cap_quota)),
_ram_quota(Genode::Child::effective_quota(ram_quota)),
_parent_services(parent_services),
_child_services(child_services),
@ -133,9 +136,19 @@ class Launchpad_child : public Genode::Child_policy,
Binary_name binary_name() const override { return _elf_name; }
Genode::Pd_session &ref_pd() override { return _env.pd(); }
Genode::Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Genode::Ram_session &ref_ram() override { return _ref_ram; }
Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
void init(Genode::Pd_session &session,
Genode::Pd_session_capability cap) override
{
session.ref_account(_env.pd_session_cap());
_env.pd().transfer_quota(cap, _cap_quota);
}
void init(Genode::Ram_session &session,
Genode::Ram_session_capability cap) override
{
@ -200,7 +213,8 @@ class Launchpad_child : public Genode::Child_policy,
Child_service(_child_services, service_name,
_session_requester.id_space(),
_child.session_factory(), *this,
_child.ram_session_cap());
_child.ram_session_cap(),
_child.pd_session_cap());
}
};
@ -233,6 +247,7 @@ class Launchpad
public:
typedef Genode::Cap_quota Cap_quota;
typedef Genode::Ram_quota Ram_quota;
Launchpad(Genode::Env &env, unsigned long initial_quota);
@ -254,7 +269,7 @@ class Launchpad
virtual void quota(unsigned long quota) { }
virtual void add_launcher(Launchpad_child::Name const &binary_name,
unsigned long default_quota,
Cap_quota caps, unsigned long default_quota,
Genode::Dataspace_capability config_ds) { }
virtual void add_child(Launchpad_child::Name const &,
@ -266,7 +281,7 @@ class Launchpad
Genode::Allocator &) { }
Launchpad_child *start_child(Launchpad_child::Name const &binary_name,
Ram_quota quota,
Cap_quota cap_quota, Ram_quota ram_quota,
Genode::Dataspace_capability config_ds);
/**

View File

@ -38,14 +38,15 @@ class Launch_entry : public Scout::Parent_element, public Loadbar_listener
/**
* Constructor
*/
Launch_entry(Scout::Launcher::Name const &prg_name, unsigned long initial_quota,
Launch_entry(Scout::Launcher::Name const &prg_name,
unsigned long caps, unsigned long initial_quota,
unsigned long max_quota, Launchpad *launchpad,
Genode::Dataspace_capability config_ds)
:
_prg_name(prg_name),
_block(Scout::Block::RIGHT), _loadbar(this, &Scout::label_font),
_config(config_ds),
_launcher(prg_name, launchpad, initial_quota * 1024UL, &_config)
_launcher(prg_name, launchpad, caps, initial_quota * 1024UL, &_config)
{
_block.append_launchertext(_prg_name.string(), &Scout::link_style, &_launcher);

View File

@ -21,6 +21,7 @@ using namespace Scout;
void Launcher::launch()
{
_launchpad->start_child(prg_name(),
Launchpad::Cap_quota{caps()},
Launchpad::Ram_quota{quota()},
_config ? _config->config_ds()
: Genode::Dataspace_capability());

View File

@ -127,12 +127,12 @@ class Launchpad_window : public Scout::Scrollbar_listener,
_status_entry.refresh();
}
void add_launcher(Launchpad_child::Name const &name,
void add_launcher(Launchpad_child::Name const &name, Cap_quota caps,
unsigned long default_quota,
Genode::Dataspace_capability config_ds = Genode::Dataspace_capability()) override
{
Launch_entry<PT> *le;
le = new Launch_entry<PT>(name, default_quota / 1024,
le = new Launch_entry<PT>(name, caps.value, default_quota / 1024,
initial_quota() / 1024,
this, config_ds);
_launch_section.append(le);

View File

@ -149,7 +149,7 @@ Document *create_document()
b0->append_plaintext("that can be started by clicking on the application's name. Before starting an", &plain_style);
b0->append_plaintext("application, the user can define the amount of memory quota to donate to the", &plain_style);
b0->append_plaintext("new application by adjusting the red bar using the mouse.", &plain_style);
Launcher *l0 = new Launcher("launchpad", 1, 22*1024*1024);
Launcher *l0 = new Launcher("launchpad", 1, 100000, 22*1024*1024);
b0->append_launchertext("Start the launchpad by clicking on this link...", &link_style, l0);
chapter->append(b0);

View File

@ -227,12 +227,13 @@ class Scout::Launcher : public Anchor
private:
Name _prg_name;
int _active;
int _exec_once;
Launchpad *_launchpad;
unsigned long _quota;
Launcher_config *_config;
Name _prg_name;
int _active;
int _exec_once;
Launchpad *_launchpad;
unsigned long const _caps;
unsigned long _quota;
Launcher_config *_config;
public:
@ -242,22 +243,30 @@ class Scout::Launcher : public Anchor
* Constructors
*/
Launcher(Name const &prg_name, int exec_once = 0,
unsigned long quota = 0, Launcher_config *config = 0) :
unsigned long caps = 0, unsigned long quota = 0,
Launcher_config *config = 0)
:
_prg_name(prg_name), _active(1),
_exec_once(exec_once), _quota(quota), _config(config) { }
_exec_once(exec_once), _caps(caps), _quota(quota), _config(config)
{ }
Launcher(Name const &prg_name, Launchpad *launchpad,
unsigned long quota, Launcher_config *config = 0) :
_prg_name(prg_name), _launchpad(launchpad), _quota(quota),
_config(config) { }
unsigned long caps, unsigned long quota,
Launcher_config *config = 0)
:
_prg_name(prg_name), _launchpad(launchpad),
_caps(caps), _quota(quota), _config(config)
{ }
int active() { return _active; }
int active() const { return _active; }
Name prg_name() { return _prg_name; }
Name prg_name() const { return _prg_name; }
void quota(unsigned long quota) { _quota = quota; }
unsigned long quota() { return _quota; }
unsigned long quota() const { return _quota; }
unsigned long caps() const { return _caps; }
Launcher_config *config() { return _config; }

View File

@ -115,6 +115,7 @@ void Launcher::launch()
}
_launchpad_ptr->start_child(prg_name(),
Launchpad::Cap_quota{caps()},
Launchpad::Ram_quota{quota()},
config_registry.config(prg_name().string()));
}

View File

@ -106,6 +106,8 @@ void Launchpad::process_config(Genode::Xml_node config_node)
Number_of_bytes default_ram_quota =
node.attribute_value("ram_quota", Number_of_bytes(0));
Launchpad::Cap_quota const cap_quota { node.attribute_value("caps", 0UL) };
/*
* Obtain configuration for the child
*/
@ -137,13 +139,13 @@ void Launchpad::process_config(Genode::Xml_node config_node)
}
/* add launchpad entry */
add_launcher(*name, default_ram_quota, config_ds);
add_launcher(*name, cap_quota, default_ram_quota, config_ds);
});
}
Launchpad_child *Launchpad::start_child(Launchpad_child::Name const &binary_name,
Ram_quota ram_quota,
Cap_quota cap_quota, Ram_quota ram_quota,
Dataspace_capability config_ds)
{
log("starting ", binary_name, " with quota ", ram_quota);
@ -165,6 +167,17 @@ Launchpad_child *Launchpad::start_child(Launchpad_child::Name const &binary_name
ram_quota = Ram_quota { avail - preserved };
}
size_t const avail_caps = _env.pd().avail_caps().value;
if (cap_quota.value > avail_caps) {
warning("child's cap quota (", cap_quota.value, ") exceeds the "
"number of available capabilities (", avail_caps, ")");
size_t const preserved_caps = min(avail_caps, 25UL);
cap_quota = Cap_quota { avail_caps - preserved_caps };
}
size_t metadata_size = 4096*16 + sizeof(Launchpad_child);
if (metadata_size > ram_quota.value) {
@ -176,7 +189,8 @@ Launchpad_child *Launchpad::start_child(Launchpad_child::Name const &binary_name
try {
Launchpad_child *c = new (&_sliced_heap)
Launchpad_child(_env, _heap, unique_name, binary_name, ram_quota,
Launchpad_child(_env, _heap, unique_name, binary_name,
cap_quota, ram_quota,
_parent_services, _child_services, config_ds);
Lock::Guard lock_guard(_children_lock);

View File

@ -45,16 +45,20 @@ class Report_rom_slave : public Genode::Noncopyable
static Name _name() { return "report_rom"; }
static Genode::Ram_quota _quota() { return { 1024*1024 }; }
static Genode::Cap_quota _caps() { return { 25 }; }
public:
Policy(Genode::Rpc_entrypoint &ep,
Genode::Region_map &rm,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
const char *config)
:
Genode::Slave::Policy(_name(), _name(), *this, ep, rm,
ref_pd, ref_pd_cap, _caps(),
ref_ram, ref_ram_cap, _quota())
{
if (config)
@ -76,14 +80,15 @@ class Report_rom_slave : public Genode::Noncopyable
* \param ram RAM session used to allocate the configuration
* dataspace
*/
Report_rom_slave(Genode::Pd_session &pd,
Genode::Region_map &rm,
Report_rom_slave(Genode::Region_map &rm,
Genode::Pd_session &pd,
Genode::Pd_session_capability pd_cap,
Genode::Ram_session &ram,
Genode::Ram_session_capability ram_cap,
char const *config)
:
_ep(&pd, _ep_stack_size, "report_rom"),
_policy(_ep, rm, ram, ram_cap, config),
_policy(_ep, rm, pd, pd_cap, ram, ram_cap, config),
_child(rm, _ep, _policy)
{ }

View File

@ -196,11 +196,10 @@ class Launcher::Fading_dialog : private Input_event_handler
_fader_slave_ep(&env.pd(), _fader_slave_ep_stack_size, "nit_fader"),
_nitpicker_connection(env, "menu"),
_nitpicker_session(env, _nitpicker_connection, env.ep(), _fader_slave_ep, *this),
_nit_fader_slave(_fader_slave_ep, env.rm(),
env.ram(), env.ram_session_cap(),
_nitpicker_service),
_nit_fader_slave(_fader_slave_ep, env.rm(), env.pd(), env.pd_session_cap(),
env.ram(), env.ram_session_cap(), _nitpicker_service),
_nit_fader_connection(env.rm(), _nit_fader_slave.policy(), Slave::Args("label=menu")),
_menu_view_slave(env.pd(), env.rm(),
_menu_view_slave(env.rm(), env.pd(), env.pd_session_cap(),
env.ram(), env.ram_session_cap(),
_nit_fader_connection,
_dialog_rom, _hover_report, initial_position)

View File

@ -43,7 +43,7 @@ struct Launcher::Main
"</config>";
Report_rom_slave _report_rom_slave {
_env.pd(), _env.rm(), _env.ram(), _env.ram_session_cap(),
_env.rm(), _env.pd(), _env.pd_session_cap(), _env.ram(), _env.ram_session_cap(),
_report_rom_config };
/**

View File

@ -75,11 +75,14 @@ class Launcher::Menu_view_slave
static Name _name() { return "menu_view"; }
static Genode::Ram_quota _quota() { return { 6*1024*1024 }; }
static Genode::Cap_quota _caps() { return { 25 }; }
public:
Policy(Genode::Rpc_entrypoint &ep,
Genode::Region_map &rm,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Capability<Nitpicker::Session> nitpicker_session,
@ -88,6 +91,7 @@ class Launcher::Menu_view_slave
Position position)
:
Genode::Slave::Policy(_name(), _name(), *this, ep, rm,
ref_pd, ref_pd_cap, _caps(),
ref_ram, ref_ram_cap, _quota()),
_nitpicker(rm, nitpicker_session),
_dialog_rom(dialog_rom_session),
@ -127,8 +131,9 @@ class Launcher::Menu_view_slave
/**
* Constructor
*/
Menu_view_slave(Genode::Pd_session &pd,
Genode::Region_map &rm,
Menu_view_slave(Genode::Region_map &rm,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Capability<Nitpicker::Session> nitpicker_session,
@ -136,8 +141,8 @@ class Launcher::Menu_view_slave
Capability<Report::Session> hover_report_session,
Position initial_position)
:
_ep(&pd, _ep_stack_size, "nit_fader"),
_policy(_ep, rm, ref_ram, ref_ram_cap,
_ep(&ref_pd, _ep_stack_size, "nit_fader"),
_policy(_ep, rm, ref_pd, ref_pd_cap, ref_ram, ref_ram_cap,
nitpicker_session, dialog_rom_session,
hover_report_session, initial_position),
_child(rm, _ep, _policy)

View File

@ -47,16 +47,20 @@ class Launcher::Nit_fader_slave
static Name _name() { return "nit_fader"; }
static Genode::Ram_quota _quota() { return { 2*1024*1024 }; }
static Genode::Cap_quota _caps() { return { 25 }; }
public:
Policy(Rpc_entrypoint &ep,
Region_map &rm,
Pd_session &ref_pd,
Pd_session_capability ref_pd_cap,
Ram_session &ref_ram,
Ram_session_capability ref_ram_cap,
Genode::Service &nitpicker_service)
:
Genode::Slave::Policy(_name(), _name(), *this, ep, rm,
ref_pd, ref_pd_cap, _caps(),
ref_ram, ref_ram_cap, _quota()),
_nitpicker_service(nitpicker_service)
{
@ -95,11 +99,13 @@ class Launcher::Nit_fader_slave
*/
Nit_fader_slave(Rpc_entrypoint &ep,
Genode::Region_map &rm,
Pd_session &ref_pd,
Pd_session_capability ref_pd_cap,
Ram_session &ref_ram,
Ram_session_capability ref_ram_cap,
Genode::Service &nitpicker_service)
:
_policy(ep, rm, ref_ram, ref_ram_cap, nitpicker_service),
_policy(ep, rm, ref_pd, ref_pd_cap, ref_ram, ref_ram_cap, nitpicker_service),
_child(rm, ep, _policy)
{
visible(false);

View File

@ -147,6 +147,18 @@ class Launcher::Subsystem_manager
return Ram_config { quantum, limit };
}
static Cap_quota _caps_config(Xml_node subsystem)
{
Cap_quota const caps { subsystem.attribute_value("caps", 0UL) };
if (caps.value)
return caps;
Genode::error("missing 'caps' attribute for ",
subsystem.attribute_value("name", Label()));
throw Invalid_config();
}
public:
Subsystem_manager(Genode::Env & env,
@ -166,8 +178,7 @@ class Launcher::Subsystem_manager
{
Child::Binary_name const binary_name = _binary_name(subsystem);
Label const label = string_attribute(subsystem, "name",
Label(""));
Label const label = string_attribute(subsystem, "name", Label(""));
Ram_config const ram_config = _ram_config(subsystem);
@ -177,9 +188,11 @@ class Launcher::Subsystem_manager
Child *child = new (_heap)
Child(_ram, _heap, label, binary_name.string(),
_env.pd(),
_env.pd_session_cap(),
_env.ram(),
_env.ram_session_cap(),
_env.rm(),
_caps_config(subsystem),
ram_config.quantum, ram_config.limit,
_yield_broadcast_handler,
_exited_child_sig_cap);

View File

@ -76,6 +76,8 @@ C++ class in 'include/hello_session/hello_session.h'
!{
! static const char *service_name() { return "Hello"; }
!
! enum { CAP_QUOTA = 2 };
!
! virtual void say_hello() = 0;
! virtual int add(int a, int b) = 0;
!
@ -91,7 +93,12 @@ across component boundaries.
Furthermore, we use the interface to specify the name of the service by
providing the 'service_name' method. This method will later be used by both
the server for announcing the service at its parent and the client for
requesting the creation of a "Hello" session.
requesting the creation of a "Hello" session. The 'CAP_QUOTA' definition
specifies the amount of capabilities required to establish the session.
The specified amount is transferred from the client to the server at session
creation time. For the "Hello" session, two capabilities are required, namely
a dataspace capability for the server-side memory occupied by the session
object and the actual session capability that refers to the RPC interface.
The 'GENODE_RPC' macro is used to declare an RPC function. Its first argument
is a type name that is used to refer to the RPC function. The type name can
@ -251,6 +258,7 @@ entry to init's 'config' file, which is located at 'build/bin/config'.
! <default-route>
! <any-service> <parent/> <any-child/> </any-service>
! </default-route>
! <default caps="50"/>
! <start name="hello_server">
! <resource name="RAM" quantum="1M"/>
! <provides><service name="Hello"/></provides>
@ -345,7 +353,7 @@ of the session interface. For our case, the file
! :
! /* create session */
! Genode::Connection<Hello::Session>(env, session(env.parent(),
! "ram_quota=4K")),
! "ram_quota=4K, cap_quota=4")),
! /* initialize RPC interface */
! Session_client(cap()) { }
!};
@ -413,6 +421,7 @@ at the _run/hello.run_ and look as follows:
! <default-route>
! <any-service> <parent/> <any-child/> </any-service>
! </default-route>
! <default caps="50"/>
! <start name="hello_server">
! <resource name="RAM" quantum="1M"/>
! <provides> <service name="Hello"/> </provides>

View File

@ -43,6 +43,7 @@ run_genode_until {child ".*" exited with exit value 123.*\n} 10
grep_output {^\[init }
unify_output {\[init \-\> test\-ldso\] upgrading quota donation for .* \([0-9]+ bytes\)} ""
unify_output {ram_quota=[0-9]+} "ram_quota=UNIFIED"
unify_output {cap_quota=[0-9]+} "cap_quota=UNIFIED"
trim_lines
compare_output_to {
@ -83,7 +84,7 @@ compare_output_to {
[init -> test-ldso] Catch exceptions in program
[init -> test-ldso] ---------------------------
[init -> test-ldso] exception in remote procedure call:
[init -> test-ldso] Error: ROM-session creation failed (ram_quota=UNIFIED, label="unknown_file")
[init -> test-ldso] Error: ROM-session creation failed (ram_quota=UNIFIED, cap_quota=UNIFIED, label="unknown_file")
[init -> test-ldso] Error: Could not open ROM session for "unknown_file"
[init -> test-ldso] caught
[init -> test-ldso] exception in program: caught

View File

@ -43,6 +43,7 @@ class Cli_monitor::Child_base : public Genode::Child_policy
class Quota_exceeded : public Genode::Exception { };
typedef Genode::size_t size_t;
typedef Genode::Cap_quota Cap_quota;
typedef Genode::Registered<Genode::Parent_service> Parent_service;
@ -55,9 +56,14 @@ class Cli_monitor::Child_base : public Genode::Child_policy
Genode::Session_label const _label;
Binary_name const _binary_name;
Genode::Pd_session_capability _ref_pd_cap;
Genode::Pd_session &_ref_pd;
Genode::Ram_session_capability _ref_ram_cap;
Genode::Ram_session &_ref_ram;
Cap_quota _cap_quota;
size_t _ram_quota;
size_t _ram_limit;
@ -110,10 +116,12 @@ class Cli_monitor::Child_base : public Genode::Child_policy
Genode::Allocator &alloc,
Name const &label,
Binary_name const &binary_name,
Genode::Pd_session &pd_session,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Genode::Region_map &local_rm,
Cap_quota cap_quota,
Genode::size_t ram_quota,
Genode::size_t ram_limit,
Genode::Signal_context_capability yield_response_sig_cap,
@ -121,9 +129,10 @@ class Cli_monitor::Child_base : public Genode::Child_policy
:
_ram(ram), _alloc(alloc),
_label(label), _binary_name(binary_name),
_ref_pd_cap (ref_pd_cap), _ref_pd (ref_pd),
_ref_ram_cap(ref_ram_cap), _ref_ram(ref_ram),
_ram_quota(ram_quota), _ram_limit(ram_limit),
_entrypoint(&pd_session, ENTRYPOINT_STACK_SIZE, _label.string(), false),
_cap_quota(cap_quota), _ram_quota(ram_quota), _ram_limit(ram_limit),
_entrypoint(&ref_pd, ENTRYPOINT_STACK_SIZE, _label.string(), false),
_config_policy(local_rm, "config", _entrypoint, &ref_ram),
_yield_response_sigh_cap(yield_response_sig_cap),
_exit_sig_cap(exit_sig_cap),
@ -275,9 +284,18 @@ class Cli_monitor::Child_base : public Genode::Child_policy
Name name() const override { return _label; }
Binary_name binary_name() const override { return _binary_name; }
Genode::Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; }
Genode::Pd_session &ref_pd() override { return _ref_pd; }
Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
Genode::Ram_session &ref_ram() override { return _ref_ram; }
void init(Genode::Pd_session &session, Genode::Pd_session_capability cap) override
{
session.ref_account(_ref_pd_cap);
_ref_pd.transfer_quota(cap, _cap_quota);
}
void init(Genode::Ram_session &session, Genode::Ram_session_capability cap) override
{
session.ref_account(_ref_ram_cap);

View File

@ -34,6 +34,9 @@ struct Loader::Session_client : Genode::Rpc_client<Session>
void commit_rom_module(Name const &name) override {
call<Rpc_commit_rom_module>(name); }
void cap_quota(Cap_quota limit) override {
call<Rpc_cap_quota>(limit); }
void ram_quota(Ram_quota quantum) override {
call<Rpc_ram_quota>(quantum); }

View File

@ -26,11 +26,12 @@ struct Loader::Connection : Genode::Connection<Session>, Session_client
/**
* Constructor
*/
Connection(Genode::Env &env, Ram_quota ram_quota)
Connection(Genode::Env &env, Ram_quota ram_quota, Cap_quota cap_quota)
:
Genode::Connection<Session>(env, session(env.parent(),
"ram_quota=%ld",
ram_quota.value)),
"ram_quota=%ld, cap_quota=%ld",
ram_quota.value,
CAP_QUOTA + cap_quota.value)),
Session_client(cap())
{ }

View File

@ -19,6 +19,7 @@
#include <base/rpc_args.h>
#include <dataspace/capability.h>
#include <nitpicker_session/client.h>
#include <pd_session/pd_session.h>
#include <base/signal.h>
#include <session/session.h>
#include <util/geometry.h>
@ -32,6 +33,7 @@ namespace Loader {
using Genode::Dataspace_capability;
using Genode::Signal_context_capability;
using Genode::Ram_quota;
using Genode::Cap_quota;
struct Session;
}
@ -90,6 +92,11 @@ struct Loader::Session : Genode::Session
*/
virtual void commit_rom_module(Name const &name) = 0;
/**
* Define capability quota assigned to the subsystem
*/
virtual void cap_quota(Cap_quota) = 0;
/**
* Define RAM quota assigned to the subsystem
*
@ -167,6 +174,7 @@ struct Loader::Session : Genode::Session
GENODE_RPC_THROW(Rpc_commit_rom_module, void, commit_rom_module,
GENODE_TYPE_LIST(Rom_module_does_not_exist),
Name const &);
GENODE_RPC(Rpc_cap_quota, void, cap_quota, Cap_quota);
GENODE_RPC(Rpc_ram_quota, void, ram_quota, Ram_quota);
GENODE_RPC(Rpc_constrain_geometry, void, constrain_geometry, Area);
GENODE_RPC(Rpc_parent_view, void, parent_view, Nitpicker::View_capability);
@ -182,7 +190,7 @@ struct Loader::Session : Genode::Session
GENODE_TYPE_LIST(View_does_not_exist));
GENODE_RPC_INTERFACE(Rpc_alloc_rom_module, Rpc_commit_rom_module,
Rpc_ram_quota, Rpc_constrain_geometry,
Rpc_cap_quota, Rpc_ram_quota, Rpc_constrain_geometry,
Rpc_parent_view, Rpc_view_ready_sigh, Rpc_fault_sigh,
Rpc_start, Rpc_view_geometry, Rpc_view_size);
};

View File

@ -44,7 +44,9 @@ class Genode::Attached_mmio : public Attached_io_mem_dataspace,
*
* \throw Parent::Service_denied
* \throw Insufficient_ram_quota
* \throw Parent::Unavailable
* \throw Insufficient_cap_quota
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Rm_session::Attach_failed
*/
Attached_mmio(Env &env, addr_t base, size_t size,

View File

@ -71,6 +71,9 @@ class Genode::Child_policy_dynamic_rom_file : public Rpc_object<Rom_session>,
* \param ram RAM session used to allocate the backing store
* for buffering ROM module data
*
* \throw Out_of_ram
* \throw Out_of_caps
*
* If 'ram' is 0, the child policy is ineffective.
*/
Child_policy_dynamic_rom_file(Region_map &rm,
@ -195,6 +198,7 @@ class Genode::Child_policy_dynamic_rom_file : public Rpc_object<Rom_session>,
case Session_state::INVALID_ARGS:
case Session_state::INSUFFICIENT_RAM_QUOTA:
case Session_state::INSUFFICIENT_CAP_QUOTA:
case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED:

View File

@ -98,6 +98,21 @@ class Genode::Dynamic_rom_session : public Rpc_object<Rom_session>
*/
return true;
}
catch (Out_of_caps) {
error("ouf of child cap quota while delivering dynamic ROM");
/*
* XXX We may try to generate a resource request on
* behalf of the child.
*/
/*
* Don't let the child try again to obtain a dataspace
* by pretending that the ROM module is up-to-date.
*/
return true;
}
try {
_content_producer.produce_content(_ds->local_addr<char>(),
@ -166,6 +181,9 @@ class Genode::Dynamic_rom_session : public Rpc_object<Rom_session>
if (!_ds.constructed())
_unsynchronized_update();
if (!_ds.constructed())
return Rom_dataspace_capability();
Dataspace_capability ds_cap = _ds->cap();
return static_cap_cast<Rom_dataspace>(ds_cap);

View File

@ -52,16 +52,19 @@ class Genode::Slave::Policy : public Child_policy
private:
Label const _label;
Binary_name const _binary_name;
Label const _label;
Binary_name const _binary_name;
Pd_session &_ref_pd;
Pd_session_capability _ref_pd_cap;
Ram_session &_ref_ram;
Ram_session_capability _ref_ram_cap;
Genode::Parent_service _binary_service;
Ram_quota const _ram_quota;
Parent_services &_parent_services;
Rpc_entrypoint &_ep;
Child_policy_dynamic_rom_file _config_policy;
Session_requester _session_requester;
Genode::Parent_service _binary_service;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota;
Parent_services &_parent_services;
Rpc_entrypoint &_ep;
Child_policy_dynamic_rom_file _config_policy;
Session_requester _session_requester;
public:
@ -83,14 +86,18 @@ class Genode::Slave::Policy : public Child_policy
Parent_services &parent_services,
Rpc_entrypoint &ep,
Region_map &rm,
Pd_session &ref_pd,
Pd_session_capability ref_pd_cap,
Cap_quota cap_quota,
Ram_session &ref_ram,
Ram_session_capability ref_ram_cap,
Ram_quota ram_quota)
:
_label(label), _binary_name(binary_name),
_ref_pd(ref_pd), _ref_pd_cap(ref_pd_cap),
_ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap),
_binary_service(Rom_session::service_name()),
_ram_quota(ram_quota),
_cap_quota(cap_quota), _ram_quota(ram_quota),
_parent_services(parent_services), _ep(ep),
_config_policy(rm, "config", _ep, &_ref_ram),
_session_requester(ep, _ref_ram, rm)
@ -127,9 +134,18 @@ class Genode::Slave::Policy : public Child_policy
Binary_name binary_name() const override { return _binary_name; }
Pd_session &ref_pd() override { return _ref_pd; }
Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; }
Ram_session &ref_ram() override { return _ref_ram; }
Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
void init(Pd_session &session, Pd_session_capability cap) override
{
session.ref_account(_ref_pd_cap);
_ref_pd.transfer_quota(cap, _cap_quota);
}
void init(Ram_session &session, Ram_session_capability cap) override
{
session.ref_account(_ref_ram_cap);
@ -217,6 +233,7 @@ class Genode::Slave::Connection_base
case Session_state::INVALID_ARGS:
case Session_state::INSUFFICIENT_RAM_QUOTA:
case Session_state::INSUFFICIENT_CAP_QUOTA:
case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED:
@ -256,6 +273,22 @@ class Genode::Slave::Connection_base
return _policy.ref_ram_cap();
}
/**
* Service ('Cap_transfer::Account') interface
*/
void transfer(Pd_session_capability to, Cap_quota amount) override
{
if (to.valid()) _policy.ref_pd().transfer_quota(to, amount);
}
/**
* Service ('Cap_transfer::Account') interface
*/
Pd_session_capability cap(Cap_quota) const override
{
return _policy.ref_pd_cap();
}
} _service;
Local_connection<CONNECTION> _connection;

View File

@ -71,7 +71,7 @@ compare_output_to {
[init -> test-report_rom] Reporter: start reporting (while the ROM client still listens)
[init -> test-report_rom] ROM client: wait for update notification
[init -> test-report_rom] ROM client: try to open the same report again
[init -> test-report_rom] Error: Report-session creation failed (label="brightness", ram_quota=14336, buffer_size=4096)
[init -> test-report_rom] Error: Report-session creation failed (label="brightness", ram_quota=14336, cap_quota=3, buffer_size=4096)
[init -> test-report_rom] ROM client: catched Parent::Service_denied - OK
[init -> test-report_rom] --- test-report_rom finished ---
}

View File

@ -31,10 +31,12 @@ struct Cli_monitor::Child : Child_base, List<Child>::Element
Genode::Allocator &alloc,
Name const &label,
Binary_name const &binary,
Genode::Pd_session &pd_session,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Genode::Region_map &local_rm,
Cap_quota cap_quota,
Genode::size_t ram_quota,
Genode::size_t ram_limit,
Genode::Signal_context_capability yield_response_sig_cap,
@ -44,10 +46,12 @@ struct Cli_monitor::Child : Child_base, List<Child>::Element
alloc,
label,
binary,
pd_session,
ref_pd,
ref_pd_cap,
ref_ram,
ref_ram_cap,
local_rm,
cap_quota,
ram_quota,
ram_limit,
yield_response_sig_cap,

View File

@ -172,7 +172,8 @@ struct Cli_monitor::Main
/* initialize generic commands */
Registered<Help_command> _help_command { _commands };
Registered<Kill_command> _kill_command { _commands, _children, _heap };
Registered<Start_command> _start_command { _commands, _ram, _heap, _env.pd(),
Registered<Start_command> _start_command { _commands, _ram, _heap,
_env.pd(), _env.pd_session_cap(),
_env.ram(), _env.ram_session_cap(),
_env.rm(), _children,
_subsystem_config_registry,

View File

@ -34,7 +34,8 @@ class Cli_monitor::Start_command : public Command
Ram &_ram;
Genode::Allocator &_alloc;
Child_registry &_children;
Genode::Pd_session &_pd;
Genode::Pd_session &_ref_pd;
Genode::Pd_session_capability _ref_pd_cap;
Genode::Ram_session &_ref_ram;
Genode::Ram_session_capability _ref_ram_cap;
Genode::Region_map &_local_rm;
@ -50,6 +51,7 @@ class Cli_monitor::Start_command : public Command
size_t count = 1;
Genode::Number_of_bytes ram = 0;
Genode::Number_of_bytes ram_limit = 0;
size_t caps = subsystem_node.attribute_value("caps", 0UL);
/* read default RAM quota from config */
try {
@ -113,8 +115,10 @@ class Cli_monitor::Start_command : public Command
Child *child = 0;
try {
child = new (_alloc)
Child(_ram, _alloc, label, binary_name, _pd, _ref_ram,
_ref_ram_cap, _local_rm, ram, ram_limit,
Child(_ram, _alloc, label, binary_name,
_ref_pd, _ref_pd_cap, _ref_ram,
_ref_ram_cap, _local_rm,
Genode::Cap_quota{caps}, ram, ram_limit,
_yield_response_sigh_cap, _exit_sig_cap);
}
catch (Genode::Parent::Service_denied) {
@ -160,7 +164,8 @@ class Cli_monitor::Start_command : public Command
Start_command(Ram &ram,
Genode::Allocator &alloc,
Genode::Pd_session &pd,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Genode::Region_map &local_rm,
@ -170,8 +175,10 @@ class Cli_monitor::Start_command : public Command
Signal_context_capability exit_sig_cap)
:
Command("start", "create new subsystem"),
_ram(ram), _alloc(alloc), _children(children), _pd(pd),
_ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap), _local_rm(local_rm),
_ram(ram), _alloc(alloc), _children(children),
_ref_pd(ref_pd), _ref_pd_cap(ref_pd_cap),
_ref_ram(ref_ram), _ref_ram_cap(ref_ram_cap),
_local_rm(local_rm),
_subsystem_configs(subsustem_configs),
_yield_response_sigh_cap(yield_response_sigh_cap),
_exit_sig_cap(exit_sig_cap)

View File

@ -33,12 +33,16 @@ class Platform::Device_pd_policy
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep,
Genode::Region_map &local_rm,
Genode::Pd_session &pd_ref,
Genode::Pd_session_capability pd_ref_cap,
Genode::Cap_quota cap_quota,
Genode::Ram_session &ram_ref,
Genode::Ram_session_capability ram_ref_cap,
Genode::Ram_quota ram_quota,
Genode::Session_label const &label)
:
Genode::Slave::Policy(label, "device_pd", *this, slave_ep, local_rm,
pd_ref, pd_ref_cap, cap_quota,
ram_ref, ram_ref_cap, ram_quota)
{ }
};

View File

@ -202,6 +202,8 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
Genode::Attached_rom_dataspace &_config;
Genode::Ram_session_guard _env_ram;
Genode::Ram_session_capability _env_ram_cap;
Genode::Pd_session &_env_pd;
Genode::Pd_session_capability _env_pd_cap;
Genode::Region_map &_local_rm;
Genode::Heap _md_alloc;
Genode::Session_label const _label;
@ -254,6 +256,13 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
enum { OVERHEAD = 4096 };
try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{OVERHEAD}); }
catch (...) { throw Genode::Insufficient_ram_quota(); }
/*
* XXX instead of eagerly upgrading the RAM session, upgrade it
* on demand, paid by the client's cap session quota.
*/
using namespace Genode;
_ram.upgrade(Session::Resources { Ram_quota{0}, Cap_quota{10} });
}
bool const _ram_initialized = (_init_ram(), true);
@ -291,7 +300,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
private:
enum { RAM_QUOTA = 190 * 4096 };
enum { CAP_QUOTA = 60, RAM_QUOTA = 190 * 4096 };
Quota_reservation const _reservation;
Device_pd_policy _policy;
@ -319,11 +328,15 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
Genode::Rpc_entrypoint &ep,
Genode::Ram_session_guard &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Genode::Pd_session &ref_pd,
Genode::Pd_session_capability ref_pd_cap,
Genode::Session_label const &label)
try :
_reservation(ref_ram, RAM_QUOTA),
_policy(ep, local_rm,
ref_ram, ref_ram_cap, Genode::Ram_quota{RAM_QUOTA}, label),
ref_pd, ref_pd_cap, Genode::Cap_quota{CAP_QUOTA},
ref_ram, ref_ram_cap, Genode::Ram_quota{RAM_QUOTA},
label),
_child(local_rm, ep, _policy),
_connection(_policy, Genode::Slave::Args())
{ }
@ -331,8 +344,18 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
catch (Out_of_metadata) { throw; }
/* thrown by 'Device_pd_policy' or 'Child' */
catch (Genode::Out_of_ram) { throw Out_of_metadata(); }
/* throw by 'Slave::Connection' */
catch (Genode::Out_of_caps) {
/* XXX reflect 'Out_of_caps' exception to client */
Genode::error("Out_of_caps during device-pd creation");
throw Out_of_metadata();
}
/* thrown by 'Slave::Connection' */
catch (Genode::Insufficient_ram_quota) { throw Out_of_metadata(); }
/* thrown by 'Slave::Connection' */
catch (Genode::Insufficient_cap_quota) {
Genode::error("Insufficient_cap_quota during device-pd creation");
throw Out_of_metadata();
}
Device_pd_client &session() { return _connection; }
@ -368,13 +391,19 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
try {
_device_pd = new (_md_alloc)
Device_pd(_local_rm, _device_pd_ep, _env_ram,
_env_ram_cap, _label);
Device_pd(_local_rm, _device_pd_ep, _env_ram, _env_ram_cap,
_env_pd, _env_pd_cap, _label);
}
/* thrown by '_md_alloc' */
catch (Genode::Out_of_ram) { throw Out_of_metadata(); }
catch (Genode::Out_of_caps) {
/* XXX reflect exception to client */
Genode::error("Out_of_caps during Device_pd construction");
throw Out_of_metadata();
}
/* thrown by 'Device_pd' */
catch (Out_of_metadata) { throw; }
@ -609,6 +638,8 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
_env_ram(env.ram(), env.ram_session_cap(),
Genode::Arg_string::find_arg(args, "ram_quota").long_value(0)),
_env_ram_cap(env.ram_session_cap()),
_env_pd(env.pd()),
_env_pd_cap(env.pd_session_cap()),
_local_rm(env.rm()),
_md_alloc(_env_ram, env.rm()),
_label(Genode::label_from_args(args)),
@ -846,6 +877,10 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
return _env.ep().rpc_ep().manage(dev);
} catch (Genode::Allocator::Out_of_memory) {
throw Out_of_metadata();
} catch (Genode::Out_of_caps) {
/* XXX reflect exception to client */
Genode::error("Out_of_caps during Device_component construction");
throw Out_of_metadata();
}
};
return _env.ep().rpc_ep().apply(prev_device, lambda);
@ -945,24 +980,35 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
/* transfer ram quota to session specific ram session */
try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{size}); }
catch (Genode::Out_of_ram) { throw Out_of_metadata(); }
catch (...) { throw Fatal(); }
catch (Genode::Out_of_caps) {
Genode::error("Out_of_caps during alloc_dma_buffer (transfer_quota)");
throw Fatal();
}
catch (...) { }
enum { UPGRADE_QUOTA = 4096 };
/* allocate dataspace from session specific ram session */
Ram_capability ram_cap = Genode::retry<Genode::Out_of_ram>(
[&] () {
try {
return _ram.alloc(size, Genode::UNCACHED);
}
catch (Genode::Out_of_ram) {
Ram_capability ram = Genode::retry<Genode::Out_of_ram>(
[&] () {
try { return _ram.alloc(size, Genode::UNCACHED); }
catch (Genode::Out_of_caps) {
Genode::error("Out_of_caps during alloc_dma_buffer (alloc)");
throw Fatal();
}
},
[&] () {
if (!_env_ram.withdraw(UPGRADE_QUOTA)) {
_rollback(size);
}
if (!_env_ram.withdraw(UPGRADE_QUOTA))
_rollback(size);
throw;
}
/* upgrade meta-data quota */
_ram.upgrade_ram(UPGRADE_QUOTA);
});
return ram;
},
[&] () {
/*
@ -973,7 +1019,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
* UPGRADE_QUOTA steps.
*/
try { _env_ram.transfer_quota(_ram, Genode::Ram_quota{UPGRADE_QUOTA}); }
catch (...) { throw Genode::Out_of_ram(); }
catch (Genode::Out_of_ram) { throw Out_of_metadata(); }
});
if (!ram_cap.valid())

View File

@ -289,9 +289,20 @@ void Init::Child::report_state(Xml_generator &xml, Report_detail const &detail)
generate_ram_info(xml, _child.ram());
if (_requested_resources.constructed())
xml.attribute("requested", String<32> {
Number_of_bytes(_requested_resources->ram.value) });
if (_requested_resources.constructed() && _requested_resources->ram.value)
xml.attribute("requested", String<32>(_requested_resources->ram));
});
}
if (detail.child_caps() && _child.pd_session_cap().valid()) {
xml.node("caps", [&] () {
xml.attribute("assigned", String<32>(_resources.assigned_cap_quota));
generate_caps_info(xml, _child.pd());
if (_requested_resources.constructed() && _requested_resources->caps.value)
xml.attribute("requested", String<32>(_requested_resources->caps));
});
}
@ -320,6 +331,18 @@ void Init::Child::report_state(Xml_generator &xml, Report_detail const &detail)
}
void Init::Child::init(Pd_session &session, Pd_session_capability cap)
{
session.ref_account(_env.pd_session_cap());
Cap_quota const quota { _resources.effective_cap_quota().value };
try { _env.pd().transfer_quota(cap, quota); }
catch (Out_of_caps) {
error(name(), ": unable to initialize cap quota of PD"); }
}
void Init::Child::init(Ram_session &session, Ram_session_capability cap)
{
session.ref_account(_env.ram_session_cap());
@ -613,8 +636,10 @@ Init::Child::Child(Env &env,
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,
Prio_levels prio_levels,
Affinity::Space const &affinity_space,
@ -628,8 +653,10 @@ Init::Child::Child(Env &env,
_default_route_accessor(default_route_accessor),
_ram_limit_accessor(ram_limit_accessor),
_name_registry(name_registry),
_resources(_resources_from_start_node(start_node, prio_levels, affinity_space)),
_resources_checked((_check_ram_constraints(ram_limit), true)),
_resources(_resources_from_start_node(start_node, prio_levels, affinity_space,
default_caps_accessor.default_caps(), cap_limit)),
_resources_checked((_check_ram_constraints(ram_limit),
_check_cap_constraints(cap_limit), true)),
_parent_services(parent_services),
_child_services(child_services),
_session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm())
@ -637,6 +664,7 @@ Init::Child::Child(Env &env,
if (_verbose.enabled()) {
log("child \"", _unique_name, "\"");
log(" RAM quota: ", _resources.effective_ram_quota());
log(" cap quota: ", _resources.effective_cap_quota());
log(" ELF binary: ", _binary_name);
log(" priority: ", _resources.priority);
}

View File

@ -48,6 +48,8 @@ class Init::Child : Child_policy, Routed_service::Wakeup
struct Default_route_accessor { virtual Xml_node default_route() = 0; };
struct Default_caps_accessor { virtual Cap_quota default_caps() = 0; };
struct Ram_limit_accessor { virtual Ram_quota ram_limit() = 0; };
private:
@ -124,6 +126,7 @@ class Init::Child : Child_policy, Routed_service::Wakeup
long priority;
Affinity affinity;
Ram_quota assigned_ram_quota;
Cap_quota assigned_cap_quota;
size_t cpu_quota_pc;
bool constrain_phys;
@ -131,15 +134,39 @@ class Init::Child : Child_policy, Routed_service::Wakeup
{
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};
}
};
Resources _resources_from_start_node(Xml_node start_node, Prio_levels prio_levels,
Affinity::Space const &affinity_space)
Affinity::Space const &affinity_space,
Cap_quota default_cap_quota, Cap_quota cap_limit)
{
size_t cpu_quota_pc = 0;
bool constrain_phys = false;
Number_of_bytes ram_bytes = 0;
size_t caps = start_node.attribute_value("caps", default_cap_quota.value);
start_node.for_each_sub_node("resource", [&] (Xml_node rsc) {
typedef String<8> Name;
@ -153,6 +180,10 @@ class Init::Child : Child_policy, Routed_service::Wakeup
if (name == "CPU") {
cpu_quota_pc = rsc.attribute_value("quantum", 0UL);
}
if (name == "CAP") {
caps = rsc.attribute_value("quantum", 0UL);
}
});
return Resources { log2(prio_levels.value),
@ -160,6 +191,7 @@ class Init::Child : Child_policy, Routed_service::Wakeup
Affinity(affinity_space,
affinity_location_from_xml(affinity_space, start_node)),
Ram_quota { ram_bytes },
Cap_quota { caps },
cpu_quota_pc,
constrain_phys };
}
@ -171,6 +203,9 @@ class Init::Child : Child_policy, Routed_service::Wakeup
if (_resources.effective_ram_quota().value == 0)
warning(name(), ": no valid RAM quota defined");
if (_resources.effective_cap_quota().value == 0)
warning(name(), ": no valid cap quota defined");
/*
* If the configured RAM quota exceeds our own quota, we donate
* all remaining quota to the child.
@ -183,6 +218,20 @@ class Init::Child : Child_policy, Routed_service::Wakeup
}
}
void _check_cap_constraints(Cap_quota cap_limit)
{
if (_resources.assigned_cap_quota.value == 0)
warning(name(), ": no valid cap quota defined");
if (_resources.assigned_cap_quota.value > cap_limit.value) {
warning(name(), ": assigned caps (", _resources.assigned_cap_quota.value, ") "
"exceed available caps (", cap_limit.value, ")");
_resources.assigned_cap_quota.value = cap_limit.value;
}
}
bool const _resources_checked;
Registry<Parent_service> &_parent_services;
@ -255,10 +304,12 @@ class Init::Child : Child_policy, Routed_service::Wakeup
struct Requested_resources
{
Ram_quota const ram;
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()))
{ }
};
@ -266,16 +317,20 @@ class Init::Child : Child_policy, Routed_service::Wakeup
Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
struct Ram_accessor : Routed_service::Ram_accessor
struct Ram_pd_accessor : Routed_service::Ram_accessor,
Routed_service::Pd_accessor
{
Genode::Child &_child;
Ram_accessor(Genode::Child &child) : _child(child) { }
Ram_pd_accessor(Genode::Child &child) : _child(child) { }
Ram_session &ram() override { return _child.ram(); }
Ram_session_capability ram_cap() const override { return _child.ram_session_cap(); }
} _ram_accessor { _child };
Pd_session &pd() override { return _child.pd(); }
Pd_session_capability pd_cap() const override { return _child.pd_session_cap(); }
} _ram_pd_accessor { _child };
/**
* Async_service::Wakeup callback
@ -343,7 +398,7 @@ class Init::Child : Child_policy, Routed_service::Wakeup
new (_alloc)
Routed_service(_child_services, this->name(),
_ram_accessor,
_ram_pd_accessor, _ram_pd_accessor,
_session_requester.id_space(),
_child.session_factory(),
name, *this);
@ -375,8 +430,10 @@ class Init::Child : Child_policy, Routed_service::Wakeup
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,
Prio_levels prio_levels,
Affinity::Space const &affinity_space,
@ -391,6 +448,7 @@ class Init::Child : Child_policy, Routed_service::Wakeup
bool has_name(Child_policy::Name const &str) const { return str == name(); }
Ram_quota ram_quota() const { return _resources.assigned_ram_quota; }
Cap_quota cap_quota() const { return _resources.assigned_cap_quota; }
void initiate_env_ram_session()
{
@ -451,9 +509,13 @@ class Init::Child : Child_policy, Routed_service::Wakeup
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(); }
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void init(Pd_session &, Pd_session_capability) override;
void init(Ram_session &, Ram_session_capability) override;
void init(Cpu_session &, Cpu_session_capability) override;

View File

@ -26,7 +26,7 @@ namespace Init { struct Main; }
struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
Child::Ram_limit_accessor
Child::Default_caps_accessor, Child::Ram_limit_accessor
{
Env &_env;
@ -42,6 +42,8 @@ struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
Constructible<Buffered_xml> _default_route;
Cap_quota _default_caps { 0 };
unsigned _child_cnt = 0;
static Ram_quota _preserved_ram_from_config(Xml_node config)
@ -70,6 +72,32 @@ struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
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()
{
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
*/
@ -80,7 +108,10 @@ struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
void produce_state_report(Xml_generator &xml, Report_detail const &detail) const
{
if (detail.init_ram())
xml.node("ram", [&] () { generate_ram_info(xml, _env.ram()); });
xml.node("ram", [&] () { generate_ram_info (xml, _env.ram()); });
if (detail.init_caps())
xml.node("caps", [&] () { generate_caps_info(xml, _env.pd()); });
if (detail.children())
_children.report_state(xml, detail);
@ -95,6 +126,11 @@ struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
: Xml_node("<empty/>");
}
/**
* Default_caps_accessor interface
*/
Cap_quota default_caps() override { return _default_caps; }
State_reporter _state_reporter { _env, *this };
Signal_handler<Main> _resource_avail_handler {
@ -258,6 +294,12 @@ void Init::Main::_handle_config()
_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());
@ -278,9 +320,11 @@ void Init::Main::_handle_config()
/* 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 {
@ -300,12 +344,18 @@ void Init::Main::_handle_config()
throw Out_of_ram();
}
if (used_caps.value > avail_caps.value) {
error("capabilities exhausted while starting childen");
throw Out_of_caps();
}
try {
Init::Child &child = *new (_heap)
Init::Child(_env, _heap, *_verbose,
Init::Child::Id { ++_child_cnt }, _state_reporter,
start_node, *this, _children,
Ram_quota { avail_ram.value - used_ram.value },
start_node, *this, *this, _children,
Ram_quota { avail_ram.value - used_ram.value },
Cap_quota { avail_caps.value - used_caps.value },
*this, prio_levels, affinity_space,
_parent_services, _child_services);
_children.insert(&child);
@ -317,6 +367,9 @@ void Init::Main::_handle_config()
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) {
/*
@ -326,6 +379,8 @@ void Init::Main::_handle_config()
}
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::Attach_failed) {

View File

@ -33,7 +33,9 @@ class Init::Report_detail : Genode::Noncopyable
bool _provided = false;
bool _session_args = false;
bool _child_ram = false;
bool _child_caps = false;
bool _init_ram = false;
bool _init_caps = false;
public:
@ -47,7 +49,9 @@ class Init::Report_detail : Genode::Noncopyable
_provided = report.attribute_value("provided", false);
_session_args = report.attribute_value("session_args", false);
_child_ram = report.attribute_value("child_ram", false);
_child_caps = report.attribute_value("child_caps", false);
_init_ram = report.attribute_value("init_ram", false);
_init_caps = report.attribute_value("init_caps", false);
}
bool children() const { return _children; }
@ -56,7 +60,9 @@ class Init::Report_detail : Genode::Noncopyable
bool provided() const { return _provided; }
bool session_args() const { return _session_args; }
bool child_ram() const { return _child_ram; }
bool child_caps() const { return _child_caps; }
bool init_ram() const { return _init_ram; }
bool init_caps() const { return _init_caps; }
};

View File

@ -12,6 +12,7 @@
*/
/* Genode includes */
#include <base/quota_transfer.h>
#include <os/session_policy.h>
/* local includes */
@ -149,10 +150,14 @@ void Init::Server::session_closed(Session_state &session)
_report_update_trigger.trigger_report_update();
Ram_transfer::Account &service_ram_account = session.service();
Cap_transfer::Account &service_cap_account = session.service();
service_ram_account.try_transfer(_env.ram_session_cap(),
session.donated_ram_quota());
service_cap_account.try_transfer(_env.pd_session_cap(),
session.donated_cap_quota());
Parent::Server::Id id { session.id_at_client().value };
session.destroy();
@ -183,7 +188,9 @@ void Init::Server::_handle_create_session_request(Xml_node request,
char argbuf[Parent::Session_args::MAX_SIZE];
strncpy(argbuf, args.string(), sizeof(argbuf));
Cap_quota const cap_quota = cap_quota_from_args(argbuf);
Ram_quota const ram_quota = ram_quota_from_args(argbuf);
size_t const keep_quota = route.service.factory().session_costs();
if (ram_quota.value < keep_quota)
@ -201,10 +208,13 @@ void Init::Server::_handle_create_session_request(Xml_node request,
/* transfer session quota */
try {
Ram_transfer::Remote_account env_ram_account(_env.ram(), _env.ram_session_cap());
Cap_transfer::Remote_account env_cap_account(_env.pd(), _env.pd_session_cap());
Ram_transfer ram_transfer(forward_ram_quota, env_ram_account, route.service);
Cap_transfer cap_transfer(cap_quota, env_cap_account, route.service);
ram_transfer.acknowledge();
cap_transfer.acknowledge();
}
catch (...) {
/*
@ -212,7 +222,8 @@ void Init::Server::_handle_create_session_request(Xml_node request,
* transfor the session quota to us prior issuing the session
* request.
*/
warning("unable to transfer session quota (", ram_quota, " bytes) "
warning("unable to transfer session quota "
"(", ram_quota, " bytes, ", cap_quota, " caps) "
"of forwarded ", name, " session");
session.destroy();
throw Parent::Service_denied();
@ -233,6 +244,9 @@ void Init::Server::_handle_create_session_request(Xml_node request,
if (session.phase == Session_state::INSUFFICIENT_RAM_QUOTA)
throw Genode::Insufficient_ram_quota();
if (session.phase == Session_state::INSUFFICIENT_CAP_QUOTA)
throw Genode::Insufficient_cap_quota();
}
catch (Parent::Service_denied) {
_env.parent().session_response(Parent::Server::Id { id.value },
@ -240,6 +254,9 @@ void Init::Server::_handle_create_session_request(Xml_node request,
catch (Genode::Insufficient_ram_quota) {
_env.parent().session_response(Parent::Server::Id { id.value },
Parent::INSUFFICIENT_RAM_QUOTA); }
catch (Genode::Insufficient_cap_quota) {
_env.parent().session_response(Parent::Server::Id { id.value },
Parent::INSUFFICIENT_CAP_QUOTA); }
}
@ -249,23 +266,28 @@ void Init::Server::_handle_upgrade_session_request(Xml_node request,
_client_id_space.apply<Session_state>(id, [&] (Session_state &session) {
Ram_quota const ram_quota { request.attribute_value("ram_quota", 0UL) };
Cap_quota const cap_quota { request.attribute_value("cap_quota", 0UL) };
session.phase = Session_state::UPGRADE_REQUESTED;
try {
Ram_transfer::Remote_account env_ram_account(_env.ram(), _env.ram_session_cap());
Cap_transfer::Remote_account env_cap_account(_env.pd(), _env.pd_session_cap());
Ram_transfer ram_transfer(ram_quota, env_ram_account, session.service());
Cap_transfer cap_transfer(cap_quota, env_cap_account, session.service());
ram_transfer.acknowledge();
cap_transfer.acknowledge();
}
catch (...) {
warning("unable to upgrade session quota (", ram_quota, " bytes) "
warning("unable to upgrade session quota "
"(", ram_quota, " bytes, ", cap_quota, " caps) "
"of forwarded ", session.service().name(), " session");
return;
}
session.increase_donated_quota(ram_quota);
session.increase_donated_quota(ram_quota, cap_quota);
session.service().initiate_request(session);
session.service().wakeup();
});

View File

@ -71,11 +71,18 @@ class Init::Routed_service : public Async_service, public Abandonable
virtual Ram_session_capability ram_cap() const = 0;
};
struct Pd_accessor
{
virtual Pd_session &pd() = 0;
virtual Pd_session_capability pd_cap() const = 0;
};
private:
Child_name _child_name;
Ram_accessor &_ram_accessor;
Pd_accessor &_pd_accessor;
Session_state::Factory &_factory;
@ -94,6 +101,7 @@ class Init::Routed_service : public Async_service, public Abandonable
Routed_service(Registry<Routed_service> &services,
Child_name const &child_name,
Ram_accessor &ram_accessor,
Pd_accessor &pd_accessor,
Id_space<Parent::Server> &server_id_space,
Session_state::Factory &factory,
Service::Name const &name,
@ -101,7 +109,7 @@ class Init::Routed_service : public Async_service, public Abandonable
:
Async_service(name, server_id_space, factory, wakeup),
_child_name(child_name),
_ram_accessor(ram_accessor),
_ram_accessor(ram_accessor), _pd_accessor(pd_accessor),
_factory(factory), _registry_element(services, *this)
{ }
@ -124,6 +132,22 @@ class Init::Routed_service : public Async_service, public Abandonable
{
return _ram_accessor.ram_cap();
}
/**
* Cap_transfer::Account interface
*/
void transfer(Pd_session_capability to, Cap_quota amount) override
{
if (to.valid()) _pd_accessor.pd().transfer_quota(to, amount);
}
/**
* Cap_transfer::Account interface
*/
Pd_session_capability cap(Cap_quota) const override
{
return _pd_accessor.pd_cap();
}
};
#endif /* _SRC__INIT__SERVICE_H_ */

View File

@ -16,6 +16,7 @@
#include <util/string.h>
#include <util/list.h>
#include <session/session.h>
namespace Init {

View File

@ -136,13 +136,20 @@ namespace Init {
inline void generate_ram_info(Xml_generator &xml, Ram_session const &ram)
{
typedef String<32> Value;
xml.attribute("quota", Value(ram.ram_quota()));
xml.attribute("used", Value(ram.used_ram()));
xml.attribute("avail", Value(ram.avail_ram()));
}
inline void generate_caps_info(Xml_generator &xml, Pd_session const &pd)
{
typedef String<32> Value;
xml.attribute("quota", Value(pd.cap_quota()));
xml.attribute("used", Value(pd.used_caps()));
xml.attribute("avail", Value(pd.avail_caps()));
}
/**
* Read priority-levels declaration from config
*/

View File

@ -45,6 +45,7 @@ class Loader::Child : public Child_policy
Session_label const _label;
Name const _binary_name;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota;
Parent_services &_parent_services;
@ -62,6 +63,7 @@ class Loader::Child : public Child_policy
Allocator &alloc,
Name const &binary_name,
Session_label const &label,
Cap_quota cap_quota,
Ram_quota ram_quota,
Parent_services &parent_services,
Service &local_rom_service,
@ -74,6 +76,7 @@ class Loader::Child : public Child_policy
_alloc(alloc),
_label(label),
_binary_name(binary_name),
_cap_quota(Genode::Child::effective_quota(cap_quota)),
_ram_quota(Genode::Child::effective_quota(ram_quota)),
_parent_services(parent_services),
_local_nitpicker_service(local_nitpicker_service),
@ -94,9 +97,18 @@ class Loader::Child : public Child_policy
Binary_name binary_name() const override { return _binary_name; }
Pd_session &ref_pd() override { return _env.pd(); }
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void init(Pd_session &pd, Pd_session_capability pd_cap) override
{
pd.ref_account(ref_pd_cap());
ref_pd().transfer_quota(pd_cap, _cap_quota);
}
void init(Ram_session &ram, Ram_session_capability ram_cap) override
{
ram.ref_account(ref_ram_cap());

View File

@ -14,7 +14,6 @@
/* Genode includes */
#include <base/component.h>
#include <base/heap.h>
#include <base/rpc_server.h>
#include <base/sleep.h>
#include <loader_session/loader_session.h>
#include <root/component.h>
@ -204,9 +203,11 @@ class Loader::Session_component : public Rpc_object<Session>
Env &_env;
Session_label const _label;
Xml_node const _config;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota;
Ram_session_client_guard _local_ram { _env.ram_session_cap(), _ram_quota };
Heap _md_alloc { _local_ram, _env.rm() };
size_t _subsystem_cap_quota_limit = 0;
size_t _subsystem_ram_quota_limit = 0;
Parent_services _parent_services;
Rom_module_registry _rom_modules { _env, _config, _local_ram, _md_alloc };
@ -243,10 +244,11 @@ class Loader::Session_component : public Rpc_object<Session>
/**
* Constructor
*/
Session_component(Env &env, Session_label const &label,
Xml_node config, Ram_quota quota)
Session_component(Env &env, Session_label const &label, Xml_node config,
Cap_quota cap_quota, Ram_quota ram_quota)
:
_env(env), _label(label), _config(config), _ram_quota(quota)
_env(env), _label(label), _config(config),
_cap_quota(cap_quota), _ram_quota(ram_quota)
{
/* fetch all parent-provided ROMs according to the config */
config.for_each_sub_node("parent-rom", [&] (Xml_node rom)
@ -287,6 +289,11 @@ class Loader::Session_component : public Rpc_object<Session>
throw Rom_module_does_not_exist(); }
}
void cap_quota(Cap_quota caps) override
{
_subsystem_cap_quota_limit = caps.value;
}
void ram_quota(Ram_quota quantum) override
{
_subsystem_ram_quota_limit = quantum.value;
@ -334,6 +341,10 @@ class Loader::Session_component : public Rpc_object<Session>
return;
}
size_t const cap_quota = (_subsystem_cap_quota_limit > 0)
? min(_subsystem_cap_quota_limit, _cap_quota.value)
: _cap_quota.value;
size_t const ram_quota = (_subsystem_ram_quota_limit > 0)
? min(_subsystem_ram_quota_limit, _ram_quota.value)
: _ram_quota.value;
@ -341,7 +352,7 @@ class Loader::Session_component : public Rpc_object<Session>
try {
_child.construct(_env, _md_alloc, binary_name.string(),
prefixed_label(_label, Session_label(label.string())),
Ram_quota{ram_quota},
Cap_quota{cap_quota}, Ram_quota{ram_quota},
_parent_services, _rom_service,
_cpu_service, _pd_service, _nitpicker_service,
_fault_sigh);
@ -381,6 +392,7 @@ class Loader::Root : public Root_component<Session_component>
catch (...) { }
return new (md_alloc()) Session_component(_env, label, session_config,
cap_quota_from_args(args),
ram_quota_from_args(args));
}

View File

@ -32,6 +32,7 @@ class Bomb_child : public Child_policy
Env &_env;
Binary_name const _binary_name;
Name const _label;
Cap_quota const _cap_quota;
Ram_quota const _ram_quota;
Registry<Registered<Parent_service> > &_parent_services;
@ -45,11 +46,13 @@ class Bomb_child : public Child_policy
Bomb_child(Env &env,
Name const &binary_name,
Name const &label,
Cap_quota const cap_quota,
Ram_quota const ram_quota,
Registry<Registered<Parent_service> > &parent_services,
unsigned generation)
:
_env(env), _binary_name(binary_name), _label(label),
_cap_quota(Child::effective_quota(cap_quota)),
_ram_quota(Child::effective_quota(ram_quota)),
_parent_services(parent_services)
{
@ -68,12 +71,21 @@ class Bomb_child : public Child_policy
Binary_name binary_name() const override { return _binary_name; }
void init(Pd_session &pd, Pd_session_capability pd_cap) override
{
pd.ref_account(_env.pd_session_cap());
_env.pd().transfer_quota(pd_cap, _cap_quota);
}
void init(Ram_session &ram, Ram_session_capability ram_cap) override
{
ram.ref_account(_env.ram_session_cap());
_env.ram().transfer_quota(ram_cap, _ram_quota);
}
Pd_session &ref_pd() override { return _env.pd(); }
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
@ -154,10 +166,10 @@ struct Bomb
Attached_rom_dataspace config { env, "config" };
unsigned round = 0;
unsigned const rounds = config.xml().attribute_value("rounds", 1U);
unsigned const generation = config.xml().attribute_value("generations", 1U);
unsigned const children = config.xml().attribute_value("children", 2U);
unsigned const sleeptime = config.xml().attribute_value("sleep", 2000U);
unsigned const rounds = config.xml().attribute_value("rounds", 1U);
unsigned const generation = config.xml().attribute_value("generations", 1U);
unsigned const children = config.xml().attribute_value("children", 2U);
unsigned const sleeptime = config.xml().attribute_value("sleep", 2000U);
size_t const ram_demand = config.xml().attribute_value("demand", 1024UL * 1024);
Heap heap { env.ram(), env.rm() };
@ -177,6 +189,17 @@ struct Bomb
" - not enough memory.");
return;
}
size_t const avail_caps = env.pd().avail_caps().value;
size_t const preserved_caps = children*10;
if (avail_caps < preserved_caps) {
log("I ran out of capabilities.");
return;
}
Cap_quota const cap_quota { (avail_caps - preserved_caps) / children };
if (generation == 0) {
log("I'm a leaf node - generation 0");
return;
@ -192,7 +215,7 @@ struct Bomb
unique_child_name(child_registry,
binary_name,
generation - 1),
ram_amount,
cap_quota, ram_amount,
parent_services, generation - 1);
}

View File

@ -24,7 +24,7 @@ struct Main
Env &env;
int counter { -1 };
Loader::Connection loader { env, Ram_quota{8*1024*1024} };
Loader::Connection loader { env, Ram_quota{8*1024*1024}, Cap_quota{100} };
Timer::Connection timer { env };
Signal_handler<Main> timer_handler { env.ep(), *this, &Main::handle_timer };

View File

@ -36,6 +36,7 @@ struct Test::Policy
Policy(Env &env, Name const &name)
:
Slave::Policy(name, name, *this, env.ep().rpc_ep(), env.rm(),
env.pd(), env.pd_session_cap(), Cap_quota{100},
env.ram(), env.ram_session_cap(), Ram_quota{1024*1024})
{ }
};

View File

@ -70,6 +70,7 @@ class Test_child : public Genode::Child_policy
private:
Env &_env;
Cap_quota const _cap_quota { 30 };
Ram_quota const _ram_quota { 1024*1024 };
Binary_name const _binary_name;
Signal_context_capability _sigh;
@ -101,6 +102,9 @@ class Test_child : public Genode::Child_policy
Binary_name binary_name() const override { return _binary_name; }
Pd_session &ref_pd() override { return _env.pd(); }
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
@ -116,8 +120,11 @@ class Test_child : public Genode::Child_policy
cpu.exception_sigh(_sigh);
}
void init(Pd_session &pd, Pd_session_capability) override
void init(Pd_session &pd, Pd_session_capability pd_cap) override
{
pd.ref_account(ref_pd_cap());
ref_pd().transfer_quota(pd_cap, _cap_quota);
/* register handler for unresolvable page faults */
Region_map_client address_space(pd.address_space());
address_space.fault_handler(_sigh);
@ -162,7 +169,7 @@ struct Faulting_loader_child_test
void start_iteration(Env &env, Signal_context_capability fault_sigh)
{
loader.construct(env, Ram_quota{1024*1024});
loader.construct(env, Ram_quota{1024*1024}, Cap_quota{100});
/* register fault handler at loader session */
loader->fault_sigh(fault_sigh);
@ -207,7 +214,7 @@ struct Faulting_loader_grand_child_test
void start_iteration(Env &env, Signal_context_capability fault_sigh)
{
loader.construct(env, Ram_quota{2*1024*1024});
loader.construct(env, Ram_quota{2*1024*1024}, Cap_quota{100});
/* import config into loader session */
{

View File

@ -25,7 +25,7 @@ struct Test::Main
{
Env &_env;
Loader::Connection _loader { _env, Ram_quota{8*1024*1024} };
Loader::Connection _loader { _env, Ram_quota{8*1024*1024}, Cap_quota{100} };
Timer::Connection _timer { _env };
Loader::Area _size;

View File

@ -70,6 +70,7 @@ struct Test::Monitor
xml.node("start", [&] () {
xml.attribute("name", "test-resource_request");
xml.attribute("caps", 3000);
xml.node("resource", [&] () {
xml.attribute("name", "RAM");
xml.attribute("quantum", _ram_quota);

View File

@ -285,7 +285,7 @@ class Test::Parent
{
Parent &_parent;
enum { SLAVE_QUOTA = 10*1024*1024 };
enum { SLAVE_CAPS = 50, SLAVE_RAM = 10*1024*1024 };
void yield_response() override
{
@ -296,7 +296,8 @@ class Test::Parent
:
Slave::Policy(Label("child"), "test-resource_yield",
*this, env.ep().rpc_ep(), env.rm(),
env.ram(), env.ram_session_cap(), Ram_quota{SLAVE_QUOTA}),
env.pd(), env.pd_session_cap(), Cap_quota{SLAVE_CAPS},
env.ram(), env.ram_session_cap(), Ram_quota{SLAVE_RAM}),
_parent(parent)
{
configure("<config child=\"yes\" />");

View File

@ -50,8 +50,11 @@ class Gdb_monitor::App_child : public Child_policy
Allocator &_alloc;
Pd_session_capability _ref_pd_cap { _env.pd_session_cap() };
Pd_session &_ref_pd { _env.pd() };
Ram_session_capability _ref_ram_cap { _env.ram_session_cap() };
Ram_session_client _ref_ram { _ref_ram_cap };
Ram_session &_ref_ram { _env.ram() };
const char *_unique_name;
@ -60,6 +63,7 @@ class Gdb_monitor::App_child : public Child_policy
Region_map &_rm;
Ram_quota _ram_quota;
Cap_quota _cap_quota;
Rpc_entrypoint _entrypoint;
@ -112,6 +116,7 @@ class Gdb_monitor::App_child : public Child_policy
Allocator &alloc,
char const *unique_name,
Ram_quota ram_quota,
Cap_quota cap_quota,
Signal_receiver &signal_receiver,
Xml_node target_node)
:
@ -119,7 +124,7 @@ class Gdb_monitor::App_child : public Child_policy
_alloc(alloc),
_unique_name(unique_name),
_rm(_env.rm()),
_ram_quota(ram_quota),
_ram_quota(ram_quota), _cap_quota(cap_quota),
_entrypoint(&_env.pd(), STACK_SIZE, "GDB monitor entrypoint"),
_child_config(env.ram(), _rm, target_node),
_config_policy("config", _child_config.dataspace(), &_entrypoint),
@ -155,6 +160,10 @@ class Gdb_monitor::App_child : public Child_policy
Name name() const override { return _unique_name; }
Pd_session &ref_pd() override { return _ref_pd; }
Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; }
Ram_session &ref_ram() override { return _ref_ram; }
Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
@ -166,6 +175,13 @@ class Gdb_monitor::App_child : public Child_policy
_ref_ram.transfer_quota(cap, _ram_quota);
}
void init(Pd_session &session,
Pd_session_capability cap) override
{
session.ref_account(_ref_pd_cap);
_ref_pd.transfer_quota(cap, _cap_quota);
}
Service &resolve_session_request(Service::Name const &service_name,
Session_state::Args const &args) override
{

View File

@ -469,6 +469,17 @@ extern "C" int fork()
Number_of_bytes ram_quota = genode_env->ram().avail_ram().value - preserved_ram_quota;
Cap_quota const avail_cap_quota = genode_env->pd().avail_caps();
Genode::size_t const preserved_caps = 100;
if (avail_cap_quota.value < preserved_caps) {
error("not enough available caps for preservation of ", preserved_caps);
return -1;
}
Cap_quota const cap_quota { avail_cap_quota.value - preserved_caps };
/* start the application */
static Heap alloc(genode_env->ram(), genode_env->rm());
@ -483,6 +494,7 @@ extern "C" int fork()
alloc,
filename,
Ram_quota{ram_quota},
cap_quota,
signal_receiver,
target_node);

View File

@ -116,6 +116,15 @@ class Gdb_monitor::Pd_session_component : public Rpc_object<Pd_session>
Capability<Region_map> linker_area() override {
return _linker_area.Rpc_object<Region_map>::cap(); }
void ref_account(Capability<Pd_session> pd) override {
warning("Pd_session::ref_account not implemented"); }
void transfer_quota(Capability<Pd_session> pd, Cap_quota amount) override {
warning("Pd_session::transfer_quota not implemented"); }
Cap_quota cap_quota() const { return _pd.cap_quota(); }
Cap_quota used_caps() const { return _pd.used_caps(); }
Capability<Native_pd> native_pd() override {
return _pd.native_pd(); }
};

Some files were not shown because too many files have changed in this diff Show More