1  /*
   2   * \brief  Generic root component implementation
   3   * \author Norman Feske
   4   * \date   2006-05-22
   5   *
   6   * This class is there for your convenience. It performs the common actions
   7   * that must always be taken when creating a new session.
   8   */

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

  16  
  17  #ifndef _INCLUDE__ROOT__COMPONENT_H_
  18  #define _INCLUDE__ROOT__COMPONENT_H_
  19  
  20  #include <root/server.h>
  21  #include <base/heap.h>
  22  #include <ram_session/ram_session.h>
  23  #include <util/arg_string.h>
  24  #include <base/printf.h>
  25  
  26  namespace Genode {
  27  
  28     /**
  29      * Session creation policy for a single-client service
  30      */

  31     class Single_client
  32     {
  33        private:
  34  
  35           bool _used;

  36  
  37        public:
  38  
  39           Single_client() _used(0) { }
  40  
  41           void aquire(const char *args)
  42           {
  43              if (_used)
  44                 throw Root::Unavailable();
  45  
  46              _used = true;
  47           }

  48  
  49           void release() { _used = false; }

  50     }
;

  51  
  52  
  53     /**
  54      * Session-creation policy for a multi-client service
  55      */

  56     struct Multiple_clients
  57     {
  58        void aquire(const char *args) { }
  59        void release() { }

  60     }
;

  61  
  62  
  63     /**
  64      * Template for implementing the root interface
  65      *
  66      * \param SESSION_TYPE  session-component type to manage,
  67      *                      derived from `Server_object`
  68      * \param POLICY        session-creation policy
  69      *
  70      * The `POLICY` template parameter allows for constraining the session
  71      * creation to only one instance at a time (using the `Single_session`
  72      * policy) or multiple instances (using the `Multiple_sessions` policy).
  73      *
  74      * The `POLICY` class must provide the following two functions:
  75      *
  76      * :`aquire(const char *args)`: is called with the session arguments
  77      *   at creation time of each new session. It can therefore implement
  78      *   a session-creation policy taking session arguments into account.
  79      *   If the policy denies the creation of a new session, it throws
  80      *   one of the exceptions defined in the `Root` interface.
  81      *
  82      * :`release`: is called at the destruction time of a session. It enables
  83      *   the policy to keep track of and impose restrictions on the number
  84      *   of existing sessions.
  85      *
  86      * The default policy `Multiple_clients` imposes no restrictions on the
  87      * creation of new sessions.
  88      */

  89     template <typename SESSION_TYPEtypename POLICY = Multiple_clients>
  90     class Root_component public Root_server, private POLICY
  91     {
  92        private:
  93  
  94           /*
  95            * Entry point that manages the session objects
  96            * created by this root interface
  97            */

  98           Server_entrypoint *_ep;
  99  
 100           /*
 101            * Allocator for allocating session objects.
 102            * This allocator must be used by the derived
 103            * class when calling the `new` operator for
 104            * creating a new session.
 105            */

 106           Allocator *_md_alloc;

 107  
 108        protected:
 109  
 110           /**
 111            * Create new session (to be implemented by a derived class)
 112            *
 113            * Only a derived class knows the constructor arguments of
 114            * a specific session. Therefore, we cannot unify the call
 115            * of its `new` operator and must implement the session
 116            * creation at a place, where the required knowledge exist.
 117            *
 118            * In the implementation of this function, the heap, provided
 119            * by `Root_component` must be used for allocating the session
 120            * object.
 121            *
 122            * \throw Allocator::Out_of_memory  typically caused by the
 123            *                                  meta-data allocator
 124            * \throw Root::Invalid_args        typically caused by the
 125            *                                  session-component constructor
 126            */

 127           virtual SESSION_TYPE *_create_session(const char *args) = 0;

 128  
 129           virtual void _destroy_session(SESSION_TYPE *session) {
 130              destroy(_md_alloc, session); }

 131  
 132           /**
 133            * Return allocator to allocate server object in `_create_session()`
 134            */

 135           Allocator         *md_alloc() { return _md_alloc; }

 136           Server_entrypoint *ep()       { return _ep; }

 137  
 138        public:
 139  
 140           /**
 141            * Constructor
 142            *
 143            * \param ep           entry point that manages the sessions of this
 144            *                     root interface.
 145            * \param ram_session  provider of dataspaces for the backing store
 146            *                     of session objects and session data
 147            */

 148           Root_component(Server_entrypoint *epAllocator *metadata_alloc)
 149           Root_server()_ep(ep)_md_alloc(metadata_alloc) { }

 150  
 151  
 152           /********************
 153            ** Root interface **
 154            ********************/

 155  
 156           Session_capability session(const char *args)
 157           {
 158              POLICY::aquire(args);
 159  
 160              /*
 161               * We need to decrease `ram_quota` by
 162               * the size of the session object.
 163               */

 164              size_t ram_quota = Arg_string::find_arg(args, "ram_quota").long_value(0);
 165              long remaining_ram_quota = ram_quota - sizeof(SESSION_TYPE);
 166              if (remaining_ram_quota < 0) {
 167                 PERR("Insufficient ram quota, provided=%zd, required=%zd",
 168                      ram_quota, sizeof(SESSION_TYPE))
;

 169                 throw Quota_exceeded();
 170              }

 171  
 172              SESSION_TYPE *s = 0;
 173              try {
 174                 s = _create_session(args);
 175              }
 catch (Allocator::Out_of_memory) {
 176                 throw Quota_exceeded();
 177              }

 178  
 179              return Session_capability(_ep->manage(s));

 180           }

 181  
 182           void close(Session_capability session)
 183           {
 184              SESSION_TYPE *s;
 185  
 186              s = dynamic_cast<SESSION_TYPE *>(_ep->obj_by_cap(session));

 187              if (!s) return;
 188  
 189              /* let the entry point forget the session object */
 190              _ep->dissolve(s);
 191  
 192              _destroy_session(s);
 193  
 194              POLICY::release();
 195              return;

 196           }

 197     }
;

 198  }

 199  
 200  #endif /* _INCLUDE__ROOT__COMPONENT_H_ */