/* * \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.template call(args...); } template typename IF::Ret_type call(ARGS &&...args) const { return _cap.template call(args...); } Capability rpc_cap() const { return _cap; } }; #endif /* _INCLUDE__BASE__RPC_CLIENT_H_ */