1 /*
2 * \brief Parent interface
3 * \author Norman Feske
4 * \date 2006-05-10
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__PARENT__PARENT_H_
15 #define _INCLUDE__PARENT__PARENT_H_
16
17 #include <base/exception.h>
18 #include <base/rpc.h>
19 #include <base/rpc_args.h>
20 #include <base/thread.h>
21 #include <session/capability.h>
22 #include <root/capability.h>
23
24 namespace Genode { class Parent; }
25
26
27 class Genode::Parent
28 {
29 private:
30
31 /**
32 * Recursively announce inherited service interfaces
33 *
34 * At compile time, the `ROOT` type is inspected for the presence
35 * of the `Rpc_inherited_interface` type in the corresponding
36 * session interface. If present, the session type gets announced.
37 * This works recursively.
38 */
39 template <typename ROOT>
40 void _announce_base(Capability<ROOT> const &, Meta::Bool_to_type<false> *) { }
41
42 /*
43 * This overload gets selected if the ROOT interface corresponds to
44 * an inherited session type.
45 */
46 template <typename ROOT>
47 inline void _announce_base(Capability<ROOT> const &, Meta::Bool_to_type<true> *);
48
49 public:
50
51 /*********************
52 ** Exception types **
53 *********************/
54
55 class Exception : public ::Genode::Exception { };
56 class Service_denied : public Exception { };
57 class Quota_exceeded : public Exception { };
58 class Unavailable : public Exception { };
59
60 typedef Rpc_in_buffer<64> Service_name;
61 typedef Rpc_in_buffer<160> Session_args;
62 typedef Rpc_in_buffer<160> Upgrade_args;
63
64 /**
65 * Use `String` instead of `Rpc_in_buffer` because `Resource_args`
66 * is used as both in and out parameter.
67 */
68 typedef String<160> Resource_args;
69
70
71 virtual ~Parent() { }
72
73 /**
74 * Tell parent to exit the program
75 */
76 virtual void exit(int exit_value) = 0;
77
78 /**
79 * Announce service to the parent
80 */
81 virtual void announce(Service_name const &service_name,
82 Root_capability service_root) = 0;
83
84
85 /**
86 * Announce service to the parent
87 *
88 * \param service_root root capability
89 *
90 * The type of the specified `service_root` capability match with
91 * an interface that provides a `Session_type` type (i.e., a
92 * `Typed_root` interface). This `Session_type` is expected to
93 * host a class function called `service_name` returning the
94 * name of the provided interface as null-terminated string.
95 */
96 template <typename ROOT_INTERFACE>
97 void announce(Capability<ROOT_INTERFACE> const &service_root)
98 {
99 typedef typename ROOT_INTERFACE::Session_type Session;
100 announce(Session::service_name(), service_root);
101
102 /*
103 * Announce inherited session types
104 *
105 * Select the overload based on the presence of the type
106 * `Rpc_inherited_interface` within the session type.
107 */
108 _announce_base(service_root,
109 (Meta::Bool_to_type<Rpc_interface_is_inherited<Session>::VALUE> *)0);
110 }
111
112 /**
113 * Create session to a service
114 *
115 * \param service_name name of the requested interface
116 * \param args session constructor arguments
117 * \param affinity preferred CPU affinity for the session
118 *
119 * \throw Service_denied parent denies session request
120 * \throw Quota_exceeded our own quota does not suffice for
121 * the creation of the new session
122 * \throw Unavailable
123 *
124 * \return untyped capability to new session
125 *
126 * The use of this method is discouraged. Please use the type safe
127 * `session()` template instead.
128 */
129 virtual Session_capability session(Service_name const &service_name,
130 Session_args const &args,
131 Affinity const &affinity = Affinity()) = 0;
132
133 /**
134 * Create session to a service
135 *
136 * \param SESSION_TYPE session interface type
137 * \param args session constructor arguments
138 * \param affinity preferred CPU affinity for the session
139 *
140 * \throw Service_denied parent denies session request
141 * \throw Quota_exceeded our own quota does not suffice for
142 * the creation of the new session
143 * \throw Unavailable
144 *
145 * \return capability to new session
146 */
147 template <typename SESSION_TYPE>
148 Capability<SESSION_TYPE> session(Session_args const &args,
149 Affinity const &affinity = Affinity())
150 {
151 Session_capability cap = session(SESSION_TYPE::service_name(),
152 args, affinity);
153 return reinterpret_cap_cast<SESSION_TYPE>(cap);
154 }
155
156 /**
157 * Transfer our quota to the server that provides the specified session
158 *
159 * \param to_session recipient session
160 * \param args description of the amount of quota to transfer
161 *
162 * \throw Quota_exceeded quota could not be transferred
163 *
164 * The `args` argument has the same principle format as the `args`
165 * argument of the `session` operation.
166 * The error case indicates that there is not enough unused quota on
167 * the source side.
168 */
169 virtual void upgrade(Session_capability to_session,
170 Upgrade_args const &args) = 0;
171
172 /**
173 * Close session
174 */
175 virtual void close(Session_capability session) = 0;
176
177 /**
178 * Provide thread_cap of main thread
179 */
180 virtual Thread_capability main_thread_cap() const = 0;
181
182 /**
183 * Register signal handler for resource notifications
184 */
185 virtual void resource_avail_sigh(Signal_context_capability sigh) = 0;
186
187 /**
188 * Request additional resources
189 *
190 * By invoking this method, a process is able to inform its
191 * parent about the need for additional resources. The argument
192 * string contains a resource description in the same format as
193 * used for session-construction arguments. In particular, for
194 * requesting additional RAM quota, the argument looks like
195 * "ram_quota=<amount>" where `amount` is the amount of additional
196 * resources expected from the parent. If the parent complies with
197 * the request, it submits a resource-available signal to the
198 * handler registered via `resource_avail_sigh()`. On the reception
199 * of such a signal, the process can re-evaluate its resource quota
200 * and resume execution.
201 */
202 virtual void resource_request(Resource_args const &args) = 0;
203
204 /**
205 * Register signal handler for resource yield notifications
206 *
207 * Using the yield signal, the parent is able to inform the process
208 * about its wish to regain resources.
209 */
210 virtual void yield_sigh(Signal_context_capability sigh) = 0;
211
212 /**
213 * Obtain information about the amount of resources to free
214 *
215 * The amount of resources returned by this method is the
216 * goal set by the parent. It is not commanded but merely meant
217 * as a friendly beg to cooperate. The process is not obligated
218 * to comply. If the process decides to take action to free
219 * resources, it can inform its parent about the availability
220 * of freed up resources by calling `yield_response()`.
221 */
222 virtual Resource_args yield_request() = 0;
223
224 /**
225 * Notify the parent about a response to a yield request
226 */
227 virtual void yield_response() = 0;
228
229
230 /*********************
231 ** RPC declaration **
232 *********************/
233
234 GENODE_RPC(Rpc_exit, void, exit, int);
235 GENODE_RPC(Rpc_announce, void, announce,
236 Service_name const &, Root_capability);
237 GENODE_RPC_THROW(Rpc_session, Session_capability, session,
238 GENODE_TYPE_LIST(Service_denied, Quota_exceeded, Unavailable),
239 Service_name const &, Session_args const &, Affinity const &);
240 GENODE_RPC_THROW(Rpc_upgrade, void, upgrade,
241 GENODE_TYPE_LIST(Quota_exceeded),
242 Session_capability, Upgrade_args const &);
243 GENODE_RPC(Rpc_close, void, close, Session_capability);
244 GENODE_RPC(Rpc_main_thread, Thread_capability, main_thread_cap);
245 GENODE_RPC(Rpc_resource_avail_sigh, void, resource_avail_sigh,
246 Signal_context_capability);
247 GENODE_RPC(Rpc_resource_request, void, resource_request,
248 Resource_args const &);
249 GENODE_RPC(Rpc_yield_sigh, void, yield_sigh, Signal_context_capability);
250 GENODE_RPC(Rpc_yield_request, Resource_args, yield_request);
251 GENODE_RPC(Rpc_yield_response, void, yield_response);
252
253 typedef Meta::Type_tuple<Rpc_exit,
254 Meta::Type_tuple<Rpc_announce,
255 Meta::Type_tuple<Rpc_session,
256 Meta::Type_tuple<Rpc_upgrade,
257 Meta::Type_tuple<Rpc_close,
258 Meta::Type_tuple<Rpc_main_thread,
259 Meta::Type_tuple<Rpc_resource_avail_sigh,
260 Meta::Type_tuple<Rpc_resource_request,
261 Meta::Type_tuple<Rpc_yield_sigh,
262 Meta::Type_tuple<Rpc_yield_request,
263 Meta::Type_tuple<Rpc_yield_response,
264 Meta::Empty>
265 > > > > > > > > > > Rpc_functions;
266 };
267
268
269 template <typename ROOT_INTERFACE>
270 void
271 Genode::Parent::_announce_base(Genode::Capability<ROOT_INTERFACE> const &service_root,
272 Genode::Meta::Bool_to_type<true> *)
273 {
274 /* shortcut for inherited session type */
275 typedef typename ROOT_INTERFACE::Session_type::Rpc_inherited_interface
276 Session_type_inherited;
277
278 /* shortcut for root interface type matching the inherited session type */
279 typedef Typed_root<Session_type_inherited> Root_inherited;
280
281 /* convert root capability to match the inherited session type */
282 Capability<Root> root = service_root;
283 Capability<Root_inherited> root_inherited = static_cap_cast<Root_inherited>(root);
284
285 /* announce inherited service type */
286 announce(Session_type_inherited::service_name(), root_inherited);
287
288 /* recursively announce further inherited session types */
289 _announce_base(root_inherited,
290 (Meta::Bool_to_type<Rpc_interface_is_inherited<Session_type_inherited>::VALUE> *)0);
291 }
292
293
294 #endif /* _INCLUDE__PARENT__PARENT_H_ */