Branch data Line data Source code
1 : : // Copyright (c) The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef MP_PROXY_TYPES_H
6 : : #define MP_PROXY_TYPES_H
7 : :
8 : : #include <mp/proxy-io.h>
9 : :
10 : : #include <exception>
11 : : #include <optional>
12 : : #include <set>
13 : : #include <typeindex>
14 : : #include <vector>
15 : :
16 : : namespace mp {
17 : :
18 : : template <typename Value>
19 : : class ValueField
20 : : {
21 : : public:
22 : 0 : ValueField(Value& value) : m_value(value) {}
23 : 0 : ValueField(Value&& value) : m_value(value) {}
24 : : Value& m_value;
25 : :
26 : 0 : Value& get() { return m_value; }
27 : : Value& init() { return m_value; }
28 : : bool has() { return true; }
29 : : };
30 : :
31 : : template <typename Accessor, typename Struct>
32 : : struct StructField
33 : : {
34 : : template <typename S>
35 : 185 : StructField(S& struct_) : m_struct(struct_)
36 : : {
37 : : }
38 : : Struct& m_struct;
39 : :
40 [ + - - + : 45 : decltype(auto) get() const { return Accessor::get(this->m_struct); }
+ - - + ]
[ + - # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ][ - -
+ - + - ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
41 : :
42 : 12 : bool has() const {
43 : : if constexpr (Accessor::optional) {
44 [ # # # # : 0 : return Accessor::getHas(m_struct);
# # ]
45 : : } else if constexpr (Accessor::boxed) {
46 [ - + - + : 12 : return Accessor::has(m_struct);
+ - ][ # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # ]
[ - - + -
# # # # #
# # # # #
# # ][ # #
# # # # #
# ]
47 : : } else {
48 : : return true;
49 : : }
50 : : }
51 : :
52 : : bool want() const {
53 : : if constexpr (Accessor::requested) {
54 : : return Accessor::getWant(m_struct);
55 : : } else {
56 : : return true;
57 : : }
58 : : }
59 : :
60 : 21 : template <typename... Args> decltype(auto) set(Args &&...args) const {
61 [ # # # # ]: 21 : return Accessor::set(this->m_struct, std::forward<Args>(args)...);
[ + - # #
# # # # #
# # # #
# ][ - - +
- + - ][ #
# # # #
# ]
62 : : }
63 : :
64 : 40 : template <typename... Args> decltype(auto) init(Args &&...args) const {
65 [ + - - + : 40 : return Accessor::init(this->m_struct, std::forward<Args>(args)...);
+ - - + +
- - + ][ -
+ # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # ][ # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# ]
66 : : }
67 : :
68 : 0 : void setHas() const {
69 : : if constexpr (Accessor::optional) {
70 : 0 : Accessor::setHas(m_struct);
71 : : }
72 : : }
73 : :
74 : : void setWant() const {
75 : : if constexpr (Accessor::requested) {
76 : : Accessor::setWant(m_struct);
77 : : }
78 : : }
79 : : };
80 : :
81 : :
82 : :
83 : : // Destination parameter type that can be passed to ReadField function as an
84 : : // alternative to ReadDestUpdate. It allows the ReadField implementation to call
85 : : // the provided emplace_fn function with constructor arguments, so it only needs
86 : : // to determine the arguments, and can let the emplace function decide how to
87 : : // actually construct the read destination object. For example, if a std::string
88 : : // is being read, the ReadField call will call the custom emplace_fn with char*
89 : : // and size_t arguments, and the emplace function can decide whether to call the
90 : : // constructor via the operator or make_shared or emplace or just return a
91 : : // temporary string that is moved from.
92 : : template <typename LocalType, typename EmplaceFn>
93 : : struct ReadDestEmplace
94 : : {
95 : 8 : ReadDestEmplace(TypeList<LocalType>, EmplaceFn emplace_fn) : m_emplace_fn(std::move(emplace_fn)) {}
96 : :
97 : : //! Simple case. If ReadField implementation calls this construct() method
98 : : //! with constructor arguments, just pass them on to the emplace function.
99 : : template <typename... Args>
100 : 15 : decltype(auto) construct(Args&&... args)
101 : : {
102 [ # # ]: 14 : return m_emplace_fn(std::forward<Args>(args)...);
103 : : }
104 : :
105 : : //! More complicated case. If ReadField implementation works by calling this
106 : : //! update() method, adapt it call construct() instead. This requires
107 : : //! LocalType to have a default constructor to create new object that can be
108 : : //! passed to update()
109 : : template <typename UpdateFn>
110 [ # # ]: 3 : decltype(auto) update(UpdateFn&& update_fn)
111 : : {
112 : : if constexpr (std::is_const_v<std::remove_reference_t<std::invoke_result_t<EmplaceFn>>>) {
113 : : // If destination type is const, default construct temporary
114 : : // to pass to update, then call move constructor via construct() to
115 : : // move from that temporary.
116 : 0 : std::remove_cv_t<LocalType> temp;
117 [ # # ]: 0 : update_fn(temp);
118 : : return construct(std::move(temp));
119 : 0 : } else {
120 : : // Default construct object and pass it to update_fn.
121 : 3 : decltype(auto) temp = construct();
122 : 3 : update_fn(temp);
123 : 1 : return temp;
124 : : }
125 : : }
126 : : EmplaceFn m_emplace_fn;
127 : : };
128 : :
129 : : //! Helper function to create a ReadDestEmplace object that constructs a
130 : : //! temporary, ReadField can return.
131 : : template <typename LocalType>
132 : : auto ReadDestTemp()
133 : : {
134 : 0 : return ReadDestEmplace{TypeList<LocalType>(), [](auto&&... args) -> decltype(auto) {
135 : 0 : return LocalType{std::forward<decltype(args)>(args)...};
136 : : }};
137 : : }
138 : :
139 : : //! Destination parameter type that can be passed to ReadField function as an
140 : : //! alternative to ReadDestEmplace. Instead of requiring an emplace callback to
141 : : //! construct a new value, it just takes a reference to an existing value and
142 : : //! assigns a new value to it.
143 : : template <typename Value>
144 : : struct ReadDestUpdate
145 : : {
146 : 31 : ReadDestUpdate(Value& value) : m_value(value) {}
147 : :
148 : : //! Simple case. If ReadField works by calling update() just forward arguments to update_fn.
149 : : template <typename UpdateFn>
150 : 3 : Value& update(UpdateFn&& update_fn)
151 : : {
152 : 3 : update_fn(m_value);
153 : 3 : return m_value;
154 : : }
155 : :
156 : : //! More complicated case. If ReadField works by calling construct(), need
157 : : //! to reconstruct m_value in place.
158 : : template <typename... Args>
159 : 15 : Value& construct(Args&&... args)
160 : : {
161 : 15 : m_value.~Value();
162 : 15 : new (&m_value) Value(std::forward<Args>(args)...);
163 : 15 : return m_value;
164 : : }
165 : :
166 : : Value& m_value;
167 : : };
168 : :
169 : : template <typename... LocalTypes, typename... Args>
170 : 45 : decltype(auto) ReadField(TypeList<LocalTypes...>, Args&&... args)
171 : : {
172 : 45 : return CustomReadField(TypeList<RemoveCvRef<LocalTypes>...>(), Priority<2>(), std::forward<Args>(args)...);
173 : : }
174 : :
175 : : template <typename LocalType, typename Input>
176 : 0 : void ThrowField(TypeList<LocalType>, InvokeContext& invoke_context, Input&& input)
177 : : {
178 : 0 : ReadField(
179 : 0 : TypeList<LocalType>(), invoke_context, input, ReadDestEmplace(TypeList<LocalType>(),
180 : 0 : [](auto&& ...args) -> const LocalType& { throw LocalType{std::forward<decltype(args)>(args)...}; }));
181 : : }
182 : :
183 : : //! Special case for generic std::exception. It's an abstract type so it can't
184 : : //! be created directly. Rethrow as std::runtime_error so callers expecting it
185 : : //! will still catch it.
186 : : template <typename Input>
187 : : void ThrowField(TypeList<std::exception>, InvokeContext& invoke_context, Input&& input)
188 : : {
189 : : auto data = input.get();
190 : : throw std::runtime_error(std::string(CharCast(data.begin()), data.size()));
191 : : }
192 : :
193 : : template <typename... Values>
194 : 93 : bool CustomHasValue(InvokeContext& invoke_context, const Values&... value)
195 : : {
196 : 93 : return true;
197 : : }
198 : :
199 : : template <typename... LocalTypes, typename Context, typename... Values, typename Output>
200 : 93 : void BuildField(TypeList<LocalTypes...>, Context& context, Output&& output, Values&&... values)
201 : : {
202 [ + - ]: 93 : if (CustomHasValue(context, values...)) {
203 : 93 : CustomBuildField(TypeList<LocalTypes...>(), Priority<3>(), context, std::forward<Values>(values)...,
204 : : std::forward<Output>(output));
205 : : }
206 : 93 : }
207 : :
208 : : // Adapter to let BuildField overloads methods work set & init list elements as
209 : : // if they were fields of a struct. If BuildField is changed to use some kind of
210 : : // accessor class instead of calling method pointers, then then maybe this could
211 : : // go away or be simplified, because would no longer be a need to return
212 : : // ListOutput method pointers emulating capnp struct method pointers..
213 : : template <typename ListType>
214 : : struct ListOutput;
215 : :
216 : : template <typename T, ::capnp::Kind kind>
217 : : struct ListOutput<::capnp::List<T, kind>>
218 : : {
219 : : using Builder = typename ::capnp::List<T, kind>::Builder;
220 : :
221 : 0 : ListOutput(Builder& builder, size_t index) : m_builder(builder), m_index(index) {}
222 : : Builder& m_builder;
223 : : size_t m_index;
224 : :
225 : : // clang-format off
226 : : decltype(auto) get() const { return this->m_builder[this->m_index]; }
227 : 0 : decltype(auto) init() const { return this->m_builder[this->m_index]; }
228 : 0 : template<typename B = Builder, typename Arg> decltype(auto) set(Arg&& arg) const { return static_cast<B&>(this->m_builder).set(m_index, std::forward<Arg>(arg)); }
229 [ # # ]: 0 : template<typename B = Builder, typename Arg> decltype(auto) init(Arg&& arg) const { return static_cast<B&>(this->m_builder).init(m_index, std::forward<Arg>(arg)); }
230 : : // clang-format on
231 : : };
232 : :
233 : : template <typename LocalType, typename Value, typename Output>
234 : 3 : void CustomBuildField(TypeList<LocalType>, Priority<0>, InvokeContext& invoke_context, Value&& value, Output&& output)
235 : : {
236 : 3 : output.set(BuildPrimitive(invoke_context, std::forward<Value>(value), TypeList<decltype(output.get())>()));
237 : 3 : }
238 : :
239 : : //! PassField override for callable interface reference arguments.
240 : : template <typename Accessor, typename LocalType, typename ServerContext, typename Fn, typename... Args>
241 : 0 : auto PassField(Priority<1>, TypeList<LocalType&>, ServerContext& server_context, Fn&& fn, Args&&... args)
242 : : -> Require<typename decltype(Accessor::get(server_context.call_context.getParams()))::Calls>
243 : : {
244 : : // Just create a temporary ProxyClient if argument is a reference to an
245 : : // interface client. If argument needs to have a longer lifetime and not be
246 : : // destroyed after this call, a CustomPassField overload can be implemented
247 : : // to bypass this code, and a custom ProxyServerMethodTraits overload can be
248 : : // implemented in order to read the capability pointer out of params and
249 : : // construct a ProxyClient with a longer lifetime.
250 : 0 : const auto& params = server_context.call_context.getParams();
251 : 0 : const auto& input = Make<StructField, Accessor>(params);
252 : : using Interface = typename Decay<decltype(input.get())>::Calls;
253 [ # # ]: 0 : auto param = std::make_unique<ProxyClient<Interface>>(input.get(), server_context.proxy_server.m_context.connection, false);
254 [ # # ]: 0 : fn.invoke(server_context, std::forward<Args>(args)..., *param);
255 : 0 : }
256 : :
257 : : template <typename... Args>
258 : 37 : void MaybeBuildField(std::true_type, Args&&... args)
259 : : {
260 : 37 : BuildField(std::forward<Args>(args)...);
261 : 37 : }
262 : : template <typename... Args>
263 : : void MaybeBuildField(std::false_type, Args&&...)
264 : : {
265 : : }
266 : : template <typename... Args>
267 : 37 : void MaybeReadField(std::true_type, Args&&... args)
268 : : {
269 : 37 : ReadField(std::forward<Args>(args)...);
270 : 37 : }
271 : : template <typename... Args>
272 : : void MaybeReadField(std::false_type, Args&&...)
273 : : {
274 : : }
275 : :
276 : : template <typename LocalType, typename Value, typename Output>
277 : : void MaybeSetWant(TypeList<LocalType*>, Priority<1>, const Value& value, Output&& output)
278 : : {
279 : : if (value) {
280 : : output.setWant();
281 : : }
282 : : }
283 : :
284 : : template <typename LocalTypes, typename... Args>
285 : : void MaybeSetWant(LocalTypes, Priority<0>, const Args&...)
286 : : {
287 : : }
288 : :
289 : : //! Default PassField implementation calling MaybeReadField/MaybeBuildField.
290 : : template <typename Accessor, typename LocalType, typename ServerContext, typename Fn, typename... Args>
291 : 13 : void PassField(Priority<0>, TypeList<LocalType>, ServerContext& server_context, Fn&& fn, Args&&... args)
292 : : {
293 : 13 : InvokeContext& invoke_context = server_context;
294 : : using ArgType = RemoveCvRef<LocalType>;
295 : 13 : std::optional<ArgType> param;
296 [ + - ]: 13 : const auto& params = server_context.call_context.getParams();
297 [ - + ]: 13 : MaybeReadField(std::integral_constant<bool, Accessor::in>(), TypeList<ArgType>(), invoke_context,
298 [ + - ]: 20 : Make<StructField, Accessor>(params), ReadDestEmplace(TypeList<ArgType>(), [&](auto&&... args) -> auto& {
299 [ - + - + ]: 13 : param.emplace(std::forward<decltype(args)>(args)...);
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# ]
300 [ # # ]: 9 : return *param;
301 : : }));
302 : : if constexpr (Accessor::in) {
303 [ - + ]: 13 : assert(param);
304 : : } else {
305 [ # # ]: 0 : if (!param) param.emplace();
306 : : }
307 [ + - ]: 14 : fn.invoke(server_context, std::forward<Args>(args)..., static_cast<LocalType&&>(*param));
308 [ + - - + ]: 13 : auto&& results = server_context.call_context.getResults();
[ # # # #
# # ]
309 : 13 : MaybeBuildField(std::integral_constant<bool, Accessor::out>(), TypeList<LocalType>(), invoke_context,
310 [ # # ]: 13 : Make<StructField, Accessor>(results), *param);
311 : 13 : }
312 : :
313 : : //! Default PassField implementation for count(0) arguments, calling ReadField/BuildField
314 : : template <typename Accessor, typename ServerContext, typename Fn, typename... Args>
315 : 6 : void PassField(Priority<0>, TypeList<>, ServerContext& server_context, const Fn& fn, Args&&... args)
316 : : {
317 : 6 : const auto& params = server_context.call_context.getParams();
318 : 6 : const auto& input = Make<StructField, Accessor>(params);
319 : 6 : ReadField(TypeList<>(), server_context, input);
320 : : fn.invoke(server_context, std::forward<Args>(args)...);
321 [ + - - + ]: 6 : auto&& results = server_context.call_context.getResults();
322 : 6 : BuildField(TypeList<>(), server_context, Make<StructField, Accessor>(results));
323 : 6 : }
324 : :
325 : : template <typename Derived, size_t N = 0>
326 : : struct IterateFieldsHelper
327 : : {
328 : : template <typename Arg1, typename Arg2, typename ParamList, typename NextFn, typename... NextFnArgs>
329 : 99 : void handleChain(Arg1& arg1, Arg2& arg2, ParamList, NextFn&& next_fn, NextFnArgs&&... next_fn_args)
330 : : {
331 : : using S = Split<N, ParamList>;
332 : 85 : handleChain(arg1, arg2, typename S::First());
333 [ + - + - : 57 : next_fn.handleChain(arg1, arg2, typename S::Second(),
+ - + - +
- ][ + - +
- # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
334 : : std::forward<NextFnArgs>(next_fn_args)...);
335 : 73 : }
336 : :
337 : : template <typename Arg1, typename Arg2, typename ParamList>
338 : 92 : void handleChain(Arg1& arg1, Arg2& arg2, ParamList)
339 : : {
340 : 25 : static_cast<Derived*>(this)->handleField(arg1, arg2, ParamList());
341 : : }
342 : : private:
343 : : IterateFieldsHelper() = default;
344 : : friend Derived;
345 : : };
346 : :
347 : : struct IterateFields : IterateFieldsHelper<IterateFields, 0>
348 : : {
349 : : template <typename Arg1, typename Arg2, typename ParamList>
350 : : void handleField(Arg1&&, Arg2&&, ParamList)
351 : : {
352 : : }
353 : : };
354 : :
355 : : template <typename Exception, typename Accessor>
356 : : struct ClientException
357 : : {
358 : : struct BuildParams : IterateFieldsHelper<BuildParams, 0>
359 : : {
360 : : template <typename Params, typename ParamList>
361 : : void handleField(InvokeContext& invoke_context, Params& params, ParamList)
362 : : {
363 : : }
364 : :
365 : 0 : BuildParams(ClientException* client_exception) : m_client_exception(client_exception) {}
366 : : ClientException* m_client_exception;
367 : : };
368 : :
369 : : struct ReadResults : IterateFieldsHelper<ReadResults, 0>
370 : : {
371 : : template <typename Results, typename ParamList>
372 : 0 : void handleField(InvokeContext& invoke_context, Results& results, ParamList)
373 : : {
374 : 0 : StructField<Accessor, Results> input(results);
375 [ # # ]: 0 : if (input.has()) {
376 : 0 : ThrowField(TypeList<Exception>(), invoke_context, input);
377 : : }
378 : 0 : }
379 : :
380 : 0 : ReadResults(ClientException* client_exception) : m_client_exception(client_exception) {}
381 : : ClientException* m_client_exception;
382 : : };
383 : : };
384 : :
385 : : template <typename Accessor, typename... Types>
386 : : struct ClientParam
387 : : {
388 : 31 : ClientParam(Types&&... values) : m_values{std::forward<Types>(values)...} {}
389 : :
390 : : struct BuildParams : IterateFieldsHelper<BuildParams, sizeof...(Types)>
391 : : {
392 : : template <typename Params, typename ParamList>
393 : 55 : void handleField(ClientInvokeContext& invoke_context, Params& params, ParamList)
394 : : {
395 : 129 : auto const fun = [&]<typename... Values>(Values&&... values) {
396 : : MaybeSetWant(
397 : 37 : ParamList(), Priority<1>(), values..., Make<StructField, Accessor>(params));
398 : 37 : MaybeBuildField(std::integral_constant<bool, Accessor::in>(), ParamList(), invoke_context,
399 : 37 : Make<StructField, Accessor>(params), std::forward<Values>(values)...);
400 : : };
401 : :
402 : : // Note: The m_values tuple just consists of lvalue and rvalue
403 : : // references, so calling std::move doesn't change the tuple, it
404 : : // just causes std::apply to call the std::get overload that returns
405 : : // && instead of &, so rvalue references are preserved and not
406 : : // turned into lvalue references. This allows the BuildField call to
407 : : // move from the argument if it is an rvalue reference or was passed
408 : : // by value.
409 [ + - + - : 30 : std::apply(fun, std::move(m_client_param->m_values));
+ - + - +
- ][ + - #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ][ - - +
- + - ]
410 : : }
411 : :
412 : 30 : BuildParams(ClientParam* client_param) : m_client_param(client_param) {}
413 : : ClientParam* m_client_param;
414 : : };
415 : :
416 : : struct ReadResults : IterateFieldsHelper<ReadResults, sizeof...(Types)>
417 : : {
418 : : template <typename Results, typename... Params>
419 : 37 : void handleField(ClientInvokeContext& invoke_context, Results& results, TypeList<Params...>)
420 : : {
421 : 85 : auto const fun = [&]<typename... Values>(Values&&... values) {
422 : 24 : MaybeReadField(std::integral_constant<bool, Accessor::out>(), TypeList<Decay<Params>...>(), invoke_context,
423 : 55 : Make<StructField, Accessor>(results), ReadDestUpdate(values)...);
424 : : };
425 : :
426 [ + - # # ]: 37 : std::apply(fun, m_client_param->m_values);
[ # # ]
427 : : }
428 : :
429 : 30 : ReadResults(ClientParam* client_param) : m_client_param(client_param) {}
430 : : ClientParam* m_client_param;
431 : : };
432 : :
433 : : std::tuple<Types&&...> m_values;
434 : : };
435 : :
436 : : template <typename Accessor, typename... Types>
437 : 31 : ClientParam<Accessor, Types...> MakeClientParam(Types&&... values)
438 : : {
439 : 31 : return {std::forward<Types>(values)...};
440 : : }
441 : :
442 : : struct ServerCall
443 : : {
444 : : // FIXME: maybe call call_context.releaseParams()
445 : : template <typename ServerContext, typename... Args>
446 [ # # ]: 18 : decltype(auto) invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
447 : : {
448 : 2 : return ProxyServerMethodTraits<typename decltype(server_context.call_context.getParams())::Reads>::invoke(
449 : : server_context,
450 : 16 : std::forward<Args>(args)...);
451 : : }
452 : : };
453 : :
454 : : struct ServerDestroy
455 : : {
456 : : template <typename ServerContext, typename... Args>
457 : 6 : void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
458 : : {
459 [ + - # # : 6 : server_context.proxy_server.invokeDestroy(std::forward<Args>(args)...);
# # ][ # # ]
460 : 6 : }
461 : : };
462 : :
463 : : template <typename Accessor, typename Parent>
464 : : struct ServerRet : Parent
465 : : {
466 : : ServerRet(Parent parent) : Parent(parent) {}
467 : :
468 : : template <typename ServerContext, typename... Args>
469 [ + - ]: 18 : void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
470 : : {
471 : 27 : auto&& result = Parent::invoke(server_context, TypeList<>(), std::forward<Args>(args)...);
472 [ + - - + ]: 18 : auto&& results = server_context.call_context.getResults();
473 : 18 : InvokeContext& invoke_context = server_context;
474 [ + - ]: 18 : BuildField(TypeList<decltype(result)>(), invoke_context, Make<StructField, Accessor>(results),
475 : : std::forward<decltype(result)>(result));
476 : 18 : }
477 : : };
478 : :
479 : : template <typename Exception, typename Accessor, typename Parent>
480 : : struct ServerExcept : Parent
481 : : {
482 : : ServerExcept(Parent parent) : Parent(parent) {}
483 : :
484 : : template <typename ServerContext, typename... Args>
485 : 0 : void invoke(ServerContext& server_context, TypeList<>, Args&&... args) const
486 : : {
487 : : try {
488 : : return Parent::invoke(server_context, TypeList<>(), std::forward<Args>(args)...);
489 [ - - ]: 0 : } catch (const Exception& exception) {
490 [ - - - - ]: 0 : auto&& results = server_context.call_context.getResults();
491 [ - - ]: 0 : BuildField(TypeList<Exception>(), server_context, Make<StructField, Accessor>(results), exception);
492 : : }
493 : : }
494 : : };
495 : :
496 : : //! Helper for CustomPassField below. Call Accessor::get method if it has one,
497 : : //! otherwise return capnp::Void.
498 : : template <typename Accessor, typename Message>
499 : 0 : decltype(auto) MaybeGet(Message&& message, decltype(Accessor::get(message))* enable = nullptr)
500 : : {
501 : 0 : return Accessor::get(message);
502 : : }
503 : :
504 : : template <typename Accessor>
505 : : ::capnp::Void MaybeGet(...)
506 : : {
507 : : return {};
508 : : }
509 : :
510 : : template <class Accessor>
511 : : void CustomPassField();
512 : :
513 : : //! PassField override calling CustomPassField function, if it exists.
514 : : //! Defining a CustomPassField or CustomPassMessage overload is useful for
515 : : //! input/output parameters. If an overload is not defined these parameters will
516 : : //! just be deserialized on the server side with ReadField into a temporary
517 : : //! variable, then the server method will be called passing the temporary
518 : : //! variable as a parameter, then the temporary variable will be serialized and
519 : : //! sent back to the client with BuildField. But if a PassField or PassMessage
520 : : //! overload is defined, the overload is called with a callback to invoke and
521 : : //! pass parameters to the server side function, and run arbitrary code before
522 : : //! and after invoking the function.
523 : : template <typename Accessor, typename... Args>
524 : 0 : auto PassField(Priority<2>, Args&&... args) -> decltype(CustomPassField<Accessor>(std::forward<Args>(args)...))
525 : : {
526 : 0 : return CustomPassField<Accessor>(std::forward<Args>(args)...);
527 : : };
528 : :
529 : : template <int argc, typename Accessor, typename Parent>
530 : : struct ServerField : Parent
531 : : {
532 : : ServerField(Parent parent) : Parent(parent) {}
533 : :
534 : : const Parent& parent() const { return *this; }
535 : :
536 : : template <typename ServerContext, typename ArgTypes, typename... Args>
537 : 37 : decltype(auto) invoke(ServerContext& server_context, ArgTypes, Args&&... args) const
538 : : {
539 [ + - # # : 13 : return PassField<Accessor>(Priority<2>(),
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# ][ # # #
# # # # #
# # ]
540 : : typename Split<argc, ArgTypes>::First(),
541 : : server_context,
542 : : this->parent(),
543 : : typename Split<argc, ArgTypes>::Second(),
544 : 12 : std::forward<Args>(args)...);
545 : : }
546 : : };
547 : :
548 : : template <int argc, typename Accessor, typename Parent>
549 : : ServerField<argc, Accessor, Parent> MakeServerField(Parent parent)
550 : : {
551 : : return {parent};
552 : : }
553 : :
554 : : template <typename Request>
555 : : struct CapRequestTraits;
556 : :
557 : : template <typename _Params, typename _Results>
558 : : struct CapRequestTraits<::capnp::Request<_Params, _Results>>
559 : : {
560 : : using Params = _Params;
561 : : using Results = _Results;
562 : : };
563 : :
564 : : //! Entry point called by all generated ProxyClient destructors. This only logs
565 : : //! the object destruction. The actual cleanup happens in the ProxyClient base
566 : : //! destructor.
567 : : template <typename Client>
568 : 13 : void clientDestroy(Client& client)
569 : : {
570 [ + - ]: 13 : if (client.m_context.connection) {
571 [ + - + - ]: 26 : client.m_context.loop->log() << "IPC client destroy " << typeid(client).name();
[ # # # #
# # ]
572 : : } else {
573 [ # # ]: 0 : KJ_LOG(INFO, "IPC interrupted client destroy", typeid(client).name());
574 : : }
575 : 13 : }
576 : :
577 : : template <typename Server>
578 : 13 : void serverDestroy(Server& server)
579 : : {
580 [ + - - + : 26 : server.m_context.loop->log() << "IPC server destroy " << typeid(server).name();
+ - ]
581 : 13 : }
582 : :
583 : : //! Entry point called by generated client code that looks like:
584 : : //!
585 : : //! ProxyClient<ClassName>::M0::Result ProxyClient<ClassName>::methodName(M0::Param<0> arg0, M0::Param<1> arg1) {
586 : : //! typename M0::Result result;
587 : : //! clientInvoke(*this, &InterfaceName::Client::methodNameRequest, MakeClientParam<...>(M0::Fwd<0>(arg0)), MakeClientParam<...>(M0::Fwd<1>(arg1)), MakeClientParam<...>(result));
588 : : //! return result;
589 : : //! }
590 : : //!
591 : : //! Ellipses above are where generated Accessor<> type declarations are inserted.
592 : : template <typename ProxyClient, typename GetRequest, typename... FieldObjs>
593 : 30 : void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, FieldObjs&&... fields)
594 : : {
595 [ + + ]: 30 : if (!g_thread_context.waiter) {
596 [ - + ]: 1 : assert(g_thread_context.thread_name.empty());
597 [ + - ]: 1 : g_thread_context.thread_name = ThreadName(proxy_client.m_context.loop->m_exe_name);
598 : : // If next assert triggers, it means clientInvoke is being called from
599 : : // the capnp event loop thread. This can happen when a ProxyServer
600 : : // method implementation that runs synchronously on the event loop
601 : : // thread tries to make a blocking callback to the client. Any server
602 : : // method that makes a blocking callback or blocks in general needs to
603 : : // run asynchronously off the event loop thread. This is easy to fix by
604 : : // just adding a 'context :Proxy.Context' argument to the capnp method
605 : : // declaration so the server method runs in a dedicated thread.
606 [ - + ]: 1 : assert(!g_thread_context.loop_thread);
607 [ + - ]: 1 : g_thread_context.waiter = std::make_unique<Waiter>();
608 [ + - ]: 2 : proxy_client.m_context.loop->logPlain()
609 [ + - ]: 1 : << "{" << g_thread_context.thread_name
610 [ + - + - : 1 : << "} IPC client first request from current thread, constructing waiter";
+ - ]
611 : : }
612 : 30 : ThreadContext& thread_context{g_thread_context};
613 : 30 : std::optional<ClientInvokeContext> invoke_context; // Must outlive waiter->wait() call below
614 : 30 : std::exception_ptr exception;
615 : 30 : std::string kj_exception;
616 : 30 : bool done = false;
617 : 30 : const char* disconnected = nullptr;
618 [ + - ]: 60 : proxy_client.m_context.loop->sync([&]() {
619 [ - + - + : 30 : if (!proxy_client.m_context.connection) {
- + - + -
+ - + ][ -
+ - + # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ - - -
+ - + ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
620 : 0 : const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
621 : 0 : done = true;
622 : 0 : disconnected = "IPC client method called after disconnect.";
623 : 0 : thread_context.waiter->m_cv.notify_all();
624 [ # # # # : 0 : return;
# # # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
625 : 0 : }
626 : :
627 [ + - + - : 30 : auto request = (proxy_client.m_client.*get_request)(nullptr);
+ - + - +
- + - ][ +
- + - # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ - - +
- + - ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
628 : : using Request = CapRequestTraits<decltype(request)>;
629 : : using FieldList = typename ProxyClientMethodTraits<typename Request::Params>::Fields;
630 [ - + - + : 30 : invoke_context.emplace(*proxy_client.m_context.connection, thread_context);
- + - + -
+ - + ][ -
+ - + # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ - - -
+ - + ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
631 [ + - + - : 30 : IterateFields().handleChain(*invoke_context, request, FieldList(), typename FieldObjs::BuildParams{&fields}...);
+ - + - +
- ][ + - +
- # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ][ -
- + - +
- ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
632 [ + - + - : 60 : proxy_client.m_context.loop->logPlain()
+ - + - +
- + - + -
+ - + - +
- + - +
- ][ + - +
- + - + -
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ][ - - -
- + - + -
+ - + - ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
633 : 30 : << "{" << thread_context.thread_name << "} IPC client send "
634 [ + - + - : 180 : << TypeName<typename Request::Params>() << " " << LogEscape(request.toString());
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
[ + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ][ - -
- - - - -
- - - - -
- - - - -
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ][ # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
635 : :
636 [ + - + - : 90 : proxy_client.m_context.loop->m_task_set->add(request.send().then(
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ][ + -
+ - + - +
- + - + -
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ][ -
- - - - -
+ - + - +
- + - + -
+ - ][ # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
637 : 90 : [&](::capnp::Response<typename Request::Results>&& response) {
638 [ + - + - : 30 : proxy_client.m_context.loop->logPlain()
+ - + - +
- + - ][ +
- + - # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ - - +
- + - ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
639 : 30 : << "{" << thread_context.thread_name << "} IPC client recv "
640 [ + - + - : 180 : << TypeName<typename Request::Results>() << " " << LogEscape(response.toString());
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ][ + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ][ -
- - - - -
- - - - -
- - - - -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ][ # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
641 : : try {
642 [ + - + - : 30 : IterateFields().handleChain(
+ - + - +
- ][ + - #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ][ - - +
- + - ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
643 : : *invoke_context, response, FieldList(), typename FieldObjs::ReadResults{&fields}...);
644 : 0 : } catch (...) {
645 [ - - - - : 0 : exception = std::current_exception();
- - - - -
- ][ - - -
- - - - -
- - - - ]
[ - - - -
- - - - -
- - - - -
- - - - -
- - - -
- ][ - - -
- - - ][ -
- - - - -
- - - - -
- - - - -
- - - - -
- - - ]
646 : : }
647 : 30 : const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
648 : 30 : done = true;
649 [ + - + - : 30 : thread_context.waiter->m_cv.notify_all();
+ - + - +
- + - ][ +
- + - # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ - - +
- + - ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
650 : 30 : },
651 [ + - + - : 30 : [&](const ::kj::Exception& e) {
+ - + - +
- + - ][ +
- + - # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ - - +
- + - ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
652 [ # # # # : 0 : if (e.getType() == ::kj::Exception::Type::DISCONNECTED) {
# # # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
653 : 0 : disconnected = "IPC client method call interrupted by disconnect.";
654 : : } else {
655 [ # # # # : 0 : kj_exception = kj::str("kj::Exception: ", e).cStr();
# # # # #
# # # # #
# # # # #
# # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ][ # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
656 [ # # # # : 0 : proxy_client.m_context.loop->logPlain()
# # # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
657 [ # # # # : 0 : << "{" << thread_context.thread_name << "} IPC client exception " << kj_exception;
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ][ # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # ][ # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
658 : : }
659 : 0 : const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
660 : 0 : done = true;
661 [ # # # # : 0 : thread_context.waiter->m_cv.notify_all();
# # # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # ][ #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
662 : 0 : }));
663 : 30 : });
664 : :
665 [ + - ]: 30 : std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
666 [ + - ]: 90 : thread_context.waiter->wait(lock, [&done]() { return done; });
667 [ - + ]: 30 : if (exception) std::rethrow_exception(exception);
668 [ - + - - : 30 : if (!kj_exception.empty()) proxy_client.m_context.loop->raise() << kj_exception;
- - - - ]
669 [ - + - - : 30 : if (disconnected) proxy_client.m_context.loop->raise() << disconnected;
- - - - ]
670 [ - + ]: 30 : }
671 : :
672 : : //! Invoke callable `fn()` that may return void. If it does return void, replace
673 : : //! return value with value of `ret()`. This is useful for avoiding code
674 : : //! duplication and branching in generic code that forwards calls to functions.
675 : : template <typename Fn, typename Ret>
676 : 30 : auto ReplaceVoid(Fn&& fn, Ret&& ret)
677 : : {
678 : : if constexpr (std::is_same_v<decltype(fn()), void>) {
679 : 12 : fn();
680 : 12 : return ret();
681 : : } else {
682 : 18 : return fn();
683 : : }
684 : : }
685 : :
686 : : extern std::atomic<int> server_reqs;
687 : :
688 : : //! Entry point called by generated server code that looks like:
689 : : //!
690 : : //! kj::Promise<void> ProxyServer<InterfaceName>::methodName(CallContext call_context) {
691 : : //! return serverInvoke(*this, call_context, MakeServerField<0, ...>(MakeServerField<1, ...>(Make<ServerRet, ...>(ServerCall()))));
692 : : //! }
693 : : //!
694 : : //! Ellipses above are where generated Accessor<> type declarations are inserted.
695 : : template <typename Server, typename CallContext, typename Fn>
696 : 30 : kj::Promise<void> serverInvoke(Server& server, CallContext& call_context, Fn fn)
697 : : {
698 : 30 : auto params = call_context.getParams();
699 : : using Params = decltype(params);
700 : : using Results = typename decltype(call_context.getResults())::Builds;
701 : :
702 : 30 : int req = ++server_reqs;
703 : 30 : server.m_context.loop->log() << "IPC server recv request #" << req << " "
704 [ + - + - : 210 : << TypeName<typename Params::Reads>() << " " << LogEscape(params.toString());
+ - + - +
- + - + -
+ - ]
705 : :
706 : : try {
707 : : using ServerContext = ServerInvokeContext<Server, CallContext>;
708 : : using ArgList = typename ProxyClientMethodTraits<typename Params::Reads>::Params;
709 [ + - ]: 30 : ServerContext server_context{server, call_context, req};
710 : : // ReplaceVoid is used to support fn.invoke implementations that
711 : : // execute asynchronously and return promises, as well as
712 : : // implementations that execute synchronously and return void. The
713 : : // invoke function will be synchronous by default, but asynchronous if
714 : : // an mp.Context argument is passed, and the mp.Context PassField
715 : : // overload returns a promise executing the request in a worker thread
716 : : // and waiting for it to complete.
717 : 30 : return ReplaceVoid([&]() { return fn.invoke(server_context, ArgList()); },
718 [ + - ]: 42 : [&]() { return kj::Promise<CallContext>(kj::mv(call_context)); })
719 : 60 : .then([&server, req](CallContext call_context) {
720 [ + - + - : 60 : server.m_context.loop->log() << "IPC server send response #" << req << " " << TypeName<Results>()
+ - + - +
- + - + -
+ - + - +
- + - +
- ][ + - +
- + - + -
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ][ # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ][ - - -
- + - + -
+ - + - #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ][ # # #
# # # # #
# # # # ]
721 [ + - + - : 210 : << " " << LogEscape(call_context.getResults().toString());
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - + -
- + + - +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - + - +
- - + + -
+ - + - +
- + - + -
+ - + - -
+ + - + -
+ - + - +
- + - + -
+ - - + ]
[ + - + -
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - + -
- + # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ][ - -
- - - - -
- - - - -
- - - - -
- + - + -
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - + -
- + # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
[ # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
722 [ + - - + ]: 30 : });
723 [ - - - - ]: 0 : } catch (const std::exception& e) {
724 [ - - - - : 0 : server.m_context.loop->log() << "IPC server unhandled exception: " << e.what();
- - ]
725 : 0 : throw;
726 : 0 : } catch (...) {
727 [ - - - - : 0 : server.m_context.loop->log() << "IPC server unhandled exception";
- - ]
728 : 0 : throw;
729 : : }
730 : : }
731 : :
732 : : //! Map to convert client interface pointers to ProxyContext struct references
733 : : //! at runtime using typeids.
734 : : struct ProxyTypeRegister {
735 : : template<typename Interface>
736 : 705 : ProxyTypeRegister(TypeList<Interface>) {
737 : 1410 : types().emplace(typeid(Interface), [](void* iface) -> ProxyContext& { return static_cast<typename mp::ProxyType<Interface>::Client&>(*static_cast<Interface*>(iface)).m_context; });
738 : 705 : }
739 : : using Types = std::map<std::type_index, ProxyContext&(*)(void*)>;
740 [ + + + - ]: 705 : static Types& types() { static Types types; return types; }
741 : : };
742 : :
743 : : } // namespace mp
744 : :
745 : : #endif // MP_PROXY_TYPES_H
|