mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-27 17:18:53 +00:00
0c76bc9cfd
This patch introduces principal support for extending session interfaces with specialized functionality in a clean way. For example, an 'Uart' interface may implement the 'Terminal' interface but also offers additional functions for setting the baud rate. A service that implements the 'Uart' service will then automatically announce both the 'Uart' and 'Terminal' services.
308 lines
10 KiB
C++
308 lines
10 KiB
C++
/*
|
|
* \brief Support for defining and working with RPC interfaces
|
|
* \author Norman Feske
|
|
* \date 2011-03-28
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2011-2012 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 <util/meta.h>
|
|
|
|
|
|
/**
|
|
* 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<exc_types>::Type Exceptions; \
|
|
typedef ::Genode::Trait::Call_return<ret_type>::Type Ret_type; \
|
|
\
|
|
template <typename SERVER, typename RET> \
|
|
static void serve(SERVER &server, Server_args &args, RET &ret) { \
|
|
::Genode::Meta::call_member<RET, SERVER, Server_args> \
|
|
(ret, server, args, &SERVER::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<base::Rpc_functions, \
|
|
GENODE_TYPE_LIST(__VA_ARGS__) >::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 <typename T> struct Rpc_direction;
|
|
|
|
|
|
template <typename T> struct Rpc_direction { typedef Rpc_arg_in Type; };
|
|
template <typename T> struct Rpc_direction<T const *> { typedef Rpc_arg_in Type; };
|
|
template <typename T> struct Rpc_direction<T const &> { typedef Rpc_arg_in Type; };
|
|
template <typename T> struct Rpc_direction<T*> { typedef Rpc_arg_inout Type; };
|
|
template <typename T> struct Rpc_direction<T&> { 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 <typename T> struct Call_return { typedef T Type; };
|
|
template <> struct Call_return<void> { 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 <typename T> struct Exc_list { typedef T Type; };
|
|
template <> struct Exc_list<Meta::Type_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 <typename T>
|
|
struct Rpc_transfer_size {
|
|
enum { Value = Meta::Round_to_machine_word<sizeof(T)>::Value }; };
|
|
|
|
template <typename T>
|
|
struct Rpc_transfer_size<T *> {
|
|
enum { Value = Meta::Round_to_machine_word<sizeof(T)>::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 <typename ARGS, bool IN, bool OUT>
|
|
struct Rpc_args_size {
|
|
typedef typename ARGS::Head This;
|
|
enum { This_size = Rpc_transfer_size<This>::Value };
|
|
enum { Value = (IN && Trait::Rpc_direction<This>::Type::IN ? This_size : 0)
|
|
+ (OUT && Trait::Rpc_direction<This>::Type::OUT ? This_size : 0)
|
|
+ Rpc_args_size<typename ARGS::Tail, IN, OUT>::Value }; };
|
|
|
|
template <bool IN, bool OUT>
|
|
struct Rpc_args_size<Meta::Empty, IN, OUT> { 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 <typename RET>
|
|
struct Rpc_retval_size { enum { Value = sizeof(RET) }; };
|
|
|
|
template <>
|
|
struct Rpc_retval_size<Meta::Empty> { 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 <typename RPC_FUNCTION, bool IN, bool OUT>
|
|
struct Rpc_msg_payload_size {
|
|
typedef typename RPC_FUNCTION::Server_args Args;
|
|
enum { Value = Rpc_args_size<Args, IN, OUT>::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 <typename RPC_FUNCTION, Rpc_msg_type MSG_TYPE>
|
|
struct Rpc_function_msg_size;
|
|
|
|
template <typename RPC_FUNCTION>
|
|
struct Rpc_function_msg_size<RPC_FUNCTION, RPC_CALL> {
|
|
enum { Value = Rpc_msg_payload_size<RPC_FUNCTION, true, false>::Value
|
|
+ sizeof(Rpc_opcode) }; };
|
|
|
|
template <typename RPC_FUNCTION>
|
|
struct Rpc_function_msg_size<RPC_FUNCTION, RPC_REPLY> {
|
|
enum { Value = Rpc_msg_payload_size<RPC_FUNCTION, false, true>::Value
|
|
+ Rpc_retval_size<typename RPC_FUNCTION::Ret_type>::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 <typename RPC_FUNCTIONS, Rpc_msg_type MSG_TYPE>
|
|
struct Rpc_function_list_msg_size {
|
|
enum {
|
|
This_size = Rpc_function_msg_size<typename RPC_FUNCTIONS::Head, MSG_TYPE>::Value,
|
|
Tail_size = Rpc_function_list_msg_size<typename RPC_FUNCTIONS::Tail, MSG_TYPE>::Value,
|
|
Value = (This_size > Tail_size) ? This_size : Tail_size }; };
|
|
|
|
template <Rpc_msg_type MSG_TYPE>
|
|
struct Rpc_function_list_msg_size<Meta::Empty, MSG_TYPE> { 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 <typename RPC_IF, Rpc_msg_type MSG_TYPE>
|
|
struct Rpc_interface_msg_size {
|
|
typedef typename RPC_IF::Rpc_functions Rpc_functions;
|
|
enum { Value = Rpc_function_list_msg_size<Rpc_functions, MSG_TYPE>::Value }; };
|
|
|
|
|
|
/**
|
|
* Determine if a RPC interface is inherited
|
|
*/
|
|
template <typename INTERFACE>
|
|
struct Rpc_interface_is_inherited
|
|
{
|
|
typedef char yes[1];
|
|
typedef char no[2];
|
|
|
|
template <typename IF>
|
|
static yes &test(typename IF::Rpc_inherited_interface *);
|
|
|
|
template <typename>
|
|
static no &test(...);
|
|
|
|
enum { VALUE = sizeof(test<INTERFACE>(0)) == sizeof(yes) };
|
|
};
|
|
}
|
|
|
|
#endif /* _INCLUDE__BASE__RPC_H_ */
|