1  /*
   2   * \brief  Support for performing RPC calls
   3   * \author Norman Feske
   4   * \date   2011-04-06
   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_CLIENT_H_
  15  #define _INCLUDE__BASE__RPC_CLIENT_H_
  16  
  17  #include <base/ipc.h>
  18  #include <base/trace/events.h>
  19  
  20  namespace Genode {
  21  
  22     template <typename> struct Rpc_client;
  23  
  24     /**
  25      * Count capabilities of a RPC_FUNCTION which are out parameters.
  26      */

  27     template <typename T> struct Cap_para_out                  { enum { Value = 0 }; };

  28     template <typename T> struct Cap_para_out<Capability<T> *> { enum { Value = 1 }; };
  29     template <typename T> struct Cap_para_out<Capability<T> &> { enum { Value = 1 }; };
  30     template <> struct Cap_para_out<Native_capability *>       { enum { Value = 1 }; };
  31     template <> struct Cap_para_out<Native_capability &>       { enum { Value = 1 }; };
  32  
  33     template <typename T> struct Cap_return                  { enum { Value = 0 }; };
  34     template <typename T> struct Cap_return<Capability<T> >  { enum { Value = 1 }; };
  35     template <typename T> struct Cap_return<Capability<T> *> { enum { Value = 1 }; };
  36     template <typename T> struct Cap_return<Capability<T> &> { enum { Value = 1 }; };
  37     template <> struct Cap_return<Native_capability>         { enum { Value = 1 }; };
  38     template <> struct Cap_return<Native_capability *>       { enum { Value = 1 }; };
  39     template <> struct Cap_return<Native_capability &>       { enum { Value = 1 }; };
  40  
  41     template <typename ARGS>
  42     struct Rpc_caps_out {
  43        enum { Value = Cap_para_out<typename ARGS::Head>::Value
  44                     + Rpc_caps_out<typename ARGS::Tail>::Value
 }
;
 }
;

  45     
  46     template <>
  47     struct Rpc_caps_out<Meta::Empty> { enum { Value = 0 }; };

  48  
  49     template <typename RPC_FUNCTION>
  50     struct Rpc_function_caps_out {
  51        enum { Value = Rpc_caps_out<typename RPC_FUNCTION::Server_args>::Value +
  52                       Cap_return  <typename RPC_FUNCTION::Ret_type>::Value
}
;
 }
;

  53  
  54     /***************************************************
  55      ** Implementation of `Capability:call` functions **
  56      ***************************************************/

  57  
  58     template <typename RPC_INTERFACE>
  59     template <typename ATL>
  60     void Capability<RPC_INTERFACE>::
  61     _marshal_args(Ipc_client &ipc_client, ATL &args)
 const
  62     {
  63        if (Trait::Rpc_direction<typename ATL::Head>::Type::IN)
  64           ipc_client << args.get();

  65  
  66        _marshal_args(ipc_client, args._2);

  67     }

  68  
  69  
  70     template <typename RPC_INTERFACE>
  71     template <typename T>
  72     void Capability<RPC_INTERFACE>::
  73     _unmarshal_result(Ipc_client &ipc_client, &arg,
  74                       Meta::Overload_selector<Rpc_arg_out>)
 const
  75     {
  76        ipc_client >> arg;
  77     }

  78  
  79  
  80     template <typename RPC_INTERFACE>
  81     template <typename T>
  82     void Capability<RPC_INTERFACE>::
  83     _unmarshal_result(Ipc_client &ipc_client, &arg,
  84                       Meta::Overload_selector<Rpc_arg_inout>)
 const
  85     {
  86        _unmarshal_result(ipc_client, arg, Meta::Overload_selector<Rpc_arg_out>());
  87     }

  88  
  89  
  90     template <typename RPC_INTERFACE>
  91     template <typename ATL>
  92     void Capability<RPC_INTERFACE>::
  93     _unmarshal_results(Ipc_client &ipc_client, ATL &args)
 const
  94     {
  95        /*
  96         * Unmarshal current argument. The overload of
  97         * `_unmarshal_result` is selected depending on the RPC
  98         * direction.
  99         */

 100        typedef typename Trait::Rpc_direction<typename ATL::Head>::Type Rpc_dir;
 101        _unmarshal_result(ipc_client, args.get(), Meta::Overload_selector<Rpc_dir>());
 102  
 103        /* unmarshal remaining arguments */
 104        _unmarshal_results(ipc_client, args._2);

 105     }

 106  
 107  
 108     template <typename RPC_INTERFACE>
 109     template <typename IF>
 110     void Capability<RPC_INTERFACE>::
 111     _call(typename IF::Client_args &args, typename IF::Ret_type &ret)
 const
 112     {
 113        /**
 114         * Message buffer for RPC message
 115         *
 116         * The message buffer gets automatically dimensioned according to the
 117         * specified `IF` RPC function.
 118         */

 119        enum { PROTOCOL_OVERHEAD = 4*sizeof(long),
 120               CALL_MSG_SIZE     = Rpc_function_msg_size<IF, RPC_CALL>::Value,
 121               REPLY_MSG_SIZE    = Rpc_function_msg_size<IF, RPC_REPLY>::Value,
 122               CAP_BY_VALUE      = Rpc_function_caps_out<IF>::Value }
;

 123  
 124        Msgbuf<CALL_MSG_SIZE  + PROTOCOL_OVERHEAD>  call_buf;
 125        Msgbuf<REPLY_MSG_SIZE + PROTOCOL_OVERHEAD> reply_buf;

 126  
 127        Ipc_client ipc_client(*this, &call_buf, &reply_buf, CAP_BY_VALUE);
 128  
 129        /* determine opcode of RPC function */
 130        typedef typename RPC_INTERFACE::Rpc_functions Rpc_functions;
 131        Rpc_opcode opcode = static_cast<int>(Meta::Index_of<Rpc_functions, IF>::Value);
 132  
 133        /* marshal opcode and RPC input arguments */

 134        ipc_client << opcode;
 135        _marshal_args(ipc_client, args);
 136  
 137        {
 138           Trace::Rpc_call trace_event(IF::name(), call_buf);
 139        }

 140  
 141        /* perform RPC, unmarshal return value */
 142        ipc_client << IPC_CALL >> ret;
 143  
 144        {
 145           Trace::Rpc_returned trace_event(IF::name(), reply_buf);
 146        }

 147  
 148        /* unmarshal RPC output arguments */
 149        _unmarshal_results(ipc_client, args);
 150  
 151        /* reflect callee-side exception at the caller */
 152        _check_for_exceptions(ipc_client.result(),
 153                              Meta::Overload_selector<typename IF::Exceptions>())
;

 154     }

 155  }

 156  
 157  
 158  /**
 159   * RPC client
 160   *
 161   * This class template is the base class of the client-side implementation
 162   * of the specified `RPC_INTERFACE`. Usually, it inherits the pure virtual
 163   * functions declared in `RPC_INTERFACE` and has the built-in facility to
 164   * perform RPC calls to this particular interface. Hence, the client-side
 165   * implementation of each pure virtual interface function comes down to a
 166   * simple wrapper in the line of `return call<Rpc_function>(arguments...)`.
 167   */

 168  template <typename RPC_INTERFACE>
 169  struct Genode::Rpc_client : Capability<RPC_INTERFACE>, RPC_INTERFACE
 170  {
 171     typedef RPC_INTERFACE Rpc_interface;
 172  
 173     Rpc_client(Capability<RPC_INTERFACE> const &cap)
 174     : Capability<RPC_INTERFACE>(cap) { }

 175  }
;

 176  
 177  
 178  #endif /* _INCLUDE__BASE__RPC_CLIENT_H_ */