1  /*
   2   * \brief  Capability
   3   * \author Norman Feske
   4   * \date   2011-05-22
   5   *
   6   * A typed capability is a capability tied to one specifiec RPC interface
   7   */

   8  
   9  /*
  10   * Copyright (C) 2011-2013 Genode Labs GmbH
  11   *
  12   * This file is part of the Genode OS framework, which is distributed
  13   * under the terms of the GNU General Public License version 2.
  14   */

  15  
  16  #ifndef _INCLUDE__BASE__CAPABILITY_H_
  17  #define _INCLUDE__BASE__CAPABILITY_H_
  18  
  19  #include <util/string.h>
  20  #include <base/rpc.h>
  21  #include <base/native_types.h>
  22  
  23  namespace Genode {
  24  
  25     /**
  26      * Forward declaration needed for internal interfaces of `Capability`
  27      */

  28     class Ipc_client;
  29  
  30  
  31     /**
  32      * Capability that is not associated with a specific RPC interface
  33      */

  34     typedef Native_capability Untyped_capability;

  35  
  36     template <typename> class Capability;
  37  
  38     template <typename RPC_INTERFACE>
  39     Capability<RPC_INTERFACE> reinterpret_cap_cast(Untyped_capability const &);

  40  
  41     template <typename TO_RPC_INTERFACE, typename FROM_RPC_INTERFACE>
  42     Capability<TO_RPC_INTERFACE> static_cap_cast(Capability<FROM_RPC_INTERFACE>);

  43  }

  44  
  45  
  46  /**
  47   * Capability referring to a specific RPC interface
  48   *
  49   * \param RPC_INTERFACE  class containing the RPC interface declaration
  50   */

  51  template <typename RPC_INTERFACE>
  52  class Genode::Capability : public Untyped_capability
  53  {
  54     private:
  55  
  56        /**
  57         * Insert RPC arguments into the message buffer
  58         */

  59        template <typename ATL>
  60        void _marshal_args(Ipc_client &ipc_client, ATL &args) const;

  61  
  62        void _marshal_args(Ipc_client &, Meta::Empty &) const { }
  63  
  64        /**
  65         * Unmarshal single RPC argument from the message buffer
  66         */

  67        template <typename T>
  68        void _unmarshal_result(Ipc_client &ipc_client, &arg,
  69                               Meta::Overload_selector<Rpc_arg_out>)
 const;

  70  
  71        template <typename T>
  72        void _unmarshal_result(Ipc_client &ipc_client, &arg,
  73                               Meta::Overload_selector<Rpc_arg_inout>)
 const;

  74  
  75        template <typename T>
  76        void _unmarshal_result(Ipc_client &, &,
  77                               Meta::Overload_selector<Rpc_arg_in>)
 const { }

  78  
  79        /**
  80         * Read RPC results from the message buffer
  81         */

  82        template <typename ATL>
  83        void _unmarshal_results(Ipc_client &ipc_client, ATL &args) const;

  84  
  85        void _unmarshal_results(Ipc_client &, Meta::Empty &) const { }
  86  
  87        /**
  88         * Check RPC return code for the occurrence of exceptions
  89         *
  90         * A server-side exception is indicated by a non-zero exception
  91         * code. Each exception code corresponds to an entry in the
  92         * exception type list specified in the RPC function declaration.
  93         * The `_check_for_exception` method template throws the
  94         * exception type belonging to the received exception code.
  95         */

  96        template <typename EXC_TL>
  97        void _check_for_exceptions(Rpc_exception_code const exc_code,
  98                                   Meta::Overload_selector<EXC_TL>)
 const
  99        {
 100           enum { EXCEPTION_CODE = RPC_EXCEPTION_BASE - Meta::Length<EXC_TL>::Value };
 101  
 102           if (exc_code == EXCEPTION_CODE)
 103              throw typename EXC_TL::Head();

 104  
 105           _check_for_exceptions(exc_code, Meta::Overload_selector<typename EXC_TL::Tail>());

 106        }

 107  
 108        void _check_for_exceptions(Rpc_exception_code const,
 109                                   Meta::Overload_selector<Meta::Empty>)
 const
 110        { }

 111  
 112        /**
 113         * Perform RPC call, arguments passed a as nested `Ref_tuple` object
 114         */

 115        template <typename IF>
 116        void _call(typename IF::Client_args &args,
 117                   typename IF::Ret_type    &ret)
 const;

 118  
 119        /**
 120         * Shortcut for querying argument types used in `call` methods
 121         */

 122        template <typename IF, unsigned I>
 123        struct Arg
 124        {
 125           typedef typename Meta::Type_at<typename IF::Client_args, I>::Type Type;
 126        }
;

 127  
 128        template <typename FROM_RPC_INTERFACE>
 129        Untyped_capability
 130        
_check_compatibility(Capability<FROM_RPC_INTERFACE> const &cap) const
 131        {
 132           FROM_RPC_INTERFACE *from = 0;
 133           RPC_INTERFACE *to = from;
 134           (void)to;
 135           return cap;

 136        }

 137  
 138        /**
 139         * Wrapper for the return type instantiated by `call` overloads
 140         *
 141         * Each `call` overload creates an instance of the return value
 142         * type as local variable. A reference to this variable is passed
 143         * to the `_call` method, which will assign its value. Even
 144         * though the variable does not need to be initialized prior the
 145         * call of `_call`, the GCC will still complain "warning: ‘ret’ may
 146         * be used uninitialized in this function". Wrapping the return
 147         * value in a struct silences the compiler.
 148         */

 149        template <typename IF>
 150        struct Return
 151        {
 152           typedef typename Trait::Call_return<typename IF::Ret_type>::Type
 153              Return_type;

 154  
 155           volatile Return_type _value;
 156           Return_type &value() { return *(Return_type *)(&_value); }

 157        }
;

 158  
 159     public:
 160  
 161        typedef RPC_INTERFACE Rpc_interface;
 162  
 163        /**
 164         * Constructor
 165         *
 166         * This implicit constructor checks at compile time for the
 167         * compatibility of the source and target capability types. The
 168         * construction is performed only if the target capability type is
 169         * identical to or a base type of the source capability type.
 170         */

 171        template <typename FROM_RPC_INTERFACE>
 172        Capability(Capability<FROM_RPC_INTERFACE> const &cap)
 173        : Untyped_capability(_check_compatibility(cap))
 174        { }

 175  
 176        /**
 177         * Default constructor creates invalid capability
 178         */

 179        Capability() { }

 180  
 181        template <typename IF>
 182        typename Trait::Call_return<typename IF::Ret_type>::Type
 183        
call() const
 184        {
 185           Meta::Empty e;
 186           Return<IF> ret;
 187           _call<IF>(e, ret.value());
 188           return ret.value();

 189        }

 190  
 191        template <typename IF>
 192        typename Trait::Call_return<typename IF::Ret_type>::Type
 193        
call(typename Arg<IF, 0>::Type v1) const
 194        {
 195           Meta::Empty e;
 196           typename IF::Client_args args(v1, e);
 197           Return<IF> ret;
 198           _call<IF>(args, ret.value());
 199           return ret.value();

 200        }

 201  
 202        template <typename IF>
 203        typename Trait::Call_return<typename IF::Ret_type>::Type
 204        
call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2) const
 205        {
 206           Meta::Empty e;
 207           typename IF::Client_args args(v1, v2, e);
 208           Return<IF> ret;
 209           _call<IF>(args, ret.value());
 210           return ret.value();

 211        }

 212  
 213        template <typename IF>
 214        typename Trait::Call_return<typename IF::Ret_type>::Type
 215        
call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
 216             typename Arg<IF, 2>::Type v3)
 const
 217        {
 218           Meta::Empty e;
 219           typename IF::Client_args args(v1, v2, v3, e);
 220           Return<IF> ret;
 221           _call<IF>(args, ret.value());
 222           return ret.value();

 223        }

 224  
 225        template <typename IF>
 226        typename Trait::Call_return<typename IF::Ret_type>::Type
 227        
call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
 228             typename Arg<IF, 2>::Type v3, typename Arg<IF, 3>::Type v4)
 const
 229        {
 230           Meta::Empty e;
 231           typename IF::Client_args args(v1, v2, v3, v4, e);
 232           Return<IF> ret;
 233           _call<IF>(args, ret.value());
 234           return ret.value();

 235        }

 236  
 237        template <typename IF>
 238        typename Trait::Call_return<typename IF::Ret_type>::Type
 239        
call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
 240             typename Arg<IF, 2>::Type v3, typename Arg<IF, 3>::Type v4,
 241             typename Arg<IF, 4>::Type v5)
 const
 242        {
 243           Meta::Empty e;
 244           typename IF::Client_args args(v1, v2, v3, v4, v5, e);
 245           Return<IF> ret;
 246           _call<IF>(args, ret.value());
 247           return ret.value();

 248        }

 249  
 250        template <typename IF>
 251        typename Trait::Call_return<typename IF::Ret_type>::Type
 252        
call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
 253             typename Arg<IF, 2>::Type v3, typename Arg<IF, 3>::Type v4,
 254             typename Arg<IF, 4>::Type v5, typename Arg<IF, 5>::Type v6)
 const
 255        {
 256           Meta::Empty e;
 257           typename IF::Client_args args(v1, v2, v3, v4, v5, v6, e);
 258           Return<IF> ret;
 259           _call<IF>(args, ret.value());
 260           return ret.value();

 261        }

 262  
 263        template <typename IF>
 264        typename Trait::Call_return<typename IF::Ret_type>::Type
 265        
call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
 266             typename Arg<IF, 2>::Type v3, typename Arg<IF, 3>::Type v4,
 267             typename Arg<IF, 4>::Type v5, typename Arg<IF, 5>::Type v6,
 268             typename Arg<IF, 6>::Type v7)
 const
 269        {
 270           Meta::Empty e;
 271           typename IF::Client_args args(v1, v2, v3, v4, v5, v6, v7, e);
 272           Return<IF> ret;
 273           _call<IF>(args, ret.value());
 274           return ret.value();

 275        }

 276  }
;

 277  
 278  
 279  /**
 280   * Convert an untyped capability to a typed capability
 281   */

 282  template <typename RPC_INTERFACE>
 283  Genode::Capability<RPC_INTERFACE>
 284  
Genode::reinterpret_cap_cast(Untyped_capability const &untyped_cap)
 285  {
 286     /*
 287      * The object layout of untyped and typed capabilities is identical.
 288      * Hence we can just use it`s copy-constructors.
 289      */

 290     Untyped_capability *ptr = const_cast<Untyped_capability*>(&untyped_cap);
 291     return *static_cast<Capability<RPC_INTERFACE>*>(ptr);

 292  }

 293  
 294  
 295  /**
 296   * Convert capability type from an interface base type to an inherited
 297   * interface type
 298   */

 299  template <typename TO_RPC_INTERFACE, typename FROM_RPC_INTERFACE>
 300  Genode::Capability<TO_RPC_INTERFACE>
 301  
Genode::static_cap_cast(Capability<FROM_RPC_INTERFACE> cap)
 302  {
 303     /* check interface compatibility */
 304     (void)static_cast<TO_RPC_INTERFACE *>((FROM_RPC_INTERFACE *)0);
 305  
 306     return reinterpret_cap_cast<TO_RPC_INTERFACE>(cap);

 307  }

 308  
 309  #endif /* _INCLUDE__BASE__CAPABILITY_H_ */