1  /*
   2   * \brief  Parent interface
   3   * \author Norman Feske
   4   * \date   2006-05-10
   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__PARENT__PARENT_H_
  15  #define _INCLUDE__PARENT__PARENT_H_
  16  
  17  #include <base/exception.h>
  18  #include <base/rpc.h>
  19  #include <base/rpc_args.h>
  20  #include <base/thread.h>
  21  #include <session/capability.h>
  22  #include <root/capability.h>
  23  
  24  namespace Genode {
  25  
  26     class Parent
  27     {
  28        private:
  29  
  30           /**
  31            * Recursively announce inherited service interfaces
  32            *
  33            * At compile time, the `ROOT` type is inspected for the presence
  34            * of the `Rpc_inherited_interface` type in the corresponding
  35            * session interface. If present, the session type gets announced.
  36            * This works recursively.
  37            */

  38           template <typename ROOT>
  39           void _announce_base(Capability<ROOT> const &, Meta::Bool_to_type<false> *) { }

  40  
  41           /*
  42            * This overload gets selected if the ROOT interface corresponds to
  43            * an inherited session type.
  44            */

  45           template <typename ROOT>
  46           inline void _announce_base(Capability<ROOT> const &, Meta::Bool_to_type<true> *);

  47  
  48        public:
  49  
  50           /*********************
  51            ** Exception types **
  52            *********************/

  53  
  54           class Exception      : public ::Genode::Exception { };
  55           class Service_denied : public Exception { };
  56           class Quota_exceeded : public Exception { };
  57           class Unavailable    : public Exception { };
  58  
  59           typedef Rpc_in_buffer<64>  Service_name;
  60           typedef Rpc_in_buffer<160> Session_args;
  61           typedef Rpc_in_buffer<160> Upgrade_args;
  62  
  63           /**
  64            * Use `String` instead of `Rpc_in_buffer` because `Resource_args`
  65            * is used as both in and out parameter.
  66            */

  67           typedef String<160> Resource_args;

  68  
  69  
  70           virtual ~Parent() { }
  71  
  72           /**
  73            * Tell parent to exit the program
  74            */

  75           virtual void exit(int exit_value) = 0;

  76  
  77           /**
  78            * Announce service to the parent
  79            */

  80           virtual void announce(Service_name const &service_name,
  81                                 Root_capability service_root)
 = 0;

  82  
  83  
  84           /**
  85            * Announce service to the parent
  86            *
  87            * \param service_root  root capability
  88            *
  89            * The type of the specified `service_root` capability match with
  90            * an interface that provides a `Session_type` type (i.e., a
  91            * `Typed_root` interface). This `Session_type` is expected to
  92            * host a static function called `service_name` returning the
  93            * name of the provided interface as null-terminated string.
  94            */

  95           template <typename ROOT_INTERFACE>
  96           void announce(Capability<ROOT_INTERFACE> const &service_root)
  97           {
  98              typedef typename ROOT_INTERFACE::Session_type Session;
  99              announce(Session::service_name(), service_root);
 100  
 101              /*
 102               * Announce inherited session types
 103               *
 104               * Select the overload based on the presence of the type
 105               * `Rpc_inherited_interface` within the session type.
 106               */

 107              _announce_base(service_root,
 108                             (Meta::Bool_to_type<Rpc_interface_is_inherited<Session>::VALUE> *)0)
;

 109           }

 110  
 111           /**
 112            * Create session to a service
 113            *
 114            * \param service_name     name of the requested interface
 115            * \param args             session constructor arguments
 116            * \param affinity         preferred CPU affinity for the session
 117            *
 118            * \throw Service_denied   parent denies session request
 119            * \throw Quota_exceeded   our own quota does not suffice for
 120            *                         the creation of the new session
 121            * \throw Unavailable
 122            *
 123            * \return                 untyped capability to new session
 124            *
 125            * The use of this function is discouraged. Please use the type safe
 126            * `session()` template instead.
 127            */

 128           virtual Session_capability session(Service_name const &service_name,
 129                                              Session_args const &args,
 130                                              Affinity     const &affinity = Affinity())
 = 0;

 131  
 132           /**
 133            * Create session to a service
 134            *
 135            * \param SESSION_TYPE     session interface type
 136            * \param args             session constructor arguments
 137            * \param affinity         preferred CPU affinity for the session
 138            *
 139            * \throw Service_denied   parent denies session request
 140            * \throw Quota_exceeded   our own quota does not suffice for
 141            *                         the creation of the new session
 142            * \throw Unavailable
 143            *
 144            * \return                 capability to new session
 145            */

 146           template <typename SESSION_TYPE>
 147           Capability<SESSION_TYPE> session(Session_args const &args,
 148                                            Affinity     const &affinity = Affinity())

 149           {
 150              Session_capability cap = session(SESSION_TYPE::service_name(),
 151                                               args, affinity)
;

 152              return reinterpret_cap_cast<SESSION_TYPE>(cap);

 153           }

 154  
 155           /**
 156            * Transfer our quota to the server that provides the specified session
 157            *
 158            * \param to_session recipient session
 159            * \param args       description of the amount of quota to transfer
 160            *
 161            * \throw Quota_exceeded  quota could not be transferred
 162            *
 163            * The `args` argument has the same principle format as the `args`
 164            * argument of the `session` function.
 165            * The error case indicates that there is not enough unused quota on
 166            * the source side.
 167            */

 168           virtual void upgrade(Session_capability to_session,
 169                                Upgrade_args const &args)
 = 0;

 170  
 171           /**
 172            * Close session
 173            */

 174           virtual void close(Session_capability session) = 0;

 175  
 176           /**
 177            * Provide thread_cap of main thread
 178            */

 179           virtual Thread_capability main_thread_cap() const = 0;

 180  
 181           /**
 182            * Register signal handler for resource notifications
 183            */

 184           virtual void resource_avail_sigh(Signal_context_capability sigh) = 0;

 185  
 186           /**
 187            * Request additional resources
 188            *
 189            * By invoking this function, a process is able to inform its
 190            * parent about the need for additional resources. The argument
 191            * string contains a resource description in the same format as
 192            * used for session-construction arguments. In particular, for
 193            * requesting additional RAM quota, the argument looks like
 194            * "ram_quota=<amount>" where `amount` is the amount of additional
 195            * resources expected from the parent. If the parent complies with
 196            * the request, it submits a resource-available signal to the
 197            * handler registered via `resource_avail_sigh()`. On the reception
 198            * of such a signal, the process can re-evaluate its resource quota
 199            * and resume execution.
 200            */

 201           virtual void resource_request(Resource_args const &args) = 0;

 202  
 203           /**
 204            * Register signal handler for resource yield notifications
 205            *
 206            * Using the yield signal, the parent is able to inform the process
 207            * about its wish to regain resources.
 208            */

 209           virtual void yield_sigh(Signal_context_capability sigh) = 0;

 210  
 211           /**
 212            * Obtain information about the amount of resources to free
 213            *
 214            * The amount of resources returned by this function is the
 215            * goal set by the parent. It is not commanded but merely meant
 216            * as a friendly beg to cooperate. The process is not obligated
 217            * to comply. If the process decides to take action to free
 218            * resources, it can inform its parent about the availability
 219            * of freed up resources by calling `yield_response()`.
 220            */

 221           virtual Resource_args yield_request() = 0;

 222  
 223           /**
 224            * Notify the parent about a response to a yield request
 225            */

 226           virtual void yield_response() = 0;

 227  
 228  
 229           /*********************
 230            ** RPC declaration **
 231            *********************/

 232  
 233           GENODE_RPC(Rpc_exit, void, exit, int);
 234           GENODE_RPC(Rpc_announce, void, announce,
 235                      Service_name const &, Root_capability)
;
 236           GENODE_RPC_THROW(Rpc_session, Session_capability, session,
 237                            GENODE_TYPE_LIST(Service_denied, Quota_exceeded, Unavailable),
 238                            Service_name const &, Session_args const &, Affinity const &)
;
 239           GENODE_RPC_THROW(Rpc_upgrade, void, upgrade,
 240                            GENODE_TYPE_LIST(Quota_exceeded),
 241                            Session_capability, Upgrade_args const &)
;
 242           GENODE_RPC(Rpc_close, void, close, Session_capability);
 243           GENODE_RPC(Rpc_main_thread, Thread_capability, main_thread_cap);
 244           GENODE_RPC(Rpc_resource_avail_sigh, void, resource_avail_sigh,
 245                      Signal_context_capability)
;
 246           GENODE_RPC(Rpc_resource_request, void, resource_request,
 247                      Resource_args const &)
;
 248           GENODE_RPC(Rpc_yield_sigh, void, yield_sigh, Signal_context_capability);
 249           GENODE_RPC(Rpc_yield_request, Resource_args, yield_request);
 250           GENODE_RPC(Rpc_yield_response, void, yield_response);
 251  
 252           typedef Meta::Type_tuple<Rpc_exit,
 253                   Meta::Type_tuple<Rpc_announce,
 254                   Meta::Type_tuple<Rpc_session,
 255                   Meta::Type_tuple<Rpc_upgrade,
 256                   Meta::Type_tuple<Rpc_close,
 257                   Meta::Type_tuple<Rpc_main_thread,
 258                   Meta::Type_tuple<Rpc_resource_avail_sigh,
 259                   Meta::Type_tuple<Rpc_resource_request,
 260                   Meta::Type_tuple<Rpc_yield_sigh,
 261                   Meta::Type_tuple<Rpc_yield_request,
 262                   Meta::Type_tuple<Rpc_yield_response,
 263                                    Meta::Empty>

 264                   >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 Rpc_functions;

 265     }
;

 266  }

 267  
 268  
 269  template <typename ROOT_INTERFACE>
 270  void
 271  
Genode::Parent::_announce_base(Genode::Capability<ROOT_INTERFACE> const &service_root,
 272                                 Genode::Meta::Bool_to_type<true> *)

 273  {
 274     /* shortcut for inherited session type */
 275     typedef typename ROOT_INTERFACE::Session_type::Rpc_inherited_interface
 276             Session_type_inherited;

 277  
 278     /* shortcut for root interface type matching the inherited session type */
 279     typedef Typed_root<Session_type_inherited> Root_inherited;
 280  
 281     /* convert root capability to match the inherited session type */
 282     Capability<Root>           root           = service_root;

 283     Capability<Root_inherited> root_inherited = static_cap_cast<Root_inherited>(root);
 284  
 285     /* announce inherited service type */

 286     announce(Session_type_inherited::service_name(), root_inherited);
 287  
 288     /* recursively announce further inherited session types */
 289     _announce_base(root_inherited,
 290                    (Meta::Bool_to_type<Rpc_interface_is_inherited<Session_type_inherited>::VALUE> *)0)
;

 291  }

 292  
 293  
 294  #endif /* _INCLUDE__PARENT__PARENT_H_ */