1
/*
2
* \brief Service management framework
3
* \author Norman Feske
4
* \date 2006-07-12
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__SERVICE_H_
15
#
define _INCLUDE__BASE__SERVICE_H_
16
17
#
include <root/client.h>
18
#
include <base/printf.h>
19
#
include <util/list.h>
20
#
include <ram_session/client.h>
21
#
include <base/env.h>
22
23
namespace
Genode {
24
25
class
Client;
26
class
Server;
27
class
Service;
28
class
Local_service;
29
class
Parent_service;
30
class
Child_service;
31
class
Service_registry;
32
}
33
34
35
/**
36
* Client role
37
*
38
* A client is someone who applies for a service. If the service is not
39
* available yet, we enqueue the client into a wait queue and wake him up
40
* as soon as the requested service gets available.
41
*/
42
class
Genode::
Client :
public
List<
Client
>
::
Element
43
{
44
private
:
45
46
Cancelable_lock _service_apply_lock;
47
const
char *
_apply_for;
48
49
public
:
50
51
/**
52
* Constructor
53
*/
54
Client(
)
:
_service_apply_lock(
Lock::
LOCKED)
,
_apply_for(
0)
{
}
55
56
virtual
~
Client(
)
{
}
57
58
/**
59
* Set/Request service name that we are currently applying for
60
*/
61
void
apply_for(
const
char *
apply_for
)
{
_apply_for =
apply_for;
}
62
const
char *
apply_for(
)
{
return
_apply_for
;
}
63
64
/**
65
* Service wait queue support
66
*/
67
void
sleep(
)
{
_service_apply_lock.
lock(
)
;
}
68
void
wakeup(
)
{
_service_apply_lock.
unlock(
)
;
}
69
}
;
70
71
72
/**
73
* Server role
74
*
75
* A server is a process that provides one or multiple services. For the
76
* most part, this class is used as an opaque key to represent the server
77
* role.
78
*/
79
class
Genode::
Server
80
{
81
private
:
82
83
Ram_session_capability _ram;
84
85
public
:
86
87
/**
88
* Constructor
89
*
90
* \param ram RAM session capability of the server process used,
91
* for quota transfers from/to the server
92
*/
93
Server(
Ram_session_capability
ram
)
:
_ram(
ram)
{
}
94
95
/**
96
* Return RAM session capability of the server process
97
*/
98
Ram_session_capability
ram_session_cap(
)
const
{
return
_ram
;
}
99
}
;
100
101
102
class
Genode::
Service :
public
List<
Service
>
::
Element
103
{
104
public
:
105
106
enum
{
MAX_NAME_LEN =
32
}
;
107
108
private
:
109
110
char _name[MAX_NAME_LEN]
;
111
112
public
:
113
114
/*********************
115
** Exception types **
116
*********************/
117
118
class
Invalid_args {
}
;
119
class
Unavailable {
}
;
120
class
Quota_exceeded {
}
;
121
122
/**
123
* Constructor
124
*
125
* \param name service name
126
*/
127
Service(
const
char *
name
)
{
strncpy(
_name,
name,
sizeof
(
_name)
)
;
}
128
129
virtual
~
Service(
)
{
}
130
131
/**
132
* Return service name
133
*/
134
const
char *
name(
)
const
{
return
_name
;
}
135
136
/**
137
* Create session
138
*
139
* \param args session-construction arguments
140
* \param affinity preferred CPU affinity of session
141
*
142
* \throw Invalid_args
143
* \throw Unavailable
144
* \throw Quota_exceeded
145
*/
146
virtual
Session_capability
session(
char const
*
args
,
147
Affinity const
&
affinity
)
=
0
;
148
149
/**
150
* Extend resource donation to an existing session
151
*/
152
virtual
void
upgrade(
Session_capability
session
,
const
char *
args
)
=
0
;
153
154
/**
155
* Close session
156
*/
157
virtual
void
close(
Session_capability /*session*/
)
{
}
158
159
/**
160
* Return server providing the service
161
*/
162
virtual
Server *
server(
)
const
{
return
0
;
}
163
164
/**
165
* Return the RAM session to be used for trading resources
166
*/
167
Ram_session_capability
ram_session_cap(
)
168
{
169
if
(
server(
)
)
170
return
server(
)
->
ram_session_cap(
)
;
171
return
Ram_session_capability(
)
;
172
}
173
}
;
174
175
176
/**
177
* Representation of a locally implemented service
178
*/
179
class
Genode::
Local_service :
public
Service
180
{
181
private
:
182
183
Root *
_root;
184
185
public
:
186
187
Local_service(
const
char *
name
,
Root *
root
)
188
:
Service(
name)
,
_root(
root)
{
}
189
190
Session_capability
session(
const
char *
args
,
Affinity const
&
affinity
)
override
191
{
192
try
{
return
_root->
session(
args,
affinity)
;
}
193
catch
(
Root::
Invalid_args)
{
throw
Invalid_args(
)
;
}
194
catch
(
Root::
Unavailable)
{
throw
Unavailable(
)
;
}
195
catch
(
Root::
Quota_exceeded)
{
throw
Quota_exceeded(
)
;
}
196
catch
(
Genode::
Ipc_error)
{
throw
Unavailable(
)
;
}
197
}
198
199
void
upgrade(
Session_capability
session
,
const
char *
args
)
override
200
{
201
try
{
_root->
upgrade(
session,
args)
;
}
202
catch
(
Genode::
Ipc_error)
{
throw
Unavailable(
)
;
}
203
}
204
205
void
close(
Session_capability
session
)
override
206
{
207
try
{
_root->
close(
session)
;
}
208
catch
(
Genode::
Ipc_error)
{
throw
Blocking_canceled(
)
;
}
209
}
210
}
;
211
212
213
/**
214
* Representation of a service provided by our parent
215
*/
216
class
Genode::
Parent_service :
public
Service
217
{
218
public
:
219
220
Parent_service(
const
char *
name
)
:
Service(
name)
{
}
221
222
Session_capability
session(
const
char *
args
,
Affinity const
&
affinity
)
override
223
{
224
try
{
return
env(
)
->
parent(
)
->
session(
name(
)
,
args,
affinity)
;
}
225
catch
(
Parent::
Unavailable)
{
226
PWRN(
"parent has no service \"
%
s\""
,
name(
)
)
;
227
throw
Unavailable(
)
;
228
}
229
catch
(
Parent::
Quota_exceeded)
{
throw
Quota_exceeded(
)
;
}
230
catch
(
Genode::
Ipc_error)
{
throw
Unavailable(
)
;
}
231
}
232
233
void
upgrade(
Session_capability
session
,
const
char *
args
)
override
234
{
235
try
{
env(
)
->
parent(
)
->
upgrade(
session,
args)
;
}
236
catch
(
Genode::
Ipc_error)
{
throw
Unavailable(
)
;
}
237
}
238
239
void
close(
Session_capability
session
)
override
240
{
241
try
{
env(
)
->
parent(
)
->
close(
session)
;
}
242
catch
(
Genode::
Ipc_error)
{
throw
Blocking_canceled(
)
;
}
243
}
244
}
;
245
246
247
/**
248
* Representation of a service that is implemented in a child
249
*/
250
class
Genode::
Child_service :
public
Service
251
{
252
private
:
253
254
Root_capability _root_cap;
255
Root_client _root;
256
Server *
_server;
257
258
public
:
259
260
/**
261
* Constructor
262
*
263
* \param name name of service
264
* \param root capability to root interface
265
* \param server server process providing the service
266
*/
267
Child_service(
const
char *
name
,
268
Root_capability
root
,
269
Server *
server
)
270
:
Service(
name)
,
_root_cap(
root)
,
_root(
root)
,
_server(
server)
{
}
271
272
Server *
server(
)
const
override
{
return
_server
;
}
273
274
Session_capability
session(
const
char *
args
,
Affinity const
&
affinity
)
override
275
{
276
if
(
!
_root_cap.
valid(
)
)
277
throw
Unavailable(
)
;
278
279
try
{
return
_root.
session(
args,
affinity)
;
}
280
catch
(
Root::
Invalid_args)
{
throw
Invalid_args(
)
;
}
281
catch
(
Root::
Unavailable)
{
throw
Unavailable(
)
;
}
282
catch
(
Root::
Quota_exceeded)
{
throw
Quota_exceeded(
)
;
}
283
catch
(
Genode::
Ipc_error)
{
throw
Unavailable(
)
;
}
284
}
285
286
void
upgrade(
Session_capability
sc
,
const
char *
args
)
override
287
{
288
if
(
!
_root_cap.
valid(
)
)
289
throw
Unavailable(
)
;
290
291
try
{
_root.
upgrade(
sc,
args)
;
}
292
catch
(
Root::
Invalid_args)
{
throw
Invalid_args(
)
;
}
293
catch
(
Root::
Unavailable)
{
throw
Unavailable(
)
;
}
294
catch
(
Root::
Quota_exceeded)
{
throw
Quota_exceeded(
)
;
}
295
catch
(
Genode::
Ipc_error)
{
throw
Unavailable(
)
;
}
296
}
297
298
void
close(
Session_capability
sc
)
override
299
{
300
try
{
_root.
close(
sc)
;
}
301
catch
(
Genode::
Ipc_error)
{
throw
Blocking_canceled(
)
;
}
302
}
303
}
;
304
305
306
/**
307
* Container for holding service representations
308
*/
309
class
Genode::
Service_registry
310
{
311
protected
:
312
313
Lock _service_wait_queue_lock;
314
List<
Client
>
_service_wait_queue;
315
List<
Service
>
_services;
316
317
public
:
318
319
/**
320
* Probe for service with specified name
321
*
322
* \param name service name
323
* \param server server providing the service,
324
* default (0) for any server
325
*/
326
Service *
find(
const
char *
name
,
Server *
server
=
0
)
327
{
328
if
(
!
name)
return
0
;
329
330
Lock::
Guard
lock_guard(
_service_wait_queue_lock
)
;
331
332
for
(
Service *
s =
_services.
first(
)
; s; s =
s->
next(
)
)
333
if
(
strcmp(
s->
name(
)
,
name)
==
0
334
&&
(
!
server ||
s->
server(
)
==
server)
)
return
s
;
335
336
return
0
;
337
}
338
339
/**
340
* Check if service name is ambiguous
341
*
342
* \return true if the same service is provided multiple
343
* times
344
*/
345
bool
is_ambiguous(
const
char *
name
)
346
{
347
Lock::
Guard
lock_guard(
_service_wait_queue_lock
)
;
348
349
/* count number of services with the specified name */
350
unsigned
cnt =
0;
351
for
(
Service *
s =
_services.
first(
)
; s; s =
s->
next(
)
)
352
cnt +=
(
strcmp(
s->
name(
)
,
name)
==
0)
;
353
return
cnt >
1
;
354
}
355
356
/**
357
* Return first service provided by specified server
358
*/
359
Service *
find_by_server(
Server *
server
)
360
{
361
Lock::
Guard
lock_guard(
_service_wait_queue_lock
)
;
362
363
for
(
Service *
s =
_services.
first(
)
; s; s =
s->
next(
)
)
364
if
(
s->
server(
)
==
server)
365
return
s
;
366
367
return
0
;
368
}
369
370
/**
371
* Wait for service
372
*
373
* This method is called by the clients`s thread when requesting a
374
* session creation. It blocks if the requested service is not
375
* available.
376
*
377
* \return service structure that matches the request or
378
* 0 if the waiting was canceled.
379
*/
380
Service *
wait_for_service(
const
char *
name
,
Client *
client
,
const
char *
client_name
)
381
{
382
Service *
service;
383
384
client->
apply_for(
name)
;
385
386
_service_wait_queue_lock.
lock(
)
;
387
_service_wait_queue.
insert(
client)
;
388
_service_wait_queue_lock.
unlock(
)
;
389
390
do
{
391
service =
find(
name)
;
392
393
/*
394
* The service that we are seeking is not available today.
395
* Lets sleep a night over it.
396
*/
397
if
(
!
service)
{
398
printf(
"%s: service %s not yet available - sleeping\n"
,
399
client_name,
name)
;
400
401
try
{
402
client->
sleep(
)
;
403
printf(
"%s: service %s got available\n"
,
client_name,
name)
;
404
}
catch
(
Blocking_canceled)
{
405
printf(
"%s: cancel waiting for service\n"
,
client_name)
;
406
break;
407
}
408
}
409
410
}
while
(
!
service)
;
411
412
/* we got what we needed, stop applying */
413
_service_wait_queue_lock.
lock(
)
;
414
_service_wait_queue.
remove(
client)
;
415
_service_wait_queue_lock.
unlock(
)
;
416
417
client->
apply_for(
0)
;
418
419
return
service
;
420
}
421
422
/**
423
* Register service
424
*
425
* This method is called by the server`s thread.
426
*/
427
void
insert(
Service *
service
)
428
{
429
/* make new service known */
430
_services.
insert(
service)
;
431
432
/* wake up applicants waiting for the service */
433
Lock::
Guard
lock_guard(
_service_wait_queue_lock
)
;
434
for
(
Client *
c =
_service_wait_queue.
first(
)
; c; c =
c->
next(
)
)
435
if
(
strcmp(
service->
name(
)
,
c->
apply_for(
)
)
==
0)
436
c->
wakeup(
)
;
437
}
438
439
/**
440
* Unregister service
441
*/
442
void
remove(
Service *
service
)
{
_services.
remove(
service)
;
}
443
444
/**
445
* Unregister all services
446
*/
447
void
remove_all(
)
448
{
449
while
(
_services.
first(
)
)
450
remove(
_services.
first(
)
)
;
451
}
452
}
;
453
454
#
endif /* _INCLUDE__BASE__SERVICE_H_ */