diff --git a/base/include/ram_session/ram_session.h b/base/include/ram_session/ram_session.h
index 4e65bddf49..15a8adf812 100644
--- a/base/include/ram_session/ram_session.h
+++ b/base/include/ram_session/ram_session.h
@@ -77,7 +77,7 @@ namespace Genode {
virtual int ref_account(Ram_session_capability ram_session) = 0;
/**
- * Transfer quota the another ram session
+ * Transfer quota to another RAM session
*
* \param ram_session receiver of quota donation
* \param amount amount of quota to donate
diff --git a/os/src/server/loader/child.h b/os/src/server/loader/child.h
index 13c0192c41..d1602add2f 100644
--- a/os/src/server/loader/child.h
+++ b/os/src/server/loader/child.h
@@ -44,7 +44,9 @@ namespace Loader {
Cpu_connection cpu;
Rm_connection rm;
- Resources(char const *label, size_t ram_quota)
+ Resources(char const *label,
+ Ram_session_client &ram_session_client,
+ size_t ram_quota)
: ram(label), cpu(label)
{
/* deduce session costs from usable ram quota */
@@ -56,8 +58,8 @@ namespace Loader {
ram_quota -= session_donations;
else ram_quota = 0;
- ram.ref_account(env()->ram_session_cap());
- env()->ram_session()->transfer_quota(ram.cap(), ram_quota);
+ ram.ref_account(ram_session_client);
+ ram_session_client.transfer_quota(ram.cap(), ram_quota);
}
} _resources;
@@ -87,6 +89,7 @@ namespace Loader {
Child(const char *binary_name,
const char *label,
Rpc_entrypoint &ep,
+ Ram_session_client &ram_session_client,
size_t ram_quota,
Service_registry &parent_services,
Service &local_rom_service,
@@ -95,7 +98,7 @@ namespace Loader {
:
_label(label),
_ep(ep),
- _resources(_label.string, ram_quota),
+ _resources(_label.string, ram_session_client, ram_quota),
_parent_services(parent_services),
_local_nitpicker_service(local_nitpicker_service),
_local_rom_service(local_rom_service),
diff --git a/os/src/server/loader/main.cc b/os/src/server/loader/main.cc
index bc03576c27..81e3945b8d 100644
--- a/os/src/server/loader/main.cc
+++ b/os/src/server/loader/main.cc
@@ -13,6 +13,7 @@
/* Genode includes */
#include
+#include
#include
#include
#include
@@ -24,6 +25,7 @@
/* local includes */
#include
#include
+#include
#include
@@ -39,6 +41,7 @@ namespace Loader {
struct Local_rom_service : Service
{
Rpc_entrypoint &_ep;
+ Allocator &_md_alloc;
Parent_service _parent_rom_service;
Rom_module_registry &_rom_modules;
Lock _lock;
@@ -47,15 +50,17 @@ namespace Loader {
void _close(Rom_session_component *rom)
{
_ep.dissolve(rom);
- destroy(env()->heap(), rom);
+ destroy(&_md_alloc, rom);
_rom_sessions.remove(rom);
}
Local_rom_service(Rpc_entrypoint &ep,
+ Allocator &md_alloc,
Rom_module_registry &rom_modules)
:
Service("virtual_rom"),
_ep(ep),
+ _md_alloc(md_alloc),
_parent_rom_service(Rom_session::service_name()),
_rom_modules(rom_modules)
{ }
@@ -82,7 +87,7 @@ namespace Loader {
Rom_module &module = _rom_modules.lookup_and_lock(name);
- Rom_session_component *rom = new (env()->heap())
+ Rom_session_component *rom = new (&_md_alloc)
Rom_session_component(module);
_rom_sessions.insert(rom);
@@ -118,14 +123,19 @@ namespace Loader {
struct Local_nitpicker_service : Service
{
Rpc_entrypoint &ep;
+ Allocator &_md_alloc;
Signal_context_capability view_ready_sigh;
Nitpicker::Session_component *open_session;
- Local_nitpicker_service(Rpc_entrypoint &ep)
+ Local_nitpicker_service(Rpc_entrypoint &ep,
+ Allocator &md_alloc)
:
- Service("virtual_nitpicker"), ep(ep), open_session(0)
+ Service("virtual_nitpicker"),
+ ep(ep),
+ _md_alloc(md_alloc),
+ open_session(0)
{ }
~Local_nitpicker_service()
@@ -134,7 +144,7 @@ namespace Loader {
return;
ep.dissolve(open_session);
- destroy(env()->heap(), open_session);
+ destroy(&_md_alloc, open_session);
}
Genode::Session_capability session(const char *args)
@@ -142,11 +152,7 @@ namespace Loader {
if (open_session)
throw Unavailable();
- /*
- * XXX replace allocation from 'env()->heap()' with
- * use of session-specific allocator
- */
- open_session = new (env()->heap())
+ open_session = new (&_md_alloc)
Nitpicker::Session_component(ep, view_ready_sigh, args);
return ep.manage(open_session);
@@ -158,6 +164,8 @@ namespace Loader {
enum { STACK_SIZE = 2*4096 };
size_t _ram_quota;
+ Ram_session_client_guard _ram_session_client;
+ Heap _md_alloc;
size_t _subsystem_ram_quota_limit;
int _width, _height;
Rpc_entrypoint _ep;
@@ -186,19 +194,21 @@ namespace Loader {
Session_component(size_t quota, Ram_session &ram, Cap_session &cap)
:
_ram_quota(quota),
- _subsystem_ram_quota_limit(~0),
+ _ram_session_client(env()->ram_session_cap(), _ram_quota),
+ _md_alloc(&_ram_session_client, env()->rm_session()),
+ _subsystem_ram_quota_limit(0),
_width(-1), _height(-1),
_ep(&cap, STACK_SIZE, "session_ep"),
- _rom_modules(ram, *env()->heap()), /* XXX remove env()->heap() */
- _rom_service(_ep, _rom_modules),
- _nitpicker_service(_ep),
+ _rom_modules(_ram_session_client, _md_alloc),
+ _rom_service(_ep, _md_alloc, _rom_modules),
+ _nitpicker_service(_ep, _md_alloc),
_child(0)
{ }
~Session_component()
{
if (_child)
- destroy(env()->heap(), _child);
+ destroy(&_md_alloc, _child);
}
@@ -241,18 +251,14 @@ namespace Loader {
return;
}
- /*
- * XXX account for ROM modules
- */
- size_t const ram_quota = _subsystem_ram_quota_limit;
+ size_t const ram_quota = (_subsystem_ram_quota_limit > 0) ?
+ min(_subsystem_ram_quota_limit, _ram_session_client.avail()) :
+ _ram_session_client.avail();
- /*
- * XXX don't use 'env()->heap()'
- */
- _child = new (env()->heap())
+ _child = new (&_md_alloc)
Child(binary_name.string(), label.string(), _ep,
- ram_quota, _parent_services, _rom_service,
- _nitpicker_service, _width, _height);
+ _ram_session_client, ram_quota, _parent_services,
+ _rom_service, _nitpicker_service, _width, _height);
}
Nitpicker::View_capability view()
diff --git a/os/src/server/loader/ram_session_client_guard.h b/os/src/server/loader/ram_session_client_guard.h
new file mode 100644
index 0000000000..e97d39a5d7
--- /dev/null
+++ b/os/src/server/loader/ram_session_client_guard.h
@@ -0,0 +1,94 @@
+/*
+ * \brief A guard for RAM session clients to limit memory exhaustion
+ * \author Christian Prochaska
+ * \date 2012-04-25
+ */
+
+/*
+ * Copyright (C) 2012 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#ifndef _RAM_SESSION_CLIENT_GUARD_H_
+#define _RAM_SESSION_CLIENT_GUARD_H_
+
+#include
+#include
+#include
+#include
+
+namespace Genode {
+
+ class Ram_session_client_guard : public Ram_session_client
+ {
+ private:
+
+ size_t _amount; /* total amount */
+ size_t _consumed; /* already consumed bytes */
+ Lock _consumed_lock;
+
+ public:
+
+ Ram_session_client_guard(Ram_session_capability session, size_t amount)
+ : Ram_session_client(session), _amount(amount), _consumed(0) { }
+
+ Ram_dataspace_capability alloc(size_t size)
+ {
+ Lock::Guard _consumed_lock_guard(_consumed_lock);
+
+ if ((_amount - _consumed) < size) {
+ PWRN("Quota exceeded! amount=%zu, size=%zu, consumed=%zu",
+ _amount, size, _consumed);
+ return Ram_dataspace_capability();
+ }
+
+ Ram_dataspace_capability cap = Ram_session_client::alloc(size);
+
+ _consumed += size;
+
+ return cap;
+ }
+
+ void free(Ram_dataspace_capability ds)
+ {
+ Lock::Guard _consumed_lock_guard(_consumed_lock);
+
+ _consumed -= Dataspace_client(ds).size();
+
+ Ram_session_client::free(ds);
+ }
+
+ int transfer_quota(Ram_session_capability ram_session, size_t amount)
+ {
+ Lock::Guard _consumed_lock_guard(_consumed_lock);
+
+ if ((_amount - _consumed) < amount) {
+ PWRN("Quota exceeded! amount=%zu, size=%zu, consumed=%zu",
+ _amount, amount, _consumed);
+ return -1;
+ }
+
+ int result = Ram_session_client::transfer_quota(ram_session, amount);
+
+ if (result == 0)
+ _consumed += amount;
+
+ return result;
+ }
+
+ size_t quota()
+ {
+ return _amount;
+ }
+
+ size_t used()
+ {
+ Lock::Guard _consumed_lock_guard(_consumed_lock);
+ return _consumed;
+ }
+ };
+}
+
+#endif /* _RAM_SESSION_CLIENT_GUARD_H_ */