base: remove Child::heap

This patch improves the accounting for the backing store of
session-state meta data. Originally, the session state used to be
allocated by a child-local heap partition fed from the child's RAM
session. However, whereas this approach was somehow practical from a
runtime's (parent's) point of view, the child component could not count
on the quota in its own RAM session. I.e., if the Child::heap grew at
the parent side, the child's RAM session would magically diminish. This
caused two problems. First, it violates assumptions of components like
init that carefully manage their RAM resources (and giving most of them
away their children). Second, if a child transfers most of its RAM
session quota to another RAM session (like init does), the child's RAM
session may actually not allow the parent's heap to grow, which is a
very difficult error condition to deal with.

In the new version, there is no Child::heap anymore. Instead, session
states are allocated from the runtime's RAM session. In order to let
children pay for these costs, the parent withdraws the local session
costs from the session quota donated from the child when the child
initiates a new session. Hence, in principle, all components on the
route of the session request take a small bite from the session quota to
pay for their local book keeping

Consequently, the session quota that ends up at the server may become
depleted more or less, depending on the route. In the case where the
remaining quota is insufficient for the server, the server responds with
'QUOTA_EXCEEDED'. Since this behavior must generally be expected, this
patch equips the client-side 'Env::session' implementation with the
ability to re-issue session requests with successively growing quota
donations.

For several of core's services (ROM, IO_MEM, IRQ), the default session
quota has now increased by 2 KiB, which should suffice for session
requests to up to 3 hops as is the common case for most run scripts. For
longer routes, the retry mechanism as described above comes into effect.
For the time being, we give a warning whenever the server-side quota
check triggers the retry mechanism. The warning may eventually be
removed at a later stage.
This commit is contained in:
Norman Feske 2017-02-19 10:31:50 +01:00 committed by Christian Helmuth
parent 641fb08b5f
commit 9cba459958
35 changed files with 275 additions and 130 deletions

View File

@ -192,6 +192,14 @@ struct Genode::Child_policy
*/
virtual void session_state_changed() { }
/**
* Granularity of allocating the backing store for session meta data
*
* Session meta data is allocated from 'ref_ram'. The first batch of
* session-state objects is allocated at child-construction time.
*/
virtual size_t session_alloc_batch_size() const { return 16; }
/**
* Return region map for the child's address space
*
@ -301,6 +309,16 @@ class Genode::Child : protected Rpc_object<Parent>,
/* sessions opened by the child */
Id_space<Client> _id_space;
/* allocator used for dynamically created session state objects */
Sliced_heap _session_md_alloc { _policy.ref_ram(), _local_rm };
Session_state::Factory::Batch_size const
_session_batch_size { _policy.session_alloc_batch_size() };
/* factory for dynamically created session-state objects */
Session_state::Factory _session_factory { _session_md_alloc,
_session_batch_size };
typedef Session_state::Args Args;
static Child_policy::Route _resolve_session_request(Child_policy &,
@ -313,12 +331,6 @@ class Genode::Child : protected Rpc_object<Parent>,
void _try_construct_env_dependent_members();
/* heap for child-specific allocations using the child's quota */
Constructible<Heap> _heap;
/* factory for dynamically created session-state objects */
Constructible<Session_state::Factory> _session_factory;
Constructible<Initial_thread> _initial_thread;
struct Process
@ -584,11 +596,6 @@ class Genode::Child : protected Rpc_object<Parent>,
return ram_quota - env_ram_quota();
}
/**
* Return heap that uses the child's quota
*/
Allocator &heap() { return *_heap; }
Ram_session_capability ram_session_cap() const { return _ram.cap(); }
Parent_capability parent_cap() const { return cap(); }
@ -597,24 +604,10 @@ class Genode::Child : protected Rpc_object<Parent>,
Cpu_session &cpu() { return _cpu.session(); }
Pd_session &pd() { return _pd .session(); }
/**
* Exception type
*/
class Inactive : Exception { };
/**
* Request factory for creating session-state objects
*
* \throw Inactive factory cannot by provided because the child it
* not yet completely initialized.
*/
Session_state::Factory &session_factory()
{
if (_session_factory.constructed())
return *_session_factory;
throw Inactive();
}
Session_state::Factory &session_factory() { return _session_factory; }
/**
* Instruct the child to yield resources

View File

@ -35,7 +35,7 @@ struct Genode::Local_connection_base : Noncopyable
protected:
Session_state _session_state;
Constructible<Session_state> _session_state;
private:
@ -59,18 +59,31 @@ struct Genode::Local_connection_base : Noncopyable
Parent::Client::Id id,
Args const &args, Affinity const &affinity,
size_t ram_quota)
:
_session_state(service, id_space, id, label_from_args(args.string()),
_init_args(args, ram_quota), affinity)
{
_session_state.service().initiate_request(_session_state);
enum { NUM_ATTEMPTS = 10 };
for (unsigned i = 0; i < NUM_ATTEMPTS; i++) {
_session_state.construct(service, id_space, id,
label_from_args(args.string()),
_init_args(args, ram_quota), affinity);
_session_state->service().initiate_request(*_session_state);
if (_session_state->phase == Session_state::QUOTA_EXCEEDED)
ram_quota += 4096;
else
break;
}
if (_session_state->phase == Session_state::QUOTA_EXCEEDED)
warning("giving up to increase session quota for ", service.name(), " session "
"after ", (int)NUM_ATTEMPTS, " attempts");
}
~Local_connection_base()
{
if (_session_state.alive()) {
_session_state.phase = Session_state::CLOSE_REQUESTED;
_session_state.service().initiate_request(_session_state);
if (_session_state->alive()) {
_session_state->phase = Session_state::CLOSE_REQUESTED;
_session_state->service().initiate_request(*_session_state);
}
}
};
@ -89,7 +102,7 @@ class Genode::Local_connection : Local_connection_base
Capability<SESSION> cap() const
{
return reinterpret_cap_cast<SESSION>(_session_state.cap);
return reinterpret_cap_cast<SESSION>(_session_state->cap);
}
SESSION &session()
@ -99,15 +112,15 @@ class Genode::Local_connection : Local_connection_base
* RAM session, we return the reference to the corresponding
* component object, which can be called directly.
*/
if (_session_state.local_ptr)
return *static_cast<SESSION *>(_session_state.local_ptr);
if (_session_state->local_ptr)
return *static_cast<SESSION *>(_session_state->local_ptr);
/*
* The session is provided remotely. So return a client stub for
* interacting with the session. We construct the client object if
* we have a valid session capability.
*/
if (!_client.constructed() && _session_state.cap.valid())
if (!_client.constructed() && _session_state->cap.valid())
_client.construct(cap());
if (_client.constructed())
@ -117,7 +130,7 @@ class Genode::Local_connection : Local_connection_base
* This error is printed if the session could not be
* established or the session is provided by a child service.
*/
error(SESSION::service_name(), " session (", _session_state.args(), ") "
error(SESSION::service_name(), " session (", _session_state->args(), ") "
"unavailable");
throw Parent::Service_denied();
}

View File

@ -130,7 +130,10 @@ class Genode::Local_service : public Service
class Denied : Exception { };
/**
* Create session
*
* \throw Denied
* \throw Quota_exceeded
*/
virtual SESSION &create(Args const &, Affinity) = 0;
@ -200,6 +203,8 @@ class Genode::Local_service : public Service
}
catch (typename Factory::Denied) {
session.phase = Session_state::INVALID_ARGS; }
catch (Quota_exceeded) {
session.phase = Session_state::QUOTA_EXCEEDED; }
break;
@ -225,6 +230,7 @@ class Genode::Local_service : public Service
break;
case Session_state::INVALID_ARGS:
case Session_state::QUOTA_EXCEEDED:
case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED:
@ -317,6 +323,7 @@ class Genode::Parent_service : public Service
break;
case Session_state::INVALID_ARGS:
case Session_state::QUOTA_EXCEEDED:
case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED:

View File

@ -18,6 +18,7 @@
#include <util/list.h>
#include <util/reconstructible.h>
#include <session/capability.h>
#include <base/slab.h>
#include <base/id_space.h>
#include <base/env.h>
#include <base/log.h>
@ -78,6 +79,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
enum Phase { CREATE_REQUESTED,
INVALID_ARGS,
QUOTA_EXCEEDED,
AVAILABLE,
CAP_HANDED_OUT,
UPGRADE_REQUESTED,
@ -182,6 +184,7 @@ class Genode::Session_state : public Parent::Client, public Parent::Server,
case CREATE_REQUESTED:
case INVALID_ARGS:
case QUOTA_EXCEEDED:
case CLOSED:
return false;
@ -234,17 +237,34 @@ class Genode::Session_state::Factory : Noncopyable
{
private:
Allocator &_md_alloc;
size_t const _batch_size;
Slab _slab;
public:
struct Batch_size { size_t value; };
/**
* Constructor
*
* \param md_alloc meta-data allocator used for allocating
* 'Session_state' objects
*
* \param batch granularity of allocating blocks at 'md_alloc',
* must be greater than 0
*/
Factory(Allocator &md_alloc) : _md_alloc(md_alloc) { }
Factory(Allocator &md_alloc, Batch_size batch)
:
_batch_size(batch.value),
/*
* The calculation of 'block_size' is just an approximation as
* a slab block contains a few bytes of meta data in addition
* to the actual slab entries.
*/
_slab(sizeof(Session_state), sizeof(Session_state)*_batch_size,
nullptr, &md_alloc)
{ }
/**
* Create a new session-state object
@ -256,11 +276,16 @@ class Genode::Session_state::Factory : Noncopyable
template <typename... ARGS>
Session_state &create(ARGS &&... args)
{
Session_state &session = *new (_md_alloc) Session_state(args...);
Session_state &session = *new (_slab) Session_state(args...);
session.owner(*this);
return session;
}
/**
* Return number of bytes consumed per session
*/
size_t session_costs() const { return _slab.overhead(sizeof(Session_state)); }
private:
/*
@ -270,7 +295,7 @@ class Genode::Session_state::Factory : Noncopyable
*/
friend class Session_state;
void _destroy(Session_state &session) { Genode::destroy(_md_alloc, &session); }
void _destroy(Session_state &session) { Genode::destroy(_slab, &session); }
};

View File

@ -101,6 +101,14 @@ class Genode::Slab : public Allocator
*/
~Slab();
/**
* Return number of bytes consumed per slab entry
*
* The function takes the slab-internal meta-data needs and the actual
* slab entry into account.
*/
static size_t entry_costs(size_t slab_size, size_t block_size);
/**
* Add new slab block as backing store
*

View File

@ -30,7 +30,7 @@ struct Genode::Io_mem_connection : Connection<Io_mem_session>, Io_mem_session_cl
Capability<Io_mem_session> _session(Parent &parent, addr_t base, size_t size,
bool write_combined)
{
return session("ram_quota=4K, base=0x%p, size=0x%lx, wc=%s",
return session("ram_quota=6K, base=0x%p, size=0x%lx, wc=%s",
base, size, write_combined ? "yes" : "no");
}

View File

@ -30,7 +30,7 @@ struct Genode::Io_port_connection : Connection<Io_port_session>,
*/
Capability<Io_port_session> _session(Parent &parent, unsigned base, unsigned size)
{
return session(parent, "ram_quota=4K, io_port_base=%u, io_port_size=%u",
return session(parent, "ram_quota=6K, io_port_base=%u, io_port_size=%u",
base, size);
}

View File

@ -32,7 +32,7 @@ struct Genode::Irq_connection : Connection<Irq_session>, Irq_session_client
Irq_session::Polarity polarity,
Genode::addr_t device_config_phys)
{
return session("ram_quota=4K, irq_number=%u, irq_trigger=%u, "
return session("ram_quota=6K, irq_number=%u, irq_trigger=%u, "
" irq_polarity=%u, device_config_phys=0x%lx",
irq, trigger, polarity, device_config_phys);
}

View File

@ -183,6 +183,8 @@ class Genode::Parent
* Request session capability
*
* \throw Service_denied
* \throw Quota_exceeded session quota does not suffice for
* the creation of the new session
*
* In the exception case, the parent implicitly closes the session.
*/
@ -215,7 +217,7 @@ class Genode::Parent
* Interface for providing services
*/
enum Session_response { SESSION_OK, SESSION_CLOSED, INVALID_ARGS };
enum Session_response { SESSION_OK, SESSION_CLOSED, INVALID_ARGS, QUOTA_EXCEEDED };
/**
* Set state of a session provided by the child service

View File

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

View File

@ -130,8 +130,9 @@ class Genode::Root_component : public Rpc_object<Typed_root<SESSION_TYPE> >,
size_t needed = sizeof(SESSION_TYPE) + md_alloc()->overhead(sizeof(SESSION_TYPE));
if (needed > ram_quota) {
error("insufficient ram quota, provided=", ram_quota,
", required=", needed);
warning("insufficient ram quota "
"for ", SESSION_TYPE::service_name(), " session, "
"provided=", ram_quota, ", required=", needed);
throw Root::Quota_exceeded();
}
@ -269,6 +270,7 @@ class Genode::Root_component : public Rpc_object<Typed_root<SESSION_TYPE> >,
{
try {
return _create(args, affinity); }
catch (Root::Quota_exceeded) { throw Service::Quota_exceeded(); }
catch (...) {
throw typename Local_service<SESSION_TYPE>::Factory::Denied(); }
}

View File

@ -35,7 +35,7 @@ struct Genode::Trace::Connection : Genode::Connection<Genode::Trace::Session>,
{
return session(parent,
"ram_quota=%lu, arg_buffer_size=%lu, parent_levels=%u",
ram_quota, arg_buffer_size, parent_levels);
ram_quota + 2048, arg_buffer_size, parent_levels);
}
/**

View File

@ -189,6 +189,8 @@ class Core_child : public Child_policy
Ram_session &ref_ram() { return _core_ram; }
Ram_session_capability ref_ram_cap() const { return _core_ram_cap; }
size_t session_alloc_batch_size() const override { return 128; }
};

View File

@ -92,27 +92,7 @@ class Genode::Expanding_parent_client : public Parent_client
Session_args const &args,
Affinity const &affinity) override
{
enum { NUM_ATTEMPTS = 2 };
return retry<Parent::Quota_exceeded>(
[&] () { return Parent_client::session(id, name, args, affinity); },
[&] () {
/*
* Request amount of session quota from the parent.
*
* XXX We could deduce the available quota of our
* own RAM session from the request.
*/
size_t const ram_quota =
Arg_string::find_arg(args.string(), "ram_quota")
.ulong_value(0);
char buf[128];
snprintf(buf, sizeof(buf), "ram_quota=%lu", ram_quota);
resource_request(Resource_args(buf));
},
NUM_ATTEMPTS);
return Parent_client::session(id, name, args, affinity);
}
Upgrade_result upgrade(Client::Id id, Upgrade_args const &args) override

View File

@ -142,9 +142,15 @@ void Child::session_sigh(Signal_context_capability sigh)
* needs asynchronous handling.
*/
_id_space.for_each<Session_state const>([&] (Session_state const &session) {
if (session.phase == Session_state::AVAILABLE
&& sigh.valid() && session.async_client_notify)
Signal_transmitter(sigh).submit(); });
if (session.phase == Session_state::AVAILABLE ||
session.phase == Session_state::QUOTA_EXCEEDED ||
session.phase == Session_state::INVALID_ARGS) {
if (sigh.valid() && session.async_client_notify)
Signal_transmitter(sigh).submit();
}
});
}
@ -164,6 +170,10 @@ create_session(Child_policy::Name const &child_name, Service &service,
try {
return service.create_session(factory, id_space, id, label, args, affinity);
}
catch (Service::Quota_exceeded) {
error(child_name, " requested session with insufficient session quota");
throw Parent::Quota_exceeded();
}
catch (Allocator::Out_of_memory) {
error("could not allocate session meta data for child ", child_name);
throw Parent::Quota_exceeded();
@ -230,12 +240,27 @@ Session_capability Child::session(Parent::Client::Id id,
/* filter session affinity */
Affinity const filtered_affinity = _policy.filter_session_affinity(affinity);
size_t const ram_quota = Arg_string::find_arg(argbuf, "ram_quota").ulong_value(0);
/* portion of quota to keep for ourself to maintain the session meta data */
size_t const keep_ram_quota = _session_factory.session_costs();
if (ram_quota < keep_ram_quota)
throw Parent::Quota_exceeded();
/* ram quota to be forwarded to the server */
size_t const forward_ram_quota = ram_quota - keep_ram_quota;
/* adjust the session information as presented to the server */
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota",
forward_ram_quota);
/* may throw a 'Parent::Service_denied' exception */
Child_policy::Route route = _resolve_session_request(_policy, name.string(), argbuf);
Service &service = route.service;
Session_state &session =
create_session(_policy.name(), service, route.label, *_session_factory,
create_session(_policy.name(), service, route.label, _session_factory,
_id_space, id, argbuf, filtered_affinity);
_policy.session_state_changed();
@ -243,14 +268,12 @@ Session_capability Child::session(Parent::Client::Id id,
session.ready_callback = this;
session.closed_callback = this;
/* transfer the quota donation from the child's account to ourself */
size_t ram_quota = Arg_string::find_arg(argbuf, "ram_quota").ulong_value(0);
try {
/* transfer the quota donation from the child's account to ourself */
Transfer donation_from_child(ram_quota, _ram.cap(), _policy.ref_ram_cap());
/* transfer session quota from ourself to the service provider */
Transfer donation_to_service(ram_quota, _policy.ref_ram_cap(),
Transfer donation_to_service(forward_ram_quota, _policy.ref_ram_cap(),
service.ram());
/* try to dispatch session request synchronously */
@ -261,6 +284,11 @@ Session_capability Child::session(Parent::Client::Id id,
throw Service_denied();
}
if (session.phase == Session_state::QUOTA_EXCEEDED) {
_revert_quota_and_destroy(session);
throw Parent::Quota_exceeded();
}
/* finish transaction */
donation_from_child.acknowledge();
donation_to_service.acknowledge();
@ -298,7 +326,10 @@ Session_capability Child::session_cap(Client::Id id)
auto lamda = [&] (Session_state &session) {
if (session.phase == Session_state::INVALID_ARGS) {
if (session.phase == Session_state::INVALID_ARGS
|| session.phase == Session_state::QUOTA_EXCEEDED) {
Session_state::Phase const phase = session.phase;
/*
* Implicity discard the session request when delivering an
@ -306,7 +337,11 @@ Session_capability Child::session_cap(Client::Id id)
* of the session ID at the child anyway.
*/
_revert_quota_and_destroy(session);
throw Parent::Service_denied();
if (phase == Session_state::INVALID_ARGS)
throw Parent::Service_denied();
else
throw Parent::Quota_exceeded();
}
if (!session.alive())
@ -390,8 +425,14 @@ void Child::_revert_quota_and_destroy(Session_state &session)
Transfer donation_from_service(session.donated_ram_quota(),
session.service().ram(), _policy.ref_ram_cap());
/* transfer session quota from ourself to the client (our child) */
Transfer donation_to_client(session.donated_ram_quota(),
/*
* Transfer session quota from ourself to the client (our child). In
* addition to the quota returned from the server, we also return the
* quota that we preserved for locally storing the session meta data
* ('session_costs').
*/
Transfer donation_to_client(session.donated_ram_quota() +
_session_factory.session_costs(),
_policy.ref_ram_cap(), ram_session_cap());
/* finish transaction */
donation_from_service.acknowledge();
@ -411,7 +452,8 @@ Child::Close_result Child::_close(Session_state &session)
* If session could not be established, destruct session immediately
* without involving the server
*/
if (session.phase == Session_state::INVALID_ARGS) {
if (session.phase == Session_state::INVALID_ARGS
|| session.phase == Session_state::QUOTA_EXCEEDED) {
_revert_quota_and_destroy(session);
return CLOSE_DONE;
}
@ -501,6 +543,12 @@ void Child::session_response(Server::Id id, Session_response response)
session.ready_callback->session_ready(session);
break;
case Parent::QUOTA_EXCEEDED:
session.phase = Session_state::QUOTA_EXCEEDED;
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;
@ -638,9 +686,6 @@ void Child::_try_construct_env_dependent_members()
_policy.init(_cpu.session(), _cpu.cap());
_policy.init(_pd.session(), _pd.cap());
_heap.construct(&_ram.session(), &_local_rm);
_session_factory.construct(*_heap);
try {
_initial_thread.construct(_cpu.session(), _pd.cap(), "initial");
_process.construct(_binary.session().dataspace(), _linker_dataspace(),
@ -733,13 +778,9 @@ Child::~Child()
/*
* Make sure to destroy the users of the child's environment sessions
* before destructing those sessions. E.g., as the environment RAM session
* provides the backing store for the '_heap', we must not destroy the heap
* after the RAM session.
* before destructing those sessions.
*/
_process.destruct();
_initial_thread.destruct();
_session_factory.destruct();
_heap.destruct();
}

View File

@ -13,6 +13,7 @@
*/
/* Genode includes */
#include <util/retry.h>
#include <base/component.h>
#include <base/connection.h>
#include <base/service.h>
@ -108,12 +109,64 @@ namespace {
{
Lock::Guard guard(_lock);
Session_capability cap = _parent.session(id, name, args, affinity);
if (cap.valid())
return cap;
/*
* Since we account for the backing store for session meta data on
* 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 };
_block_for_session();
return _parent.session_cap(id);
/* extract session quota as specified by the 'Connection' */
char argbuf[Parent::Session_args::MAX_SIZE];
strncpy(argbuf, args.string(), sizeof(argbuf));
size_t ram_quota = Arg_string::find_arg(argbuf, "ram_quota").ulong_value(0);
return retry<Parent::Quota_exceeded>([&] () {
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota",
String<32>(Number_of_bytes(ram_quota)).string());
Session_capability cap =
_parent.session(id, name, Parent::Session_args(argbuf), affinity);
if (cap.valid())
return cap;
_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.
*/
if (ram_quota > ram().avail()) {
/* issue resource request */
char buf[128];
snprintf(buf, sizeof(buf), "ram_quota=%lu", ram_quota);
_parent.resource_request(Parent::Resource_args(buf));
} else {
ram_quota += 4096;
}
}, NUM_ATTEMPTS);
warning("giving up to increase session quota for ", name.string(), " session "
"after ", (int)NUM_ATTEMPTS, " attempts");
throw Parent::Quota_exceeded();
}
void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override

View File

@ -186,7 +186,7 @@ void Root_proxy::_handle_session_request(Xml_node request)
catch (Root::Invalid_args) {
_env.parent().session_response(id, Parent::INVALID_ARGS); }
catch (Root::Quota_exceeded) {
_env.parent().session_response(id, Parent::INVALID_ARGS); }
_env.parent().session_response(id, Parent::QUOTA_EXCEEDED); }
catch (Root::Unavailable) {
_env.parent().session_response(id, Parent::INVALID_ARGS); }
}

View File

@ -32,6 +32,7 @@ struct Formatted_phase
switch (_phase) {
case State::CREATE_REQUESTED: print(output, "CREATE_REQUESTED"); break;
case State::INVALID_ARGS: print(output, "INVALID_ARGS"); break;
case State::QUOTA_EXCEEDED: print(output, "QUOTA_EXCEEDED"); 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;
@ -86,6 +87,7 @@ void Session_state::generate_session_request(Xml_generator &xml) const
break;
case INVALID_ARGS:
case QUOTA_EXCEEDED:
case AVAILABLE:
case CAP_HANDED_OUT:
case CLOSED:

View File

@ -51,6 +51,8 @@ class Launchpad_child : public Genode::Child_policy,
Genode::Env &_env;
Genode::Allocator &_alloc;
Genode::Ram_session_capability _ref_ram_cap;
Genode::Ram_session_client _ref_ram { _ref_ram_cap };
Genode::size_t const _ram_quota;
@ -88,6 +90,7 @@ class Launchpad_child : public Genode::Child_policy,
public:
Launchpad_child(Genode::Env &env,
Genode::Allocator &alloc,
Genode::Session_label const &label,
Binary_name const &elf_name,
Genode::size_t ram_quota,
@ -96,7 +99,8 @@ class Launchpad_child : public Genode::Child_policy,
Genode::Dataspace_capability config_ds)
:
_name(label), _elf_name(elf_name),
_env(env), _ref_ram_cap(env.ram_session_cap()), _ram_quota(ram_quota),
_env(env), _alloc(alloc),
_ref_ram_cap(env.ram_session_cap()), _ram_quota(ram_quota),
_parent_services(parent_services),
_child_services(child_services),
_session_requester(env.ep().rpc_ep(), _env.ram(), _env.rm()),
@ -112,7 +116,7 @@ class Launchpad_child : public Genode::Child_policy,
_child_services.for_each(
[&] (Child_service &service) {
if (service.has_id_space(_session_requester.id_space()))
Genode::destroy(_child.heap(), &service); });
Genode::destroy(_alloc, &service); });
}
@ -188,7 +192,7 @@ class Launchpad_child : public Genode::Child_policy,
return;
}
new (_child.heap())
new (_alloc)
Child_service(_child_services, _session_requester.id_space(),
_child.session_factory(), service_name,
_child.ram_session_cap(), *this);

View File

@ -154,7 +154,15 @@ Launchpad_child *Launchpad::start_child(Launchpad_child::Name const &binary_name
if (ram_quota > _env.ram().avail()) {
error("child's ram quota is higher than our available quota, using available quota");
ram_quota = _env.ram().avail() - 256*1000;
size_t const avail = _env.ram().avail();
size_t const preserved = 256*1024;
if (avail < preserved) {
error("giving up, our own quota is too low (", avail, ")");
return 0;
}
ram_quota = avail - preserved;
}
size_t metadata_size = 4096*16 + sizeof(Launchpad_child);
@ -168,7 +176,7 @@ Launchpad_child *Launchpad::start_child(Launchpad_child::Name const &binary_name
try {
Launchpad_child *c = new (&_sliced_heap)
Launchpad_child(_env, unique_name, binary_name, ram_quota,
Launchpad_child(_env, _heap, unique_name, binary_name, ram_quota,
_parent_services, _child_services, config_ds);
Lock::Guard lock_guard(_children_lock);

View File

@ -26,7 +26,7 @@ struct Hello::Connection : Genode::Connection<Session>, Session_client
:
/* create session */
Genode::Connection<Hello::Session>(env, session(env.parent(),
"ram_quota=4K")),
"ram_quota=6K")),
/* initialize RPC interface */
Session_client(cap()) { }

View File

@ -31,7 +31,7 @@ struct Audio_in::Connection : Genode::Connection<Session>, Audio_in::Session_cli
Capability<Audio_in::Session> _session(Genode::Parent &parent, char const *channel)
{
return session(parent, "ram_quota=%ld, channel=\"%s\"",
2*4096 + sizeof(Stream), channel);
10*1024 + sizeof(Stream), channel);
}
/**

View File

@ -31,7 +31,7 @@ struct Audio_out::Connection : Genode::Connection<Session>, Audio_out::Session_c
Capability<Audio_out::Session> _session(Genode::Parent &parent, char const *channel)
{
return session(parent, "ram_quota=%ld, channel=\"%s\"",
2*4096 + sizeof(Stream), channel);
2*4096 + 2048 + sizeof(Stream), channel);
}
/**

View File

@ -31,7 +31,7 @@ struct Block::Connection : Genode::Connection<Session>, Session_client
char const *label, Genode::size_t tx_buf_size)
{
return session(parent, "ram_quota=%ld, tx_buf_size=%ld, label=\"%s\"",
3*4096 + tx_buf_size, tx_buf_size, label);
14*1024 + tx_buf_size, tx_buf_size, label);
}
/**

View File

@ -339,6 +339,8 @@ class Init::Child : Child_policy, Child_service::Wakeup
Env &_env;
Allocator &_alloc;
Verbose const &_verbose;
Id const _id;
@ -424,9 +426,7 @@ class Init::Child : Child_policy, Child_service::Wakeup
/*
* If the configured RAM quota exceeds our own quota, we donate
* all remaining quota to the child but we need to count in
* our allocation of the child meta data from the heap.
* Hence, we preserve some of our own quota.
* all remaining quota to the child.
*/
if (ram_quota > ram_avail) {
ram_quota = ram_avail;
@ -506,12 +506,18 @@ class Init::Child : Child_policy, Child_service::Wakeup
/**
* Constructor
*
* \param alloc allocator solely used for configuration-dependent
* allocations. It is not used for allocations on behalf
* of the child's behavior.
*
*
* \throw Ram_session::Alloc_failed allocation of config buffer failed
* \throw Region_map::Attach_failed failed to temporarily attach
* config dataspace to local address
* space
*/
Child(Env &env,
Allocator &alloc,
Verbose const &verbose,
Id id,
Report_update_trigger &report_update_trigger,
@ -523,7 +529,7 @@ class Init::Child : Child_policy, Child_service::Wakeup
Registry<Parent_service> &parent_services,
Registry<Routed_service> &child_services)
:
_env(env), _verbose(verbose), _id(id),
_env(env), _alloc(alloc), _verbose(verbose), _id(id),
_report_update_trigger(report_update_trigger),
_list_element(this),
_start_node(start_node),
@ -567,24 +573,21 @@ class Init::Child : Child_policy, Child_service::Wakeup
if (_verbose.enabled())
log(" provides service ", Cstring(name));
new (_child.heap())
new (_alloc)
Routed_service(child_services, this->name(),
_session_requester.id_space(),
_child.session_factory(),
name, _child.ram_session_cap(), *this);
}
}
catch (Xml_node::Nonexistent_sub_node) { }
catch (Genode::Child::Inactive) {
error(this->name(), ": incomplete environment at construction time"); }
}
virtual ~Child()
{
_child_services.for_each([&] (Routed_service &service) {
if (service.has_id_space(_session_requester.id_space()))
destroy(_child.heap(), &service); });
destroy(_alloc, &service); });
}
/**

View File

@ -27,7 +27,7 @@ struct Input::Connection : Genode::Connection<Session>, Session_client
* \noapi
*/
Capability<Input::Session> _session(Genode::Parent &parent, char const *label) {
return session(parent, "ram_quota=16K, label=\"%s\"", label); }
return session(parent, "ram_quota=18K, label=\"%s\"", label); }
/**
* Constructor
@ -48,7 +48,7 @@ struct Input::Connection : Genode::Connection<Session>, Session_client
Connection() __attribute__((deprecated))
:
Genode::Connection<Input::Session>(
session(*Genode::env_deprecated()->parent(), "ram_quota=16K")),
session(*Genode::env_deprecated()->parent(), "ram_quota=18K")),
Session_client(*Genode::env_deprecated()->rm_session(), cap())
{ }
};

View File

@ -194,6 +194,7 @@ class Genode::Child_policy_dynamic_rom_file : public Rpc_object<Rom_session>,
break;
case Session_state::INVALID_ARGS:
case Session_state::QUOTA_EXCEEDED:
case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED:

View File

@ -213,6 +213,7 @@ class Genode::Slave::Connection_base
break;
case Session_state::INVALID_ARGS:
case Session_state::QUOTA_EXCEEDED:
case Session_state::AVAILABLE:
case Session_state::CAP_HANDED_OUT:
case Session_state::CLOSED:

View File

@ -27,7 +27,7 @@ struct Platform::Connection : Genode::Connection<Session>, Client
* Constructor
*/
Connection(Genode::Env &env)
: Genode::Connection<Session>(env, session(env.parent(), "ram_quota=4K")),
: Genode::Connection<Session>(env, session(env.parent(), "ram_quota=6K")),
Client(cap()) { }
/**
@ -38,7 +38,7 @@ struct Platform::Connection : Genode::Connection<Session>, Client
* argument instead
*/
Connection() __attribute__((deprecated))
: Genode::Connection<Session>(session("ram_quota=4K")),
: Genode::Connection<Session>(session("ram_quota=6K")),
Client(cap()) { }
};

View File

@ -22,7 +22,7 @@ namespace Report { struct Connection; }
struct Report::Connection : Genode::Connection<Session>, Session_client
{
enum { RAM_QUOTA = 4*4096 }; /* value used for 'Slave::Connection' */
enum { RAM_QUOTA = 6*4096 }; /* value used for 'Slave::Connection' */
/**
* Issue session request
@ -33,7 +33,7 @@ struct Report::Connection : Genode::Connection<Session>, Session_client
char const *label, size_t buffer_size)
{
return session(parent, "label=\"%s\", ram_quota=%ld, buffer_size=%zd",
label, 2*4096 + buffer_size, buffer_size);
label, 10*1024 + buffer_size, buffer_size);
}
/**

View File

@ -28,7 +28,7 @@ struct Rtc::Connection : Genode::Connection<Session>, Session_client
*/
Connection(Genode::Env &env)
:
Genode::Connection<Rtc::Session>(env, session(env.parent(), "ram_quota=4K")),
Genode::Connection<Rtc::Session>(env, session(env.parent(), "ram_quota=8K")),
Session_client(cap())
{ }
@ -41,7 +41,7 @@ struct Rtc::Connection : Genode::Connection<Session>, Session_client
*/
Connection() __attribute__((deprecated))
:
Genode::Connection<Rtc::Session>(session("ram_quota=4K")),
Genode::Connection<Rtc::Session>(session("ram_quota=8K")),
Session_client(cap())
{ }
};

View File

@ -51,7 +51,7 @@ struct Terminal::Connection : Genode::Connection<Session>, Session_client
:
Genode::Connection<Session>(env, session(env.parent(),
"ram_quota=%ld, label=\"%s\"",
2*4096, label)),
10*1024, label)),
Session_client(env.rm(), cap())
{
wait_for_connection(cap());

View File

@ -40,7 +40,7 @@ class Timer::Connection : public Genode::Connection<Session>, public Session_cli
*/
Connection(Genode::Env &env, char const *label = "")
:
Genode::Connection<Session>(env, session(env.parent(), "ram_quota=8K, label=\"%s\"", label)),
Genode::Connection<Session>(env, session(env.parent(), "ram_quota=10K, label=\"%s\"", label)),
Session_client(cap())
{
/* register default signal handler */
@ -56,7 +56,7 @@ class Timer::Connection : public Genode::Connection<Session>, public Session_cli
*/
Connection() __attribute__((deprecated))
:
Genode::Connection<Session>(session("ram_quota=8K")),
Genode::Connection<Session>(session("ram_quota=10K")),
Session_client(cap())
{
/* register default signal handler */

View File

@ -70,7 +70,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=12288, buffer_size=4096)
[init -> test-report_rom] Error: Report-session creation failed (label="brightness", ram_quota=14336, buffer_size=4096)
[init -> test-report_rom] ROM client: catched Parent::Service_denied - OK
[init -> test-report_rom] --- test-report_rom finished ---
}

View File

@ -486,7 +486,7 @@ void Init::Main::_handle_config()
try {
_children.insert(new (_heap)
Init::Child(_env, *_verbose,
Init::Child(_env, _heap, *_verbose,
Init::Child::Id { ++_child_cnt },
_state_reporter,
start_node, default_route_node,