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 { class Parent; }
  25  
  26  
  27  class Genode::Parent
  28  {
  29     private:
  30  
  31        /**
  32         * Recursively announce inherited service interfaces
  33         *
  34         * At compile time, the `ROOT` type is inspected for the presence
  35         * of the `Rpc_inherited_interface` type in the corresponding
  36         * session interface. If present, the session type gets announced.
  37         * This works recursively.
  38         */

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

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

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

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

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

  68        typedef String<160> Resource_args;

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

  76        virtual void exit(int exit_value) = 0;

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

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

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

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

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

 110        }

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

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

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

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

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

 153           return reinterpret_cap_cast<SESSION_TYPE>(cap);

 154        }

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

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

 171  
 172        /**
 173         * Close session
 174         */

 175        virtual void close(Session_capability session) = 0;

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

 180        virtual Thread_capability main_thread_cap() const = 0;

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

 185        virtual void resource_avail_sigh(Signal_context_capability sigh) = 0;

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

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

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

 210        virtual void yield_sigh(Signal_context_capability sigh) = 0;

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

 222        virtual Resource_args yield_request() = 0;

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

 227        virtual void yield_response() = 0;

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

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

 265                
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 Rpc_functions;

 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_ */