1
/*
2
* \brief Support for defining and working with RPC interfaces
3
* \author Norman Feske
4
* \date 2011-03-28
5
*/
6
7
/*
8
* Copyright (C) 2011-2013 Genode Labs GmbH
9
*
10
* This file is part of the Genode OS framework, which is distributed
11
* under the terms of the GNU General Public License version 2.
12
*/
13
14
#
ifndef _INCLUDE__BASE__RPC_H_
15
#
define _INCLUDE__BASE__RPC_H_
16
17
#
include <util/meta.h>
18
19
20
/**
21
* Macro for declaring an RPC function
22
*
23
* \param rpc_name type name representing the RPC function
24
* \param ret_type RPC return type
25
* \param func_name RPC function name
26
* \param exc_types type list of exceptions that may be thrown by the
27
* function
28
* \param ... variable number of RPC function arguments
29
*
30
* Each RPC function is represented by a struct that contains the meta data
31
* about the function arguments, the return type, and the exception types.
32
* Furthermore, it contains an adapter function called `serve`, which is used
33
* on the server side to invoke the server-side implementation of the RPC
34
* function. It takes an a `Pod_tuple` argument structure and calls the
35
* server-side function with individual arguments using the `call_member`
36
* mechanism provided by `meta.h`.
37
*/
38
#
define GENODE_RPC_THROW(rpc_name, ret_type, func_name, exc_types, ...) \
39
struct rpc_name { \
40
typedef ::Genode::Meta::Ref_args<__VA_ARGS__>::Type Client_args; \
41
typedef ::Genode::Meta::Pod_args<__VA_ARGS__>::Type Server_args; \
42
typedef ::Genode::Trait::Exc_list<exc_types>::Type Exceptions; \
43
typedef ::Genode::Trait::Call_return<ret_type>::Type Ret_type; \
44
\
45
template <typename SERVER, typename RET> \
46
static void serve(SERVER &server, Server_args &args, RET &ret) { \
47
::Genode::Meta::call_member<RET, SERVER, Server_args> \
48
(ret, server, args, &SERVER::func_name); } \
49
\
50
static const char* name() { return #
func_name; } \
51
};
52
53
/**
54
* Shortcut for `GENODE_RPC_THROW` for an RPC that throws no exceptions
55
*/
56
#
define GENODE_RPC(rpc_name, ret_type, func_name, ...) \
57
GENODE_RPC_THROW(rpc_name, ret_type, func_name, GENODE_TYPE_LIST(), __VA_ARGS__)
58
59
/**
60
* Macro for declaring a RPC interface
61
*
62
* \param ... list of RPC functions as declared via `GENODE_RPC`
63
*
64
* An RPC interface is represented as type list of RPC functions. The RPC
65
* opcode for each function is implicitly defined by its position within
66
* this type list.
67
*/
68
#
define GENODE_RPC_INTERFACE(...) \
69
typedef GENODE_TYPE_LIST(__VA_ARGS__) Rpc_functions
70
71
/**
72
* Macro for declaring a RPC interface derived from another RPC interface
73
*
74
* \param base class hosting the RPC interface to be inherited
75
* \param ... list of the locally declared RPC functions
76
*
77
* RPC interface inheritance is simply the concatenation of the type list
78
* of RPC functions declared for the base interface and the locally declared
79
* RPC functions. By appending the local RPC functions, the RPC opcodes of
80
* the inherited RPC functions are preserved.
81
*/
82
#
define GENODE_RPC_INTERFACE_INHERIT(base, ...) \
83
typedef ::Genode::Meta::Append<base::Rpc_functions, \
84
GENODE_TYPE_LIST(__VA_ARGS__) >::Type \
85
Rpc_functions; \
86
typedef base Rpc_inherited_interface;
87
88
89
namespace
Genode {
90
91
struct
Rpc_arg_in {
enum
{
IN =
true
,
OUT =
false
}
;
}
;
92
struct
Rpc_arg_out {
enum
{
IN =
false
,
OUT =
true
}
;
}
;
93
struct
Rpc_arg_inout {
enum
{
IN =
true
,
OUT =
true
}
;
}
;
94
95
namespace
Trait {
96
97
/*****************************************
98
** Type meta data used for marshalling **
99
*****************************************/
100
101
template
<
typename
T
>
struct
Rpc_direction;
102
103
104
template
<
typename
T
>
struct
Rpc_direction {
typedef
Rpc_arg_in Type
;
}
;
105
template
<
typename
T
>
struct
Rpc_direction<
T const
*
>
{
typedef
Rpc_arg_in Type
;
}
;
106
template
<
typename
T
>
struct
Rpc_direction<
T const
&
>
{
typedef
Rpc_arg_in Type
;
}
;
107
template
<
typename
T
>
struct
Rpc_direction<
T*
>
{
typedef
Rpc_arg_inout Type
;
}
;
108
template
<
typename
T
>
struct
Rpc_direction<
T&
>
{
typedef
Rpc_arg_inout Type
;
}
;
109
110
/**
111
* Representation of function return type
112
*
113
* For RPC functions with no return value, we use a pseudo return value
114
* of type `Empty` instead. This way, we can process all functions
115
* regardless of the presence of a return type with the same meta
116
* program.
117
*/
118
template
<
typename
T
>
struct
Call_return {
typedef
T Type
;
}
;
119
template
<
>
struct
Call_return<
void
>
{
typedef
Meta::
Empty Type
;
}
;
120
121
/**
122
* Representation of the list of exception types
123
*
124
* This template maps the special case of a `Type_list` with no arguments
125
* to the `Empty` type.
126
*/
127
template
<
typename
T
>
struct
Exc_list {
typedef
T Type
;
}
;
128
template
<
>
struct
Exc_list<
Meta::
Type_list<
>
>
{
typedef
Meta::
Empty Type
;
}
;
129
}
130
131
132
/*******************************************************
133
** Automated computation of RPC message-buffer sizes **
134
*******************************************************/
135
136
/**
137
* Determine transfer size of an RPC argument
138
*
139
* For data arguments, the transfer size is the size of the data type. For
140
* pointer arguments, the transfer size is the size of the pointed-to
141
* object.
142
*/
143
template
<
typename
T
>
144
struct
Rpc_transfer_size {
145
enum
{
Value =
Meta::
Round_to_machine_word<
sizeof
(
T)
>
::
Value
}
;
}
;
146
147
template
<
typename
T
>
148
struct
Rpc_transfer_size<
T *
>
{
149
enum
{
Value =
Meta::
Round_to_machine_word<
sizeof
(
T)
>
::
Value
}
;
}
;
150
151
152
/**
153
* Type used for transmitting the opcode of a RPC function (used for RPC call)
154
*/
155
typedef
int Rpc_opcode
;
156
157
158
/**
159
* Type used for transmitting exception information (used for RPC reply)
160
*/
161
typedef
int Rpc_exception_code
;
162
163
164
/**
165
* Special exception code used to respond to illegal opcodes
166
*/
167
enum
{
RPC_INVALID_OPCODE =
-
1
}
;
168
169
170
/**
171
* Opcode base used for passing exception information
172
*/
173
enum
{
RPC_EXCEPTION_BASE =
-
1000
}
;
174
175
176
/**
177
* Return the accumulated size of RPC arguments
178
*
179
* \param ARGS typelist with RPC arguments
180
* \param IN true to account for RPC-input arguments
181
* \param OUT true to account for RPC-output arguments
182
*/
183
template
<
typename
ARGS
,
bool
IN
,
bool
OUT
>
184
struct
Rpc_args_size {
185
typedef
typename
ARGS::
Head This;
186
enum
{
This_size =
Rpc_transfer_size<
This
>
::
Value
}
;
187
enum
{
Value
=
(
IN &&
Trait::
Rpc_direction<
This
>
::
Type::
IN ?
This_size : 0)
188
+
(
OUT &&
Trait::
Rpc_direction<
This
>
::
Type::
OUT ?
This_size : 0)
189
+
Rpc_args_size<
typename
ARGS::
Tail
,
IN
,
OUT
>
::
Value
}
;
}
;
190
191
template
<
bool
IN
,
bool
OUT
>
192
struct
Rpc_args_size<
Meta::
Empty
,
IN
,
OUT
>
{
enum
{
Value =
0
}
;
}
;
193
194
195
/**
196
* Return the size of the return value
197
*
198
* The return type of an RPC function can be either a real type or
199
* `Meta::Empty` if the function has no return value. In the latter case,
200
* `Retval_size` returns 0 instead of the non-zero size of `Meta::Empty`.
201
*/
202
template
<
typename
RET
>
203
struct
Rpc_retval_size {
enum
{
Value
=
sizeof
(
RET)
}
;
}
;
204
205
template
<
>
206
struct
Rpc_retval_size<
Meta::
Empty
>
{
enum
{
Value =
0
}
;
}
;
207
208
209
/**
210
* Calculate the payload size of a RPC message
211
*
212
* Setting either IN or OUT to true, the call size or respectively the
213
* reply size is calculated. Protocol-related message parts (such as RPC
214
* opcode or exception status) is not accounted for.
215
*/
216
template
<
typename
RPC_FUNCTION
,
bool
IN
,
bool
OUT
>
217
struct
Rpc_msg_payload_size {
218
typedef
typename
RPC_FUNCTION::
Server_args Args;
219
enum
{
Value =
Rpc_args_size<
Args
,
IN
,
OUT
>
::
Value
}
;
}
;
220
221
222
/**
223
* RPC message type
224
*
225
* An RPC message can be either a `RPC_CALL` (from client to server) or a
226
* `RPC_REPLY` (from server to client). The message payload for each type
227
* depends on the RPC function arguments as well as protocol-specific
228
* message parts. For example, a `RPC_CALL` requires the transmission of
229
* the RPC opcode to select the server-side RPC function. In contrast, a
230
* `RPC_REPLY` message carries along the exception state returned from the
231
* server-side RPC implementation. The `Rpc_msg_type` is used as template
232
* argument to specialize the calculation of message sizes for each of both
233
* cases.
234
*/
235
enum
Rpc_msg_type {
RPC_CALL
,
RPC_REPLY
}
;
236
237
238
/**
239
* Calculate size of RPC message
240
*
241
* The send and receive cases are handled by respective template
242
* specializations for the `MSG_TYPE` template argument.
243
*/
244
template
<
typename
RPC_FUNCTION
,
Rpc_msg_type
MSG_TYPE
>
245
struct
Rpc_function_msg_size;
246
247
template
<
typename
RPC_FUNCTION
>
248
struct
Rpc_function_msg_size<
RPC_FUNCTION
,
RPC_CALL
>
{
249
enum
{
Value =
Rpc_msg_payload_size<
RPC_FUNCTION
,
true
,
false
>
::
Value
250
+
sizeof
(
Rpc_opcode)
}
;
}
;
251
252
template
<
typename
RPC_FUNCTION
>
253
struct
Rpc_function_msg_size<
RPC_FUNCTION
,
RPC_REPLY
>
{
254
enum
{
Value =
Rpc_msg_payload_size<
RPC_FUNCTION
,
false
,
true
>
::
Value
255
+
Rpc_retval_size<
typename
RPC_FUNCTION::
Ret_type
>
::
Value
256
+
sizeof
(
Rpc_exception_code)
}
;
}
;
257
258
259
/**
260
* Calculate size of message buffer needed for a list of RPC functions
261
*
262
* \param RPC_FUNCTIONS type list of RPC functions
263
*
264
* The returned `Value` is the maximum of all function`s message sizes.
265
*/
266
template
<
typename
RPC_FUNCTIONS
,
Rpc_msg_type
MSG_TYPE
>
267
struct
Rpc_function_list_msg_size {
268
enum
{
269
This_size =
Rpc_function_msg_size<
typename
RPC_FUNCTIONS::
Head
,
MSG_TYPE
>
::
Value
,
270
Tail_size =
Rpc_function_list_msg_size<
typename
RPC_FUNCTIONS::
Tail
,
MSG_TYPE
>
::
Value
,
271
Value
=
(
This_size >
Tail_size)
?
This_size
: Tail_size
}
;
}
;
272
273
template
<
Rpc_msg_type
MSG_TYPE
>
274
struct
Rpc_function_list_msg_size<
Meta::
Empty
,
MSG_TYPE
>
{
enum
{
Value =
0
}
;
}
;
275
276
277
/**
278
* Calculate size of message buffer needed for an RPC interface
279
*
280
* \param RPC_IF class that hosts the RPC interface declaration
281
*
282
* This is a convenience wrapper for `Rpc_function_list_msg_size`.
283
*/
284
template
<
typename
RPC_IF
,
Rpc_msg_type
MSG_TYPE
>
285
struct
Rpc_interface_msg_size {
286
typedef
typename
RPC_IF::
Rpc_functions Rpc_functions;
287
enum
{
Value =
Rpc_function_list_msg_size<
Rpc_functions
,
MSG_TYPE
>
::
Value
}
;
}
;
288
289
290
/**
291
* Determine if a RPC interface is inherited
292
*/
293
template
<
typename
INTERFACE
>
294
struct
Rpc_interface_is_inherited
295
{
296
typedef
char yes[1]
;
297
typedef
char no[2]
;
298
299
template
<
typename
IF
>
300
static
yes &
test(
typename
IF::
Rpc_inherited_interface *
)
;
301
302
template
<
typename
>
303
static
no &
test(
.
.
.
)
;
304
305
enum
{
VALUE
=
sizeof
(
test<
INTERFACE
>
(
0)
)
==
sizeof
(
yes)
}
;
306
}
;
307
}
308
309
#
endif /* _INCLUDE__BASE__RPC_H_ */