1
/*
2
* \brief Server-side API of the RPC framework
3
* \author Norman Feske
4
* \date 2006-04-28
5
*/
6
7
/*
8
* Copyright (C) 2006-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_SERVER_H_
15
#
define _INCLUDE__BASE__RPC_SERVER_H_
16
17
#
include <base/rpc.h>
18
#
include <base/thread.h>
19
#
include <base/ipc.h>
20
#
include <base/object_pool.h>
21
#
include <base/lock.h>
22
#
include <base/printf.h>
23
#
include <base/trace/events.h>
24
#
include <cap_session/cap_session.h>
25
26
namespace
Genode {
27
template
<
typename
,
typename
>
class
Rpc_dispatcher;
28
class
Rpc_object_base;
29
template
<
typename
,
typename
>
struct
Rpc_object;
30
class
Rpc_entrypoint;
31
}
32
33
34
/**
35
* RPC dispatcher implementing the specified RPC interface
36
*
37
* \param RPC_INTERFACE class providing the RPC interface description
38
* \param SERVER class to invoke for the server-side RPC functions
39
*
40
* This class is the base class of each server-side RPC implementation. It
41
* contains the logic for dispatching incoming RPC requests and calls the
42
* server functions according to the RPC declarations in `RPC_INTERFACE`.
43
*
44
* If using the default argument for `SERVER`, the `RPC_INTERFACE` is expected
45
* to contain the abstract interface for all RPC functions. So virtual methods
46
* must be declared in `RPC_INTERFACE`. In contrast, by explicitly specifying
47
* the `SERVER` argument, the server-side dispatching performs direct
48
* calls to the respective methods of the `SERVER` class and thereby
49
* omits virtual method calls.
50
*/
51
template
<
typename
RPC_INTERFACE
,
typename
SERVER
=
RPC_INTERFACE
>
52
class
Genode::
Rpc_dispatcher :
public
RPC_INTERFACE
53
{
54
/**
55
* Shortcut for the type list of RPC functions provided by this server
56
* component
57
*/
58
typedef
typename
RPC_INTERFACE::
Rpc_functions Rpc_functions;
59
60
protected
:
61
62
template
<
typename
ARG_LIST
>
63
void
_read_args(
Ipc_istream &
is
,
ARG_LIST &
args
)
64
{
65
if
(
Trait::
Rpc_direction<
typename
ARG_LIST::
Head
>
::
Type::
IN)
66
is >>
args.
_1;
67
68
_read_args(
is,
args.
_2)
;
69
}
70
71
void
_read_args(
Ipc_istream &
,
Meta::
Empty
)
{
}
72
73
template
<
typename
ARG_LIST
>
74
void
_write_results(
Ipc_ostream &
os
,
ARG_LIST &
args
)
75
{
76
if
(
Trait::
Rpc_direction<
typename
ARG_LIST::
Head
>
::
Type::
OUT)
77
os <<
args.
_1;
78
79
_write_results(
os,
args.
_2)
;
80
}
81
82
void
_write_results(
Ipc_ostream &
,
Meta::
Empty
)
{
}
83
84
template
<
typename
RPC_FUNCTION
,
typename
EXC_TL
>
85
Rpc_exception_code
_do_serve(
typename
RPC_FUNCTION::
Server_args &
args
,
86
typename
RPC_FUNCTION::
Ret_type &
ret
,
87
Meta::
Overload_selector<
RPC_FUNCTION
,
EXC_TL
>
)
88
{
89
enum
{
EXCEPTION_CODE =
RPC_EXCEPTION_BASE -
Meta::
Length<
EXC_TL
>
::
Value
}
;
90
try
{
91
typedef
typename
EXC_TL::
Tail Exc_tail;
92
return
_do_serve(
args,
ret,
93
Meta::
Overload_selector<
RPC_FUNCTION
,
Exc_tail
>
(
)
)
;
94
}
catch
(
typename
EXC_TL::
Head)
{
return
EXCEPTION_CODE
;
}
95
}
96
97
template
<
typename
RPC_FUNCTION
>
98
Rpc_exception_code
_do_serve(
typename
RPC_FUNCTION::
Server_args &
args
,
99
typename
RPC_FUNCTION::
Ret_type &
ret
,
100
Meta::
Overload_selector<
RPC_FUNCTION
,
Meta::
Empty
>
)
101
{
102
RPC_FUNCTION::
serve(
*
static_cast
<
SERVER *
>
(
this)
,
args,
ret)
;
103
return
0
;
104
}
105
106
template
<
typename
RPC_FUNCTIONS_TO_CHECK
>
107
Rpc_exception_code
_do_dispatch(
Rpc_opcode
opcode
,
Ipc_istream &
is
,
Ipc_ostream &
os
,
108
Meta::
Overload_selector<
RPC_FUNCTIONS_TO_CHECK
>
)
109
{
110
using
namespace
Meta;
111
112
typedef
typename
RPC_FUNCTIONS_TO_CHECK::
Head This_rpc_function;
113
114
if
(
opcode ==
Index_of<
Rpc_functions
,
This_rpc_function
>
::
Value)
{
115
116
typename
This_rpc_function::
Server_args args{
}
;
117
118
/* read arguments from istream */
119
_read_args(
is,
args)
;
120
121
{
122
Trace::
Rpc_dispatch
trace_event(
This_rpc_function::
name(
)
)
;
123
}
124
125
/*
126
* Dispatch call to matching RPC base class, using
127
* `This_rpc_function` and the list of its exceptions to
128
* select the overload.
129
*/
130
typedef
typename
This_rpc_function::
Exceptions Exceptions;
131
132
typename
This_rpc_function::
Ret_type ret {
}
;
133
Rpc_exception_code exc;
134
exc =
_do_serve(
args,
ret,
Overload_selector<
This_rpc_function
,
Exceptions
>
(
)
)
;
135
os <<
ret;
136
137
{
138
Trace::
Rpc_reply
trace_event(
This_rpc_function::
name(
)
)
;
139
}
140
141
/* write results to ostream `os` */
142
_write_results(
os,
args)
;
143
144
return
exc
;
145
}
146
147
typedef
typename
RPC_FUNCTIONS_TO_CHECK::
Tail Tail;
148
return
_do_dispatch(
opcode,
is,
os,
Overload_selector<
Tail
>
(
)
)
;
149
}
150
151
int
_do_dispatch(
int
opcode
,
Ipc_istream &
,
Ipc_ostream &
,
152
Meta::
Overload_selector<
Meta::
Empty
>
)
153
{
154
PERR(
"invalid opcode %d\n"
,
opcode)
;
155
return
RPC_INVALID_OPCODE
;
156
}
157
158
/**
159
* Handle corner case of having an RPC interface with no RPC functions
160
*/
161
Rpc_exception_code
_do_dispatch(
int
opcode
,
Ipc_istream &
,
Ipc_ostream &
,
162
Meta::
Overload_selector<
Meta::
Type_list<
>
>
)
163
{
164
return
0
;
165
}
166
167
/**
168
* Protected constructor
169
*
170
* This class is only usable as base class.
171
*/
172
Rpc_dispatcher(
)
{
}
173
174
public
:
175
176
Rpc_exception_code
dispatch(
int
opcode
,
Ipc_istream &
is
,
Ipc_ostream &
os
)
177
{
178
return
_do_dispatch(
opcode,
is,
os,
179
Meta::
Overload_selector<
Rpc_functions
>
(
)
)
;
180
}
181
}
;
182
183
184
class
Genode::
Rpc_object_base :
public
Object_pool<
Rpc_object_base
>
::
Entry
185
{
186
public
:
187
188
virtual
~
Rpc_object_base(
)
{
}
189
190
/**
191
* Interface to be implemented by a derived class
192
*
193
* \param op opcode of invoked method
194
* \param is Ipc_input stream with method arguments
195
* \param os Ipc_output stream for storing method results
196
*/
197
virtual
int
dispatch(
int
op
,
Ipc_istream &
is
,
Ipc_ostream &
os
)
=
0
;
198
}
;
199
200
201
/**
202
* Object that is accessible from remote protection domains
203
*
204
* A `Rpc_object` is a locally implemented object that can be referenced
205
* from the outer world using a capability. The capability gets created
206
* when attaching a `Rpc_object` to a `Rpc_entrypoint`.
207
*/
208
template
<
typename
RPC_INTERFACE
,
typename
SERVER
=
RPC_INTERFACE
>
209
struct
Genode::
Rpc_object :
Rpc_object_base,
Rpc_dispatcher<
RPC_INTERFACE
,
SERVER
>
210
{
211
/*****************************
212
** Server-object interface **
213
*****************************/
214
215
Rpc_exception_code
dispatch(
int
opcode
,
Ipc_istream &
is
,
Ipc_ostream &
os
)
216
{
217
return
Rpc_dispatcher<
RPC_INTERFACE
,
SERVER
>
::
dispatch(
opcode,
is,
os)
;
218
}
219
220
Capability<
RPC_INTERFACE
>
const
cap(
)
const
221
{
222
return
reinterpret_cap_cast<
RPC_INTERFACE
>
(
Rpc_object_base::
cap(
)
)
;
223
}
224
}
;
225
226
227
/**
228
* RPC entrypoint serving RPC objects
229
*
230
* The entrypoint`s thread will initialize its capability but will not
231
* immediately enable the processing of requests. This way, the
232
* activation-using server can ensure that it gets initialized completely
233
* before the first capability invocations come in. Once the server is
234
* ready, it must enable the entrypoint explicitly by calling the
235
* `activate()` method. The `start_on_construction` argument is a
236
* shortcut for the common case where the server`s capability is handed
237
* over to other parties _after_ the server is completely initialized.
238
*/
239
class
Genode::
Rpc_entrypoint :
Thread_base,
public
Object_pool<
Rpc_object_base
>
240
{
241
private
:
242
243
/**
244
* Prototype capability to derive capabilities for RPC objects
245
* from.
246
*/
247
Untyped_capability _cap;
248
249
enum
{
SND_BUF_SIZE =
1024
,
RCV_BUF_SIZE =
1024
}
;
250
Msgbuf<
SND_BUF_SIZE
>
_snd_buf;
251
Msgbuf<
RCV_BUF_SIZE
>
_rcv_buf;
252
253
/**
254
* Hook to let low-level thread init code access private members
255
*
256
* This method is only used on NOVA.
257
*/
258
static
void
_activation_entry(
)
;
259
260
struct
Exit
261
{
262
GENODE_RPC
(
Rpc_exit,
void,
_exit)
;
263
GENODE_RPC_INTERFACE
(
Rpc_exit)
;
264
}
;
265
266
struct
Exit_handler :
Rpc_object<
Exit
,
Exit_handler
>
267
{
268
int exit;
269
270
Exit_handler(
)
:
exit(
false)
{
}
271
272
void
_exit(
)
{
exit =
true;
}
273
}
;
274
275
protected
:
276
277
Ipc_server *
_ipc_server;
278
Lock _cap_valid;
/* thread startup synchronization */
279
Lock _delay_start;
/* delay start of request dispatching */
280
Lock _delay_exit;
/* delay destructor until server settled */
281
Pd_session &
_pd_session;
/* for creating capabilities */
282
Exit_handler _exit_handler;
283
Capability<
Exit
>
_exit_cap;
284
285
/**
286
* Access to kernel-specific part of the PD session interface
287
*
288
* Some kernels like NOVA need a special interface for creating RPC
289
* object capabilities.
290
*/
291
Capability<
Pd_session::
Native_pd
>
_native_pd_cap;
292
293
/**
294
* Back end used to associate RPC object with the entry point
295
*
296
* \noapi
297
*/
298
Untyped_capability
_manage(
Rpc_object_base *
obj
)
;
299
300
/**
301
* Back end used to Dissolve RPC object from entry point
302
*
303
* \noapi
304
*/
305
void
_dissolve(
Rpc_object_base *
obj
)
;
306
307
/**
308
* Wait until the entrypoint activation is initialized
309
*
310
* \noapi
311
*/
312
void
_block_until_cap_valid(
)
;
313
314
/**
315
* Allocate new RPC object capability
316
*
317
* Regular servers allocate capabilities from their protection domain
318
* via the component`s environment. This method allows core to have a
319
* special implementation that does not rely on a PD session.
320
*
321
* The `entry` argument is used only on NOVA. It is the server-side
322
* instruction pointer to be associated with the RPC object capability.
323
*/
324
Native_capability
_alloc_rpc_cap(
Pd_session &
,
Native_capability
ep
,
325
addr_t
entry
=
0
)
;
326
327
/**
328
* Free RPC object capability
329
*/
330
void
_free_rpc_cap(
Pd_session &
,
Native_capability
)
;
331
332
/**
333
* Thread interface
334
*
335
* \noapi
336
*/
337
void
entry(
)
;
338
339
public
:
340
341
/**
342
* Constructor
343
*
344
* \param cap_session `Cap_session` for creating capabilities
345
* for the RPC objects managed by this entry
346
* point
347
* \param stack_size stack size of entrypoint thread
348
* \param name name of entrypoint thread
349
* \param location CPU affinity
350
*/
351
Rpc_entrypoint(
Pd_session *
pd_session
,
size_t
stack_size
,
352
char const
*
name
,
bool
start_on_construction
=
true
,
353
Affinity::
Location location =
Affinity::
Location(
)
)
;
354
355
~
Rpc_entrypoint(
)
;
356
357
/**
358
* Associate RPC object with the entry point
359
*/
360
template
<
typename
RPC_INTERFACE
,
typename
RPC_SERVER
>
361
Capability<
RPC_INTERFACE
>
362
manage(
Rpc_object<
RPC_INTERFACE
,
RPC_SERVER
>
*
obj
)
363
{
364
return
reinterpret_cap_cast<
RPC_INTERFACE
>
(
_manage(
obj)
)
;
365
}
366
367
/**
368
* Dissolve RPC object from entry point
369
*/
370
template
<
typename
RPC_INTERFACE
,
typename
RPC_SERVER
>
371
void
dissolve(
Rpc_object<
RPC_INTERFACE
,
RPC_SERVER
>
*
obj
)
372
{
373
_dissolve(
obj)
;
374
}
375
376
/**
377
* Activate entrypoint, start processing RPC requests
378
*/
379
void
activate(
)
;
380
381
/**
382
* Request reply capability for current call
383
*
384
* \noapi
385
*
386
* Note: This is a temporary API method, which is going to be
387
* removed. Please do not use this method.
388
*
389
* Typically, a capability obtained via this method is used as
390
* argument of `intermediate_reply`.
391
*/
392
Untyped_capability
reply_dst(
)
;
393
394
/**
395
* Prevent reply of current request
396
*
397
* \noapi
398
*
399
* Note: This is a temporary API method, which is going to be
400
* removed. Please do not use this method.
401
*
402
* This method can be used to keep the calling client blocked
403
* after the server has finished the processing of the client`s
404
* request. At a later time, the server may chose to unblock the
405
* client via the `intermedate_reply` method.
406
*/
407
void
omit_reply(
)
;
408
409
/**
410
* Send a reply out of the normal call-reply order
411
*
412
* \noapi
413
*
414
* In combination with the `reply_dst` accessor method, this method
415
* allows for the dispatching of client requests out of order. The only
416
* designated user of this method is core`s PD service. The
417
* `Pd_session::submit` RPC function uses it to send a reply to a
418
* caller of the `Signal_source::wait_for_signal` RPC function before
419
* returning from the `submit` call.
420
*/
421
void
reply_signal_info(
Untyped_capability
reply_cap
,
422
unsigned
long
imprint
,
unsigned
long
cnt
)
;
423
424
/**
425
* Return true if the caller corresponds to the entrypoint called
426
*
427
* \noapi
428
*
429
* This method is solely needed on Linux.
430
*/
431
bool
is_myself(
)
const
;
432
}
;
433
434
#
endif /* _INCLUDE__BASE__RPC_SERVER_H_ */