1 /*
2 * \brief Capability
3 * \author Norman Feske
4 * \date 2011-05-22
5 *
6 * A typed capability is a capability tied to one specifiec RPC interface
7 */
8
9 /*
10 * Copyright (C) 2011-2013 Genode Labs GmbH
11 *
12 * This file is part of the Genode OS framework, which is distributed
13 * under the terms of the GNU General Public License version 2.
14 */
15
16 #ifndef _INCLUDE__BASE__CAPABILITY_H_
17 #define _INCLUDE__BASE__CAPABILITY_H_
18
19 #include <util/string.h>
20 #include <base/rpc.h>
21 #include <base/native_types.h>
22
23 namespace Genode {
24
25 /**
26 * Forward declaration needed for internal interfaces of `Capability`
27 */
28 class Ipc_client;
29
30
31 /**
32 * Capability that is not associated with a specific RPC interface
33 */
34 typedef Native_capability Untyped_capability;
35
36 template <typename> class Capability;
37
38 template <typename RPC_INTERFACE>
39 Capability<RPC_INTERFACE> reinterpret_cap_cast(Untyped_capability const &);
40
41 template <typename TO_RPC_INTERFACE, typename FROM_RPC_INTERFACE>
42 Capability<TO_RPC_INTERFACE> static_cap_cast(Capability<FROM_RPC_INTERFACE>);
43 }
44
45
46 /**
47 * Capability referring to a specific RPC interface
48 *
49 * \param RPC_INTERFACE class containing the RPC interface declaration
50 */
51 template <typename RPC_INTERFACE>
52 class Genode::Capability : public Untyped_capability
53 {
54 private:
55
56 /**
57 * Insert RPC arguments into the message buffer
58 */
59 template <typename ATL>
60 void _marshal_args(Ipc_client &ipc_client, ATL &args) const;
61
62 void _marshal_args(Ipc_client &, Meta::Empty &) const { }
63
64 /**
65 * Unmarshal single RPC argument from the message buffer
66 */
67 template <typename T>
68 void _unmarshal_result(Ipc_client &ipc_client, T &arg,
69 Meta::Overload_selector<Rpc_arg_out>) const;
70
71 template <typename T>
72 void _unmarshal_result(Ipc_client &ipc_client, T &arg,
73 Meta::Overload_selector<Rpc_arg_inout>) const;
74
75 template <typename T>
76 void _unmarshal_result(Ipc_client &, T &,
77 Meta::Overload_selector<Rpc_arg_in>) const { }
78
79 /**
80 * Read RPC results from the message buffer
81 */
82 template <typename ATL>
83 void _unmarshal_results(Ipc_client &ipc_client, ATL &args) const;
84
85 void _unmarshal_results(Ipc_client &, Meta::Empty &) const { }
86
87 /**
88 * Check RPC return code for the occurrence of exceptions
89 *
90 * A server-side exception is indicated by a non-zero exception
91 * code. Each exception code corresponds to an entry in the
92 * exception type list specified in the RPC function declaration.
93 * The `_check_for_exception` method template throws the
94 * exception type belonging to the received exception code.
95 */
96 template <typename EXC_TL>
97 void _check_for_exceptions(Rpc_exception_code const exc_code,
98 Meta::Overload_selector<EXC_TL>) const
99 {
100 enum { EXCEPTION_CODE = RPC_EXCEPTION_BASE - Meta::Length<EXC_TL>::Value };
101
102 if (exc_code == EXCEPTION_CODE)
103 throw typename EXC_TL::Head();
104
105 _check_for_exceptions(exc_code, Meta::Overload_selector<typename EXC_TL::Tail>());
106 }
107
108 void _check_for_exceptions(Rpc_exception_code const,
109 Meta::Overload_selector<Meta::Empty>) const
110 { }
111
112 /**
113 * Perform RPC call, arguments passed a as nested `Ref_tuple` object
114 */
115 template <typename IF>
116 void _call(typename IF::Client_args &args,
117 typename IF::Ret_type &ret) const;
118
119 /**
120 * Shortcut for querying argument types used in `call` methods
121 */
122 template <typename IF, unsigned I>
123 struct Arg
124 {
125 typedef typename Meta::Type_at<typename IF::Client_args, I>::Type Type;
126 };
127
128 template <typename FROM_RPC_INTERFACE>
129 Untyped_capability
130 _check_compatibility(Capability<FROM_RPC_INTERFACE> const &cap) const
131 {
132 FROM_RPC_INTERFACE *from = 0;
133 RPC_INTERFACE *to = from;
134 (void)to;
135 return cap;
136 }
137
138 /**
139 * Wrapper for the return type instantiated by `call` overloads
140 *
141 * Each `call` overload creates an instance of the return value
142 * type as local variable. A reference to this variable is passed
143 * to the `_call` method, which will assign its value. Even
144 * though the variable does not need to be initialized prior the
145 * call of `_call`, the GCC will still complain "warning: ‘ret’ may
146 * be used uninitialized in this function". Wrapping the return
147 * value in a struct silences the compiler.
148 */
149 template <typename IF>
150 struct Return
151 {
152 typedef typename Trait::Call_return<typename IF::Ret_type>::Type
153 Return_type;
154
155 volatile Return_type _value;
156 Return_type &value() { return *(Return_type *)(&_value); }
157 };
158
159 public:
160
161 typedef RPC_INTERFACE Rpc_interface;
162
163 /**
164 * Constructor
165 *
166 * This implicit constructor checks at compile time for the
167 * compatibility of the source and target capability types. The
168 * construction is performed only if the target capability type is
169 * identical to or a base type of the source capability type.
170 */
171 template <typename FROM_RPC_INTERFACE>
172 Capability(Capability<FROM_RPC_INTERFACE> const &cap)
173 : Untyped_capability(_check_compatibility(cap))
174 { }
175
176 /**
177 * Default constructor creates invalid capability
178 */
179 Capability() { }
180
181 template <typename IF>
182 typename Trait::Call_return<typename IF::Ret_type>::Type
183 call() const
184 {
185 Meta::Empty e;
186 Return<IF> ret;
187 _call<IF>(e, ret.value());
188 return ret.value();
189 }
190
191 template <typename IF>
192 typename Trait::Call_return<typename IF::Ret_type>::Type
193 call(typename Arg<IF, 0>::Type v1) const
194 {
195 Meta::Empty e;
196 typename IF::Client_args args(v1, e);
197 Return<IF> ret;
198 _call<IF>(args, ret.value());
199 return ret.value();
200 }
201
202 template <typename IF>
203 typename Trait::Call_return<typename IF::Ret_type>::Type
204 call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2) const
205 {
206 Meta::Empty e;
207 typename IF::Client_args args(v1, v2, e);
208 Return<IF> ret;
209 _call<IF>(args, ret.value());
210 return ret.value();
211 }
212
213 template <typename IF>
214 typename Trait::Call_return<typename IF::Ret_type>::Type
215 call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
216 typename Arg<IF, 2>::Type v3) const
217 {
218 Meta::Empty e;
219 typename IF::Client_args args(v1, v2, v3, e);
220 Return<IF> ret;
221 _call<IF>(args, ret.value());
222 return ret.value();
223 }
224
225 template <typename IF>
226 typename Trait::Call_return<typename IF::Ret_type>::Type
227 call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
228 typename Arg<IF, 2>::Type v3, typename Arg<IF, 3>::Type v4) const
229 {
230 Meta::Empty e;
231 typename IF::Client_args args(v1, v2, v3, v4, e);
232 Return<IF> ret;
233 _call<IF>(args, ret.value());
234 return ret.value();
235 }
236
237 template <typename IF>
238 typename Trait::Call_return<typename IF::Ret_type>::Type
239 call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
240 typename Arg<IF, 2>::Type v3, typename Arg<IF, 3>::Type v4,
241 typename Arg<IF, 4>::Type v5) const
242 {
243 Meta::Empty e;
244 typename IF::Client_args args(v1, v2, v3, v4, v5, e);
245 Return<IF> ret;
246 _call<IF>(args, ret.value());
247 return ret.value();
248 }
249
250 template <typename IF>
251 typename Trait::Call_return<typename IF::Ret_type>::Type
252 call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
253 typename Arg<IF, 2>::Type v3, typename Arg<IF, 3>::Type v4,
254 typename Arg<IF, 4>::Type v5, typename Arg<IF, 5>::Type v6) const
255 {
256 Meta::Empty e;
257 typename IF::Client_args args(v1, v2, v3, v4, v5, v6, e);
258 Return<IF> ret;
259 _call<IF>(args, ret.value());
260 return ret.value();
261 }
262
263 template <typename IF>
264 typename Trait::Call_return<typename IF::Ret_type>::Type
265 call(typename Arg<IF, 0>::Type v1, typename Arg<IF, 1>::Type v2,
266 typename Arg<IF, 2>::Type v3, typename Arg<IF, 3>::Type v4,
267 typename Arg<IF, 4>::Type v5, typename Arg<IF, 5>::Type v6,
268 typename Arg<IF, 6>::Type v7) const
269 {
270 Meta::Empty e;
271 typename IF::Client_args args(v1, v2, v3, v4, v5, v6, v7, e);
272 Return<IF> ret;
273 _call<IF>(args, ret.value());
274 return ret.value();
275 }
276 };
277
278
279 /**
280 * Convert an untyped capability to a typed capability
281 */
282 template <typename RPC_INTERFACE>
283 Genode::Capability<RPC_INTERFACE>
284 Genode::reinterpret_cap_cast(Untyped_capability const &untyped_cap)
285 {
286 /*
287 * The object layout of untyped and typed capabilities is identical.
288 * Hence we can just use it`s copy-constructors.
289 */
290 Untyped_capability *ptr = const_cast<Untyped_capability*>(&untyped_cap);
291 return *static_cast<Capability<RPC_INTERFACE>*>(ptr);
292 }
293
294
295 /**
296 * Convert capability type from an interface base type to an inherited
297 * interface type
298 */
299 template <typename TO_RPC_INTERFACE, typename FROM_RPC_INTERFACE>
300 Genode::Capability<TO_RPC_INTERFACE>
301 Genode::static_cap_cast(Capability<FROM_RPC_INTERFACE> cap)
302 {
303 /* check interface compatibility */
304 (void)static_cast<TO_RPC_INTERFACE *>((FROM_RPC_INTERFACE *)0);
305
306 return reinterpret_cap_cast<TO_RPC_INTERFACE>(cap);
307 }
308
309 #endif /* _INCLUDE__BASE__CAPABILITY_H_ */