/* * \brief Child creation framework * \author Norman Feske * \date 2006-07-22 */ /* * Copyright (C) 2006-2013 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__CHILD_H_ #define _INCLUDE__BASE__CHILD_H_ #include #include #include #include #include #include #include namespace Genode { /** * Child policy interface * * A child-policy object is an argument to a 'Child'. It is responsible for * taking policy decisions regarding the parent interface. Most importantly, * it defines how session requests are resolved and how session arguments * are passed to servers when creating sessions. */ struct Child_policy { virtual ~Child_policy() { } /** * Return process name of the child */ virtual const char *name() const = 0; /** * 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 */ virtual Service *resolve_session_request(const char * /*service_name*/, const char * /*args*/) { return 0; } /** * Apply transformations to session arguments */ virtual void filter_session_args(const char * /*service*/, 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; } /** * Apply session affinity policy * * \param affinity affinity passed along with a session request * \return affinity subordinated to the child policy */ virtual Affinity filter_session_affinity(Affinity const &affinity) { return affinity; } /** * Unregister services that had been provided by the child */ virtual void unregister_services() { } /** * Exit child */ virtual void exit(int exit_value) { PDBG("child exited with exit value %d", exit_value); } /** * Reference RAM session * * The RAM session returned by this function is used for session-quota * transfers. */ virtual Ram_session *ref_ram_session() { return env()->ram_session(); } /** * Return platform-specific PD-session arguments * * This function is used on Linux to supply additional PD-session * argument to core, i.e., the chroot path, the UID, and the GID. */ virtual Native_pd_args const *pd_args() const { return 0; } }; /** * Implementation of the parent interface that supports resource trading * * There are three possible cases of how a session can be provided to * a child: * * # The service is implemented locally * # The session was obtained by asking our parent * # The session is provided by one of our children * * These types must be differentiated for the quota management when a child * issues the closing of a session or a transfers quota via our parent * interface. * * If we close a session to a local service, we transfer the session quota * from our own account to the client. * * If we close a parent session, we receive the session quota on our own * account and must transfer this amount to the session-closing child. * * If we close a session provided by a server child, we close the session * at the server, transfer the session quota from the server's ram session * to our account, and subsequently transfer the same amount from our * account to the client. */ class Child : protected Rpc_object { private: class Session; /* RAM session that contains the quota of the child */ Ram_session_capability _ram; Ram_session_client _ram_session_client; /* CPU session that contains the quota of the child */ Cpu_session_capability _cpu; /* RM session representing the address space of the child */ Rm_session_capability _rm; /* Services where the RAM, CPU, and RM resources come from */ Service &_ram_service; Service &_cpu_service; Service &_rm_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; /* sessions opened by the child */ Lock _lock; /* protect list manipulation */ Object_pool _session_pool; List _session_list; /* server role */ Server _server; /** * Session-argument buffer */ char _args[Parent::Session_args::MAX_SIZE]; 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); /** * Close session and revert quota donation associated with it */ void _remove_session(Session *s); /** * Return service interface targetting the parent * * The service returned by this function 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. */ static Service *_parent_service(); public: /** * Constructor * * \param elf_ds dataspace containing the binary * \param ram RAM session with the child's quota * \param cpu CPU session with the child's quota * \param rm RM session representing the address space * of the child * \param entrypoint server entrypoint to serve the parent interface * \param policy child policy * \param ram_service provider of the 'ram' session * \param cpu_service provider of the 'cpu' session * \param rm_service provider of the 'rm' session * * If assigning a separate entry point to each child, the host of * multiple children is able to handle a blocking invocation of * the parent interface of one child while still maintaining the * service to other children, each having an independent entry * point. * * The 'ram_service', 'cpu_service', and 'rm_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, Ram_session_capability ram, Cpu_session_capability cpu, Rm_session_capability rm, Rpc_entrypoint *entrypoint, Child_policy *policy, Service &ram_service = *_parent_service(), Service &cpu_service = *_parent_service(), Service &rm_service = *_parent_service()); /** * Destructor * * On destruction of a child, we close all sessions of the child to * other services. */ virtual ~Child(); /** * Return heap that uses the child's quota */ Allocator *heap() { return &_heap; } Ram_session_capability ram_session_cap() const { return _ram; } Cpu_session_capability cpu_session_cap() const { return _cpu; } Rm_session_capability rm_session_cap() const { return _rm; } Parent_capability parent_cap() const { return cap(); } /** * Discard all sessions to specified service * * When this function 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! */ void revoke_server(const Server *server); /********************** ** Parent interface ** **********************/ void announce(Service_name const &, Root_capability); Session_capability session(Service_name const &, Session_args const &, Affinity const &); void upgrade(Session_capability, Upgrade_args const &); void close(Session_capability); void exit(int); Thread_capability main_thread_cap() const; }; } #endif /* _INCLUDE__BASE__CHILD_H_ */