/* * \brief Support for defining and working with RPC interfaces * \author Norman Feske * \date 2011-03-28 */ /* * 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_H_ #define _INCLUDE__BASE__RPC_H_ #include /** * Macro for declaring a RPC function * * \param rpc_name type name representing the RPC function * \param ret_type RPC return type * \param func_name RPC function name * \param exc_types type list of exceptions that may be thrown by the * function * \param ... variable number of RPC function arguments * * Each RPC function is represented by a struct that contains the meta data * about the function arguments, the return type, and the exception types. * Furthermore, it contains an adapter function called 'serve', which is used * on the server side to invoke the server-side implementation of the RPC * function. It takes an a 'Pod_tuple' argument structure and calls the * server-side function with individual arguments using the 'call_member' * mechanism provided by 'meta.h'. */ #define GENODE_RPC_THROW(rpc_name, ret_type, func_name, exc_types, ...) \ struct rpc_name { \ typedef ::Genode::Meta::Ref_args<__VA_ARGS__>::Type Client_args; \ typedef ::Genode::Meta::Pod_args<__VA_ARGS__>::Type Server_args; \ typedef ::Genode::Trait::Exc_list::Type Exceptions; \ typedef ::Genode::Trait::Call_return::Type Ret_type; \ \ template \ static void serve(SERVER &server, Server_args &args, RET &ret) { \ ::Genode::Meta::call_member \ (ret, server, args, &SERVER::func_name); } \ \ static const char* name() { return #func_name; } \ }; /** * Shortcut for 'GENODE_RPC_THROW' for an RPC that throws no exceptions */ #define GENODE_RPC(rpc_name, ret_type, func_name, ...) \ GENODE_RPC_THROW(rpc_name, ret_type, func_name, GENODE_TYPE_LIST(), __VA_ARGS__) /** * Macro for declaring a RPC interface * * \param ... list of RPC functions as declared via 'GENODE_RPC' * * An RPC interface is represented as type list of RPC functions. The RPC * opcode for each function is implicitly defined by its position within * this type list. */ #define GENODE_RPC_INTERFACE(...) \ typedef GENODE_TYPE_LIST(__VA_ARGS__) Rpc_functions /** * Macro for declaring a RPC interface derived from another RPC interface * * \param base class hosting the RPC interface to be inherited * \param ... list of the locally declared RPC functions * * RPC interface inheritance is simply the concatenation of the type list * of RPC functions declared for the base interface and the locally declared * RPC functions. By appending the local RPC functions, the RPC opcodes of * the inherited RPC functions are preserved. */ #define GENODE_RPC_INTERFACE_INHERIT(base, ...) \ typedef ::Genode::Meta::Append::Type \ Rpc_functions; \ typedef base Rpc_inherited_interface; namespace Genode { struct Rpc_arg_in { enum { IN = true, OUT = false }; }; struct Rpc_arg_out { enum { IN = false, OUT = true }; }; struct Rpc_arg_inout { enum { IN = true, OUT = true }; }; namespace Trait { /***************************************** ** Type meta data used for marshalling ** *****************************************/ template struct Rpc_direction; template struct Rpc_direction { typedef Rpc_arg_in Type; }; template struct Rpc_direction { typedef Rpc_arg_in Type; }; template struct Rpc_direction { typedef Rpc_arg_in Type; }; template struct Rpc_direction { typedef Rpc_arg_inout Type; }; template struct Rpc_direction { typedef Rpc_arg_inout Type; }; /** * Representation of function return type * * For RPC functions with no return value, we use a pseudo return value * of type 'Empty' instead. This way, we can process all functions * regardless of the presence of a return type with the same meta * program. */ template struct Call_return { typedef T Type; }; template <> struct Call_return { typedef Meta::Empty Type; }; /** * Representation of the list of exception types * * This template maps the special case of a 'Type_list' with no arguments * to the 'Empty' type. */ template struct Exc_list { typedef T Type; }; template <> struct Exc_list > { typedef Meta::Empty Type; }; } /******************************************************* ** Automated computation of RPC message-buffer sizes ** *******************************************************/ /** * Determine transfer size of an RPC argument * * For data arguments, the transfer size is the size of the data type. For * pointer arguments, the transfer size is the size of the pointed-to * object. */ template struct Rpc_transfer_size { enum { Value = Meta::Round_to_machine_word::Value }; }; template struct Rpc_transfer_size { enum { Value = Meta::Round_to_machine_word::Value }; }; /** * Type used for transmitting the opcode of a RPC function (used for RPC call) */ typedef int Rpc_opcode; /** * Type used for transmitting exception information (used for RPC reply) */ typedef int Rpc_exception_code; /** * Special exception code used to respond to illegal opcodes */ enum { RPC_INVALID_OPCODE = -1 }; /** * Opcode base used for passing exception information */ enum { RPC_EXCEPTION_BASE = -1000 }; /** * Return the accumulated size of RPC arguments * * \param ARGS typelist with RPC arguments * \param IN true to account for RPC-input arguments * \param OUT true to account for RPC-output arguments */ template struct Rpc_args_size { typedef typename ARGS::Head This; enum { This_size = Rpc_transfer_size::Value }; enum { Value = (IN && Trait::Rpc_direction::Type::IN ? This_size : 0) + (OUT && Trait::Rpc_direction::Type::OUT ? This_size : 0) + Rpc_args_size::Value }; }; template struct Rpc_args_size { enum { Value = 0 }; }; /** * Return the size of the return value * * The return type of an RPC function can be either a real type or * 'Meta::Empty' if the function has no return value. In the latter case, * 'Retval_size' returns 0 instead of the non-zero size of 'Meta::Empty'. */ template struct Rpc_retval_size { enum { Value = sizeof(RET) }; }; template <> struct Rpc_retval_size { enum { Value = 0 }; }; /** * Calculate the payload size of a RPC message * * Setting either IN or OUT to true, the call size or respectively the * reply size is calculated. Protocol-related message parts (such as RPC * opcode or exception status) is not accounted for. */ template struct Rpc_msg_payload_size { typedef typename RPC_FUNCTION::Server_args Args; enum { Value = Rpc_args_size::Value }; }; /** * RPC message type * * An RPC message can be either a 'RPC_CALL' (from client to server) or a * 'RPC_REPLY' (from server to client). The message payload for each type * depends on the RPC function arguments as well as protocol-specific * message parts. For example, a 'RPC_CALL' requires the transmission of * the RPC opcode to select the server-side RPC function. In contrast, a * 'RPC_REPLY' message carries along the exception state returned from the * server-side RPC implementation. The 'Rpc_msg_type' is used as template * argument to specialize the calculation of message sizes for each of both * cases. */ enum Rpc_msg_type { RPC_CALL, RPC_REPLY }; /** * Calculate size of RPC message * * The send and receive cases are handled by respective template * specializations for the 'MSG_TYPE' template argument. */ template struct Rpc_function_msg_size; template struct Rpc_function_msg_size { enum { Value = Rpc_msg_payload_size::Value + sizeof(Rpc_opcode) }; }; template struct Rpc_function_msg_size { enum { Value = Rpc_msg_payload_size::Value + Rpc_retval_size::Value + sizeof(Rpc_exception_code) }; }; /** * Calculate size of message buffer needed for a list of RPC functions * * \param RPC_FUNCTIONS type list of RPC functions * * The returned 'Value' is the maximum of all function's message sizes. */ template struct Rpc_function_list_msg_size { enum { This_size = Rpc_function_msg_size::Value, Tail_size = Rpc_function_list_msg_size::Value, Value = (This_size > Tail_size) ? This_size : Tail_size }; }; template struct Rpc_function_list_msg_size { enum { Value = 0 }; }; /** * Calculate size of message buffer needed for an RPC interface * * \param RPC_IF class that hosts the RPC interface declaration * * This is a convenience wrapper for 'Rpc_function_list_msg_size'. */ template struct Rpc_interface_msg_size { typedef typename RPC_IF::Rpc_functions Rpc_functions; enum { Value = Rpc_function_list_msg_size::Value }; }; /** * Determine if a RPC interface is inherited */ template struct Rpc_interface_is_inherited { typedef char yes[1]; typedef char no[2]; template static yes &test(typename IF::Rpc_inherited_interface *); template static no &test(...); enum { VALUE = sizeof(test(0)) == sizeof(yes) }; }; } #endif /* _INCLUDE__BASE__RPC_H_ */