/* * \brief PD-session client that issues resource requests on demand * \author Norman Feske * \date 2013-09-25 */ /* * Copyright (C) 2006-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _INCLUDE__BASE__INTERNAL__EXPANDING_PD_SESSION_CLIENT_H_ #define _INCLUDE__BASE__INTERNAL__EXPANDING_PD_SESSION_CLIENT_H_ /* Genode includes */ #include #include namespace Genode { class Expanding_pd_session_client; } struct Genode::Expanding_pd_session_client : Pd_session_client { Parent &_parent; void _request_ram_from_parent(size_t amount) { _parent.resource_request(String<128>("ram_quota=", amount).string()); } void _request_caps_from_parent(size_t amount) { _parent.resource_request(String<128>("cap_quota=", amount).string()); } Expanding_pd_session_client(Parent &parent, Pd_session_capability cap) : Pd_session_client(cap), _parent(parent) { } Ram_dataspace_capability alloc(size_t size, Cache_attribute cached = UNCACHED) override { /* * If the RAM session runs out of quota, issue a resource request * to the parent and retry. */ enum { NUM_ATTEMPTS = 10 }; enum { UPGRADE_CAPS = 4 }; return retry( [&] () { return retry( [&] () { return Pd_session_client::alloc(size, cached); }, [&] () { 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 * from the RAM quota. In the worst case, a new slab block * may be needed. To cover the worst case, we need to take * this possible overhead into account when requesting * additional RAM quota from the parent. * * Because the worst case almost never happens, we request * a bit too much quota for the most time. */ enum { OVERHEAD = 4096UL }; _request_ram_from_parent(size + OVERHEAD); }, NUM_ATTEMPTS); } void transfer_quota(Pd_session_capability pd_session, Ram_quota amount) override { /* * Should the transfer fail because we don't have enough quota, request * the needed amount from the parent. */ enum { NUM_ATTEMPTS = 2 }; retry( [&] () { Pd_session_client::transfer_quota(pd_session, amount); }, [&] () { _request_ram_from_parent(amount.value); }, NUM_ATTEMPTS); } void transfer_quota(Pd_session_capability pd_session, Cap_quota amount) override { enum { NUM_ATTEMPTS = 2 }; retry( [&] () { Pd_session_client::transfer_quota(pd_session, amount); }, [&] () { _request_caps_from_parent(amount.value); }, NUM_ATTEMPTS); } }; #endif /* _INCLUDE__BASE__INTERNAL__EXPANDING_PD_SESSION_CLIENT_H_ */