diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index c23683c5cb..b6dab9deb1 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -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, /* sessions opened by the child */ Id_space _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, void _try_construct_env_dependent_members(); - /* heap for child-specific allocations using the child's quota */ - Constructible _heap; - - /* factory for dynamically created session-state objects */ - Constructible _session_factory; - Constructible _initial_thread; struct Process @@ -584,11 +596,6 @@ class Genode::Child : protected Rpc_object, 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, 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 diff --git a/repos/base/include/base/local_connection.h b/repos/base/include/base/local_connection.h index c45b917cc1..2fbb7ce32d 100644 --- a/repos/base/include/base/local_connection.h +++ b/repos/base/include/base/local_connection.h @@ -35,7 +35,7 @@ struct Genode::Local_connection_base : Noncopyable protected: - Session_state _session_state; + Constructible _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 cap() const { - return reinterpret_cap_cast(_session_state.cap); + return reinterpret_cap_cast(_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_state.local_ptr); + if (_session_state->local_ptr) + return *static_cast(_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(); } diff --git a/repos/base/include/base/service.h b/repos/base/include/base/service.h index e9207e3ddf..200df961ae 100644 --- a/repos/base/include/base/service.h +++ b/repos/base/include/base/service.h @@ -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: diff --git a/repos/base/include/base/session_state.h b/repos/base/include/base/session_state.h index 6ef8b66661..2f956e0670 100644 --- a/repos/base/include/base/session_state.h +++ b/repos/base/include/base/session_state.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -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 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); } }; diff --git a/repos/base/include/base/slab.h b/repos/base/include/base/slab.h index b4a7be6133..9f16664e48 100644 --- a/repos/base/include/base/slab.h +++ b/repos/base/include/base/slab.h @@ -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 * diff --git a/repos/base/include/io_mem_session/connection.h b/repos/base/include/io_mem_session/connection.h index 7ac62ff531..779e92a7b2 100644 --- a/repos/base/include/io_mem_session/connection.h +++ b/repos/base/include/io_mem_session/connection.h @@ -30,7 +30,7 @@ struct Genode::Io_mem_connection : Connection, Io_mem_session_cl Capability _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"); } diff --git a/repos/base/include/io_port_session/connection.h b/repos/base/include/io_port_session/connection.h index 1a2af2edf2..31eaf1749e 100644 --- a/repos/base/include/io_port_session/connection.h +++ b/repos/base/include/io_port_session/connection.h @@ -30,7 +30,7 @@ struct Genode::Io_port_connection : Connection, */ Capability _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); } diff --git a/repos/base/include/irq_session/connection.h b/repos/base/include/irq_session/connection.h index 3c961ac6a1..4a8cf21c02 100644 --- a/repos/base/include/irq_session/connection.h +++ b/repos/base/include/irq_session/connection.h @@ -32,7 +32,7 @@ struct Genode::Irq_connection : Connection, 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); } diff --git a/repos/base/include/parent/parent.h b/repos/base/include/parent/parent.h index 76c20c2d59..9e598d4d47 100644 --- a/repos/base/include/parent/parent.h +++ b/repos/base/include/parent/parent.h @@ -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 diff --git a/repos/base/include/rom_session/connection.h b/repos/base/include/rom_session/connection.h index 2eed9c43cf..0dd66f0d91 100644 --- a/repos/base/include/rom_session/connection.h +++ b/repos/base/include/rom_session/connection.h @@ -28,7 +28,7 @@ class Genode::Rom_connection : public Connection, class Rom_connection_failed : public Parent::Exception { }; - enum { RAM_QUOTA = 4096UL }; + enum { RAM_QUOTA = 6*1024UL }; private: diff --git a/repos/base/include/root/component.h b/repos/base/include/root/component.h index d3041cf4e9..81ef7d2d4f 100644 --- a/repos/base/include/root/component.h +++ b/repos/base/include/root/component.h @@ -130,8 +130,9 @@ class Genode::Root_component : public Rpc_object >, 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 >, { try { return _create(args, affinity); } + catch (Root::Quota_exceeded) { throw Service::Quota_exceeded(); } catch (...) { throw typename Local_service::Factory::Denied(); } } diff --git a/repos/base/include/trace_session/connection.h b/repos/base/include/trace_session/connection.h index e8d14b1848..233b40cd3b 100644 --- a/repos/base/include/trace_session/connection.h +++ b/repos/base/include/trace_session/connection.h @@ -35,7 +35,7 @@ struct Genode::Trace::Connection : Genode::Connection, { 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); } /** diff --git a/repos/base/src/core/main.cc b/repos/base/src/core/main.cc index 1ba2580ed1..fa4d9724b4 100644 --- a/repos/base/src/core/main.cc +++ b/repos/base/src/core/main.cc @@ -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; } }; diff --git a/repos/base/src/include/base/internal/expanding_parent_client.h b/repos/base/src/include/base/internal/expanding_parent_client.h index 6ef975c2fe..c347513887 100644 --- a/repos/base/src/include/base/internal/expanding_parent_client.h +++ b/repos/base/src/include/base/internal/expanding_parent_client.h @@ -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( - [&] () { 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 diff --git a/repos/base/src/lib/base/child.cc b/repos/base/src/lib/base/child.cc index 4dc2052ea9..d9351af9c0 100644 --- a/repos/base/src/lib/base/child.cc +++ b/repos/base/src/lib/base/child.cc @@ -142,9 +142,15 @@ void Child::session_sigh(Signal_context_capability sigh) * needs asynchronous handling. */ _id_space.for_each([&] (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(); } diff --git a/repos/base/src/lib/base/component.cc b/repos/base/src/lib/base/component.cc index afc190547e..0e0b7dff4a 100644 --- a/repos/base/src/lib/base/component.cc +++ b/repos/base/src/lib/base/component.cc @@ -13,6 +13,7 @@ */ /* Genode includes */ +#include #include #include #include @@ -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([&] () { + + 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 diff --git a/repos/base/src/lib/base/root_proxy.cc b/repos/base/src/lib/base/root_proxy.cc index 23472ab720..78d485bd72 100644 --- a/repos/base/src/lib/base/root_proxy.cc +++ b/repos/base/src/lib/base/root_proxy.cc @@ -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); } } diff --git a/repos/base/src/lib/base/session_state.cc b/repos/base/src/lib/base/session_state.cc index 330335285f..3d31e91113 100644 --- a/repos/base/src/lib/base/session_state.cc +++ b/repos/base/src/lib/base/session_state.cc @@ -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: diff --git a/repos/demo/include/launchpad/launchpad.h b/repos/demo/include/launchpad/launchpad.h index 6195847844..f424b2065a 100644 --- a/repos/demo/include/launchpad/launchpad.h +++ b/repos/demo/include/launchpad/launchpad.h @@ -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); diff --git a/repos/demo/src/lib/launchpad/launchpad.cc b/repos/demo/src/lib/launchpad/launchpad.cc index e3d4356a44..d1c7a14073 100644 --- a/repos/demo/src/lib/launchpad/launchpad.cc +++ b/repos/demo/src/lib/launchpad/launchpad.cc @@ -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); diff --git a/repos/hello_tutorial/include/hello_session/connection.h b/repos/hello_tutorial/include/hello_session/connection.h index dffb9a3934..cce2b502fb 100644 --- a/repos/hello_tutorial/include/hello_session/connection.h +++ b/repos/hello_tutorial/include/hello_session/connection.h @@ -26,7 +26,7 @@ struct Hello::Connection : Genode::Connection, Session_client : /* create session */ Genode::Connection(env, session(env.parent(), - "ram_quota=4K")), + "ram_quota=6K")), /* initialize RPC interface */ Session_client(cap()) { } diff --git a/repos/os/include/audio_in_session/connection.h b/repos/os/include/audio_in_session/connection.h index 3977be6291..dbde2e0fb9 100644 --- a/repos/os/include/audio_in_session/connection.h +++ b/repos/os/include/audio_in_session/connection.h @@ -31,7 +31,7 @@ struct Audio_in::Connection : Genode::Connection, Audio_in::Session_cli Capability _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); } /** diff --git a/repos/os/include/audio_out_session/connection.h b/repos/os/include/audio_out_session/connection.h index e12df105b5..ca3a2b298c 100644 --- a/repos/os/include/audio_out_session/connection.h +++ b/repos/os/include/audio_out_session/connection.h @@ -31,7 +31,7 @@ struct Audio_out::Connection : Genode::Connection, Audio_out::Session_c Capability _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); } /** diff --git a/repos/os/include/block_session/connection.h b/repos/os/include/block_session/connection.h index 2713e2ae20..d821968949 100644 --- a/repos/os/include/block_session/connection.h +++ b/repos/os/include/block_session/connection.h @@ -31,7 +31,7 @@ struct Block::Connection : Genode::Connection, 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); } /** diff --git a/repos/os/include/init/child.h b/repos/os/include/init/child.h index 1dc75e7b3d..d9639207fe 100644 --- a/repos/os/include/init/child.h +++ b/repos/os/include/init/child.h @@ -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_services, Registry &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); }); } /** diff --git a/repos/os/include/input_session/connection.h b/repos/os/include/input_session/connection.h index c395f593cc..d7982d7641 100644 --- a/repos/os/include/input_session/connection.h +++ b/repos/os/include/input_session/connection.h @@ -27,7 +27,7 @@ struct Input::Connection : Genode::Connection, Session_client * \noapi */ Capability _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_client Connection() __attribute__((deprecated)) : Genode::Connection( - session(*Genode::env_deprecated()->parent(), "ram_quota=16K")), + session(*Genode::env_deprecated()->parent(), "ram_quota=18K")), Session_client(*Genode::env_deprecated()->rm_session(), cap()) { } }; diff --git a/repos/os/include/os/child_policy_dynamic_rom.h b/repos/os/include/os/child_policy_dynamic_rom.h index 7790a6232f..c957236b59 100644 --- a/repos/os/include/os/child_policy_dynamic_rom.h +++ b/repos/os/include/os/child_policy_dynamic_rom.h @@ -194,6 +194,7 @@ class Genode::Child_policy_dynamic_rom_file : public Rpc_object, 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: diff --git a/repos/os/include/os/slave.h b/repos/os/include/os/slave.h index 29662a2fe4..a48181eacb 100644 --- a/repos/os/include/os/slave.h +++ b/repos/os/include/os/slave.h @@ -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: diff --git a/repos/os/include/platform_session/connection.h b/repos/os/include/platform_session/connection.h index f02780806d..ab7967d80d 100644 --- a/repos/os/include/platform_session/connection.h +++ b/repos/os/include/platform_session/connection.h @@ -27,7 +27,7 @@ struct Platform::Connection : Genode::Connection, Client * Constructor */ Connection(Genode::Env &env) - : Genode::Connection(env, session(env.parent(), "ram_quota=4K")), + : Genode::Connection(env, session(env.parent(), "ram_quota=6K")), Client(cap()) { } /** @@ -38,7 +38,7 @@ struct Platform::Connection : Genode::Connection, Client * argument instead */ Connection() __attribute__((deprecated)) - : Genode::Connection(session("ram_quota=4K")), + : Genode::Connection(session("ram_quota=6K")), Client(cap()) { } }; diff --git a/repos/os/include/report_session/connection.h b/repos/os/include/report_session/connection.h index 1498a012e3..58b5198558 100644 --- a/repos/os/include/report_session/connection.h +++ b/repos/os/include/report_session/connection.h @@ -22,7 +22,7 @@ namespace Report { struct Connection; } struct Report::Connection : Genode::Connection, 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_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); } /** diff --git a/repos/os/include/rtc_session/connection.h b/repos/os/include/rtc_session/connection.h index 4836f0cd83..6c1791ff44 100644 --- a/repos/os/include/rtc_session/connection.h +++ b/repos/os/include/rtc_session/connection.h @@ -28,7 +28,7 @@ struct Rtc::Connection : Genode::Connection, Session_client */ Connection(Genode::Env &env) : - Genode::Connection(env, session(env.parent(), "ram_quota=4K")), + Genode::Connection(env, session(env.parent(), "ram_quota=8K")), Session_client(cap()) { } @@ -41,7 +41,7 @@ struct Rtc::Connection : Genode::Connection, Session_client */ Connection() __attribute__((deprecated)) : - Genode::Connection(session("ram_quota=4K")), + Genode::Connection(session("ram_quota=8K")), Session_client(cap()) { } }; diff --git a/repos/os/include/terminal_session/connection.h b/repos/os/include/terminal_session/connection.h index dd682e55e9..555ac13e1a 100644 --- a/repos/os/include/terminal_session/connection.h +++ b/repos/os/include/terminal_session/connection.h @@ -51,7 +51,7 @@ struct Terminal::Connection : Genode::Connection, Session_client : Genode::Connection(env, session(env.parent(), "ram_quota=%ld, label=\"%s\"", - 2*4096, label)), + 10*1024, label)), Session_client(env.rm(), cap()) { wait_for_connection(cap()); diff --git a/repos/os/include/timer_session/connection.h b/repos/os/include/timer_session/connection.h index e7a81f3b49..b3aad1df8d 100644 --- a/repos/os/include/timer_session/connection.h +++ b/repos/os/include/timer_session/connection.h @@ -40,7 +40,7 @@ class Timer::Connection : public Genode::Connection, public Session_cli */ Connection(Genode::Env &env, char const *label = "") : - Genode::Connection(env, session(env.parent(), "ram_quota=8K, label=\"%s\"", label)), + Genode::Connection(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, public Session_cli */ Connection() __attribute__((deprecated)) : - Genode::Connection(session("ram_quota=8K")), + Genode::Connection(session("ram_quota=10K")), Session_client(cap()) { /* register default signal handler */ diff --git a/repos/os/run/report_rom.run b/repos/os/run/report_rom.run index 039bb4230b..871d4cf30c 100644 --- a/repos/os/run/report_rom.run +++ b/repos/os/run/report_rom.run @@ -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 --- } diff --git a/repos/os/src/init/main.cc b/repos/os/src/init/main.cc index 985462415a..7f19d54b47 100644 --- a/repos/os/src/init/main.cc +++ b/repos/os/src/init/main.cc @@ -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,