1  /*
   2   * \brief  Support for defining and working with RPC interfaces
   3   * \author Norman Feske
   4   * \date   2011-03-28
   5   */

   6  
   7  /*
   8   * Copyright (C) 2011-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_H_
  15  #define _INCLUDE__BASE__RPC_H_
  16  
  17  #include <util/meta.h>
  18  
  19  
  20  /**
  21   * Macro for declaring an RPC function
  22   *
  23   * \param rpc_name   type name representing the RPC function
  24   * \param ret_type   RPC return type
  25   * \param func_name  RPC function name
  26   * \param exc_types  type list of exceptions that may be thrown by the
  27   *                   function
  28   * \param ...        variable number of RPC function arguments
  29   *
  30   * Each RPC function is represented by a struct that contains the meta data
  31   * about the function arguments, the return type, and the exception types.
  32   * Furthermore, it contains an adapter function called `serve`, which is used
  33   * on the server side to invoke the server-side implementation of the RPC
  34   * function. It takes an a `Pod_tuple` argument structure and calls the
  35   * server-side function with individual arguments using the `call_member`
  36   * mechanism provided by `meta.h`.
  37   */

  38  #define GENODE_RPC_THROW(rpc_name, ret_type, func_name, exc_types, ...) \
  39     struct rpc_name { \
  40        typedef ::Genode::Meta::Ref_args<__VA_ARGS__>::Type  Client_args; \
  41        typedef ::Genode::Meta::Pod_args<__VA_ARGS__>::Type  Server_args; \
  42        typedef ::Genode::Trait::Exc_list<exc_types>::Type   Exceptions; \
  43        typedef ::Genode::Trait::Call_return<ret_type>::Type Ret_type; \
  44        \
  45        template <typename SERVER, typename RET> \
  46        static void serve(SERVER &server, Server_args &args, RET &ret) { \
  47           ::Genode::Meta::call_member<RET, SERVER, Server_args> \
  48              (ret, server, args, &SERVER::func_name); } \
  49        \
  50        static const char* name() { return #func_name; } \
  51     };

  52  
  53  /**
  54   * Shortcut for `GENODE_RPC_THROW` for an RPC that throws no exceptions
  55   */

  56  #define GENODE_RPC(rpc_name, ret_type, func_name, ...) \
  57     GENODE_RPC_THROW(rpc_name, ret_type, func_name, GENODE_TYPE_LIST(), __VA_ARGS__)

  58  
  59  /**
  60   * Macro for declaring a RPC interface
  61   *
  62   * \param ...  list of RPC functions as declared via `GENODE_RPC`
  63   *
  64   * An RPC interface is represented as type list of RPC functions. The RPC
  65   * opcode for each function is implicitly defined by its position within
  66   * this type list.
  67   */

  68  #define GENODE_RPC_INTERFACE(...) \
  69     typedef GENODE_TYPE_LIST(__VA_ARGS__) Rpc_functions

  70  
  71  /**
  72   * Macro for declaring a RPC interface derived from another RPC interface
  73   *
  74   * \param base  class hosting the RPC interface to be inherited
  75   * \param ...   list of the locally declared RPC functions
  76   *
  77   * RPC interface inheritance is simply the concatenation of the type list
  78   * of RPC functions declared for the base interface and the locally declared
  79   * RPC functions. By appending the local RPC functions, the RPC opcodes of
  80   * the inherited RPC functions are preserved.
  81   */

  82  #define GENODE_RPC_INTERFACE_INHERIT(base, ...) \
  83     typedef ::Genode::Meta::Append<base::Rpc_functions, \
  84                                    GENODE_TYPE_LIST(__VA_ARGS__) >::Type \
  85        Rpc_functions; \
  86     typedef base Rpc_inherited_interface;

  87  
  88  
  89  namespace Genode {
  90  
  91     struct Rpc_arg_in    { enum { IN = true,  OUT = false }; };
  92     struct Rpc_arg_out   { enum { IN = false, OUT = true  }; };
  93     struct Rpc_arg_inout { enum { IN = true,  OUT = true  }; };
  94  
  95     namespace Trait {
  96  
  97        /*****************************************
  98         ** Type meta data used for marshalling **
  99         *****************************************/

 100  
 101        template <typename T> struct Rpc_direction;
 102  
 103  
 104        template <typename T> struct Rpc_direction            { typedef Rpc_arg_in    Type; };
 105        template <typename T> struct Rpc_direction<const *> { typedef Rpc_arg_in    Type; };
 106        template <typename T> struct Rpc_direction<const &> { typedef Rpc_arg_in    Type; };
 107        template <typename T> struct Rpc_direction<T*>        { typedef Rpc_arg_inout Type; };
 108        template <typename T> struct Rpc_direction<T&>        { typedef Rpc_arg_inout Type; };
 109  
 110        /**
 111         * Representation of function return type
 112         *
 113         * For RPC functions with no return value, we use a pseudo return value
 114         * of type `Empty` instead. This way, we can process all functions
 115         * regardless of the presence of a return type with the same meta
 116         * program.
 117         */

 118        template <typename T> struct Call_return       { typedef T Type; };

 119        template <>           struct Call_return<void> { typedef Meta::Empty Type; };
 120  
 121        /**
 122         * Representation of the list of exception types
 123         *
 124         * This template maps the special case of a `Type_list` with no arguments
 125         * to the `Empty` type.
 126         */

 127        template <typename T> struct Exc_list { typedef T Type; };

 128        template <> struct Exc_list<Meta::Type_list<> > { typedef Meta::Empty Type; };
 129     }

 130  
 131  
 132     /*******************************************************
 133      ** Automated computation of RPC message-buffer sizes **
 134      *******************************************************/

 135  
 136     /**
 137      * Determine transfer size of an RPC argument
 138      *
 139      * For data arguments, the transfer size is the size of the data type. For
 140      * pointer arguments, the transfer size is the size of the pointed-to
 141      * object.
 142      */

 143     template <typename T>
 144     struct Rpc_transfer_size {
 145        enum { Value = Meta::Round_to_machine_word<sizeof(T)>::Value }; }
;

 146  
 147     template <typename T>
 148     struct Rpc_transfer_size<*> {
 149        enum { Value = Meta::Round_to_machine_word<sizeof(T)>::Value }; }
;

 150  
 151  
 152     /**
 153      * Type used for transmitting the opcode of a RPC function (used for RPC call)
 154      */

 155     typedef int Rpc_opcode;

 156  
 157  
 158     /**
 159      * Type used for transmitting exception information (used for RPC reply)
 160      */

 161     typedef int Rpc_exception_code;

 162  
 163  
 164     /**
 165      * Special exception code used to respond to illegal opcodes
 166      */

 167     enum { RPC_INVALID_OPCODE = -1 };

 168  
 169  
 170     /**
 171      * Opcode base used for passing exception information
 172      */

 173     enum { RPC_EXCEPTION_BASE = -1000 };

 174  
 175  
 176     /**
 177      * Return the accumulated size of RPC arguments
 178      *
 179      * \param ARGS  typelist with RPC arguments
 180      * \param IN    true to account for RPC-input arguments
 181      * \param OUT   true to account for RPC-output arguments
 182      */

 183     template <typename ARGS, bool IN, bool OUT>
 184     struct Rpc_args_size {
 185        typedef typename ARGS::Head This;
 186        enum { This_size = Rpc_transfer_size<This>::Value };
 187        enum { Value = (IN  && Trait::Rpc_direction<This>::Type::IN  ? This_size : 0)
 188                     + (OUT && Trait::Rpc_direction<This>::Type::OUT ? This_size : 0)
 189                     + Rpc_args_size<typename ARGS::Tail, IN, OUT>::Value }
;
 }
;

 190     
 191     template <bool IN, bool OUT>
 192     struct Rpc_args_size<Meta::Empty, IN, OUT> { enum { Value = 0 }; };

 193  
 194  
 195     /**
 196      * Return the size of the return value
 197      *
 198      * The return type of an RPC function can be either a real type or
 199      * `Meta::Empty` if the function has no return value. In the latter case,
 200      * `Retval_size` returns 0 instead of the non-zero size of `Meta::Empty`.
 201      */

 202     template <typename RET>
 203     struct Rpc_retval_size { enum { Value = sizeof(RET) }; };

 204  
 205     template <>
 206     struct Rpc_retval_size<Meta::Empty> { enum { Value = 0 }; };

 207  
 208  
 209     /**
 210      * Calculate the payload size of a RPC message
 211      *
 212      * Setting either IN or OUT to true, the call size or respectively the
 213      * reply size is calculated. Protocol-related message parts (such as RPC
 214      * opcode or exception status) is not accounted for.
 215      */

 216     template <typename RPC_FUNCTION, bool IN, bool OUT>
 217     struct Rpc_msg_payload_size {
 218        typedef typename RPC_FUNCTION::Server_args Args;
 219        enum { Value = Rpc_args_size<Args, IN, OUT>::Value };
 }
;

 220  
 221  
 222     /**
 223      * RPC message type
 224      *
 225      * An RPC message can be either a `RPC_CALL` (from client to server) or a
 226      * `RPC_REPLY` (from server to client). The message payload for each type
 227      * depends on the RPC function arguments as well as protocol-specific
 228      * message parts. For example, a `RPC_CALL` requires the transmission of
 229      * the RPC opcode to select the server-side RPC function. In contrast, a
 230      * `RPC_REPLY` message carries along the exception state returned from the
 231      * server-side RPC implementation. The `Rpc_msg_type` is used as template
 232      * argument to specialize the calculation of message sizes for each of both
 233      * cases.
 234      */

 235     enum Rpc_msg_type { RPC_CALL, RPC_REPLY };

 236  
 237  
 238     /**
 239      * Calculate size of RPC message
 240      *
 241      * The send and receive cases are handled by respective template
 242      * specializations for the `MSG_TYPE` template argument.
 243      */

 244     template <typename RPC_FUNCTION, Rpc_msg_type MSG_TYPE>
 245     struct Rpc_function_msg_size;

 246  
 247     template <typename RPC_FUNCTION>
 248     struct Rpc_function_msg_size<RPC_FUNCTION, RPC_CALL> {
 249        enum { Value = Rpc_msg_payload_size<RPC_FUNCTION, true, false>::Value
 250                     + sizeof(Rpc_opcode) }
;
 }
;

 251  
 252     template <typename RPC_FUNCTION>
 253     struct Rpc_function_msg_size<RPC_FUNCTION, RPC_REPLY> {
 254        enum { Value = Rpc_msg_payload_size<RPC_FUNCTION, false, true>::Value
 255                     + Rpc_retval_size<typename RPC_FUNCTION::Ret_type>::Value

 256                     + sizeof(Rpc_exception_code) }
;
 }
;

 257  
 258  
 259     /**
 260      * Calculate size of message buffer needed for a list of RPC functions
 261      *
 262      * \param RPC_FUNCTIONS  type list of RPC functions
 263      *
 264      * The returned `Value` is the maximum of all function`s message sizes.
 265      */

 266     template <typename RPC_FUNCTIONS, Rpc_msg_type MSG_TYPE>
 267     struct Rpc_function_list_msg_size {
 268        enum {
 269           This_size = Rpc_function_msg_size<typename RPC_FUNCTIONS::Head, MSG_TYPE>::Value,
 270           Tail_size = Rpc_function_list_msg_size<typename RPC_FUNCTIONS::Tail, MSG_TYPE>::Value,
 271           Value     = (This_size > Tail_size) ? This_size : Tail_size }
;
 }
;

 272  
 273     template <Rpc_msg_type MSG_TYPE>
 274     struct Rpc_function_list_msg_size<Meta::Empty, MSG_TYPE> { enum { Value = 0 }; };

 275  
 276  
 277     /**
 278      * Calculate size of message buffer needed for an RPC interface
 279      *
 280      * \param RPC_IF  class that hosts the RPC interface declaration
 281      *
 282      * This is a convenience wrapper for `Rpc_function_list_msg_size`.
 283      */

 284     template <typename RPC_IF, Rpc_msg_type MSG_TYPE>
 285     struct Rpc_interface_msg_size {
 286        typedef typename RPC_IF::Rpc_functions Rpc_functions;
 287        enum { Value = Rpc_function_list_msg_size<Rpc_functions, MSG_TYPE>::Value };
 }
;

 288  
 289  
 290     /**
 291      * Determine if a RPC interface is inherited
 292      */

 293     template <typename INTERFACE>
 294     struct Rpc_interface_is_inherited
 295     {
 296        typedef char yes[1];
 297        typedef char  no[2];
 298  
 299        template <typename IF>
 300        static yes &test(typename IF::Rpc_inherited_interface *);

 301  
 302        template <typename>
 303        static no &test(...);

 304  
 305        enum { VALUE = sizeof(test<INTERFACE>(0)) == sizeof(yes) };

 306     }
;

 307  }

 308  
 309  #endif /* _INCLUDE__BASE__RPC_H_ */