1  /*
   2   * \brief  Child creation framework
   3   * \author Norman Feske
   4   * \date   2006-07-22
   5   */

   6  
   7  /*
   8   * Copyright (C) 2006-2013 Genode Labs GmbH
   9   *
  10   * This file is part of the Genode OS framework, which is distributed
  11   * under the terms of the GNU General Public License version 2.
  12   */

  13  
  14  #ifndef _INCLUDE__BASE__CHILD_H_
  15  #define _INCLUDE__BASE__CHILD_H_
  16  
  17  #include <base/rpc_server.h>
  18  #include <base/heap.h>
  19  #include <base/process.h>
  20  #include <base/service.h>
  21  #include <base/lock.h>
  22  #include <util/arg_string.h>
  23  #include <parent/parent.h>
  24  
  25  namespace Genode {
  26  
  27     struct Child_policy;
  28     struct Child;
  29  }

  30  
  31  
  32  /**
  33   * Child policy interface
  34   *
  35   * A child-policy object is an argument to a `Child`. It is responsible for
  36   * taking policy decisions regarding the parent interface. Most importantly,
  37   * it defines how session requests are resolved and how session arguments
  38   * are passed to servers when creating sessions.
  39   */

  40  struct Genode::Child_policy
  41  {
  42     virtual ~Child_policy() { }
  43  
  44     /**
  45      * Return process name of the child
  46      */

  47     virtual const char *name() const = 0;

  48  
  49     /**
  50      * Determine service to provide a session request
  51      *
  52      * \return  Service to be contacted for the new session, or
  53      *          0 if session request could not be resolved
  54      */

  55     virtual Service *resolve_session_request(const char * /*service_name*/,
  56                                              const char * /*args*/)

  57     { return 0; }

  58  
  59     /**
  60      * Apply transformations to session arguments
  61      */

  62     virtual void filter_session_args(const char * /*service*/,
  63                                      char * /*args*/, size_t /*args_len*/)
 { }

  64  
  65     /**
  66      * Register a service provided by the child
  67      *
  68      * \param name   service name
  69      * \param root   interface for creating sessions for the service
  70      * \param alloc  allocator to be used for child-specific
  71      *               meta-data allocations
  72      * \return       true if announcement succeeded, or false if
  73      *               child is not permitted to announce service
  74      */

  75     virtual bool announce_service(const char            * /*name*/,
  76                                   Root_capability         /*root*/,
  77                                   Allocator             * /*alloc*/,
  78                                   Server                * /*server*/)

  79     { return false; }

  80  
  81     /**
  82      * Apply session affinity policy
  83      *
  84      * \param affinity  affinity passed along with a session request
  85      * \return          affinity subordinated to the child policy
  86      */

  87     virtual Affinity filter_session_affinity(Affinity const &affinity)
  88     {
  89        return affinity;
  90     }

  91  
  92     /**
  93      * Unregister services that had been provided by the child
  94      */

  95     virtual void unregister_services() { }

  96  
  97     /**
  98      * Exit child
  99      */

 100     virtual void exit(int exit_value)
 101     {
 102        PDBG("child \"%s\" exited with exit value %d", name(), exit_value);
 103     }

 104  
 105     /**
 106      * Reference RAM session
 107      *
 108      * The RAM session returned by this method is used for session-quota
 109      * transfers.
 110      */

 111     virtual Ram_session *ref_ram_session() { return env()->ram_session(); }

 112     virtual Ram_session_capability ref_ram_cap() const { return env()->ram_session_cap(); }
 113  
 114     /**
 115      * Respond to the release of resources by the child
 116      *
 117      * This method is called when the child confirms the release of
 118      * resources in response to a yield request.
 119      */

 120     virtual void yield_response() { }

 121  
 122     /**
 123      * Take action on additional resource needs by the child
 124      */

 125     virtual void resource_request(Parent::Resource_args const &) { }

 126  }
;

 127  
 128  
 129  /**
 130   * Implementation of the parent interface that supports resource trading
 131   *
 132   * There are three possible cases of how a session can be provided to
 133   * a child: The service is implemented locally, the session was obtained by
 134   * asking our parent, or the session is provided by one of our children.
 135   *
 136   * These types must be differentiated for the quota management when a child
 137   * issues the closing of a session or transfers quota via our parent
 138   * interface.
 139   *
 140   * If we close a session to a local service, we transfer the session quota
 141   * from our own account to the client.
 142   *
 143   * If we close a parent session, we receive the session quota on our own
 144   * account and must transfer this amount to the session-closing child.
 145   *
 146   * If we close a session provided by a server child, we close the session
 147   * at the server, transfer the session quota from the server`s RAM session
 148   * to our account, and subsequently transfer the same amount from our
 149   * account to the client.
 150   */

 151  class Genode::Child : protected Rpc_object<Parent>
 152  {
 153     private:
 154  
 155        class Session;
 156  
 157        /* PD session representing the protection domain of the child */
 158        Pd_session_capability   _pd;
 159        Pd_session_client       _pd_session_client;
 160  
 161        /* RAM session that contains the quota of the child */

 162        Ram_session_capability  _ram;
 163        Ram_session_client      _ram_session_client;
 164  
 165        /* CPU session that contains the quota of the child */

 166        Cpu_session_capability  _cpu;
 167  
 168        /* RM session representing the address space of the child */

 169        Rm_session_capability   _rm;
 170  
 171        /* Services where the PD, RAM, CPU, and RM resources come from */

 172        Service                &_pd_service;
 173        Service                &_ram_service;
 174        Service                &_cpu_service;
 175        Service                &_rm_service;
 176  
 177        /* heap for child-specific allocations using the child`s quota */

 178        Heap                    _heap;
 179  
 180        Rpc_entrypoint         *_entrypoint;
 181        Parent_capability       _parent_cap;
 182  
 183        /* child policy */

 184        Child_policy           *_policy;
 185  
 186        /* sessions opened by the child */

 187        Lock                    _lock;   /* protect list manipulation */
 188        Object_pool<Session>    _session_pool;
 189        List<Session>           _session_list;
 190  
 191        /* server role */

 192        Server                 _server;
 193  
 194        /* session-argument buffer */

 195        char _args[Parent::Session_args::MAX_SIZE];
 196  
 197        /* signal handlers registered by the child */

 198        Signal_context_capability _resource_avail_sigh;
 199        Signal_context_capability _yield_sigh;
 200  
 201        /* arguments fetched by the child in response to a yield signal */

 202        Lock          _yield_request_lock;
 203        Resource_args _yield_request_args;
 204  
 205        Process _process;
 206  
 207        /**
 208         * Attach session information to a child
 209         *
 210         * \throw Ram_session::Quota_exceeded  the child`s heap partition cannot
 211         *                                     hold the session meta data
 212         */

 213        void _add_session(const Session &s);

 214  
 215        /**
 216         * Close session and revert quota donation associated with it
 217         */

 218        void _remove_session(Session *s);

 219  
 220        void _close(Session *s);
 221  
 222        /**
 223         * Return service interface targetting the parent
 224         *
 225         * The service returned by this method is used as default
 226         * provider for the RAM, CPU, and RM resources of the child. It is
 227         * solely used for targeting resource donations during
 228         * `Parent::upgrade_quota()` calls.
 229         */

 230        static Service *_parent_service();

 231  
 232     public:
 233  
 234        /**
 235         * Constructor
 236         *
 237         * \param elf_ds       dataspace containing the binary
 238         * \param pd           PD session representing the protection domain
 239         * \param ram          RAM session with the child`s quota
 240         * \param cpu          CPU session with the child`s quota
 241         * \param rm           RM session representing the address space
 242         *                     of the child
 243         * \param entrypoint   server entrypoint to serve the parent interface
 244         * \param policy       child policy
 245         * \param pd_service   provider of the `pd` session
 246         * \param ram_service  provider of the `ram` session
 247         * \param cpu_service  provider of the `cpu` session
 248         * \param rm_service   provider of the `rm` session
 249         *
 250         * If assigning a separate entry point to each child, the host of
 251         * multiple children is able to handle a blocking invocation of
 252         * the parent interface of one child while still maintaining the
 253         * service to other children, each having an independent entry
 254         * point.
 255         *
 256         * The `ram_service`, `cpu_service`, and `rm_service` arguments are
 257         * needed to direct quota upgrades referring to the resources of
 258         * the child environment. By default, we expect that these
 259         * resources are provided by the parent.
 260         */

 261        Child(Dataspace_capability    elf_ds,
 262              Pd_session_capability   pd,
 263              Ram_session_capability  ram,
 264              Cpu_session_capability  cpu,
 265              Rm_session_capability   rm,
 266              Rpc_entrypoint         *entrypoint,
 267              Child_policy           *policy,
 268              Service                &pd_service  = *_parent_service(),
 269              Service                &ram_service = *_parent_service(),
 270              Service                &cpu_service = *_parent_service(),
 271              Service                &rm_service  = *_parent_service())
;

 272  
 273        /**
 274         * Destructor
 275         *
 276         * On destruction of a child, we close all sessions of the child to
 277         * other services.
 278         */

 279        virtual ~Child();

 280  
 281        /**
 282         * Return heap that uses the child`s quota
 283         */

 284        Allocator *heap() { return &_heap; }

 285  
 286        Pd_session_capability  pd_session_cap()  const { return _pd; }
 287        Ram_session_capability ram_session_cap() const { return _ram; }
 288        Cpu_session_capability cpu_session_cap() const { return _cpu; }
 289        Rm_session_capability  rm_session_cap()  const { return _rm;  }
 290        Parent_capability      parent_cap()      const { return cap(); }
 291  
 292        /**
 293         * Discard all sessions to specified service
 294         *
 295         * When this method is called, we assume the server protection
 296         * domain to be dead and all that all server quota was already
 297         * transferred back to our own `env()->ram_session()` account. Note
 298         * that the specified server object may not exist anymore. We do
 299         * not de-reference the server argument in here!
 300         */

 301        void revoke_server(const Server *server);

 302  
 303        /**
 304         * Instruct the child to yield resources
 305         *
 306         * By calling this method, the child will be notified about the
 307         * need to release the specified amount of resources. For more
 308         * details about the protocol between a child and its parent,
 309         * refer to the description given in `parent/parent.h`.
 310         */

 311        void yield(Resource_args const &args);

 312  
 313        /**
 314         * Notify the child about newly available resources
 315         */

 316        void notify_resource_avail() const;

 317  
 318  
 319        /**********************
 320         ** Parent interface **
 321         **********************/

 322  
 323        void announce(Service_name const &, Root_capability) override;
 324        Session_capability session(Service_name const &, Session_args const &,
 325                                   Affinity const &)
 override;

 326        void upgrade(Session_capability, Upgrade_args const &) override;
 327        void close(Session_capability) override;
 328        void exit(int) override;
 329        Thread_capability main_thread_cap() const override;
 330        void resource_avail_sigh(Signal_context_capability) override;
 331        void resource_request(Resource_args const &) override;
 332        void yield_sigh(Signal_context_capability) override;
 333        Resource_args yield_request() override;
 334        void yield_response() override;

 335  }
;

 336  
 337  #endif /* _INCLUDE__BASE__CHILD_H_ */