1  /*
   2   * \brief  Server-side API of the RPC framework
   3   * \author Norman Feske
   4   * \date   2006-04-28
   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__RPC_SERVER_H_
  15  #define _INCLUDE__BASE__RPC_SERVER_H_
  16  
  17  #include <base/rpc.h>
  18  #include <base/thread.h>
  19  #include <base/ipc.h>
  20  #include <base/object_pool.h>
  21  #include <base/lock.h>
  22  #include <base/printf.h>
  23  #include <base/trace/events.h>
  24  #include <cap_session/cap_session.h>
  25  
  26  namespace Genode {
  27     template <typename, typename> class Rpc_dispatcher;
  28     class Rpc_object_base;
  29     template <typename, typename> struct Rpc_object;
  30     class Rpc_entrypoint;
  31  }

  32  
  33  
  34  /**
  35   * RPC dispatcher implementing the specified RPC interface
  36   *
  37   * \param RPC_INTERFACE  class providing the RPC interface description
  38   * \param SERVER         class to invoke for the server-side RPC functions
  39   *
  40   * This class is the base class of each server-side RPC implementation. It
  41   * contains the logic for dispatching incoming RPC requests and calls the
  42   * server functions according to the RPC declarations in `RPC_INTERFACE`.
  43   *
  44   * If using the default argument for `SERVER`, the `RPC_INTERFACE` is expected
  45   * to contain the abstract interface for all RPC functions. So virtual methods
  46   * must be declared in `RPC_INTERFACE`. In contrast, by explicitly specifying
  47   * the `SERVER` argument, the server-side dispatching performs direct
  48   * calls to the respective methods of the `SERVER` class and thereby
  49   * omits virtual method calls.
  50   */

  51  template <typename RPC_INTERFACE, typename SERVER = RPC_INTERFACE>
  52  class Genode::Rpc_dispatcher : public RPC_INTERFACE
  53  {
  54     /**
  55      * Shortcut for the type list of RPC functions provided by this server
  56      * component
  57      */

  58     typedef typename RPC_INTERFACE::Rpc_functions Rpc_functions;
  59  
  60     protected:
  61  
  62        template <typename ARG_LIST>
  63        void _read_args(Ipc_istream &is, ARG_LIST &args)
  64        {
  65           if (Trait::Rpc_direction<typename ARG_LIST::Head>::Type::IN)
  66              is >> args._1;

  67  
  68           _read_args(is, args._2);

  69        }

  70  
  71        void _read_args(Ipc_istream &, Meta::Empty) { }
  72  
  73        template <typename ARG_LIST>
  74        void _write_results(Ipc_ostream &os, ARG_LIST &args)
  75        {
  76           if (Trait::Rpc_direction<typename ARG_LIST::Head>::Type::OUT)
  77              os << args._1;

  78  
  79           _write_results(os, args._2);

  80        }

  81  
  82        void _write_results(Ipc_ostream &, Meta::Empty) { }
  83  
  84        template <typename RPC_FUNCTION, typename EXC_TL>
  85        Rpc_exception_code _do_serve(typename RPC_FUNCTION::Server_args &args,
  86                                     typename RPC_FUNCTION::Ret_type    &ret,
  87                                     Meta::Overload_selector<RPC_FUNCTION, EXC_TL>)

  88        {
  89           enum { EXCEPTION_CODE = RPC_EXCEPTION_BASE - Meta::Length<EXC_TL>::Value };
  90           try {
  91              typedef typename EXC_TL::Tail Exc_tail;
  92              return _do_serve(args, ret,
  93                               Meta::Overload_selector<RPC_FUNCTION, Exc_tail>())
;

  94           }
 catch (typename EXC_TL::Head) { return EXCEPTION_CODE; }

  95        }

  96  
  97        template <typename RPC_FUNCTION>
  98        Rpc_exception_code _do_serve(typename RPC_FUNCTION::Server_args &args,
  99                                     typename RPC_FUNCTION::Ret_type    &ret,
 100                                     Meta::Overload_selector<RPC_FUNCTION, Meta::Empty>)

 101        {
 102           RPC_FUNCTION::serve(*static_cast<SERVER *>(this), args, ret);
 103           return 0;

 104        }

 105  
 106        template <typename RPC_FUNCTIONS_TO_CHECK>
 107        Rpc_exception_code _do_dispatch(Rpc_opcode opcode, Ipc_istream &is, Ipc_ostream &os,
 108                                        Meta::Overload_selector<RPC_FUNCTIONS_TO_CHECK>)

 109        {
 110           using namespace Meta;
 111  
 112           typedef typename RPC_FUNCTIONS_TO_CHECK::Head This_rpc_function;
 113  
 114           if (opcode == Index_of<Rpc_functions, This_rpc_function>::Value) {
 115  
 116              typename This_rpc_function::Server_args args{};
 117  
 118              /* read arguments from istream */
 119              _read_args(is, args);
 120  
 121              {
 122                 Trace::Rpc_dispatch trace_event(This_rpc_function::name());
 123              }

 124  
 125              /*
 126               * Dispatch call to matching RPC base class, using
 127               * `This_rpc_function` and the list of its exceptions to
 128               * select the overload.
 129               */

 130              typedef typename This_rpc_function::Exceptions Exceptions;
 131  
 132              typename This_rpc_function::Ret_type ret { };
 133              Rpc_exception_code exc;
 134              exc = _do_serve(args, ret, Overload_selector<This_rpc_function, Exceptions>());
 135              os << ret;
 136  
 137              {
 138                 Trace::Rpc_reply trace_event(This_rpc_function::name());
 139              }

 140  
 141              /* write results to ostream `os` */
 142              _write_results(os, args);
 143  
 144              return exc;

 145           }

 146  
 147           typedef typename RPC_FUNCTIONS_TO_CHECK::Tail Tail;
 148           return _do_dispatch(opcode, is, os, Overload_selector<Tail>());

 149        }

 150  
 151        int _do_dispatch(int opcode, Ipc_istream &, Ipc_ostream &,
 152                         Meta::Overload_selector<Meta::Empty>)

 153        {
 154           PERR("invalid opcode %d\n", opcode);
 155           return RPC_INVALID_OPCODE;

 156        }

 157  
 158        /**
 159         * Handle corner case of having an RPC interface with no RPC functions
 160         */

 161        Rpc_exception_code _do_dispatch(int opcode, Ipc_istream &, Ipc_ostream &,
 162                                        Meta::Overload_selector<Meta::Type_list<> >)

 163        {
 164           return 0;
 165        }

 166  
 167        /**
 168         * Protected constructor
 169         *
 170         * This class is only usable as base class.
 171         */

 172        Rpc_dispatcher() { }

 173  
 174     public:
 175  
 176        Rpc_exception_code dispatch(int opcode, Ipc_istream &is, Ipc_ostream &os)
 177        {
 178           return _do_dispatch(opcode, is, os,
 179                               Meta::Overload_selector<Rpc_functions>())
;

 180        }

 181  }
;

 182  
 183  
 184  class Genode::Rpc_object_base : public Object_pool<Rpc_object_base>::Entry
 185  {
 186     public:
 187  
 188        virtual ~Rpc_object_base() { }
 189  
 190        /**
 191         * Interface to be implemented by a derived class
 192         *
 193         * \param op   opcode of invoked method
 194         * \param is   Ipc_input stream with method arguments
 195         * \param os   Ipc_output stream for storing method results
 196         */

 197        virtual int dispatch(int op, Ipc_istream &is, Ipc_ostream &os) = 0;

 198  }
;

 199  
 200  
 201  /**
 202   * Object that is accessible from remote protection domains
 203   *
 204   * A `Rpc_object` is a locally implemented object that can be referenced
 205   * from the outer world using a capability. The capability gets created
 206   * when attaching a `Rpc_object` to a `Rpc_entrypoint`.
 207   */

 208  template <typename RPC_INTERFACE, typename SERVER = RPC_INTERFACE>
 209  struct Genode::Rpc_object : Rpc_object_base, Rpc_dispatcher<RPC_INTERFACE, SERVER>
 210  {
 211     /*****************************
 212      ** Server-object interface **
 213      *****************************/

 214  
 215     Rpc_exception_code dispatch(int opcode, Ipc_istream &is, Ipc_ostream &os)
 216     {
 217        return Rpc_dispatcher<RPC_INTERFACE, SERVER>::dispatch(opcode, is, os);
 218     }

 219  
 220     Capability<RPC_INTERFACE> const cap() const
 221     {
 222        return reinterpret_cap_cast<RPC_INTERFACE>(Rpc_object_base::cap());
 223     }

 224  }
;

 225  
 226  
 227  /**
 228   * RPC entrypoint serving RPC objects
 229   *
 230   * The entrypoint`s thread will initialize its capability but will not
 231   * immediately enable the processing of requests. This way, the
 232   * activation-using server can ensure that it gets initialized completely
 233   * before the first capability invocations come in. Once the server is
 234   * ready, it must enable the entrypoint explicitly by calling the
 235   * `activate()` method. The `start_on_construction` argument is a
 236   * shortcut for the common case where the server`s capability is handed
 237   * over to other parties _after_ the server is completely initialized.
 238   */

 239  class Genode::Rpc_entrypoint : Thread_base, public Object_pool<Rpc_object_base>
 240  {
 241     private:
 242  
 243        /**
 244         * Prototype capability to derive capabilities for RPC objects
 245         * from.
 246         */

 247        Untyped_capability _cap;
 248  
 249        enum { SND_BUF_SIZE = 1024, RCV_BUF_SIZE = 1024 };
 250        Msgbuf<SND_BUF_SIZE> _snd_buf;
 251        Msgbuf<RCV_BUF_SIZE> _rcv_buf;
 252  
 253        /**
 254         * Hook to let low-level thread init code access private members
 255         *
 256         * This method is only used on NOVA.
 257         */

 258        static void _activation_entry();

 259  
 260        struct Exit
 261        {
 262           GENODE_RPC(Rpc_exit, void, _exit);
 263           GENODE_RPC_INTERFACE(Rpc_exit);
 264        }
;

 265  
 266        struct Exit_handler : Rpc_object<Exit, Exit_handler>
 267        {
 268           int exit;
 269  
 270           Exit_handler() : exit(false) { }
 271  
 272           void _exit() { exit = true; }

 273        }
;

 274  
 275     protected:
 276  
 277        Ipc_server      *_ipc_server;
 278        Lock             _cap_valid;      /* thread startup synchronization        */
 279        Lock             _delay_start;    /* delay start of request dispatching    */
 280        Lock             _delay_exit;     /* delay destructor until server settled */
 281        Pd_session      &_pd_session;     /* for creating capabilities             */
 282        Exit_handler     _exit_handler;
 283        Capability<Exit> _exit_cap;
 284  
 285        /**
 286         * Access to kernel-specific part of the PD session interface
 287         *
 288         * Some kernels like NOVA need a special interface for creating RPC
 289         * object capabilities.
 290         */

 291        Capability<Pd_session::Native_pd> _native_pd_cap;
 292  
 293        /**
 294         * Back end used to associate RPC object with the entry point
 295         *
 296         * \noapi
 297         */

 298        Untyped_capability _manage(Rpc_object_base *obj);

 299  
 300        /**
 301         * Back end used to Dissolve RPC object from entry point
 302         *
 303         * \noapi
 304         */

 305        void _dissolve(Rpc_object_base *obj);

 306  
 307        /**
 308         * Wait until the entrypoint activation is initialized
 309         *
 310         * \noapi
 311         */

 312        void _block_until_cap_valid();

 313  
 314        /**
 315         * Allocate new RPC object capability
 316         *
 317         * Regular servers allocate capabilities from their protection domain
 318         * via the component`s environment. This method allows core to have a
 319         * special implementation that does not rely on a PD session.
 320         *
 321         * The `entry` argument is used only on NOVA. It is the server-side
 322         * instruction pointer to be associated with the RPC object capability.
 323         */

 324        Native_capability _alloc_rpc_cap(Pd_session &, Native_capability ep,
 325                                         addr_t entry = 0)
;

 326  
 327        /**
 328         * Free RPC object capability
 329         */

 330        void _free_rpc_cap(Pd_session &, Native_capability);

 331  
 332        /**
 333         * Thread interface
 334         *
 335         * \noapi
 336         */

 337        void entry();

 338  
 339     public:
 340  
 341        /**
 342         * Constructor
 343         *
 344         * \param cap_session  `Cap_session` for creating capabilities
 345         *                     for the RPC objects managed by this entry
 346         *                     point
 347         * \param stack_size   stack size of entrypoint thread
 348         * \param name         name of entrypoint thread
 349         * \param location     CPU affinity
 350         */

 351        Rpc_entrypoint(Pd_session *pd_session, size_t stack_size,
 352                       char const *name, bool start_on_construction = true,
 353                       Affinity::Location location = Affinity::Location())
;

 354  
 355        ~Rpc_entrypoint();
 356  
 357        /**
 358         * Associate RPC object with the entry point
 359         */

 360        template <typename RPC_INTERFACE, typename RPC_SERVER>
 361        Capability<RPC_INTERFACE>
 362        
manage(Rpc_object<RPC_INTERFACE, RPC_SERVER> *obj)
 363        {
 364           return reinterpret_cap_cast<RPC_INTERFACE>(_manage(obj));
 365        }

 366  
 367        /**
 368         * Dissolve RPC object from entry point
 369         */

 370        template <typename RPC_INTERFACE, typename RPC_SERVER>
 371        void dissolve(Rpc_object<RPC_INTERFACE, RPC_SERVER> *obj)
 372        {
 373           _dissolve(obj);
 374        }

 375  
 376        /**
 377         * Activate entrypoint, start processing RPC requests
 378         */

 379        void activate();

 380  
 381        /**
 382         * Request reply capability for current call
 383         *
 384         * \noapi
 385         *
 386         * Note: This is a temporary API method, which is going to be
 387         * removed. Please do not use this method.
 388         *
 389         * Typically, a capability obtained via this method is used as
 390         * argument of `intermediate_reply`.
 391         */

 392        Untyped_capability reply_dst();

 393  
 394        /**
 395         * Prevent reply of current request
 396         *
 397         * \noapi
 398         *
 399         * Note: This is a temporary API method, which is going to be
 400         * removed. Please do not use this method.
 401         *
 402         * This method can be used to keep the calling client blocked
 403         * after the server has finished the processing of the client`s
 404         * request. At a later time, the server may chose to unblock the
 405         * client via the `intermedate_reply` method.
 406         */

 407        void omit_reply();

 408  
 409        /**
 410         * Send a reply out of the normal call-reply order
 411         *
 412         * \noapi
 413         *
 414         * In combination with the `reply_dst` accessor method, this method
 415         * allows for the dispatching of client requests out of order. The only
 416         * designated user of this method is core`s PD service. The
 417         * `Pd_session::submit` RPC function uses it to send a reply to a
 418         * caller of the `Signal_source::wait_for_signal` RPC function before
 419         * returning from the `submit` call.
 420         */

 421        void reply_signal_info(Untyped_capability reply_cap,
 422                               unsigned long imprint, unsigned long cnt)
;

 423  
 424        /**
 425         * Return true if the caller corresponds to the entrypoint called
 426         *
 427         * \noapi
 428         *
 429         * This method is solely needed on Linux.
 430         */

 431        bool is_myself() const;

 432  }
;

 433  
 434  #endif /* _INCLUDE__BASE__RPC_SERVER_H_ */