/* * \brief Support for performing RPC calls * \author Norman Feske * \date 2011-04-06 */ /* * Copyright (C) 2011-2013 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #ifndef _INCLUDE__BASE__RPC_CLIENT_H_ #define _INCLUDE__BASE__RPC_CLIENT_H_ #include #include namespace Genode { /** * 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 struct Rpc_client : Capability, RPC_INTERFACE { typedef RPC_INTERFACE Rpc_interface; Rpc_client(Capability const &cap) : Capability(cap) { } }; /********************************************************* ** Implementation of 'Capability:call' functions ** *********************************************************/ template template void Capability:: _marshal_args(Ipc_client &ipc_client, ATL &args) const { if (Trait::Rpc_direction::Type::IN) ipc_client << args.get(); _marshal_args(ipc_client, args._2); } template template void Capability:: _unmarshal_result(Ipc_client &ipc_client, T &arg, Meta::Overload_selector) const { ipc_client >> arg; } template template void Capability:: _unmarshal_result(Ipc_client &ipc_client, T &arg, Meta::Overload_selector) const { _unmarshal_result(ipc_client, arg, Meta::Overload_selector()); } template template void Capability:: _unmarshal_results(Ipc_client &ipc_client, 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(ipc_client, args.get(), Meta::Overload_selector()); /* unmarshal remaining arguments */ _unmarshal_results(ipc_client, args._2); } template template void Capability:: _call(typename IF::Client_args &args, typename IF::Ret_type &ret) 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 }; Msgbuf call_buf; Msgbuf reply_buf; Ipc_client ipc_client(*this, &call_buf, &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 */ ipc_client << opcode; _marshal_args(ipc_client, args); { Trace::Rpc_call trace_event(IF::name(), call_buf); } /* perform RPC, unmarshal return value */ ipc_client << IPC_CALL >> ret; { Trace::Rpc_returned trace_event(IF::name(), reply_buf); } /* unmarshal RPC output arguments */ _unmarshal_results(ipc_client, args); /* reflect callee-side exception at the caller */ _check_for_exceptions(ipc_client.result(), Meta::Overload_selector()); } } #endif /* _INCLUDE__BASE__RPC_CLIENT_H_ */