/*
* \brief Support for performing RPC calls
* \author Norman Feske
* \date 2011-04-06
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__BASE__RPC_CLIENT_H_
#define _INCLUDE__BASE__RPC_CLIENT_H_
#include
#include
namespace Genode {
template struct Rpc_client;
/**
* Count capabilities of a RPC_FUNCTION which are out parameters.
*/
template struct Cap_para_out { enum { Value = 0 }; };
template struct Cap_para_out *> { enum { Value = 1 }; };
template struct Cap_para_out &> { enum { Value = 1 }; };
template <> struct Cap_para_out { enum { Value = 1 }; };
template <> struct Cap_para_out { enum { Value = 1 }; };
template struct Cap_return { enum { Value = 0 }; };
template struct Cap_return > { enum { Value = 1 }; };
template struct Cap_return *> { enum { Value = 1 }; };
template struct Cap_return &> { enum { Value = 1 }; };
template <> struct Cap_return { enum { Value = 1 }; };
template <> struct Cap_return { enum { Value = 1 }; };
template <> struct Cap_return { enum { Value = 1 }; };
template
struct Rpc_caps_out {
enum { Value = Cap_para_out::Value
+ Rpc_caps_out::Value }; };
template <>
struct Rpc_caps_out { enum { Value = 0 }; };
template
struct Rpc_function_caps_out {
enum { Value = Rpc_caps_out::Value +
Cap_return ::Value}; };
/***************************************************
** Implementation of 'Capability:call' functions **
***************************************************/
template
template
void Capability::
_marshal_args(Msgbuf_base &msg, ATL &args) const
{
if (Trait::Rpc_direction::Type::IN)
msg.insert(args.get());
_marshal_args(msg, args._2);
}
template
template
void Capability::
_unmarshal_result(Ipc_unmarshaller &unmarshaller, T &arg,
Meta::Overload_selector) const
{
unmarshaller.extract(arg);
}
template
template
void Capability::
_unmarshal_result(Ipc_unmarshaller &unmarshaller, T &arg,
Meta::Overload_selector) const
{
_unmarshal_result(unmarshaller, arg, Meta::Overload_selector());
}
template
template
void Capability::
_unmarshal_results(Ipc_unmarshaller &unmarshaller, ATL &args) const
{
/*
* Unmarshal current argument. The overload of
* '_unmarshal_result' is selected depending on the RPC
* direction.
*/
typedef typename Trait::Rpc_direction::Type Rpc_dir;
_unmarshal_result(unmarshaller, args.get(), Meta::Overload_selector());
/* unmarshal remaining arguments */
_unmarshal_results(unmarshaller, args._2);
}
template
template
typename IF::Ret_type Capability::
_call(typename IF::Client_args &args) const
{
/**
* Message buffer for RPC message
*
* The message buffer gets automatically dimensioned according to the
* specified 'IF' RPC function.
*/
enum { PROTOCOL_OVERHEAD = 4*sizeof(long),
CALL_MSG_SIZE = Rpc_function_msg_size::Value,
REPLY_MSG_SIZE = Rpc_function_msg_size::Value,
RECEIVE_CAPS = Rpc_function_caps_out::Value };
Msgbuf call_buf;
Msgbuf reply_buf;
/* determine opcode of RPC function */
typedef typename RPC_INTERFACE::Rpc_functions Rpc_functions;
Rpc_opcode opcode(static_cast(Meta::Index_of::Value));
/* marshal opcode and RPC input arguments */
call_buf.insert(opcode);
_marshal_args(call_buf, args);
{
Trace::Rpc_call trace_event(IF::name(), call_buf);
}
/* perform RPC, unmarshal return value */
Rpc_exception_code const exception_code =
ipc_call(*this, call_buf, reply_buf, RECEIVE_CAPS);
if (exception_code.value == Rpc_exception_code::INVALID_OBJECT)
throw Ipc_error();
Ipc_unmarshaller unmarshaller(reply_buf);
{
Trace::Rpc_returned trace_event(IF::name(), reply_buf);
}
/* unmarshal RPC output arguments */
_unmarshal_results(unmarshaller, args);
/* reflect callee-side exception at the caller */
_check_for_exceptions(exception_code,
Meta::Overload_selector());
/* the return value does only exist if no exception was thrown */
Meta::Overload_selector ret_overloader;
return unmarshaller.extract(ret_overloader);
}
}
/**
* RPC client
*
* This class template is the base class of the client-side implementation
* of the specified 'RPC_INTERFACE'. Usually, it inherits the pure virtual
* functions declared in 'RPC_INTERFACE' and has the built-in facility to
* perform RPC calls to this particular interface. Hence, the client-side
* implementation of each pure virtual interface function comes down to a
* simple wrapper in the line of 'return call(arguments...)'.
*/
template
class Genode::Rpc_client : public RPC_INTERFACE
{
private:
Capability _cap;
public:
typedef RPC_INTERFACE Rpc_interface;
Rpc_client(Capability const &cap) : _cap(cap) { }
template
typename IF::Ret_type call(ARGS &&...args)
{
return _cap.call(args...);
}
template
typename IF::Ret_type call(ARGS &&...args) const
{
return _cap.call(args...);
}
/**
* Return RPC capablity for client object
*
* \deprecated use 'rpc_cap' accessor instead
*/
operator Capability() const { return _cap; }
Capability rpc_cap() const { return _cap; }
};
#endif /* _INCLUDE__BASE__RPC_CLIENT_H_ */