1
/*
2
* \brief Generic root component implementation
3
* \author Norman Feske
4
* \date 2006-05-22
5
*
6
* This class is there for your convenience. It performs the common actions
7
* that must always be taken when creating a new session.
8
*/
9
10
/*
11
* Copyright (C) 2006-2013 Genode Labs GmbH
12
*
13
* This file is part of the Genode OS framework, which is distributed
14
* under the terms of the GNU General Public License version 2.
15
*/
16
17
#
ifndef _INCLUDE__ROOT__COMPONENT_H_
18
#
define _INCLUDE__ROOT__COMPONENT_H_
19
20
#
include <root/root.h>
21
#
include <base/rpc_server.h>
22
#
include <base/heap.h>
23
#
include <ram_session/ram_session.h>
24
#
include <util/arg_string.h>
25
#
include <base/printf.h>
26
27
namespace
Genode {
28
29
class
Single_client;
30
class
Multiple_clients;
31
template
<
typename
,
typename
POLICY
=
Multiple_clients
>
class
Root_component;
32
}
33
34
35
/**
36
* Session creation policy for a single-client service
37
*/
38
class
Genode::
Single_client
39
{
40
private
:
41
42
bool _used;
43
44
public
:
45
46
Single_client(
)
:
_used(
0)
{
}
47
48
void
aquire(
const
char *
)
49
{
50
if
(
_used)
51
throw
Root::
Unavailable(
)
;
52
53
_used =
true;
54
}
55
56
void
release(
)
{
_used =
false;
}
57
}
;
58
59
60
/**
61
* Session-creation policy for a multi-client service
62
*/
63
struct
Genode::
Multiple_clients
64
{
65
void
aquire(
const
char *
)
{
}
66
void
release(
)
{
}
67
}
;
68
69
70
/**
71
* Template for implementing the root interface
72
*
73
* \param SESSION_TYPE session-component type to manage,
74
* derived from `Rpc_object`
75
* \param POLICY session-creation policy
76
*
77
* The `POLICY` template parameter allows for constraining the session
78
* creation to only one instance at a time (using the `Single_session`
79
* policy) or multiple instances (using the `Multiple_sessions` policy).
80
*
81
* The `POLICY` class must provide the following two methods:
82
*
83
* `aquire(const char *args)` is called with the session arguments
84
* at creation time of each new session. It can therefore implement
85
* a session-creation policy taking session arguments into account.
86
* If the policy denies the creation of a new session, it throws
87
* one of the exceptions defined in the `Root` interface.
88
*
89
* `release` is called at the destruction time of a session. It enables
90
* the policy to keep track of and impose restrictions on the number
91
* of existing sessions.
92
*
93
* The default policy `Multiple_clients` imposes no restrictions on the
94
* creation of new sessions.
95
*/
96
template
<
typename
SESSION_TYPE
,
typename
POLICY
>
97
class
Genode::
Root_component :
public
Rpc_object<
Typed_root<
SESSION_TYPE
>
>
,
98
private
POLICY
99
{
100
private
:
101
102
/*
103
* Entry point that manages the session objects
104
* created by this root interface
105
*/
106
Rpc_entrypoint *
_ep;
107
108
/*
109
* Allocator for allocating session objects.
110
* This allocator must be used by the derived
111
* class when calling the `new` operator for
112
* creating a new session.
113
*/
114
Allocator *
_md_alloc;
115
116
protected
:
117
118
/**
119
* Create new session (to be implemented by a derived class)
120
*
121
* Only a derived class knows the constructor arguments of
122
* a specific session. Therefore, we cannot unify the call
123
* of its `new` operator and must implement the session
124
* creation at a place, where the required knowledge exist.
125
*
126
* In the implementation of this method, the heap, provided
127
* by `Root_component` must be used for allocating the session
128
* object.
129
*
130
* If the server implementation does not evaluate the session
131
* affinity, it suffices to override the overload without the
132
* affinity argument.
133
*
134
* \throw Allocator::Out_of_memory typically caused by the
135
* meta-data allocator
136
* \throw Root::Invalid_args typically caused by the
137
* session-component constructor
138
*/
139
virtual
SESSION_TYPE *
_create_session(
const
char *
args
,
140
Affinity const
&
)
141
{
142
return
_create_session(
args)
;
143
}
144
145
virtual
SESSION_TYPE *
_create_session(
const
char *
args
)
146
{
147
throw
Root::
Invalid_args(
)
;
148
}
149
150
/**
151
* Inform session about a quota upgrade
152
*
153
* Once a session is created, its client can successively extend
154
* its quota donation via the `Parent::transfer_quota` operation.
155
* This will result in the invokation of `Root::upgrade` at the
156
* root interface the session was created with. The root interface,
157
* in turn, informs the session about the new resources via the
158
* `_upgrade_session` method. The default implementation is
159
* suited for sessions that use a static amount of resources
160
* accounted for at session-creation time. For such sessions, an
161
* upgrade is not useful. However, sessions that dynamically
162
* allocate resources on behalf of its client, should respond to
163
* quota upgrades by implementing this method.
164
*
165
* \param session session to upgrade
166
* \param args description of additional resources in the
167
* same format as used at session creation
168
*/
169
virtual
void
_upgrade_session(
SESSION_TYPE *
,
const
char *
)
{
}
170
171
virtual
void
_destroy_session(
SESSION_TYPE *
session
)
{
172
destroy(
_md_alloc,
session)
;
}
173
174
/**
175
* Return allocator to allocate server object in `_create_session()`
176
*/
177
Allocator *
md_alloc(
)
{
return
_md_alloc
;
}
178
179
/**
180
* Return entrypoint that serves the root component
181
*/
182
Rpc_entrypoint *
ep(
)
{
return
_ep
;
}
183
184
public
:
185
186
/**
187
* Constructor
188
*
189
* \param ep entry point that manages the sessions of this
190
* root interface.
191
* \param ram_session provider of dataspaces for the backing store
192
* of session objects and session data
193
*/
194
Root_component(
Rpc_entrypoint *
ep
,
Allocator *
metadata_alloc
)
195
:
_ep(
ep)
,
_md_alloc(
metadata_alloc)
{
}
196
197
198
/********************
199
** Root interface **
200
********************/
201
202
Session_capability
session(
Root::
Session_args const
&
args
,
203
Affinity const
&
affinity
)
override
204
{
205
if
(
!
args.
is_valid_string(
)
)
throw
Root::
Invalid_args(
)
;
206
207
POLICY::
aquire(
args.
string(
)
)
;
208
209
/*
210
* We need to decrease `ram_quota` by
211
* the size of the session object.
212
*/
213
size_t ram_quota =
Arg_string::
find_arg(
args.
string(
)
,
"ram_quota"
)
.
ulong_value(
0)
;
214
size_t needed =
sizeof
(
SESSION_TYPE)
+
md_alloc(
)
->
overhead(
sizeof
(
SESSION_TYPE)
)
;
215
216
if
(
needed >
ram_quota)
{
217
PERR(
"Insufficient ram quota, provided=%zu, required=%zu"
,
218
ram_quota,
needed)
;
219
throw
Root::
Quota_exceeded(
)
;
220
}
221
222
size_t const
remaining_ram_quota =
ram_quota -
needed;
223
224
/*
225
* Deduce ram quota needed for allocating the session object from the
226
* donated ram quota.
227
*
228
* XXX the size of the `adjusted_args` buffer should dependent
229
* on the message-buffer size and stack size.
230
*/
231
enum
{
MAX_ARGS_LEN =
256
}
;
232
char adjusted_args[MAX_ARGS_LEN]
;
233
strncpy(
adjusted_args,
args.
string(
)
,
sizeof
(
adjusted_args)
)
;
234
char ram_quota_buf[64]
;
235
snprintf(
ram_quota_buf,
sizeof
(
ram_quota_buf)
,
"%zu"
,
236
remaining_ram_quota)
;
237
Arg_string::
set_arg(
adjusted_args,
sizeof
(
adjusted_args)
,
238
"ram_quota"
,
ram_quota_buf)
;
239
240
SESSION_TYPE *
s =
0;
241
try
{
s =
_create_session(
adjusted_args,
affinity)
;
}
242
catch
(
Allocator::
Out_of_memory)
{
throw
Root::
Quota_exceeded(
)
;
}
243
244
return
_ep->
manage(
s)
;
245
}
246
247
void
upgrade(
Session_capability
session
,
Root::
Upgrade_args const
&
args
)
override
248
{
249
if
(
!
args.
is_valid_string(
)
)
throw
Root::
Invalid_args(
)
;
250
251
_ep->
apply(
session,
[&
] (
SESSION_TYPE *
s)
{
252
if
(
!
s)
return
;
253
254
_upgrade_session(
s,
args.
string(
)
)
;
255
}
)
;
256
}
257
258
void
close(
Session_capability
session_cap
)
override
259
{
260
SESSION_TYPE *
session;
261
262
_ep->
apply(
session_cap,
[&
] (
SESSION_TYPE *
s)
{
263
session =
s;
264
265
/* let the entry point forget the session object */
266
if
(
session)
_ep->
dissolve(
session)
;
267
}
)
;
268
269
if
(
!
session)
return
;
270
271
_destroy_session(
session)
;
272
273
POLICY::
release(
)
;
274
}
275
}
;
276
277
#
endif /* _INCLUDE__ROOT__COMPONENT_H_ */