diff --git a/repos/base-hw/src/core/env.cc b/repos/base-hw/src/core/env.cc
index cfb2d1517..88d6dfb72 100644
--- a/repos/base-hw/src/core/env.cc
+++ b/repos/base-hw/src/core/env.cc
@@ -18,4 +18,4 @@
#include
-void Genode::upgrade_pd_session_quota(Genode::size_t quota) { assert(false); }
+void Genode::upgrade_pd_quota_non_blocking(Genode::size_t quota) { assert(false); }
diff --git a/repos/base-hw/src/core/spec/arndale/platform_services.cc b/repos/base-hw/src/core/spec/arndale/platform_services.cc
index 32d358a94..94a9959a5 100644
--- a/repos/base-hw/src/core/spec/arndale/platform_services.cc
+++ b/repos/base-hw/src/core/spec/arndale/platform_services.cc
@@ -15,21 +15,21 @@
#include
#include
-/* Core includes */
+/* core includes */
#include
+#include /* for 'Core_service' type */
#include
/*
* Add ARM virtualization specific vm service
*/
-void Genode::platform_add_local_services(Genode::Rpc_entrypoint *ep,
- Genode::Sliced_heap *sh,
- Genode::Service_registry *ls)
+void Genode::platform_add_local_services(Rpc_entrypoint *ep,
+ Sliced_heap *sh,
+ Registry *services)
{
using namespace Genode;
static Vm_root vm_root(ep, sh);
- static Local_service vm_ls(Vm_session::service_name(), &vm_root);
- ls->insert(&vm_ls);
+ static Core_service vm_service(*services, vm_root);
}
diff --git a/repos/base-hw/src/core/spec/imx53/trustzone/platform_services.cc b/repos/base-hw/src/core/spec/imx53/trustzone/platform_services.cc
index 9ce1fc6c8..ccb9ce07b 100644
--- a/repos/base-hw/src/core/spec/imx53/trustzone/platform_services.cc
+++ b/repos/base-hw/src/core/spec/imx53/trustzone/platform_services.cc
@@ -18,19 +18,17 @@
/* Core includes */
#include
#include
+#include
#include
/*
* Add TrustZone specific vm service
*/
-void Genode::platform_add_local_services(Genode::Rpc_entrypoint *ep,
- Genode::Sliced_heap *sh,
- Genode::Service_registry *ls)
+void Genode::platform_add_local_services(Rpc_entrypoint *ep,
+ Sliced_heap *sliced_heap,
+ Registry *local_services)
{
- using namespace Genode;
-
- static Vm_root vm_root(ep, sh);
- static Local_service vm_ls(Vm_session::service_name(), &vm_root);
- ls->insert(&vm_ls);
+ static Vm_root vm_root(ep, sliced_heap);
+ static Core_service vm_service(*local_services, vm_root);
}
diff --git a/repos/base-hw/src/core/spec/x86_64/muen/platform_services.cc b/repos/base-hw/src/core/spec/x86_64/muen/platform_services.cc
index c16100267..3b436ba93 100644
--- a/repos/base-hw/src/core/spec/x86_64/muen/platform_services.cc
+++ b/repos/base-hw/src/core/spec/x86_64/muen/platform_services.cc
@@ -14,7 +14,7 @@
/* Genode includes */
#include
-/* Core includes */
+/* core includes */
#include
#include
#include
@@ -24,18 +24,15 @@
/*
* Add I/O port service and virtualization specific vm service
*/
-void Genode::platform_add_local_services(Genode::Rpc_entrypoint *ep,
- Genode::Sliced_heap *sh,
- Genode::Service_registry *ls)
+void Genode::platform_add_local_services(Rpc_entrypoint *ep,
+ Sliced_heap *sh,
+ Registry *services)
{
- using namespace Genode;
-
static Vm_root vm_root(ep, sh);
- static Local_service vm_ls(Vm_session::service_name(), &vm_root);
+ static Core_service vm_ls(*services, vm_root);
+
static Io_port_root io_port_root(core_env()->pd_session(),
platform()->io_port_alloc(), sh);
- static Local_service io_port_ls(Io_port_session::service_name(),
- &io_port_root);
- ls->insert(&vm_ls);
- ls->insert(&io_port_ls);
+ static Core_service io_port_ls(*services,
+ io_port_root);
}
diff --git a/repos/base-hw/src/include/base/internal/native_env.h b/repos/base-hw/src/include/base/internal/native_env.h
index 9966948ff..40d307949 100644
--- a/repos/base-hw/src/include/base/internal/native_env.h
+++ b/repos/base-hw/src/include/base/internal/native_env.h
@@ -20,9 +20,13 @@
namespace Genode
{
/**
- * Upgrade quota of the PD session within my Genode environment
+ * Upgrade quota of the PD session within my Genode environment non-blocking
+ *
+ * This function doesn't lock the environment when upgrading. This is
+ * needed when doing upgrades in situations where the environment is
+ * already locked due to the operation that triggered the upgrade.
*/
- void upgrade_pd_session_quota(Genode::size_t);
+ void upgrade_pd_quota_non_blocking(size_t);
};
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_ENV_H_ */
diff --git a/repos/base-hw/src/lib/base/env.cc b/repos/base-hw/src/lib/base/env.cc
index ddfdd45e5..c293471c5 100644
--- a/repos/base-hw/src/lib/base/env.cc
+++ b/repos/base-hw/src/lib/base/env.cc
@@ -12,18 +12,14 @@
*/
/* Genode includes */
-#include
#include
/* base-internal includes */
+#include
#include
-
-void Genode::upgrade_pd_session_quota(Genode::size_t quota)
+void Genode::upgrade_pd_quota_non_blocking(size_t quota)
{
- char buf[128];
- snprintf(buf, sizeof(buf), "ram_quota=%lu", quota);
- Pd_session_capability cap =
- *static_cast(env()->pd_session());
- env()->parent()->upgrade(cap, buf);
+ internal_env().parent().upgrade(Parent::Env::pd(),
+ String<64>("ram_quota=", quota).string());
}
diff --git a/repos/base-hw/src/lib/base/ipc.cc b/repos/base-hw/src/lib/base/ipc.cc
index 8603d6469..8787f2542 100644
--- a/repos/base-hw/src/lib/base/ipc.cc
+++ b/repos/base-hw/src/lib/base/ipc.cc
@@ -109,7 +109,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
}
},
- [&] () { upgrade_pd_session_quota(3*4096); });
+ [&] () { upgrade_pd_quota_non_blocking(3 * 1024 * sizeof(addr_t)); });
return Rpc_exception_code(utcb.exception_code());
}
@@ -154,7 +154,7 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &,
default: break;
}
},
- [&] () { upgrade_pd_session_quota(3*4096); });
+ [&] () { upgrade_pd_quota_non_blocking(3 * 1024 * sizeof(addr_t)); });
copy_utcb_to_msg(utcb, request_msg);
diff --git a/repos/base-hw/src/lib/base/signal.cc b/repos/base-hw/src/lib/base/signal.cc
index fc0d5c78d..4e81d365f 100644
--- a/repos/base-hw/src/lib/base/signal.cc
+++ b/repos/base-hw/src/lib/base/signal.cc
@@ -20,7 +20,9 @@
/* base-internal includes */
#include
+#include
#include
+#include
using namespace Genode;
@@ -63,12 +65,10 @@ void Signal_transmitter::submit(unsigned cnt)
Signal_receiver::Signal_receiver()
{
retry(
- [&] () {
- _cap = env()->pd_session()->alloc_signal_source();
- },
+ [&] () { _cap = internal_env().pd().alloc_signal_source(); },
[&] () {
log("upgrading quota donation for PD session");
- env()->parent()->upgrade(env()->pd_session_cap(), "ram_quota=8K");
+ internal_env().upgrade(Parent::Env::pd(), "ram_quota=8K");
}
);
}
@@ -104,11 +104,7 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
_contexts.insert(&c->_receiver_le);
return c->_cap;
},
- [&] () {
- log("upgrading quota donation for PD session");
- env()->parent()->upgrade(env()->pd_session_cap(), "ram_quota=8K");
- }
- );
+ [&] () { upgrade_pd_quota_non_blocking(1024 * sizeof(addr_t)); });
return c->_cap;
}
diff --git a/repos/base-linux/src/core/include/core_env.h b/repos/base-linux/src/core/include/core_env.h
index b6073b12c..a30dd4f19 100644
--- a/repos/base-linux/src/core/include/core_env.h
+++ b/repos/base-linux/src/core/include/core_env.h
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
/* base-internal includes */
#include
@@ -138,8 +139,6 @@ namespace Genode {
typedef Synchronized_ram_session Core_ram_session;
- Core_parent _core_parent;
-
/*
* Initialize the stack area before creating the first thread,
* which happens to be the '_entrypoint'.
@@ -163,6 +162,10 @@ namespace Genode {
Heap _heap;
Ram_session_capability const _ram_session_cap;
+ Registry _services;
+
+ Core_parent _core_parent { _heap, _services };
+
public:
/**
@@ -210,6 +213,8 @@ namespace Genode {
warning(__FILE__, ":", __LINE__, " not implemented");
return Cpu_session_capability();
}
+
+ Registry &services() { return _services; }
};
diff --git a/repos/base-linux/src/include/base/internal/local_parent.h b/repos/base-linux/src/include/base/internal/local_parent.h
index dcef6b77c..b35d88e45 100644
--- a/repos/base-linux/src/include/base/internal/local_parent.h
+++ b/repos/base-linux/src/include/base/internal/local_parent.h
@@ -23,7 +23,11 @@
/* base-internal includes */
#include
-namespace Genode { class Local_parent; }
+namespace Genode {
+
+ class Local_session;
+ class Local_parent;
+}
/**
@@ -42,6 +46,7 @@ class Genode::Local_parent : public Expanding_parent_client
private:
Allocator &_alloc;
+ Id_space _local_sessions_id_space;
public:
@@ -49,10 +54,9 @@ class Genode::Local_parent : public Expanding_parent_client
** Parent interface **
**********************/
- Session_capability session(Service_name const &,
- Session_args const &,
- Affinity const & = Affinity());
- void close(Session_capability);
+ Session_capability session(Client::Id, Service_name const &, Session_args const &,
+ Affinity const & = Affinity()) override;
+ Close_result close(Client::Id) override;
/**
* Constructor
diff --git a/repos/base-linux/src/include/base/internal/local_rm_session.h b/repos/base-linux/src/include/base/internal/local_rm_session.h
index f81ba41c8..b03f08ea1 100644
--- a/repos/base-linux/src/include/base/internal/local_rm_session.h
+++ b/repos/base-linux/src/include/base/internal/local_rm_session.h
@@ -19,17 +19,22 @@
#include
/* base-internal includes */
+#include
#include
#include
namespace Genode { struct Local_rm_session; }
-struct Genode::Local_rm_session : Rm_session
+struct Genode::Local_rm_session : Rm_session, Local_session
{
Allocator &md_alloc;
- Local_rm_session(Allocator &md_alloc) : md_alloc(md_alloc) { }
+ Local_rm_session(Allocator &md_alloc, Id_space &id_space,
+ Parent::Client::Id id)
+ :
+ Local_session(id_space, id, *this), md_alloc(md_alloc)
+ { }
Capability create(size_t size)
{
diff --git a/repos/base-linux/src/include/base/internal/local_session.h b/repos/base-linux/src/include/base/internal/local_session.h
new file mode 100644
index 000000000..0c660967c
--- /dev/null
+++ b/repos/base-linux/src/include/base/internal/local_session.h
@@ -0,0 +1,44 @@
+/*
+ * \brief Meta data for component-local sessions
+ * \author Norman Feske
+ * \date 2016-10-13
+ */
+
+/*
+ * Copyright (C) 2016 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 _INCLUDE__BASE__INTERNAL__LOCAL_SESSION_H_
+#define _INCLUDE__BASE__INTERNAL__LOCAL_SESSION_H_
+
+/* Genode includes */
+#include
+
+namespace Genode { struct Local_session; }
+
+
+struct Genode::Local_session : Parent::Client
+{
+ private:
+
+ Id_space::Element _id_space_element;
+
+ Session_capability _cap;
+
+ public:
+
+ Local_session(Id_space &id_space, Parent::Client::Id id,
+ Session &session)
+ :
+ _id_space_element(*this, id_space, id),
+ _cap(Local_capability::local_cap(&session))
+ { }
+
+ Capability local_session_cap() { return _cap; }
+};
+
+
+#endif /* _INCLUDE__BASE__INTERNAL__LOCAL_SESSION_H_ */
diff --git a/repos/base-linux/src/include/base/internal/platform_env.h b/repos/base-linux/src/include/base/internal/platform_env.h
index c6b10dd09..ebd8ae5a6 100644
--- a/repos/base-linux/src/include/base/internal/platform_env.h
+++ b/repos/base-linux/src/include/base/internal/platform_env.h
@@ -69,9 +69,9 @@ class Genode::Platform_env_base : public Env_deprecated
Pd_session_capability pd_cap)
:
_ram_session_cap(ram_cap),
- _ram_session_client(_ram_session_cap),
+ _ram_session_client(_ram_session_cap, Parent::Env::ram()),
_cpu_session_cap(cpu_cap),
- _cpu_session_client(cpu_cap),
+ _cpu_session_client(cpu_cap, Parent::Env::cpu()),
_region_map_mmap(false),
_pd_session_cap(pd_cap),
_local_pd_session(_pd_session_cap)
diff --git a/repos/base-linux/src/lib/base/platform_env.cc b/repos/base-linux/src/lib/base/platform_env.cc
index 77fd27abe..167a5b48d 100644
--- a/repos/base-linux/src/lib/base/platform_env.cc
+++ b/repos/base-linux/src/lib/base/platform_env.cc
@@ -59,37 +59,44 @@ bool Region_map_mmap::_dataspace_writable(Dataspace_capability ds)
** Local_parent **
******************/
-Session_capability Local_parent::session(Service_name const &service_name,
+Session_capability Local_parent::session(Parent::Client::Id id,
+ Service_name const &service_name,
Session_args const &args,
Affinity const &affinity)
{
- if (strcmp(service_name.string(), Rm_session::service_name()) == 0)
- {
- Local_rm_session *session = new (_alloc) Local_rm_session(_alloc);
+ if (strcmp(service_name.string(), Rm_session::service_name()) == 0) {
- return Local_capability::local_cap(session);
+ Local_rm_session *local_rm_session = new (_alloc)
+ Local_rm_session(_alloc, _local_sessions_id_space, id);
+
+ return local_rm_session->local_session_cap();
}
- return Expanding_parent_client::session(service_name, args, affinity);
+ return Expanding_parent_client::session(id, service_name, args, affinity);
}
-void Local_parent::close(Session_capability session)
+Parent::Close_result Local_parent::close(Client::Id id)
{
+ auto close_local_fn = [&] (Local_session &local_session)
+ {
+ Capability rm =
+ static_cap_cast(local_session.local_session_cap());
+ destroy(_alloc, Local_capability::deref(rm));
+ };
+
/*
- * Handle non-local capabilities
+ * Local RM sessions are present in the '_local_sessions_id_space'. If the
+ * apply succeeds, 'id' referred to the local session. Otherwise, we
+ * forward the request to the parent.
*/
- if (session.valid()) {
- Parent_client::close(session);
- return;
+ try {
+ _local_sessions_id_space.apply(id, close_local_fn);
+ return CLOSE_DONE;
}
+ catch (Id_space::Unknown_id) { }
- /*
- * Detect capability to local RM session
- */
- Capability rm = static_cap_cast(session);
-
- destroy(_alloc, Local_capability::deref(rm));
+ return Parent_client::close(id);
}
@@ -148,9 +155,9 @@ Local_parent &Platform_env::_parent()
Platform_env::Platform_env()
:
- Platform_env_base(static_cap_cast(_parent().session("Env::ram_session", "")),
- static_cap_cast(_parent().session("Env::cpu_session", "")),
- static_cap_cast (_parent().session("Env::pd_session", ""))),
+ Platform_env_base(static_cap_cast(_parent().session_cap(Parent::Env::ram())),
+ static_cap_cast(_parent().session_cap(Parent::Env::cpu())),
+ static_cap_cast (_parent().session_cap(Parent::Env::pd()))),
_heap(Platform_env_base::ram_session(), Platform_env_base::rm_session()),
_emergency_ram_ds(ram_session()->alloc(_emergency_ram_size()))
{
diff --git a/repos/base-nova/src/lib/base/rpc_cap_alloc.cc b/repos/base-nova/src/lib/base/rpc_cap_alloc.cc
index b5ec4816b..fa3e6fd56 100644
--- a/repos/base-nova/src/lib/base/rpc_cap_alloc.cc
+++ b/repos/base-nova/src/lib/base/rpc_cap_alloc.cc
@@ -17,6 +17,9 @@
#include
#include
+/* base-internal includes */
+#include
+
/* NOVA-specific part of the PD session interface */
#include
@@ -37,11 +40,7 @@ Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &pd, Native_capabili
return native_pd.alloc_rpc_cap(ep, entry, 0);
},
[&] () {
- Pd_session_client *client =
- dynamic_cast(&pd);
-
- if (client)
- env()->parent()->upgrade(*client, "ram_quota=16K");
+ internal_env().upgrade(Parent::Env::pd(), "ram_quota=16K");
});
native_pd.imprint_rpc_cap(new_obj_cap, new_obj_cap.local_name());
diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h
index ba1399a05..b3a4ba5ab 100644
--- a/repos/base/include/base/child.h
+++ b/repos/base/include/base/child.h
@@ -18,11 +18,14 @@
#include
#include
#include
+#include
#include
-#include
+#include
#include
-#include
-#include
+#include
+#include
+#include
+#include
#include
namespace Genode {
@@ -41,44 +44,47 @@ namespace Genode {
*/
struct Genode::Child_policy
{
+ typedef String<64> Name;
+ typedef String<64> Binary_name;
+ typedef String<64> Linker_name;
+
virtual ~Child_policy() { }
/**
- * Return process name of the child
+ * Name of the child used as the child's label prefix
*/
- virtual const char *name() const = 0;
+ virtual Name name() const = 0;
+
+ /**
+ * ROM module name of the binary to start
+ */
+ virtual Binary_name binary_name() const { return name(); }
+
+ /**
+ * ROM module name of the dynamic linker
+ */
+ virtual Linker_name linker_name() const { return "ld.lib.so"; }
/**
* Determine service to provide a session request
*
- * \return Service to be contacted for the new session, or
- * 0 if session request could not be resolved
+ * \return service to be contacted for the new session
+ *
+ * \throw Parent::Service_denied
*/
- virtual Service *resolve_session_request(const char * /*service_name*/,
- const char * /*args*/)
- { return 0; }
+ virtual Service &resolve_session_request(Service::Name const &,
+ Session_state::Args const &) = 0;
/**
* Apply transformations to session arguments
*/
- virtual void filter_session_args(const char * /*service*/,
+ virtual void filter_session_args(Service::Name const &,
char * /*args*/, size_t /*args_len*/) { }
/**
* Register a service provided by the child
- *
- * \param name service name
- * \param root interface for creating sessions for the service
- * \param alloc allocator to be used for child-specific
- * meta-data allocations
- * \return true if announcement succeeded, or false if
- * child is not permitted to announce service
*/
- virtual bool announce_service(const char * /*name*/,
- Root_capability /*root*/,
- Allocator * /*alloc*/,
- Server * /*server*/)
- { return false; }
+ virtual void announce_service(Service::Name const &) { }
/**
* Apply session affinity policy
@@ -91,11 +97,6 @@ struct Genode::Child_policy
return affinity;
}
- /**
- * Unregister services that had been provided by the child
- */
- virtual void unregister_services() { }
-
/**
* Exit child
*/
@@ -110,8 +111,8 @@ struct Genode::Child_policy
* The RAM session returned by this method is used for session-quota
* transfers.
*/
- virtual Ram_session *ref_ram_session() { return env()->ram_session(); }
- virtual Ram_session_capability ref_ram_cap() const { return env()->ram_session_cap(); }
+ virtual Ram_session &ref_ram() = 0;
+ virtual Ram_session_capability ref_ram_cap() const = 0;
/**
* Respond to the release of resources by the child
@@ -125,6 +126,56 @@ struct Genode::Child_policy
* Take action on additional resource needs by the child
*/
virtual void resource_request(Parent::Resource_args const &) { }
+
+ /**
+ * Initialize the child's RAM session
+ *
+ * The function must define the child's reference account and transfer
+ * the child's initial RAM quota.
+ */
+ virtual void init(Ram_session &, Capability) = 0;
+
+ /**
+ * Initialize the child's CPU session
+ *
+ * The function may install an exception signal handler or assign CPU quota
+ * to the child.
+ */
+ virtual void init(Cpu_session &, Capability) { }
+
+ /**
+ * Initialize the child's PD session
+ *
+ * The function may install a region-map fault handler for the child's
+ * address space ('Pd_session::address_space');.
+ */
+ virtual void init(Pd_session &, Capability) { }
+
+ class Nonexistent_id_space : Exception { };
+
+ /**
+ * ID space for sessions provided by the child
+ *
+ * \throw Nonexistent_id_space
+ */
+ virtual Id_space &server_id_space() { throw Nonexistent_id_space(); }
+
+ /**
+ * Return region map for the child's address space
+ *
+ * \param pd the child's PD session capability
+ *
+ * By default, the function returns a 'nullptr'. In this case, the 'Child'
+ * interacts with the address space of the child's PD session via RPC calls
+ * to the 'Pd_session::address_space'.
+ *
+ * By overriding the default, those RPC calls can be omitted, which is
+ * useful if the child's PD session (including the PD's address space) is
+ * virtualized by the parent. If the virtual PD session is served by the
+ * same entrypoint as the child's parent interface, an RPC call to 'pd'
+ * would otherwise produce a deadlock.
+ */
+ virtual Region_map *address_space(Pd_session &) { return nullptr; }
};
@@ -150,9 +201,11 @@ struct Genode::Child_policy
* to our account, and subsequently transfer the same amount from our
* account to the client.
*/
-class Genode::Child : protected Rpc_object
+class Genode::Child : protected Rpc_object,
+ Session_state::Ready_callback,
+ Session_state::Closed_callback
{
- public:
+ private:
struct Initial_thread_base
{
@@ -192,52 +245,114 @@ class Genode::Child : protected Rpc_object
Capability cap() { return _cap; }
};
- private:
-
- class Session;
-
- /* PD session representing the protection domain of the child */
- Pd_session_capability _pd;
-
- /* RAM session that contains the quota of the child */
- Ram_session_capability _ram;
-
- /* CPU session that contains the quota of the child */
- Cpu_session_capability _cpu;
-
- /* services where the PD, RAM, and CPU resources come from */
- Service &_pd_service;
- Service &_ram_service;
- Service &_cpu_service;
-
- /* heap for child-specific allocations using the child's quota */
- Heap _heap;
-
- Rpc_entrypoint &_entrypoint;
- Parent_capability _parent_cap;
-
/* child policy */
- Child_policy &_policy;
+ Child_policy &_policy;
/* sessions opened by the child */
- Lock _lock; /* protect list manipulation */
- Object_pool _session_pool;
- List _session_list;
+ Id_space _id_space;
- /* server role */
- Server _server;
+ typedef Session_state::Args Args;
- /* session-argument buffer */
- char _args[Parent::Session_args::MAX_SIZE];
+ template
+ struct Env_connection
+ {
+ typedef String<64> Label;
+
+ Args const _args;
+ Service &_service;
+ Local_connection _connection;
+
+ /**
+ * Construct session arguments with the child policy applied
+ */
+ Args _construct_args(Child_policy &policy, Label const &label)
+ {
+ /* copy original arguments into modifiable buffer */
+ char buf[Session_state::Args::capacity()];
+ buf[0] = 0;
+
+ /* supply label as session argument */
+ if (label.valid())
+ Arg_string::set_arg_string(buf, sizeof(buf), "label", label.string());
+
+ /* apply policy to argument buffer */
+ policy.filter_session_args(CONNECTION::service_name(), buf, sizeof(buf));
+
+ return Session_state::Args(Cstring(buf));
+ }
+
+ Env_connection(Child_policy &policy, Id_space &id_space,
+ Id_space::Id id, Label const &label = Label())
+ :
+ _args(_construct_args(policy, label)),
+ _service(policy.resolve_session_request(CONNECTION::service_name(), _args)),
+ _connection(_service, id_space, id, _args,
+ policy.filter_session_affinity(Affinity()))
+ { }
+
+ typedef typename CONNECTION::Session_type SESSION;
+
+ SESSION &session() { return _connection.session(); }
+ Capability cap() const { return _connection.cap(); }
+ };
+
+ Env_connection _ram { _policy,
+ _id_space, Parent::Env::ram() };
+
+ Env_connection _pd { _policy,
+ _id_space, Parent::Env::pd() };
+
+ Env_connection _cpu { _policy,
+ _id_space, Parent::Env::cpu() };
+
+ Env_connection _log { _policy,
+ _id_space, Parent::Env::log() };
+
+ Env_connection _binary { _policy,
+ _id_space, Parent::Env::binary(), _policy.binary_name() };
+
+ Lazy_volatile_object > _linker { _policy,
+ _id_space, Parent::Env::linker(), _policy.linker_name() };
+
+ /* call 'Child_policy::init' methods for the environment sessions */
+ void _init_env_sessions()
+ {
+ _policy.init(_ram.session(), _ram.cap());
+ _policy.init(_cpu.session(), _cpu.cap());
+ _policy.init(_pd.session(), _pd.cap());
+ }
+ bool const _env_sessions_initialized = ( _init_env_sessions(), true );
+
+ Dataspace_capability _linker_dataspace()
+ {
+ try {
+ _linker.construct(_policy, _id_space,
+ Parent::Env::linker(), _policy.linker_name());
+ return _linker->session().dataspace();
+ }
+ catch (Parent::Service_denied) { return Rom_dataspace_capability(); }
+ }
+
+ /* heap for child-specific allocations using the child's quota */
+ Heap _heap;
+
+ /* factory for dynamically created session-state objects */
+ Session_state::Factory _session_factory { _heap };
+
+ Rpc_entrypoint &_entrypoint;
+ Parent_capability _parent_cap;
/* signal handlers registered by the child */
Signal_context_capability _resource_avail_sigh;
Signal_context_capability _yield_sigh;
+ Signal_context_capability _session_sigh;
/* arguments fetched by the child in response to a yield signal */
Lock _yield_request_lock;
Resource_args _yield_request_args;
+ Initial_thread _initial_thread { _cpu.session(), _pd.cap(), "initial" };
+
struct Process
{
class Missing_dynamic_linker : Exception { };
@@ -313,30 +428,19 @@ class Genode::Child : protected Rpc_object
Process _process;
- /**
- * Attach session information to a child
- *
- * \throw Ram_session::Quota_exceeded the child's heap partition cannot
- * hold the session meta data
- */
- void _add_session(const Session &s);
+ void _revert_quota_and_destroy(Session_state &);
+
+ Close_result _close(Session_state &);
/**
- * Close session and revert quota donation associated with it
+ * Session_state::Ready_callback
*/
- void _remove_session(Session *s);
-
- void _close(Session *s);
+ void session_ready(Session_state &session) override;
/**
- * Return service interface targetting the parent
- *
- * The service returned by this method is used as default
- * provider for the RAM, CPU, and RM resources of the child. It is
- * solely used for targeting resource donations during
- * 'Parent::upgrade_quota()' calls.
+ * Session_state::Closed_callback
*/
- static Service &_parent_service();
+ void session_closed(Session_state &) override;
public:
@@ -357,60 +461,18 @@ class Genode::Child : protected Rpc_object
/**
* Constructor
*
- * \param elf_ds dataspace that contains the ELF binary
- * \param ldso_ds dataspace that contains the dynamic linker,
- * started if 'elf_ds' is a dynamically linked
- * executable
- * \param pd_cap capability of the new protection domain,
- * used as argument for creating the initial
- * thread, and handed out to the child as its
- * environment
- * \param pd PD session used for assigning the parent
- * capability of the new process
- * \param ram_cap RAM session capability handed out to the
- * child as its environment
- * \param ram RAM session used to allocate the BSS and
- * DATA segments and as backing store for the
- * local heap partition to keep child-specific
- * meta data
- * \param cpu_cap CPU session capability handed out to the
- * child as its environment
- * \param initial_thread initial thread of the new protection domain
- * \param local_rm local address space
- * \param remote_rm address space of new protection domain
- * \param pd_service provider of the 'pd' session
- * \param ram_service provider of the 'ram' session
- * \param cpu_service provider of the 'cpu' session
+ * \param rm local address space, usually 'env.rm()'
+ * \param entrypoint entrypoint used to serve the parent interface of
+ * the child
+ * \param policy policy for the child
*
+ * \throw Parent::Service_denied if the initial sessions for the
+ * child's environment could not be
+ * opened
* \throw Ram_session::Alloc_failed
* \throw Process_startup_failed
- *
- * Usually, the pairs of 'pd' and 'pd_cap', 'initial_thread' and
- * 'cpu_cap', 'ram' and 'ram_cap' belong to each other. References to
- * the session interfaces are passed as separate arguments in addition
- * to the capabilities to allow the creator of a child to operate on
- * locally implemented interfaces during the child initialization.
- *
- * The 'ram_service', 'cpu_service', and 'pd_service' arguments are
- * needed to direct quota upgrades referring to the resources of
- * the child environment. By default, we expect that these
- * resources are provided by the parent.
*/
- Child(Dataspace_capability elf_ds,
- Dataspace_capability ldso_ds,
- Pd_session_capability pd_cap,
- Pd_session &pd,
- Ram_session_capability ram_cap,
- Ram_session &ram,
- Cpu_session_capability cpu_cap,
- Initial_thread_base &initial_thread,
- Region_map &local_rm,
- Region_map &remote_rm,
- Rpc_entrypoint &entrypoint,
- Child_policy &policy,
- Service &pd_service = _parent_service(),
- Service &ram_service = _parent_service(),
- Service &cpu_service = _parent_service());
+ Child(Region_map &rm, Rpc_entrypoint &entrypoint, Child_policy &policy);
/**
* Destructor
@@ -421,25 +483,40 @@ class Genode::Child : protected Rpc_object
virtual ~Child();
/**
- * Return heap that uses the child's quota
+ * RAM quota unconditionally consumed by the child's environment
*/
- Allocator *heap() { return &_heap; }
-
- Pd_session_capability pd_session_cap() const { return _pd; }
- Ram_session_capability ram_session_cap() const { return _ram; }
- Cpu_session_capability cpu_session_cap() const { return _cpu; }
- Parent_capability parent_cap() const { return cap(); }
+ static size_t env_ram_quota()
+ {
+ return Cpu_connection::RAM_QUOTA + Ram_connection::RAM_QUOTA +
+ Pd_connection::RAM_QUOTA + Log_connection::RAM_QUOTA +
+ 2*Rom_connection::RAM_QUOTA;
+ }
/**
- * Discard all sessions to specified service
- *
- * When this method is called, we assume the server protection
- * domain to be dead and all that all server quota was already
- * transferred back to our own 'env()->ram_session()' account. Note
- * that the specified server object may not exist anymore. We do
- * not de-reference the server argument in here!
+ * Deduce session costs from usable ram quota
*/
- void revoke_server(const Server *server);
+ static size_t effective_ram_quota(size_t const ram_quota)
+ {
+ if (ram_quota < env_ram_quota())
+ return 0;
+
+ 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(); }
+
+ Ram_session &ram() { return _ram.session(); }
+ Cpu_session &cpu() { return _cpu.session(); }
+ Pd_session &pd() { return _pd .session(); }
+
+ Session_state::Factory &session_factory() { return _session_factory; }
/**
* Instruct the child to yield resources
@@ -461,12 +538,16 @@ class Genode::Child : protected Rpc_object
** Parent interface **
**********************/
- void announce(Service_name const &, Root_capability) override;
- Session_capability session(Service_name const &, Session_args const &,
- Affinity const &) override;
- void upgrade(Session_capability, Upgrade_args const &) override;
- void close(Session_capability) override;
+ void announce(Service_name const &) override;
+ void session_sigh(Signal_context_capability) override;
+ Session_capability session(Client::Id, Service_name const &,
+ Session_args const &, Affinity const &) override;
+ Session_capability session_cap(Client::Id) override;
+ Upgrade_result upgrade(Client::Id, Upgrade_args const &) override;
+ Close_result close(Client::Id) override;
void exit(int) override;
+ void session_response(Server::Id, Session_response) override;
+ void deliver_session_cap(Server::Id, Session_capability) override;
Thread_capability main_thread_cap() const override;
void resource_avail_sigh(Signal_context_capability) override;
void resource_request(Resource_args const &) override;
diff --git a/repos/base/include/base/connection.h b/repos/base/include/base/connection.h
index fbf51ccc0..d09213a23 100644
--- a/repos/base/include/base/connection.h
+++ b/repos/base/include/base/connection.h
@@ -16,20 +16,56 @@
#include
#include
+#include
-namespace Genode { template class Connection; }
+namespace Genode {
+
+ class Connection_base;
+ template class Connection;
+}
+
+
+class Genode::Connection_base : public Noncopyable
+{
+ protected:
+
+ Env &_env;
+
+ Parent::Client _parent_client;
+
+ Id_space::Element const _id_space_element;
+
+ void _block_for_session_response();
+
+ public:
+
+ Connection_base(Env &env)
+ :
+ _env(env),
+ _id_space_element(_parent_client, _env.id_space())
+ { }
+
+ /**
+ * Legacy constructor
+ *
+ * \noapi
+ */
+ Connection_base();
+
+ void upgrade_ram(size_t bytes)
+ {
+ String<64> const args("ram_quota=", bytes);
+ _env.upgrade(_id_space_element.id(), args.string());
+ }
+};
/**
* Representation of an open connection to a service
*/
template
-class Genode::Connection : public Noncopyable
+class Genode::Connection : public Connection_base
{
- public:
-
- enum On_destruction { CLOSE = false, KEEP_OPEN = true };
-
private:
/*
@@ -37,15 +73,12 @@ class Genode::Connection : public Noncopyable
* 'session' method that is called before the 'Connection' is
* constructed.
*/
+
enum { FORMAT_STRING_SIZE = Parent::Session_args::MAX_SIZE };
char _session_args[FORMAT_STRING_SIZE];
char _affinity_arg[sizeof(Affinity)];
- Parent &_parent;
-
- On_destruction _on_destruction;
-
void _session(Parent &parent,
Affinity const &affinity,
const char *format_args, va_list list)
@@ -63,7 +96,8 @@ class Genode::Connection : public Noncopyable
memcpy(&affinity, _affinity_arg, sizeof(Affinity));
try {
- return env()->parent()->session(_session_args, affinity); }
+ return _env.session(_id_space_element.id(),
+ _session_args, affinity); }
catch (...) {
error(SESSION_TYPE::service_name(), "-session creation failed "
"(", Cstring(_session_args), ")");
@@ -75,20 +109,15 @@ class Genode::Connection : public Noncopyable
public:
+ typedef SESSION_TYPE Session_type;
+
/**
* Constructor
- *
- * \param od session policy applied when destructing the connection
- *
- * The 'op' argument defines whether the session should automatically
- * be closed by the destructor of the connection (CLOSE), or the
- * session should stay open (KEEP_OPEN). The latter is useful in
- * situations where the creator a connection merely passes the
- * session capability of the connection to another party but never
- * invokes any of the session's RPC functions.
*/
- Connection(Env &env, Capability, On_destruction od = CLOSE)
- : _parent(env.parent()), _on_destruction(od) { }
+ Connection(Env &env, Capability)
+ :
+ Connection_base(env), _cap(_request_cap())
+ { }
/**
* Constructor
@@ -97,28 +126,18 @@ class Genode::Connection : public Noncopyable
* \deprecated Use the constructor with 'Env &' as first
* argument instead
*/
- Connection(Capability, On_destruction od = CLOSE)
- : _parent(*env()->parent()), _on_destruction(od) { }
+ Connection(Capability) : _cap(_request_cap()) { }
/**
* Destructor
*/
- ~Connection()
- {
- if (_on_destruction == CLOSE)
- _parent.close(_cap);
- }
+ ~Connection() { _env.close(_id_space_element.id()); }
/**
* Return session capability
*/
Capability cap() const { return _cap; }
- /**
- * Define session policy
- */
- void on_destruction(On_destruction od) { _on_destruction = od; }
-
/**
* Issue session request to the parent
*/
diff --git a/repos/base/include/base/env.h b/repos/base/include/base/env.h
index 421130489..202a1f411 100644
--- a/repos/base/include/base/env.h
+++ b/repos/base/include/base/env.h
@@ -73,6 +73,61 @@ struct Genode::Env
* Once we add 'Env::upgrade', we can remove this accessor.
*/
virtual Pd_session_capability pd_session_cap() = 0;
+
+ /**
+ * ID space of sessions obtained from the parent
+ */
+ virtual Id_space &id_space() = 0;
+
+ virtual Session_capability session(Parent::Service_name const &,
+ Parent::Client::Id,
+ Parent::Session_args const &,
+ Affinity const &) = 0;
+
+ /**
+ * Create session to a service
+ *
+ * \param SESSION_TYPE session interface type
+ * \param id session ID of new session
+ * \param args session constructor arguments
+ * \param affinity preferred CPU affinity for the session
+ *
+ * \throw Service_denied parent denies session request
+ * \throw Quota_exceeded our own quota does not suffice for
+ * the creation of the new session
+ * \throw Unavailable
+ *
+ * This method blocks until the session is available or an error
+ * occurred.
+ */
+ template
+ Capability session(Parent::Client::Id id,
+ Parent::Session_args const &args,
+ Affinity const &affinity)
+ {
+ Session_capability cap = session(SESSION_TYPE::service_name(),
+ id, args, affinity);
+ return static_cap_cast(cap);
+ }
+
+ /**
+ * Upgrade session quota
+ *
+ * \param id ID of recipient session
+ * \param args description of the amount of quota to transfer
+ *
+ * \throw Quota_exceeded quota could not be transferred
+ *
+ * The 'args' argument has the same principle format as the 'args'
+ * argument of the 'session' operation.
+ */
+ virtual void upgrade(Parent::Client::Id id,
+ Parent::Upgrade_args const &args) = 0;
+
+ /**
+ * Close session and block until the session is gone
+ */
+ virtual void close(Parent::Client::Id) = 0;
};
#endif /* _INCLUDE__BASE__ENV_H_ */
diff --git a/repos/base/include/base/local_connection.h b/repos/base/include/base/local_connection.h
new file mode 100644
index 000000000..bb064d2c1
--- /dev/null
+++ b/repos/base/include/base/local_connection.h
@@ -0,0 +1,135 @@
+/*
+ * \brief Connection to a local child
+ * \author Norman Feske
+ * \date 2016-11-10
+ *
+ * The 'Local_connection' can be used to locally establish a connection
+ * to a 'Local_service' or a 'Parent_service'.
+ */
+
+/*
+ * Copyright (C) 2016 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 _INCLUDE__BASE__LOCAL_CONNECTION_H_
+#define _INCLUDE__BASE__LOCAL_CONNECTION_H_
+
+#include
+#include
+
+namespace Genode {
+
+ class Local_connection_base;
+ template class Local_connection;
+}
+
+
+struct Genode::Local_connection_base : Noncopyable
+{
+ public:
+
+ typedef Session_state::Args Args;
+
+ protected:
+
+ Session_state _session_state;
+
+ private:
+
+ static Args _init_args(Args const &args, size_t const &ram_quota)
+ {
+ /* copy original arguments into modifiable buffer */
+ char buf[Args::capacity()];
+ strncpy(buf, args.string(), sizeof(buf));
+
+ Arg_string::set_arg(buf, sizeof(buf), "ram_quota",
+ String<64>(ram_quota).string());
+
+ /* return result as a copy */
+ return Args(Cstring(buf));
+ }
+
+ protected:
+
+ Local_connection_base(Service &service,
+ Id_space &id_space,
+ Parent::Client::Id id,
+ Args const &args, Affinity const &affinity,
+ size_t ram_quota)
+ :
+ _session_state(service, id_space, id, _init_args(args, ram_quota),
+ affinity)
+ {
+ _session_state.service().initiate_request(_session_state);
+ }
+
+ ~Local_connection_base()
+ {
+ if (_session_state.alive()) {
+ _session_state.phase = Session_state::CLOSE_REQUESTED;
+ _session_state.service().initiate_request(_session_state);
+ }
+ }
+};
+
+
+template
+class Genode::Local_connection : Local_connection_base
+{
+ private:
+
+ typedef typename CONNECTION::Session_type SESSION;
+
+ Lazy_volatile_object _client;
+
+ public:
+
+ Capability cap() const
+ {
+ return reinterpret_cap_cast(_session_state.cap);
+ }
+
+ SESSION &session()
+ {
+ /*
+ * If session comes from a local service (e.g,. a virtualized
+ * RAM session, we return the reference to the corresponding
+ * component object, which can be called directly.
+ *
+ * Otherwise, if the session is provided
+ */
+ 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.
+ */
+ if (_client.constructed())
+ return *_client;
+
+ /*
+ * 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(), ") "
+ "unavailable");
+ throw Parent::Service_denied();
+ }
+
+ Local_connection(Service &service, Id_space &id_space,
+ Parent::Client::Id id, Args const &args,
+ Affinity const &affinity)
+ :
+ Local_connection_base(service, id_space, id, args,
+ affinity, CONNECTION::RAM_QUOTA)
+ {
+ if (_session_state.cap.valid())
+ _client.construct(cap());
+ }
+};
+
+#endif /* _INCLUDE__BASE__LOCAL_CONNECTION_H_ */
diff --git a/repos/base/include/base/service.h b/repos/base/include/base/service.h
index 0bc4ec2fc..3a932d7ee 100644
--- a/repos/base/include/base/service.h
+++ b/repos/base/include/base/service.h
@@ -14,100 +14,42 @@
#ifndef _INCLUDE__BASE__SERVICE_H_
#define _INCLUDE__BASE__SERVICE_H_
-#include
-#include
#include
#include
#include
+#include
+#include
+#include
namespace Genode {
- class Client;
- class Server;
class Service;
- class Local_service;
+ template class Session_factory;
+ template class Local_service;
class Parent_service;
class Child_service;
- class Service_registry;
}
-/**
- * Client role
- *
- * A client is someone who applies for a service. If the service is not
- * available yet, we enqueue the client into a wait queue and wake him up
- * as soon as the requested service gets available.
- */
-class Genode::Client : public List::Element
-{
- private:
-
- Cancelable_lock _service_apply_lock;
- const char *_apply_for;
-
- public:
-
- /**
- * Constructor
- */
- Client(): _service_apply_lock(Lock::LOCKED), _apply_for(0) { }
-
- virtual ~Client() { }
-
- /**
- * Set/Request service name that we are currently applying for
- */
- void apply_for(const char *apply_for) { _apply_for = apply_for; }
- const char *apply_for() { return _apply_for; }
-
- /**
- * Service wait queue support
- */
- void sleep() { _service_apply_lock.lock(); }
- void wakeup() { _service_apply_lock.unlock(); }
-};
-
-
-/**
- * Server role
- *
- * A server is a process that provides one or multiple services. For the
- * most part, this class is used as an opaque key to represent the server
- * role.
- */
-class Genode::Server
-{
- private:
-
- Ram_session_capability _ram;
-
- public:
-
- /**
- * Constructor
- *
- * \param ram RAM session capability of the server process used,
- * for quota transfers from/to the server
- */
- Server(Ram_session_capability ram): _ram(ram) { }
-
- /**
- * Return RAM session capability of the server process
- */
- Ram_session_capability ram_session_cap() const { return _ram; }
-};
-
-
-class Genode::Service : public List::Element
+class Genode::Service : Noncopyable
{
public:
- enum { MAX_NAME_LEN = 32 };
+ typedef Session_state::Name Name;
private:
- char _name[MAX_NAME_LEN];
+ Name const _name;
+ Ram_session_capability const _ram;
+
+ protected:
+
+ typedef Session_state::Factory Factory;
+
+ /**
+ * Return factory to use for creating 'Session_state' objects
+ */
+ virtual Factory &_factory(Factory &client_factory) { return client_factory; }
public:
@@ -123,52 +65,52 @@ class Genode::Service : public List::Element
* Constructor
*
* \param name service name
+ * \param ram RAM session to receive/withdraw session quota
*/
- Service(const char *name) { strncpy(_name, name, sizeof(_name)); }
+ Service(Name const &name, Ram_session_capability ram)
+ : _name(name), _ram(ram) { }
virtual ~Service() { }
/**
* Return service name
*/
- const char *name() const { return _name; }
+ Name const &name() const { return _name; }
/**
- * Create session
+ * Create new session-state object
*
- * \param args session-construction arguments
- * \param affinity preferred CPU affinity of session
+ * The 'service' argument for the 'Session_state' corresponds to this
+ * session state. All subsequent 'Session_state' arguments correspond
+ * to the forwarded 'args'.
+ */
+ template
+ Session_state &create_session(Factory &client_factory, ARGS &&... args)
+ {
+ return _factory(client_factory).create(*this, args...);
+ }
+
+ /**
+ * Attempt the immediate (synchronous) creation of a session
*
- * \throw Invalid_args
- * \throw Unavailable
- * \throw Quota_exceeded
+ * Sessions to local services and parent services are usually created
+ * immediately during the dispatching of the 'Parent::session' request.
+ * In these cases, it is not needed to wait for an asynchronous
+ * response.
*/
- virtual Session_capability session(char const *args,
- Affinity const &affinity) = 0;
+ virtual void initiate_request(Session_state &session) = 0;
/**
- * Extend resource donation to an existing session
+ * Wake up service to query session requests
*/
- virtual void upgrade(Session_capability session, const char *args) = 0;
-
- /**
- * Close session
- */
- virtual void close(Session_capability /*session*/) { }
-
- /**
- * Return server providing the service
- */
- virtual Server *server() const { return 0; }
+ virtual void wakeup() { }
/**
* Return the RAM session to be used for trading resources
*/
- Ram_session_capability ram_session_cap()
+ Ram_session_capability ram() const
{
- if (server())
- return server()->ram_session_cap();
- return Ram_session_capability();
+ return _ram;
}
};
@@ -176,36 +118,118 @@ class Genode::Service : public List::Element
/**
* Representation of a locally implemented service
*/
+template
class Genode::Local_service : public Service
{
+ public:
+
+ struct Factory
+ {
+ typedef Session_state::Args Args;
+
+ class Denied : Exception { };
+
+ /**
+ * \throw Denied
+ */
+ virtual SESSION &create(Args const &, Affinity) = 0;
+
+ virtual void upgrade(SESSION &, Args const &) = 0;
+ virtual void destroy(SESSION &) = 0;
+ };
+
+ /**
+ * Factory of a local service that provides a single static session
+ */
+ class Single_session_factory : public Factory
+ {
+ private:
+
+ typedef Session_state::Args Args;
+
+ SESSION &_s;
+
+ public:
+
+ Single_session_factory(SESSION &session) : _s(session) { }
+
+ SESSION &create (Args const &, Affinity) override { return _s; }
+ void upgrade (SESSION &, Args const &) override { }
+ void destroy (SESSION &) override { }
+ };
+
private:
- Root *_root;
+ Factory &_factory;
+
+ template
+ void _apply_to_rpc_obj(Session_state &session, FUNC const &fn)
+ {
+ SESSION *rpc_obj = dynamic_cast(session.local_ptr);
+
+ if (rpc_obj)
+ fn(*rpc_obj);
+ else
+ warning("local ", SESSION::service_name(), " session "
+ "(", session.args(), ") has no valid RPC object");
+ }
public:
- Local_service(const char *name, Root *root)
- : Service(name), _root(root) { }
+ /**
+ * Constructor
+ */
+ Local_service(Factory &factory)
+ :
+ Service(SESSION::service_name(), Ram_session_capability()),
+ _factory(factory)
+ { }
- Session_capability session(const char *args, Affinity const &affinity) override
+ void initiate_request(Session_state &session) override
{
- try { return _root->session(args, affinity); }
- catch (Root::Invalid_args) { throw Invalid_args(); }
- catch (Root::Unavailable) { throw Unavailable(); }
- catch (Root::Quota_exceeded) { throw Quota_exceeded(); }
- catch (Genode::Ipc_error) { throw Unavailable(); }
- }
+ switch (session.phase) {
- void upgrade(Session_capability session, const char *args) override
- {
- try { _root->upgrade(session, args); }
- catch (Genode::Ipc_error) { throw Unavailable(); }
- }
+ case Session_state::CREATE_REQUESTED:
- void close(Session_capability session) override
- {
- try { _root->close(session); }
- catch (Genode::Ipc_error) { throw Blocking_canceled(); }
+ try {
+ SESSION &rpc_obj = _factory.create(session.args(),
+ session.affinity());
+ session.local_ptr = &rpc_obj;
+ session.cap = rpc_obj.cap();
+ session.phase = Session_state::AVAILABLE;
+ }
+ catch (typename Factory::Denied) {
+ session.phase = Session_state::INVALID_ARGS; }
+
+ break;
+
+ case Session_state::UPGRADE_REQUESTED:
+ {
+ String<64> const args("ram_quota=", session.ram_upgrade);
+
+ _apply_to_rpc_obj(session, [&] (SESSION &rpc_obj) {
+ _factory.upgrade(rpc_obj, args.string()); });
+
+ session.phase = Session_state::CAP_HANDED_OUT;
+ session.confirm_ram_upgrade();
+ }
+ break;
+
+ case Session_state::CLOSE_REQUESTED:
+ {
+ _apply_to_rpc_obj(session, [&] (SESSION &rpc_obj) {
+ _factory.destroy(rpc_obj); });
+
+ session.phase = Session_state::CLOSED;
+ }
+ break;
+
+ case Session_state::INVALID_ARGS:
+ case Session_state::AVAILABLE:
+ case Session_state::CAP_HANDED_OUT:
+ case Session_state::CLOSED:
+ break;
+ }
}
};
@@ -215,31 +239,88 @@ class Genode::Local_service : public Service
*/
class Genode::Parent_service : public Service
{
+ private:
+
+ /*
+ * \deprecated
+ */
+ Env &_env_deprecated();
+ Env &_env;
+
public:
- Parent_service(const char *name) : Service(name) { }
+ /**
+ * Constructor
+ */
+ Parent_service(Env &env, Service::Name const &name)
+ : Service(name, Ram_session_capability()), _env(env) { }
- Session_capability session(const char *args, Affinity const &affinity) override
+ /**
+ * Constructor
+ *
+ * \deprecated
+ */
+ Parent_service(Service::Name const &name)
+ : Service(name, Ram_session_capability()), _env(_env_deprecated()) { }
+
+ void initiate_request(Session_state &session) override
{
- try { return env()->parent()->session(name(), args, affinity); }
- catch (Parent::Unavailable) {
- warning("parent has no service \"", name(), "\"");
- throw Unavailable();
+ switch (session.phase) {
+
+ case Session_state::CREATE_REQUESTED:
+
+ session.id_at_parent.construct(session.parent_client,
+ _env.id_space());
+ try {
+ session.cap = _env.session(name().string(),
+ session.id_at_parent->id(),
+ session.args().string(),
+ session.affinity());
+
+ session.phase = Session_state::AVAILABLE;
+ }
+ catch (Parent::Quota_exceeded) {
+ session.id_at_parent.destruct();
+ session.phase = Session_state::INVALID_ARGS; }
+
+ catch (Parent::Service_denied) {
+ session.id_at_parent.destruct();
+ session.phase = Session_state::INVALID_ARGS; }
+
+ break;
+
+ case Session_state::UPGRADE_REQUESTED:
+ {
+ String<64> const args("ram_quota=", session.ram_upgrade);
+
+ if (!session.id_at_parent.constructed())
+ error("invalid parent-session state: ", session);
+
+ try {
+ _env.upgrade(session.id_at_parent->id(), args.string()); }
+ catch (Parent::Quota_exceeded) {
+ warning("quota exceeded while upgrading parent session"); }
+
+ session.confirm_ram_upgrade();
+ session.phase = Session_state::CAP_HANDED_OUT;
+ }
+ break;
+
+ case Session_state::CLOSE_REQUESTED:
+
+ if (session.id_at_parent.constructed())
+ _env.close(session.id_at_parent->id());
+
+ session.id_at_parent.destruct();
+ session.phase = Session_state::CLOSED;
+ break;
+
+ case Session_state::INVALID_ARGS:
+ case Session_state::AVAILABLE:
+ case Session_state::CAP_HANDED_OUT:
+ case Session_state::CLOSED:
+ break;
}
- catch (Parent::Quota_exceeded) { throw Quota_exceeded(); }
- catch (Genode::Ipc_error) { throw Unavailable(); }
- }
-
- void upgrade(Session_capability session, const char *args) override
- {
- try { env()->parent()->upgrade(session, args); }
- catch (Genode::Ipc_error) { throw Unavailable(); }
- }
-
- void close(Session_capability session) override
- {
- try { env()->parent()->close(session); }
- catch (Genode::Ipc_error) { throw Blocking_canceled(); }
}
};
@@ -249,205 +330,66 @@ class Genode::Parent_service : public Service
*/
class Genode::Child_service : public Service
{
+ public:
+
+ struct Wakeup { virtual void wakeup_child_service() = 0; };
+
private:
- Root_capability _root_cap;
- Root_client _root;
- Server *_server;
+ Id_space &_server_id_space;
+
+ Session_state::Factory &_server_factory;
+
+ Wakeup &_wakeup;
+
+ protected:
+
+ /*
+ * In contrast to local services and parent services, session-state
+ * objects for child services are owned by the server. This enables
+ * the server to asynchronouly respond to close requests when the
+ * client is already gone.
+ */
+ Factory &_factory(Factory &) override { return _server_factory; }
public:
+
/**
* Constructor
*
- * \param name name of service
- * \param root capability to root interface
- * \param server server process providing the service
- */
- Child_service(const char *name,
- Root_capability root,
- Server *server)
- : Service(name), _root_cap(root), _root(root), _server(server) { }
-
- Server *server() const override { return _server; }
-
- Session_capability session(const char *args, Affinity const &affinity) override
- {
- if (!_root_cap.valid())
- throw Unavailable();
-
- try { return _root.session(args, affinity); }
- catch (Root::Invalid_args) { throw Invalid_args(); }
- catch (Root::Unavailable) { throw Unavailable(); }
- catch (Root::Quota_exceeded) { throw Quota_exceeded(); }
- catch (Genode::Ipc_error) { throw Unavailable(); }
- }
-
- void upgrade(Session_capability sc, const char *args) override
- {
- if (!_root_cap.valid())
- throw Unavailable();
-
- try { _root.upgrade(sc, args); }
- catch (Root::Invalid_args) { throw Invalid_args(); }
- catch (Root::Unavailable) { throw Unavailable(); }
- catch (Root::Quota_exceeded) { throw Quota_exceeded(); }
- catch (Genode::Ipc_error) { throw Unavailable(); }
- }
-
- void close(Session_capability sc) override
- {
- try { _root.close(sc); }
- catch (Genode::Ipc_error) { throw Blocking_canceled(); }
- }
-};
-
-
-/**
- * Container for holding service representations
- */
-class Genode::Service_registry
-{
- protected:
-
- Lock _service_wait_queue_lock;
- List _service_wait_queue;
- List _services;
-
- public:
-
- /**
- * Probe for service with specified name
+ * \param factory server-side session-state factory
+ * \param name name of service
+ * \param ram recipient of session quota
+ * \param wakeup callback to be notified on the arrival of new
+ * session requests
*
- * \param name service name
- * \param server server providing the service,
- * default (0) for any server
*/
- Service *find(const char *name, Server *server = 0)
+ Child_service(Id_space &server_id_space,
+ Session_state::Factory &factory,
+ Service::Name const &name,
+ Ram_session_capability ram,
+ Wakeup &wakeup)
+ :
+ Service(name, ram),
+ _server_id_space(server_id_space),
+ _server_factory(factory), _wakeup(wakeup)
+ { }
+
+ void initiate_request(Session_state &session) override
{
- if (!name) return 0;
+ if (!session.id_at_server.constructed())
+ session.id_at_server.construct(session, _server_id_space);
- Lock::Guard lock_guard(_service_wait_queue_lock);
-
- for (Service *s = _services.first(); s; s = s->next())
- if (strcmp(s->name(), name) == 0
- && (!server || s->server() == server)) return s;
-
- return 0;
+ session.async_client_notify = true;
}
- /**
- * Check if service name is ambiguous
- *
- * \return true if the same service is provided multiple
- * times
- */
- bool is_ambiguous(const char *name)
+ bool has_id_space(Id_space const &id_space) const
{
- Lock::Guard lock_guard(_service_wait_queue_lock);
-
- /* count number of services with the specified name */
- unsigned cnt = 0;
- for (Service *s = _services.first(); s; s = s->next())
- cnt += (strcmp(s->name(), name) == 0);
- return cnt > 1;
+ return &_server_id_space == &id_space;
}
- /**
- * Return first service provided by specified server
- */
- Service *find_by_server(Server *server)
- {
- Lock::Guard lock_guard(_service_wait_queue_lock);
-
- for (Service *s = _services.first(); s; s = s->next())
- if (s->server() == server)
- return s;
-
- return 0;
- }
-
- /**
- * Wait for service
- *
- * This method is called by the clients's thread when requesting a
- * session creation. It blocks if the requested service is not
- * available.
- *
- * \return service structure that matches the request or
- * 0 if the waiting was canceled.
- */
- Service *wait_for_service(const char *name, Client *client, const char *client_name)
- {
- Service *service;
-
- client->apply_for(name);
-
- _service_wait_queue_lock.lock();
- _service_wait_queue.insert(client);
- _service_wait_queue_lock.unlock();
-
- do {
- service = find(name);
-
- /*
- * The service that we are seeking is not available today.
- * Lets sleep a night over it.
- */
- if (!service) {
- log(client_name, ": service ", name, " not yet available - sleeping");
-
- try {
- client->sleep();
- log(client_name, ": service ", name, " got available");
- } catch (Blocking_canceled) {
- log(client_name, ": cancel waiting for service");
- break;
- }
- }
-
- } while (!service);
-
- /* we got what we needed, stop applying */
- _service_wait_queue_lock.lock();
- _service_wait_queue.remove(client);
- _service_wait_queue_lock.unlock();
-
- client->apply_for(0);
-
- return service;
- }
-
- /**
- * Register service
- *
- * This method is called by the server's thread.
- */
- void insert(Service *service)
- {
- /* make new service known */
- _services.insert(service);
-
- /* wake up applicants waiting for the service */
- Lock::Guard lock_guard(_service_wait_queue_lock);
- for (Client *c = _service_wait_queue.first(); c; c = c->next())
- if (strcmp(service->name(), c->apply_for()) == 0)
- c->wakeup();
- }
-
- /**
- * Unregister service
- */
- void remove(Service *service) { _services.remove(service); }
-
- /**
- * Unregister all services
- */
- void remove_all()
- {
- while (_services.first())
- remove(_services.first());
- }
+ void wakeup() override { _wakeup.wakeup_child_service(); }
};
#endif /* _INCLUDE__BASE__SERVICE_H_ */
diff --git a/repos/base/include/base/session_state.h b/repos/base/include/base/session_state.h
new file mode 100644
index 000000000..21241758d
--- /dev/null
+++ b/repos/base/include/base/session_state.h
@@ -0,0 +1,245 @@
+/*
+ * \brief Representation of a session request
+ * \author Norman Feske
+ * \date 2016-10-10
+ */
+
+/*
+ * Copyright (C) 2016 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 _INCLUDE__BASE__SESSION_STATE_H_
+#define _INCLUDE__BASE__SESSION_STATE_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Genode {
+
+ class Session_state;
+ class Service;
+}
+
+
+class Genode::Session_state : public Parent::Client, public Parent::Server,
+ Noncopyable
+{
+ public:
+
+ class Factory;
+
+ typedef String<32> Name;
+ typedef String<256> Args;
+
+ struct Ready_callback
+ {
+ virtual void session_ready(Session_state &) = 0;
+ };
+
+ struct Closed_callback
+ {
+ virtual void session_closed(Session_state &) = 0;
+ };
+
+ private:
+
+ Service &_service;
+
+ /**
+ * Total of quota associated with this session
+ */
+ size_t _donated_ram_quota = 0;
+
+ Factory *_factory = nullptr;
+
+ Volatile_object::Element> _id_at_client;
+
+ Args _args;
+ Affinity _affinity;
+
+ public:
+
+ Lazy_volatile_object::Element> id_at_server;
+
+ /* ID for session requests towards the parent */
+ Lazy_volatile_object::Element> id_at_parent;
+
+ Parent::Client parent_client;
+
+ enum Phase { CREATE_REQUESTED,
+ INVALID_ARGS,
+ AVAILABLE,
+ CAP_HANDED_OUT,
+ UPGRADE_REQUESTED,
+ CLOSE_REQUESTED,
+ CLOSED };
+
+ /**
+ * If set, the server reponds asynchronously to the session request.
+ * The client waits for a notification that is delivered as soon as
+ * the server delivers the session capability.
+ */
+ bool async_client_notify = false;
+
+ Phase phase = CREATE_REQUESTED;
+
+ Ready_callback *ready_callback = nullptr;
+ Closed_callback *closed_callback = nullptr;
+
+ /*
+ * Pointer to session interface for sessions that are implemented
+ * locally.
+ */
+ Session *local_ptr = nullptr;
+
+ Session_capability cap;
+
+ size_t ram_upgrade = 0;
+
+ void print(Output &out) const;
+
+ /**
+ * Constructor
+ *
+ * \param service interface that was used to create the session
+ * \param client_id_space ID space for client-side session IDs
+ * \param client_id session ID picked by the client
+ * \param args session arguments
+ *
+ * \throw Id_space::Conflicting_id
+ */
+ Session_state(Service &service,
+ Id_space &client_id_space,
+ Parent::Client::Id client_id,
+ Args const &args,
+ Affinity const &affinity);
+
+ ~Session_state()
+ {
+ if (id_at_parent.is_constructed())
+ error("dangling session in parent-side ID space: ", *this);
+ }
+
+ Service &service() { return _service; }
+
+ /**
+ * Extend amount of ram attached to the session
+ */
+ void confirm_ram_upgrade()
+ {
+ ram_upgrade = 0;
+ }
+
+ void increase_donated_quota(size_t upgrade)
+ {
+ _donated_ram_quota += upgrade;
+ ram_upgrade = upgrade;
+ }
+
+ Parent::Client::Id id_at_client() const
+ {
+ return _id_at_client->id();
+ }
+
+ void discard_id_at_client()
+ {
+ _id_at_client.destruct();
+ }
+
+ Args const &args() const { return _args; }
+
+ Affinity const &affinity() const { return _affinity; }
+
+ void generate_session_request(Xml_generator &xml) const;
+
+ size_t donated_ram_quota() const { return _donated_ram_quota; }
+
+ bool alive() const
+ {
+ switch (phase) {
+
+ case CREATE_REQUESTED:
+ case INVALID_ARGS:
+ case CLOSED:
+ return false;
+
+ case AVAILABLE:
+ case CAP_HANDED_OUT:
+ case UPGRADE_REQUESTED:
+ case CLOSE_REQUESTED:
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Assign owner
+ *
+ * This function is called if the session-state object is created by
+ * 'Factory'. For statically created session objects, the '_factory' is
+ * a nullptr. The owner can be defined only once.
+ */
+ void owner(Factory &factory) { if (!_factory) _factory = &factory; }
+
+ /**
+ * Destroy session-state object
+ *
+ * This function has no effect for sessions not created via a 'Factory'.
+ */
+ void destroy();
+};
+
+
+class Genode::Session_state::Factory : Noncopyable
+{
+ private:
+
+ Allocator &_md_alloc;
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param md_alloc meta-data allocator used for allocating
+ * 'Session_state' objects
+ */
+ Factory(Allocator &md_alloc) : _md_alloc(md_alloc) { }
+
+ /**
+ * Create a new session-state object
+ *
+ * The 'args' are passed the 'Session_state' constructor.
+ *
+ * \throw Allocator::Out_of_memory
+ */
+ template
+ Session_state &create(ARGS &&... args)
+ {
+ Session_state &session = *new (_md_alloc) Session_state(args...);
+ session.owner(*this);
+ return session;
+ }
+
+ private:
+
+ /*
+ * Allow only 'Session_state::destroy' to call 'Factory::_destroy'.
+ * This way, we make sure that the 'Session_state' is destroyed with
+ * the same factory that was used for creating it.
+ */
+ friend class Session_state;
+
+ void _destroy(Session_state &session) { Genode::destroy(_md_alloc, &session); }
+};
+
+
+#endif /* _INCLUDE__BASE__SESSION_STATE_H_ */
diff --git a/repos/base/include/cpu_session/cpu_session.h b/repos/base/include/cpu_session/cpu_session.h
index 3c0f157cd..35a2e2a88 100644
--- a/repos/base/include/cpu_session/cpu_session.h
+++ b/repos/base/include/cpu_session/cpu_session.h
@@ -23,11 +23,20 @@
#include
#include
-namespace Genode { struct Cpu_session; }
+namespace Genode {
+
+ struct Cpu_session;
+ struct Cpu_session_client;
+}
struct Genode::Cpu_session : Session
{
+ static const char *service_name() { return "CPU"; }
+
+ typedef Cpu_session_client Client;
+
+
/*********************
** Exception types **
*********************/
@@ -36,7 +45,6 @@ struct Genode::Cpu_session : Session
class Quota_exceeded : public Thread_creation_failed { };
class Out_of_metadata : public Exception { };
- static const char *service_name() { return "CPU"; }
enum { THREAD_NAME_LEN = 32 };
enum { PRIORITY_LIMIT = 1 << 16 };
diff --git a/repos/base/include/deprecated/env.h b/repos/base/include/deprecated/env.h
index d6fd7ee4c..aa6d08418 100644
--- a/repos/base/include/deprecated/env.h
+++ b/repos/base/include/deprecated/env.h
@@ -119,7 +119,6 @@ struct Genode::Env_deprecated
* \noapi
*/
virtual void reinit_main_thread(Capability &stack_area_rm) = 0;
-
};
#endif /* _INCLUDE__DEPRECATED__ENV_H_ */
diff --git a/repos/base/include/log_session/connection.h b/repos/base/include/log_session/connection.h
index 0d05c3ec0..905fd8b3a 100644
--- a/repos/base/include/log_session/connection.h
+++ b/repos/base/include/log_session/connection.h
@@ -23,14 +23,16 @@ namespace Genode { struct Log_connection; }
struct Genode::Log_connection : Connection, Log_session_client
{
+ enum { RAM_QUOTA = 8*1024UL };
+
/**
* Constructor
*/
Log_connection(Env &env, Session_label label = Session_label())
:
Connection(env, session(env.parent(),
- "ram_quota=8K, label=\"%s\"",
- label.string())),
+ "ram_quota=%ld, label=\"%s\"",
+ RAM_QUOTA, label.string())),
Log_session_client(cap())
{ }
@@ -43,8 +45,8 @@ struct Genode::Log_connection : Connection, Log_session_client
*/
Log_connection(Session_label label = Session_label())
:
- Connection(session("ram_quota=8K, label=\"%s\"",
- label.string())),
+ Connection(session("ram_quota=%ld, label=\"%s\"",
+ RAM_QUOTA, label.string())),
Log_session_client(cap())
{ }
};
diff --git a/repos/base/include/log_session/log_session.h b/repos/base/include/log_session/log_session.h
index 0a57d69e4..9d38eb929 100644
--- a/repos/base/include/log_session/log_session.h
+++ b/repos/base/include/log_session/log_session.h
@@ -19,13 +19,19 @@
#include
#include
-namespace Genode { struct Log_session; }
+namespace Genode {
+
+ struct Log_session;
+ struct Log_session_client;
+}
struct Genode::Log_session : Session
{
static const char *service_name() { return "LOG"; }
+ typedef Log_session_client Client;
+
virtual ~Log_session() { }
/* the lowest platform-specific maximum IPC payload size (OKL4) */
diff --git a/repos/base/include/parent/client.h b/repos/base/include/parent/client.h
index d75ec89f4..825548994 100644
--- a/repos/base/include/parent/client.h
+++ b/repos/base/include/parent/client.h
@@ -27,18 +27,32 @@ struct Genode::Parent_client : Rpc_client
void exit(int exit_value) override { call(exit_value); }
- void announce(Service_name const &service, Root_capability root) override {
- call(service, root); }
+ void announce(Service_name const &service) override {
+ call(service); }
- Session_capability session(Service_name const &service,
+ void session_sigh(Signal_context_capability sigh) override {
+ call(sigh); }
+
+ Session_capability session(Client::Id id,
+ Service_name const &service,
Session_args const &args,
Affinity const &affinity) override {
- return call(service, args, affinity); }
+ return call(id, service, args, affinity); }
- void upgrade(Session_capability to_session, Upgrade_args const &args) override {
- call(to_session, args); }
+ Session_capability session_cap(Client::Id id) override {
+ return call(id); }
- void close(Session_capability session) override { call(session); }
+ Upgrade_result upgrade(Client::Id to_session, Upgrade_args const &args) override {
+ return call(to_session, args); }
+
+ Close_result close(Client::Id id) override { return call(id); }
+
+ void session_response(Id_space::Id id, Session_response response) override {
+ call(id, response); }
+
+ void deliver_session_cap(Id_space::Id id,
+ Session_capability cap) override {
+ call(id, cap); }
Thread_capability main_thread_cap() const override {
return call(); }
diff --git a/repos/base/include/parent/parent.h b/repos/base/include/parent/parent.h
index a15b7d426..76c20c2d5 100644
--- a/repos/base/include/parent/parent.h
+++ b/repos/base/include/parent/parent.h
@@ -18,10 +18,15 @@
#include
#include
#include
+#include
#include
#include
-namespace Genode { class Parent; }
+namespace Genode {
+
+ class Session_state;
+ class Parent;
+}
class Genode::Parent
@@ -61,13 +66,35 @@ class Genode::Parent
typedef Rpc_in_buffer<160> Session_args;
typedef Rpc_in_buffer<160> Upgrade_args;
+ struct Client { typedef Id_space::Id Id; };
+ struct Server { typedef Id_space::Id Id; };
+
+ /**
+ * Predefined session IDs corresponding to the environment sessions
+ * created by the parent at the component-construction time
+ */
+ struct Env
+ {
+ static Client::Id ram() { return { 1 }; }
+ static Client::Id cpu() { return { 2 }; }
+ static Client::Id pd() { return { 3 }; }
+ static Client::Id log() { return { 4 }; }
+ static Client::Id binary() { return { 5 }; }
+ static Client::Id linker() { return { 6 }; }
+
+ /**
+ * True if session ID refers to an environment session
+ */
+ static bool session_id(Client::Id id) {
+ return id.value >= 1 && id.value <= 6; }
+ };
+
/**
* Use 'String' instead of 'Rpc_in_buffer' because 'Resource_args'
* is used as both in and out parameter.
*/
typedef String<160> Resource_args;
-
virtual ~Parent() { }
/**
@@ -78,9 +105,20 @@ class Genode::Parent
/**
* Announce service to the parent
*/
- virtual void announce(Service_name const &service_name,
- Root_capability service_root) = 0;
+ virtual void announce(Service_name const &service_name) = 0;
+ /**
+ * Emulation of the original synchronous root interface
+ *
+ * This function transparently spawns a proxy "root" entrypoint that
+ * dispatches asynchronous session-management operations (as issued
+ * by the parent) to the local root interfaces via component-local
+ * RPC calls.
+ *
+ * The function solely exists for API compatibility.
+ */
+ static void announce(Service_name const &service_name,
+ Root_capability service_root);
/**
* Announce service to the parent
@@ -109,9 +147,15 @@ class Genode::Parent
(Meta::Bool_to_type::VALUE> *)0);
}
+ /**
+ * Register signal handler for session notifications
+ */
+ virtual void session_sigh(Signal_context_capability) = 0;
+
/**
* Create session to a service
*
+ * \param id client-side ID of new session
* \param service_name name of the requested interface
* \param args session constructor arguments
* \param affinity preferred CPU affinity for the session
@@ -119,60 +163,73 @@ class Genode::Parent
* \throw Service_denied parent denies session request
* \throw Quota_exceeded our own quota does not suffice for
* the creation of the new session
+ *
+ * \return session capability of the new session is immediately
+ * available, or an invalid capability
+ *
+ * If the returned capability is invalid, the request is pending at the
+ * server. The parent delivers a signal to the handler as registered
+ * via 'session_sigh' once the server responded to the request. Now the
+ * session capability can be picked up by calling 'session_cap'.
+ *
* \throw Unavailable
- *
- * \return untyped capability to new session
- *
- * The use of this method is discouraged. Please use the type safe
- * 'session()' template instead.
*/
- virtual Session_capability session(Service_name const &service_name,
+ virtual Session_capability session(Client::Id id,
+ Service_name const &service_name,
Session_args const &args,
Affinity const &affinity = Affinity()) = 0;
/**
- * Create session to a service
+ * Request session capability
*
- * \param SESSION_TYPE session interface type
- * \param args session constructor arguments
- * \param affinity preferred CPU affinity for the session
+ * \throw Service_denied
*
- * \throw Service_denied parent denies session request
- * \throw Quota_exceeded our own quota does not suffice for
- * the creation of the new session
- * \throw Unavailable
- *
- * \return capability to new session
+ * In the exception case, the parent implicitly closes the session.
*/
- template
- Capability session(Session_args const &args,
- Affinity const &affinity = Affinity())
- {
- Session_capability cap = session(SESSION_TYPE::service_name(),
- args, affinity);
- return reinterpret_cap_cast(cap);
- }
+ virtual Session_capability session_cap(Client::Id id) = 0;
+
+ enum Upgrade_result { UPGRADE_DONE, UPGRADE_PENDING };
/**
* Transfer our quota to the server that provides the specified session
*
- * \param to_session recipient session
+ * \param id ID of recipient session
* \param args description of the amount of quota to transfer
*
* \throw Quota_exceeded quota could not be transferred
*
* The 'args' argument has the same principle format as the 'args'
* argument of the 'session' operation.
- * The error case indicates that there is not enough unused quota on
- * the source side.
*/
- virtual void upgrade(Session_capability to_session,
- Upgrade_args const &args) = 0;
+ virtual Upgrade_result upgrade(Client::Id to_session,
+ Upgrade_args const &args) = 0;
+
+ enum Close_result { CLOSE_DONE, CLOSE_PENDING };
/**
* Close session
*/
- virtual void close(Session_capability session) = 0;
+ virtual Close_result close(Client::Id) = 0;
+
+ /*
+ * Interface for providing services
+ */
+
+ enum Session_response { SESSION_OK, SESSION_CLOSED, INVALID_ARGS };
+
+ /**
+ * Set state of a session provided by the child service
+ */
+ virtual void session_response(Server::Id, Session_response) = 0;
+
+ /**
+ * Deliver capability for a new session provided by the child service
+ */
+ virtual void deliver_session_cap(Server::Id, Session_capability) = 0;
+
+ /*
+ * Dynamic resource balancing
+ */
/**
* Provide thread_cap of main thread
@@ -233,14 +290,23 @@ class Genode::Parent
GENODE_RPC(Rpc_exit, void, exit, int);
GENODE_RPC(Rpc_announce, void, announce,
- Service_name const &, Root_capability);
+ 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, Quota_exceeded, Unavailable),
- Service_name const &, Session_args const &, Affinity const &);
- GENODE_RPC_THROW(Rpc_upgrade, void, upgrade,
+ 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, Quota_exceeded, Unavailable),
+ Client::Id);
+ GENODE_RPC_THROW(Rpc_upgrade, Upgrade_result, upgrade,
GENODE_TYPE_LIST(Quota_exceeded),
- Session_capability, Upgrade_args const &);
- GENODE_RPC(Rpc_close, void, close, Session_capability);
+ Client::Id, Upgrade_args const &);
+ GENODE_RPC(Rpc_close, Close_result, close, Client::Id);
+ GENODE_RPC(Rpc_session_response, void, session_response,
+ Server::Id, Session_response);
+ GENODE_RPC(Rpc_deliver_session_cap, void, deliver_session_cap,
+ Server::Id, Session_capability);
GENODE_RPC(Rpc_main_thread, Thread_capability, main_thread_cap);
GENODE_RPC(Rpc_resource_avail_sigh, void, resource_avail_sigh,
Signal_context_capability);
@@ -250,10 +316,12 @@ class Genode::Parent
GENODE_RPC(Rpc_yield_request, Resource_args, yield_request);
GENODE_RPC(Rpc_yield_response, void, yield_response);
- GENODE_RPC_INTERFACE(Rpc_exit, Rpc_announce, Rpc_session, Rpc_upgrade,
- Rpc_close, Rpc_main_thread, Rpc_resource_avail_sigh,
- Rpc_resource_request, Rpc_yield_sigh, Rpc_yield_request,
- Rpc_yield_response);
+ GENODE_RPC_INTERFACE(Rpc_exit, Rpc_announce, Rpc_session_sigh,
+ Rpc_session, Rpc_session_cap, Rpc_upgrade,
+ Rpc_close, Rpc_session_response, Rpc_main_thread,
+ Rpc_deliver_session_cap, Rpc_resource_avail_sigh,
+ Rpc_resource_request, Rpc_yield_sigh,
+ Rpc_yield_request, Rpc_yield_response);
};
diff --git a/repos/base/include/pd_session/pd_session.h b/repos/base/include/pd_session/pd_session.h
index b3053382c..67d51dde6 100644
--- a/repos/base/include/pd_session/pd_session.h
+++ b/repos/base/include/pd_session/pd_session.h
@@ -25,6 +25,7 @@
namespace Genode {
struct Pd_session;
+ struct Pd_session_client;
struct Parent;
struct Signal_context;
}
@@ -34,6 +35,8 @@ struct Genode::Pd_session : Session
{
static const char *service_name() { return "PD"; }
+ typedef Pd_session_client Client;
+
virtual ~Pd_session() { }
/**
diff --git a/repos/base/include/ram_session/ram_session.h b/repos/base/include/ram_session/ram_session.h
index 5cc41bd63..e1a79e08a 100644
--- a/repos/base/include/ram_session/ram_session.h
+++ b/repos/base/include/ram_session/ram_session.h
@@ -27,6 +27,7 @@ namespace Genode {
struct Ram_dataspace;
typedef Capability Ram_dataspace_capability;
+ struct Ram_session_client;
struct Ram_session;
}
@@ -41,6 +42,8 @@ struct Genode::Ram_session : Session
{
static const char *service_name() { return "RAM"; }
+ typedef Ram_session_client Client;
+
/*********************
** Exception types **
diff --git a/repos/base/include/rom_session/connection.h b/repos/base/include/rom_session/connection.h
index 6d962a85e..9a5f29862 100644
--- a/repos/base/include/rom_session/connection.h
+++ b/repos/base/include/rom_session/connection.h
@@ -28,11 +28,13 @@ class Genode::Rom_connection : public Connection,
class Rom_connection_failed : public Parent::Exception { };
+ enum { RAM_QUOTA = 4096UL };
+
private:
Rom_session_capability _session(Parent &parent, char const *label)
{
- return session("ram_quota=4K, label=\"%s\"", label);
+ return session("ram_quota=%ld, label=\"%s\"", RAM_QUOTA, label);
}
public:
diff --git a/repos/base/include/rom_session/rom_session.h b/repos/base/include/rom_session/rom_session.h
index a218703b7..da6256cc4 100644
--- a/repos/base/include/rom_session/rom_session.h
+++ b/repos/base/include/rom_session/rom_session.h
@@ -25,6 +25,7 @@ namespace Genode {
struct Rom_dataspace;
struct Rom_session;
+ struct Rom_session_client;
typedef Capability Rom_dataspace_capability;
}
@@ -37,6 +38,8 @@ struct Genode::Rom_session : Session
{
static const char *service_name() { return "ROM"; }
+ typedef Rom_session_client Client;
+
virtual ~Rom_session() { }
/**
diff --git a/repos/base/include/root/component.h b/repos/base/include/root/component.h
index 9eda01444..7bf58d3fc 100644
--- a/repos/base/include/root/component.h
+++ b/repos/base/include/root/component.h
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
@@ -95,6 +96,7 @@ struct Genode::Multiple_clients
*/
template
class Genode::Root_component : public Rpc_object >,
+ public Local_service::Factory,
private POLICY
{
private:
@@ -113,6 +115,53 @@ class Genode::Root_component : public Rpc_object >,
*/
Allocator *_md_alloc;
+ /*
+ * Used by both the legacy 'Root::session' and the new 'Factory::create'
+ */
+ SESSION_TYPE &_create(Session_state::Args const &args, Affinity affinity)
+ {
+ POLICY::aquire(args.string());
+
+ /*
+ * We need to decrease 'ram_quota' by
+ * the size of the session object.
+ */
+ size_t ram_quota = Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0);
+ 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);
+ throw Root::Quota_exceeded();
+ }
+
+ size_t const remaining_ram_quota = ram_quota - needed;
+
+ /*
+ * Deduce ram quota needed for allocating the session object from the
+ * donated ram quota.
+ *
+ * XXX the size of the 'adjusted_args' buffer should dependent
+ * on the message-buffer size and stack size.
+ */
+ enum { MAX_ARGS_LEN = 256 };
+ char adjusted_args[MAX_ARGS_LEN];
+ strncpy(adjusted_args, args.string(), sizeof(adjusted_args));
+ char ram_quota_buf[64];
+ snprintf(ram_quota_buf, sizeof(ram_quota_buf), "%lu",
+ remaining_ram_quota);
+ Arg_string::set_arg(adjusted_args, sizeof(adjusted_args),
+ "ram_quota", ram_quota_buf);
+
+ SESSION_TYPE *s = 0;
+ try { s = _create_session(adjusted_args, affinity); }
+ catch (Allocator::Out_of_memory) { throw Root::Unavailable(); }
+
+ _ep->manage(s);
+
+ return *s;
+ }
+
protected:
/**
@@ -169,7 +218,7 @@ class Genode::Root_component : public Rpc_object >,
virtual void _upgrade_session(SESSION_TYPE *, const char *) { }
virtual void _destroy_session(SESSION_TYPE *session) {
- destroy(_md_alloc, session); }
+ Genode::destroy(_md_alloc, session); }
/**
* Return allocator to allocate server object in '_create_session()'
@@ -208,6 +257,31 @@ class Genode::Root_component : public Rpc_object >,
{ }
+ /**************************************
+ ** Local_service::Factory interface **
+ **************************************/
+
+ SESSION_TYPE &create(Session_state::Args const &args,
+ Affinity affinity) override
+ {
+ try {
+ return _create(args, affinity); }
+ catch (...) {
+ throw typename Local_service::Factory::Denied(); }
+ }
+
+ void upgrade(SESSION_TYPE &session,
+ Session_state::Args const &args) override
+ {
+ _upgrade_session(&session, args.string());
+ }
+
+ void destroy(SESSION_TYPE &session) override
+ {
+ close(session.cap());
+ }
+
+
/********************
** Root interface **
********************/
@@ -216,45 +290,8 @@ class Genode::Root_component : public Rpc_object >,
Affinity const &affinity) override
{
if (!args.valid_string()) throw Root::Invalid_args();
-
- POLICY::aquire(args.string());
-
- /*
- * We need to decrease 'ram_quota' by
- * the size of the session object.
- */
- size_t ram_quota = Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0);
- 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);
- throw Root::Quota_exceeded();
- }
-
- size_t const remaining_ram_quota = ram_quota - needed;
-
- /*
- * Deduce ram quota needed for allocating the session object from the
- * donated ram quota.
- *
- * XXX the size of the 'adjusted_args' buffer should dependent
- * on the message-buffer size and stack size.
- */
- enum { MAX_ARGS_LEN = 256 };
- char adjusted_args[MAX_ARGS_LEN];
- strncpy(adjusted_args, args.string(), sizeof(adjusted_args));
- char ram_quota_buf[64];
- snprintf(ram_quota_buf, sizeof(ram_quota_buf), "%lu",
- remaining_ram_quota);
- Arg_string::set_arg(adjusted_args, sizeof(adjusted_args),
- "ram_quota", ram_quota_buf);
-
- SESSION_TYPE *s = 0;
- try { s = _create_session(adjusted_args, affinity); }
- catch (Allocator::Out_of_memory) { throw Root::Unavailable(); }
-
- return _ep->manage(s);
+ SESSION_TYPE &session = _create(args.string(), affinity);
+ return session.cap();
}
void upgrade(Session_capability session, Root::Upgrade_args const &args) override
diff --git a/repos/base/include/session/session.h b/repos/base/include/session/session.h
index dfbb2e6f4..342f68a03 100644
--- a/repos/base/include/session/session.h
+++ b/repos/base/include/session/session.h
@@ -21,13 +21,13 @@
*/
#include
-namespace Genode { class Session; }
+namespace Genode { struct Session; }
/**
* Base class of session interfaces
*/
-class Genode::Session
+struct Genode::Session
{
/*
* Each session interface must implement the class function 'service_name'
@@ -35,6 +35,8 @@ class Genode::Session
* This function returns the name of the service provided via the session
* interface.
*/
+
+ virtual ~Session() { }
};
#endif /* _INCLUDE__SESSION__SESSION_H_ */
diff --git a/repos/base/lib/mk/base-common.inc b/repos/base/lib/mk/base-common.inc
index b74b9fec4..694b4bd61 100644
--- a/repos/base/lib/mk/base-common.inc
+++ b/repos/base/lib/mk/base-common.inc
@@ -15,6 +15,7 @@ SRC_CC += console.cc
SRC_CC += output.cc
SRC_CC += child.cc
SRC_CC += child_process.cc
+SRC_CC += session_state.cc
SRC_CC += elf_binary.cc
SRC_CC += ipc.cc
SRC_CC += lock.cc
@@ -29,6 +30,8 @@ SRC_CC += region_map_client.cc
SRC_CC += rm_session_client.cc
SRC_CC += stack_allocator.cc
SRC_CC += trace.cc
+SRC_CC += root_proxy.cc
+SRC_CC += env_session_id_space.cc
INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include
diff --git a/repos/base/src/core/cpu_session_component.cc b/repos/base/src/core/cpu_session_component.cc
index 823d3159d..8aa6111d7 100644
--- a/repos/base/src/core/cpu_session_component.cc
+++ b/repos/base/src/core/cpu_session_component.cc
@@ -56,6 +56,7 @@ Thread_capability Cpu_session_component::create_thread(Capability pd
error("create_thread: invalid PD argument");
throw Thread_creation_failed();
}
+
Lock::Guard slab_lock_guard(_thread_alloc_lock);
thread = new (&_thread_alloc)
Cpu_thread_component(
diff --git a/repos/base/src/core/include/core_env.h b/repos/base/src/core/include/core_env.h
index 6fc7075ec..dd18b2604 100644
--- a/repos/base/src/core/include/core_env.h
+++ b/repos/base/src/core/include/core_env.h
@@ -116,8 +116,6 @@ namespace Genode {
typedef Synchronized_ram_session Core_ram_session;
- Core_parent _core_parent;
-
enum { ENTRYPOINT_STACK_SIZE = 2048 * sizeof(Genode::addr_t) };
/*
@@ -144,6 +142,10 @@ namespace Genode {
Heap _heap;
+ Registry _services;
+
+ Core_parent _core_parent { _heap, _services };
+
public:
/**
@@ -202,6 +204,8 @@ namespace Genode {
void reinit(Capability::Raw) override { }
void reinit_main_thread(Capability &) override { }
+
+ Registry &services() { return _services; }
};
diff --git a/repos/base/src/core/include/core_parent.h b/repos/base/src/core/include/core_parent.h
index c0239a846..e01d6c872 100644
--- a/repos/base/src/core/include/core_parent.h
+++ b/repos/base/src/core/include/core_parent.h
@@ -16,38 +16,83 @@
#define _CORE__INCLUDE__CORE_PARENT_H_
#include
+#include
+#include
-namespace Genode { struct Core_parent; }
+namespace Genode {
+
+ template struct Core_service;
+ struct Core_parent;
+}
+
+
+template
+struct Genode::Core_service : Local_service, Registry::Element
+{
+ Core_service(Registry ®istry,
+ typename Local_service::Factory &factory)
+ :
+ Local_service(factory),
+ Registry::Element(registry, *this)
+ { }
+};
/**
- * In fact, Core has _no_ parent. But most of our libraries could work
- * seamlessly inside Core too, if it had one. Core_parent fills this gap.
+ * Core has no parent. But most of Genode's library code could work seamlessly
+ * inside core if it had one. Core_parent fills this gap.
*/
-struct Genode::Core_parent : Parent
+class Genode::Core_parent : public Parent
{
- void exit(int);
+ private:
- void announce(Service_name const &, Root_capability) { }
+ Id_space _id_space;
+ Allocator &_alloc;
+ Registry &_services;
- Session_capability session(Service_name const &, Session_args const &,
- Affinity const &);
+ public:
- void upgrade(Session_capability, Upgrade_args const &) { throw Quota_exceeded(); }
+ /**
+ * Constructor
+ *
+ * \alloc allocator to be used for allocating core-local
+ * 'Session_state' objects
+ */
+ Core_parent(Allocator &alloc, Registry &services)
+ : _alloc(alloc), _services(services) { }
- void close(Session_capability) { }
+ void exit(int) override;
- Thread_capability main_thread_cap() const { return Thread_capability(); }
+ void announce(Service_name const &) override { }
- void resource_avail_sigh(Signal_context_capability) { }
+ void session_sigh(Signal_context_capability) override { }
- void resource_request(Resource_args const &) { }
+ Session_capability session(Client::Id, Service_name const &, Session_args const &,
+ Affinity const &) override;
- void yield_sigh(Signal_context_capability) { }
+ Session_capability session_cap(Client::Id) override { return Session_capability(); }
- Resource_args yield_request() { return Resource_args(); }
+ Upgrade_result upgrade(Client::Id, Upgrade_args const &) override {
+ throw Quota_exceeded(); }
- void yield_response() { }
+ Close_result close(Client::Id) override { return CLOSE_DONE; }
+
+ void session_response(Server::Id, Session_response) override { }
+
+ void deliver_session_cap(Server::Id,
+ Session_capability) override { }
+
+ Thread_capability main_thread_cap() const override { return Thread_capability(); }
+
+ void resource_avail_sigh(Signal_context_capability) override { }
+
+ void resource_request(Resource_args const &) override { }
+
+ void yield_sigh(Signal_context_capability) override { }
+
+ Resource_args yield_request() override { return Resource_args(); }
+
+ void yield_response() override { }
};
#endif /* _CORE__INCLUDE__CORE_PARENT_H_ */
diff --git a/repos/base/src/core/include/platform_services.h b/repos/base/src/core/include/platform_services.h
index d8fa53aee..3ca7f637e 100644
--- a/repos/base/src/core/include/platform_services.h
+++ b/repos/base/src/core/include/platform_services.h
@@ -14,11 +14,12 @@
#ifndef _CORE__INCLUDE__PLATFORM_SERVICES_H_
#define _CORE__INCLUDE__PLATFORM_SERVICES_H_
+#include
+
namespace Genode {
class Rpc_entrypoint;
class Sliced_heap;
- class Service_registry;
/**
@@ -31,7 +32,7 @@ namespace Genode {
*/
void platform_add_local_services(Rpc_entrypoint *ep,
Sliced_heap *md,
- Service_registry *reg);
+ Registry *reg);
}
#endif /* _CORE__INCLUDE__PLATFORM_SERVICES_H_ */
diff --git a/repos/base/src/core/main.cc b/repos/base/src/core/main.cc
index 840ece989..adbf96c70 100644
--- a/repos/base/src/core/main.cc
+++ b/repos/base/src/core/main.cc
@@ -42,10 +42,6 @@
using namespace Genode;
-/* pool of provided core services */
-static Service_registry local_services;
-
-
/***************************************
** Core environment/platform support **
***************************************/
@@ -85,17 +81,30 @@ Platform_generic *Genode::platform() { return platform_specific(); }
** Core parent support **
*************************/
-Session_capability Core_parent::session(Parent::Service_name const &name,
+Session_capability Core_parent::session(Parent::Client::Id id,
+ Parent::Service_name const &name,
Parent::Session_args const &args,
Affinity const &affinity)
{
- Service *service = local_services.find(name.string());
+ Session_capability cap;
- if (service)
- return service->session(args.string(), affinity);
+ _services.for_each([&] (Service &service) {
- warning("service_name=\"", name.string(), "\" args=\"", args.string(), "\" not handled");
- return Session_capability();
+ if ((service.name() != name.string()) || cap.valid())
+ return;
+
+ Session_state &session = *new (_alloc)
+ Session_state(service, _id_space, id, args.string(), affinity);
+
+ service.initiate_request(session);
+
+ cap = session.cap;
+ });
+
+ if (!cap.valid())
+ error("unexpected core-parent ", name.string(), " session request");
+
+ return cap;
}
@@ -113,21 +122,15 @@ class Core_child : public Child_policy
Rpc_entrypoint _entrypoint;
enum { STACK_SIZE = 2 * 1024 * sizeof(Genode::addr_t)};
- Service_registry &_local_services;
+ Registry &_services;
- /*
- * Dynamic linker, does not need to be valid because init is statically
- * linked
- */
- Dataspace_capability _ldso_ds;
+ Capability _core_ram_cap;
+ Ram_session &_core_ram;
- Pd_session_client _pd;
- Ram_session_client _ram;
- Cpu_session_client _cpu;
+ Capability _core_cpu_cap;
+ Cpu_session &_core_cpu;
- Child::Initial_thread _initial_thread { _cpu, _pd, "init_main" };
-
- Region_map_client _address_space;
+ size_t const _ram_quota;
Child _child;
@@ -136,20 +139,16 @@ class Core_child : public Child_policy
/**
* Constructor
*/
- Core_child(Dataspace_capability elf_ds, Pd_session_capability pd,
- Ram_session_capability ram,
- Cpu_session_capability cpu,
- Service_registry &services)
+ Core_child(Registry &services, Ram_session &core_ram,
+ Capability core_ram_cap, size_t ram_quota,
+ Cpu_session &core_cpu, Capability core_cpu_cap)
:
_entrypoint(nullptr, STACK_SIZE, "init_child", false),
- _local_services(services),
- _pd(pd), _ram(ram), _cpu(cpu),
- _address_space(Pd_session_client(pd).address_space()),
- _child(elf_ds, _ldso_ds, _pd, _pd, _ram, _ram, _cpu, _initial_thread,
- *env()->rm_session(), _address_space, _entrypoint, *this,
- *_local_services.find(Pd_session::service_name()),
- *_local_services.find(Ram_session::service_name()),
- *_local_services.find(Cpu_session::service_name()))
+ _services(services),
+ _core_ram_cap(core_ram_cap), _core_ram(core_ram),
+ _core_cpu_cap(core_cpu_cap), _core_cpu(core_cpu),
+ _ram_quota(Child::effective_ram_quota(ram_quota)),
+ _child(*env()->rm_session(), _entrypoint, *this)
{
_entrypoint.activate();
}
@@ -159,8 +158,7 @@ class Core_child : public Child_policy
** Child-policy interface **
****************************/
- void filter_session_args(const char *, char *args,
- Genode::size_t args_len)
+ void filter_session_args(Service::Name const &, char *args, size_t args_len) override
{
using namespace Genode;
@@ -177,13 +175,36 @@ class Core_child : public Child_policy
Arg_string::set_arg(args, args_len, "label", value_buf);
}
+ Name name() const { return "init"; }
- const char *name() const { return "init"; }
-
- Service *resolve_session_request(const char *service, const char *)
+ Service &resolve_session_request(Service::Name const &name,
+ Session_state::Args const &args) override
{
- return _local_services.find(service);
+ Service *service = nullptr;
+ _services.for_each([&] (Service &s) {
+ if (!service && s.name() == name)
+ service = &s; });
+
+ if (!service)
+ throw Parent::Service_denied();
+
+ return *service;
}
+
+ void init(Ram_session &session, Capability cap) override
+ {
+ session.ref_account(_core_ram_cap);
+ _core_ram.transfer_quota(cap, _ram_quota);
+ }
+
+ void init(Cpu_session &session, Capability cap) override
+ {
+ session.ref_account(_core_cpu_cap);
+ _core_cpu.transfer_quota(cap, Cpu_session::quota_lim_upscale(100, 100));
+ }
+
+ Ram_session &ref_ram() { return _core_ram; }
+ Ram_session_capability ref_ram_cap() const { return _core_ram_cap; }
};
@@ -240,6 +261,8 @@ int main()
*/
Rpc_entrypoint *e = core_env()->entrypoint();
+ Registry &services = core_env()->services();
+
/*
* Allocate session meta data on distinct dataspaces to enable independent
* destruction (to enable quota trading) of session component objects.
@@ -266,70 +289,42 @@ int main()
platform()->irq_alloc(), &sliced_heap);
static Trace::Root trace_root (e, &sliced_heap, Trace::sources(), trace_policies);
- /*
- * Play our role as parent of init and declare our services.
- */
-
- static Local_service ls[] = {
- Local_service(Rom_session::service_name(), &rom_root),
- Local_service(Ram_session::service_name(), &ram_root),
- Local_service(Rm_session::service_name(), &rm_root),
- Local_service(Cpu_session::service_name(), &cpu_root),
- Local_service(Pd_session::service_name(), &pd_root),
- Local_service(Log_session::service_name(), &log_root),
- Local_service(Io_mem_session::service_name(), &io_mem_root),
- Local_service(Irq_session::service_name(), &irq_root),
- Local_service(Trace::Session::service_name(), &trace_root)
- };
-
- /* make our local services known to service pool */
- for (unsigned i = 0; i < sizeof(ls) / sizeof(Local_service); i++)
- local_services.insert(&ls[i]);
+ static Core_service rom_service (services, rom_root);
+ static Core_service ram_service (services, ram_root);
+ static Core_service rm_service (services, rm_root);
+ static Core_service cpu_service (services, cpu_root);
+ static Core_service pd_service (services, pd_root);
+ static Core_service log_service (services, log_root);
+ static Core_service io_mem_service (services, io_mem_root);
+ static Core_service irq_service (services, irq_root);
+ static Core_service trace_service (services, trace_root);
/* make platform-specific services known to service pool */
- platform_add_local_services(e, &sliced_heap, &local_services);
+ platform_add_local_services(e, &sliced_heap, &services);
- /* obtain ROM session with init binary */
- Rom_session_capability init_rom_session_cap;
- try {
- static Rom_connection rom("init");
- init_rom_session_cap = rom.cap(); }
- catch (...) {
- error("ROM module \"init\" not present"); }
-
- /* create ram session for init and transfer some of our own quota */
- Ram_session_capability init_ram_session_cap
- = static_cap_cast(ram_root.session("ram_quota=32K", Affinity()));
- Ram_session_client(init_ram_session_cap).ref_account(env()->ram_session_cap());
-
- /* create CPU session for init and transfer all of the CPU quota to it */
+ /* create CPU session representing core */
static Cpu_session_component
- cpu(e, e, &pager_ep, &sliced_heap, Trace::sources(),
- "label=\"core\"", Affinity(), Cpu_session::QUOTA_LIMIT);
- Cpu_session_capability cpu_cap = core_env()->entrypoint()->manage(&cpu);
- Cpu_connection init_cpu("init");
- init_cpu.ref_account(cpu_cap);
- cpu.transfer_quota(init_cpu, Cpu_session::quota_lim_upscale(100, 100));
+ core_cpu(e, e, &pager_ep, &sliced_heap, Trace::sources(),
+ "label=\"core\"", Affinity(), Cpu_session::QUOTA_LIMIT);
+ Cpu_session_capability core_cpu_cap = core_env()->entrypoint()->manage(&core_cpu);
- /* transfer all left memory to init, but leave some memory left for core */
- /* NOTE: exception objects thrown in core components are currently allocated on
- core's heap and not accounted by the component's meta data allocator */
- Genode::size_t init_quota = platform()->ram_alloc()->avail() - 224*1024;
- env()->ram_session()->transfer_quota(init_ram_session_cap, init_quota);
- log("", init_quota / (1024*1024), " MiB RAM assigned to init");
+ /*
+ * Transfer all left memory to init, but leave some memory left for core
+ *
+ * NOTE: exception objects thrown in core components are currently
+ * allocated on core's heap and not accounted by the component's meta data
+ * allocator
+ */
- Pd_connection init_pd("init");
- Core_child *init = new (env()->heap())
- Core_child(Rom_session_client(init_rom_session_cap).dataspace(),
- init_pd, init_ram_session_cap, init_cpu.cap(),
- local_services);
+ Genode::size_t const ram_quota = platform()->ram_alloc()->avail() - 224*1024;
+ log("", ram_quota / (1024*1024), " MiB RAM assigned to init");
+
+ static Volatile_object
+ init(services, *env()->ram_session(), env()->ram_session_cap(),
+ ram_quota, core_cpu, core_cpu_cap);
platform()->wait_for_exit();
- destroy(env()->heap(), init);
-
- rom_root.close(init_rom_session_cap);
- ram_root.close(init_ram_session_cap);
-
+ init.destruct();
return 0;
}
diff --git a/repos/base/src/core/platform_services.cc b/repos/base/src/core/platform_services.cc
index 55ab6d00b..68cbfed5b 100644
--- a/repos/base/src/core/platform_services.cc
+++ b/repos/base/src/core/platform_services.cc
@@ -15,5 +15,5 @@
#include
-void Genode::platform_add_local_services(Rpc_entrypoint*, Sliced_heap*,
- Service_registry*) { }
+void Genode::platform_add_local_services(Rpc_entrypoint *, Sliced_heap*,
+ Registry *) { }
diff --git a/repos/base/src/core/ram_session_component.cc b/repos/base/src/core/ram_session_component.cc
index e31d2f38c..d49170f67 100644
--- a/repos/base/src/core/ram_session_component.cc
+++ b/repos/base/src/core/ram_session_component.cc
@@ -78,8 +78,10 @@ int Ram_session_component::_transfer_quota(Ram_session_component *dst, size_t am
/* decrease quota limit of this session - check against used quota */
if (_quota_limit < amount + _payload) {
- warning("Insufficient quota for transfer: ", Cstring(_label));
- warning(" have ", _quota_limit - _payload, ", need ", amount);
+ warning("insufficient quota for transfer: "
+ "'", Cstring(_label), "' to '", Cstring(dst->_label), "' "
+ "have ", (_quota_limit - _payload)/1024, " KiB, "
+ "need ", amount/1024, " KiB");
return -3;
}
@@ -262,6 +264,10 @@ int Ram_session_component::transfer_quota(Ram_session_capability ram_session_cap
{
auto lambda = [&] (Ram_session_component *dst) {
return _transfer_quota(dst, amount); };
+
+ if (this->cap() == ram_session_cap)
+ return 0;
+
return _ram_session_ep->apply(ram_session_cap, lambda);
}
diff --git a/repos/base/src/core/spec/x86/platform_services.cc b/repos/base/src/core/spec/x86/platform_services.cc
index af266aff9..87df265fa 100644
--- a/repos/base/src/core/spec/x86/platform_services.cc
+++ b/repos/base/src/core/spec/x86/platform_services.cc
@@ -26,11 +26,11 @@
*/
void Genode::platform_add_local_services(Rpc_entrypoint*,
Sliced_heap *sliced_heap,
- Service_registry *local_services)
+ Registry *local_services)
{
static Io_port_root io_port_root(core_env()->pd_session(),
platform()->io_port_alloc(), sliced_heap);
- static Local_service io_port_ls(Io_port_session::service_name(),
- &io_port_root);
- local_services->insert(&io_port_ls);
+
+ static Core_service
+ io_port_ls(*local_services, io_port_root);
}
diff --git a/repos/base/src/include/base/internal/attached_stack_area.h b/repos/base/src/include/base/internal/attached_stack_area.h
index 9e9fc5361..f6bea35e5 100644
--- a/repos/base/src/include/base/internal/attached_stack_area.h
+++ b/repos/base/src/include/base/internal/attached_stack_area.h
@@ -30,7 +30,8 @@ struct Genode::Attached_stack_area : Expanding_region_map_client
{
Attached_stack_area(Parent &parent, Pd_session_capability pd)
:
- Expanding_region_map_client(pd, Pd_session_client(pd).stack_area())
+ Expanding_region_map_client(pd, Pd_session_client(pd).stack_area(),
+ Parent::Env::pd())
{
Region_map_client address_space(Pd_session_client(pd).address_space());
diff --git a/repos/base/src/include/base/internal/expanding_cpu_session_client.h b/repos/base/src/include/base/internal/expanding_cpu_session_client.h
index 140c44e9a..6a7f9c3c0 100644
--- a/repos/base/src/include/base/internal/expanding_cpu_session_client.h
+++ b/repos/base/src/include/base/internal/expanding_cpu_session_client.h
@@ -27,7 +27,7 @@ namespace Genode { struct Expanding_cpu_session_client; }
struct Genode::Expanding_cpu_session_client : Upgradeable_client
{
- Expanding_cpu_session_client(Genode::Cpu_session_capability cap)
+ Expanding_cpu_session_client(Genode::Cpu_session_capability cap, Parent::Client::Id id)
:
/*
* We need to upcast the capability because on some platforms (i.e.,
@@ -35,7 +35,7 @@ struct Genode::Expanding_cpu_session_client : Upgradeable_client
- (static_cap_cast(cap))
+ (static_cap_cast(cap), id)
{ }
Thread_capability
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 9e29b82f2..6ef975c2f 100644
--- a/repos/base/src/include/base/internal/expanding_parent_client.h
+++ b/repos/base/src/include/base/internal/expanding_parent_client.h
@@ -87,13 +87,14 @@ class Genode::Expanding_parent_client : public Parent_client
** Parent interface **
**********************/
- Session_capability session(Service_name const &name,
+ Session_capability session(Client::Id id,
+ Service_name const &name,
Session_args const &args,
Affinity const &affinity) override
{
enum { NUM_ATTEMPTS = 2 };
return retry(
- [&] () { return Parent_client::session(name, args, affinity); },
+ [&] () { return Parent_client::session(id, name, args, affinity); },
[&] () {
/*
@@ -114,7 +115,7 @@ class Genode::Expanding_parent_client : public Parent_client
NUM_ATTEMPTS);
}
- void upgrade(Session_capability to_session, Upgrade_args const &args) override
+ Upgrade_result upgrade(Client::Id id, Upgrade_args const &args) override
{
/*
* If the upgrade fails, attempt to issue a resource request twice.
@@ -131,8 +132,8 @@ class Genode::Expanding_parent_client : public Parent_client
* caller to issue (and respond to) a resource request.
*/
enum { NUM_ATTEMPTS = 2 };
- retry(
- [&] () { Parent_client::upgrade(to_session, args); },
+ return retry(
+ [&] () { return Parent_client::upgrade(id, args); },
[&] () { resource_request(Resource_args(args.string())); },
NUM_ATTEMPTS);
}
diff --git a/repos/base/src/include/base/internal/expanding_ram_session_client.h b/repos/base/src/include/base/internal/expanding_ram_session_client.h
index 45d9d8198..69ac703d3 100644
--- a/repos/base/src/include/base/internal/expanding_ram_session_client.h
+++ b/repos/base/src/include/base/internal/expanding_ram_session_client.h
@@ -26,8 +26,8 @@ namespace Genode { class Expanding_ram_session_client; }
struct Genode::Expanding_ram_session_client : Upgradeable_client
{
- Expanding_ram_session_client(Ram_session_capability cap)
- : Upgradeable_client(cap) { }
+ Expanding_ram_session_client(Ram_session_capability cap, Parent::Client::Id id)
+ : Upgradeable_client(cap, id) { }
Ram_dataspace_capability alloc(size_t size, Cache_attribute cached = UNCACHED) override
{
diff --git a/repos/base/src/include/base/internal/expanding_region_map_client.h b/repos/base/src/include/base/internal/expanding_region_map_client.h
index 1ac5b45b7..4126cf78e 100644
--- a/repos/base/src/include/base/internal/expanding_region_map_client.h
+++ b/repos/base/src/include/base/internal/expanding_region_map_client.h
@@ -29,8 +29,9 @@ struct Genode::Expanding_region_map_client : Region_map_client
{
Upgradeable_client _pd_client;
- Expanding_region_map_client(Pd_session_capability pd, Capability rm)
- : Region_map_client(rm), _pd_client(pd) { }
+ Expanding_region_map_client(Pd_session_capability pd, Capability rm,
+ Parent::Client::Id pd_id)
+ : Region_map_client(rm), _pd_client(pd, pd_id) { }
Local_addr attach(Dataspace_capability ds, size_t size, off_t offset,
bool use_local_addr, Local_addr local_addr,
diff --git a/repos/base/src/include/base/internal/globals.h b/repos/base/src/include/base/internal/globals.h
index e3975b7cc..a67f897ec 100644
--- a/repos/base/src/include/base/internal/globals.h
+++ b/repos/base/src/include/base/internal/globals.h
@@ -17,11 +17,14 @@
#ifndef _INCLUDE__BASE__INTERNAL__GLOBALS_H_
#define _INCLUDE__BASE__INTERNAL__GLOBALS_H_
+#include
+
namespace Genode {
class Region_map;
class Ram_session;
class Env;
+ class Local_session_id_space;
extern Region_map *env_stack_area_region_map;
extern Ram_session *env_stack_area_ram_session;
@@ -30,7 +33,11 @@ namespace Genode {
void init_cxx_heap(Env &);
void init_ldso_phdr(Env &);
void init_signal_thread(Env &);
+ void init_root_proxy(Env &);
void init_log();
+
+ Id_space &env_session_id_space();
+ Env &internal_env();
}
#endif /* _INCLUDE__BASE__INTERNAL__GLOBALS_H_ */
diff --git a/repos/base/src/include/base/internal/platform_env.h b/repos/base/src/include/base/internal/platform_env.h
index 32173dcaf..47064442e 100644
--- a/repos/base/src/include/base/internal/platform_env.h
+++ b/repos/base/src/include/base/internal/platform_env.h
@@ -48,9 +48,9 @@ class Genode::Platform_env : public Env_deprecated,
struct Resources
{
template
- Capability request(Parent &parent, char const *service)
+ Capability request(Parent &parent, Parent::Client::Id id)
{
- return static_cap_cast(parent.session(service, ""));
+ return static_cap_cast(parent.session_cap(id));
}
Expanding_ram_session_client ram;
@@ -60,10 +60,12 @@ class Genode::Platform_env : public Env_deprecated,
Resources(Parent &parent)
:
- ram(request(parent, "Env::ram_session")),
- cpu(request(parent, "Env::cpu_session")),
- pd (request (parent, "Env::pd_session")),
- rm (pd, pd.address_space())
+ ram(request(parent, Parent::Env::ram()),
+ Parent::Env::ram()),
+ cpu(request(parent, Parent::Env::cpu()),
+ Parent::Env::cpu()),
+ pd (request