Line data Source code
1 : //===------- RPCUTils.h - Utilities for building RPC APIs -------*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // Utilities to support construction of simple RPC APIs.
11 : //
12 : // The RPC utilities aim for ease of use (minimal conceptual overhead) for C++
13 : // programmers, high performance, low memory overhead, and efficient use of the
14 : // communications channel.
15 : //
16 : //===----------------------------------------------------------------------===//
17 :
18 : #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
19 : #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
20 :
21 : #include <map>
22 : #include <thread>
23 : #include <vector>
24 :
25 : #include "llvm/ADT/STLExtras.h"
26 : #include "llvm/ExecutionEngine/Orc/OrcError.h"
27 : #include "llvm/ExecutionEngine/Orc/RPCSerialization.h"
28 : #include "llvm/Support/MSVCErrorWorkarounds.h"
29 :
30 : #include <future>
31 :
32 : namespace llvm {
33 : namespace orc {
34 : namespace rpc {
35 :
36 : /// Base class of all fatal RPC errors (those that necessarily result in the
37 : /// termination of the RPC session).
38 : class RPCFatalError : public ErrorInfo<RPCFatalError> {
39 : public:
40 : static char ID;
41 : };
42 :
43 : /// RPCConnectionClosed is returned from RPC operations if the RPC connection
44 : /// has already been closed due to either an error or graceful disconnection.
45 : class ConnectionClosed : public ErrorInfo<ConnectionClosed> {
46 : public:
47 : static char ID;
48 : std::error_code convertToErrorCode() const override;
49 : void log(raw_ostream &OS) const override;
50 : };
51 :
52 : /// BadFunctionCall is returned from handleOne when the remote makes a call with
53 : /// an unrecognized function id.
54 : ///
55 : /// This error is fatal because Orc RPC needs to know how to parse a function
56 : /// call to know where the next call starts, and if it doesn't recognize the
57 : /// function id it cannot parse the call.
58 : template <typename FnIdT, typename SeqNoT>
59 : class BadFunctionCall
60 : : public ErrorInfo<BadFunctionCall<FnIdT, SeqNoT>, RPCFatalError> {
61 : public:
62 : static char ID;
63 :
64 0 : BadFunctionCall(FnIdT FnId, SeqNoT SeqNo)
65 0 : : FnId(std::move(FnId)), SeqNo(std::move(SeqNo)) {}
66 :
67 0 : std::error_code convertToErrorCode() const override {
68 0 : return orcError(OrcErrorCode::UnexpectedRPCCall);
69 : }
70 :
71 0 : void log(raw_ostream &OS) const override {
72 0 : OS << "Call to invalid RPC function id '" << FnId << "' with "
73 0 : "sequence number " << SeqNo;
74 0 : }
75 :
76 : private:
77 : FnIdT FnId;
78 : SeqNoT SeqNo;
79 : };
80 :
81 : template <typename FnIdT, typename SeqNoT>
82 : char BadFunctionCall<FnIdT, SeqNoT>::ID = 0;
83 :
84 : /// InvalidSequenceNumberForResponse is returned from handleOne when a response
85 : /// call arrives with a sequence number that doesn't correspond to any in-flight
86 : /// function call.
87 : ///
88 : /// This error is fatal because Orc RPC needs to know how to parse the rest of
89 : /// the response call to know where the next call starts, and if it doesn't have
90 : /// a result parser for this sequence number it can't do that.
91 : template <typename SeqNoT>
92 : class InvalidSequenceNumberForResponse
93 : : public ErrorInfo<InvalidSequenceNumberForResponse<SeqNoT>, RPCFatalError> {
94 : public:
95 : static char ID;
96 :
97 0 : InvalidSequenceNumberForResponse(SeqNoT SeqNo)
98 0 : : SeqNo(std::move(SeqNo)) {}
99 :
100 0 : std::error_code convertToErrorCode() const override {
101 0 : return orcError(OrcErrorCode::UnexpectedRPCCall);
102 : };
103 :
104 0 : void log(raw_ostream &OS) const override {
105 0 : OS << "Response has unknown sequence number " << SeqNo;
106 0 : }
107 : private:
108 : SeqNoT SeqNo;
109 : };
110 :
111 : template <typename SeqNoT>
112 : char InvalidSequenceNumberForResponse<SeqNoT>::ID = 0;
113 :
114 : /// This non-fatal error will be passed to asynchronous result handlers in place
115 : /// of a result if the connection goes down before a result returns, or if the
116 : /// function to be called cannot be negotiated with the remote.
117 0 : class ResponseAbandoned : public ErrorInfo<ResponseAbandoned> {
118 : public:
119 : static char ID;
120 :
121 : std::error_code convertToErrorCode() const override;
122 : void log(raw_ostream &OS) const override;
123 : };
124 :
125 : /// This error is returned if the remote does not have a handler installed for
126 : /// the given RPC function.
127 : class CouldNotNegotiate : public ErrorInfo<CouldNotNegotiate> {
128 : public:
129 : static char ID;
130 :
131 : CouldNotNegotiate(std::string Signature);
132 : std::error_code convertToErrorCode() const override;
133 : void log(raw_ostream &OS) const override;
134 : const std::string &getSignature() const { return Signature; }
135 : private:
136 : std::string Signature;
137 : };
138 :
139 : template <typename DerivedFunc, typename FnT> class Function;
140 :
141 : // RPC Function class.
142 : // DerivedFunc should be a user defined class with a static 'getName()' method
143 : // returning a const char* representing the function's name.
144 : template <typename DerivedFunc, typename RetT, typename... ArgTs>
145 : class Function<DerivedFunc, RetT(ArgTs...)> {
146 : public:
147 : /// User defined function type.
148 : using Type = RetT(ArgTs...);
149 :
150 : /// Return type.
151 : using ReturnType = RetT;
152 :
153 : /// Returns the full function prototype as a string.
154 1923 : static const char *getPrototype() {
155 : std::lock_guard<std::mutex> Lock(NameMutex);
156 1923 : if (Name.empty())
157 : raw_string_ostream(Name)
158 1908 : << RPCTypeName<RetT>::getName() << " " << DerivedFunc::getName()
159 1400 : << "(" << llvm::orc::rpc::RPCTypeNameSequence<ArgTs...>() << ")";
160 1923 : return Name.data();
161 : }
162 67 :
163 : private:
164 67 : static std::mutex NameMutex;
165 : static std::string Name;
166 76 : };
167 46 :
168 67 : template <typename DerivedFunc, typename RetT, typename... ArgTs>
169 : std::mutex Function<DerivedFunc, RetT(ArgTs...)>::NameMutex;
170 72 :
171 : template <typename DerivedFunc, typename RetT, typename... ArgTs>
172 72 : std::string Function<DerivedFunc, RetT(ArgTs...)>::Name;
173 :
174 116 : /// Allocates RPC function ids during autonegotiation.
175 66 : /// Specializations of this class must provide four members:
176 72 : ///
177 : /// static T getInvalidId():
178 275 : /// Should return a reserved id that will be used to represent missing
179 : /// functions during autonegotiation.
180 275 : ///
181 : /// static T getResponseId():
182 118 : /// Should return a reserved id that will be used to send function responses
183 118 : /// (return values).
184 275 : ///
185 : /// static T getNegotiateId():
186 68 : /// Should return a reserved id for the negotiate function, which will be used
187 : /// to negotiate ids for user defined functions.
188 68 : ///
189 : /// template <typename Func> T allocate():
190 116 : /// Allocate a unique id for function Func.
191 106 : template <typename T, typename = void> class RPCFunctionIdAllocator;
192 68 :
193 : /// This specialization of RPCFunctionIdAllocator provides a default
194 115 : /// implementation for integral types.
195 : template <typename T>
196 115 : class RPCFunctionIdAllocator<
197 : T, typename std::enable_if<std::is_integral<T>::value>::type> {
198 114 : public:
199 82 : static T getInvalidId() { return T(0); }
200 115 : static T getResponseId() { return T(1); }
201 : static T getNegotiateId() { return T(2); }
202 134 :
203 : template <typename Func> T allocate() { return NextId++; }
204 134 :
205 : private:
206 122 : T NextId = 3;
207 122 : };
208 134 :
209 : namespace detail {
210 137 :
211 : /// Provides a typedef for a tuple containing the decayed argument types.
212 137 : template <typename T> class FunctionArgsTuple;
213 :
214 110 : template <typename RetT, typename... ArgTs>
215 110 : class FunctionArgsTuple<RetT(ArgTs...)> {
216 137 : public:
217 : using Type = std::tuple<typename std::decay<
218 137 : typename std::remove_reference<ArgTs>::type>::type...>;
219 : };
220 137 :
221 : // ResultTraits provides typedefs and utilities specific to the return type
222 148 : // of functions.
223 98 : template <typename RetT> class ResultTraits {
224 137 : public:
225 : // The return type wrapped in llvm::Expected.
226 122 : using ErrorReturnType = Expected<RetT>;
227 :
228 122 : #ifdef _MSC_VER
229 : // The ErrorReturnType wrapped in a std::promise.
230 124 : using ReturnPromiseType = std::promise<MSVCPExpected<RetT>>;
231 68 :
232 122 : // The ErrorReturnType wrapped in a std::future.
233 : using ReturnFutureType = std::future<MSVCPExpected<RetT>>;
234 56 : #else
235 : // The ErrorReturnType wrapped in a std::promise.
236 56 : using ReturnPromiseType = std::promise<ErrorReturnType>;
237 :
238 64 : // The ErrorReturnType wrapped in a std::future.
239 32 : using ReturnFutureType = std::future<ErrorReturnType>;
240 56 : #endif
241 :
242 136 : // Create a 'blank' value of the ErrorReturnType, ready and safe to
243 : // overwrite.
244 136 : static ErrorReturnType createBlankErrorReturnValue() {
245 : return ErrorReturnType(RetT());
246 112 : }
247 88 :
248 136 : // Consume an abandoned ErrorReturnType.
249 : static void consumeAbandoned(ErrorReturnType RetOrErr) {
250 40 : consumeError(RetOrErr.takeError());
251 : }
252 40 : };
253 :
254 64 : // ResultTraits specialization for void functions.
255 56 : template <> class ResultTraits<void> {
256 40 : public:
257 : // For void functions, ErrorReturnType is llvm::Error.
258 0 : using ErrorReturnType = Error;
259 :
260 0 : #ifdef _MSC_VER
261 : // The ErrorReturnType wrapped in a std::promise.
262 0 : using ReturnPromiseType = std::promise<MSVCPError>;
263 0 :
264 0 : // The ErrorReturnType wrapped in a std::future.
265 : using ReturnFutureType = std::future<MSVCPError>;
266 24 : #else
267 : // The ErrorReturnType wrapped in a std::promise.
268 57 : using ReturnPromiseType = std::promise<ErrorReturnType>;
269 :
270 48 : // The ErrorReturnType wrapped in a std::future.
271 24 : using ReturnFutureType = std::future<ErrorReturnType>;
272 24 : #endif
273 :
274 130 : // Create a 'blank' value of the ErrorReturnType, ready and safe to
275 2 : // overwrite.
276 130 : static ErrorReturnType createBlankErrorReturnValue() {
277 : return ErrorReturnType::success();
278 96 : }
279 48 :
280 130 : // Consume an abandoned ErrorReturnType.
281 : static void consumeAbandoned(ErrorReturnType Err) {
282 130 : consumeError(std::move(Err));
283 : }
284 130 : };
285 :
286 96 : // ResultTraits<Error> is equivalent to ResultTraits<void>. This allows
287 72 : // handlers for void RPC functions to return either void (in which case they
288 130 : // implicitly succeed) or Error (in which case their error return is
289 : // propagated). See usage in HandlerTraits::runHandlerHelper.
290 136 : template <> class ResultTraits<Error> : public ResultTraits<void> {};
291 :
292 152 : // ResultTraits<Expected<T>> is equivalent to ResultTraits<T>. This allows
293 : // handlers for RPC functions returning a T to return either a T (in which
294 96 : // case they implicitly succeed) or Expected<T> (in which case their error
295 96 : // return is propagated). See usage in HandlerTraits::runHandlerHelper.
296 136 : template <typename RetT>
297 : class ResultTraits<Expected<RetT>> : public ResultTraits<RetT> {};
298 24 :
299 96 : // Determines whether an RPC function's defined error return type supports
300 24 : // error return value.
301 : template <typename T>
302 48 : class SupportsErrorReturn {
303 24 : public:
304 24 : static const bool value = false;
305 : };
306 24 :
307 : template <>
308 24 : class SupportsErrorReturn<Error> {
309 : public:
310 48 : static const bool value = true;
311 24 : };
312 24 :
313 : template <typename T>
314 24 : class SupportsErrorReturn<Expected<T>> {
315 : public:
316 24 : static const bool value = true;
317 : };
318 48 :
319 24 : // RespondHelper packages return values based on whether or not the declared
320 24 : // RPC function return type supports error returns.
321 0 : template <bool FuncSupportsErrorReturn>
322 24 : class RespondHelper;
323 0 :
324 24 : // RespondHelper specialization for functions that support error returns.
325 : template <>
326 48 : class RespondHelper<true> {
327 48 : public:
328 24 :
329 : // Send Expected<T>.
330 24 : template <typename WireRetT, typename HandlerRetT, typename ChannelT,
331 : typename FunctionIdT, typename SequenceNumberT>
332 48 : static Error sendResult(ChannelT &C, const FunctionIdT &ResponseId,
333 : SequenceNumberT SeqNo,
334 48 : Expected<HandlerRetT> ResultOrErr) {
335 24 : if (!ResultOrErr && ResultOrErr.template errorIsA<RPCFatalError>())
336 24 : return ResultOrErr.takeError();
337 :
338 24 : // Open the response message.
339 24 : if (auto Err = C.startSendMessage(ResponseId, SeqNo))
340 24 : return Err;
341 :
342 48 : // Serialize the result.
343 24 : if (auto Err =
344 24 : SerializationTraits<ChannelT, WireRetT,
345 0 : Expected<HandlerRetT>>::serialize(
346 0 : C, std::move(ResultOrErr)))
347 0 : return Err;
348 0 :
349 0 : // Close the response message.
350 0 : return C.endSendMessage();
351 0 : }
352 0 :
353 0 : template <typename ChannelT, typename FunctionIdT, typename SequenceNumberT>
354 0 : static Error sendResult(ChannelT &C, const FunctionIdT &ResponseId,
355 0 : SequenceNumberT SeqNo, Error Err) {
356 0 : if (Err && Err.isA<RPCFatalError>())
357 : return Err;
358 : if (auto Err2 = C.startSendMessage(ResponseId, SeqNo))
359 : return Err2;
360 : if (auto Err2 = serializeSeq(C, std::move(Err)))
361 : return Err2;
362 : return C.endSendMessage();
363 : }
364 :
365 : };
366 :
367 : // RespondHelper specialization for functions that do not support error returns.
368 : template <>
369 : class RespondHelper<false> {
370 : public:
371 :
372 : template <typename WireRetT, typename HandlerRetT, typename ChannelT,
373 : typename FunctionIdT, typename SequenceNumberT>
374 : static Error sendResult(ChannelT &C, const FunctionIdT &ResponseId,
375 : SequenceNumberT SeqNo,
376 : Expected<HandlerRetT> ResultOrErr) {
377 : if (auto Err = ResultOrErr.takeError())
378 : return Err;
379 :
380 24 : // Open the response message.
381 24 : if (auto Err = C.startSendMessage(ResponseId, SeqNo))
382 : return Err;
383 :
384 : // Serialize the result.
385 0 : if (auto Err =
386 0 : SerializationTraits<ChannelT, WireRetT, HandlerRetT>::serialize(
387 480 : C, *ResultOrErr))
388 0 : return Err;
389 0 :
390 0 : // Close the response message.
391 0 : return C.endSendMessage();
392 0 : }
393 0 :
394 0 : template <typename ChannelT, typename FunctionIdT, typename SequenceNumberT>
395 0 : static Error sendResult(ChannelT &C, const FunctionIdT &ResponseId,
396 0 : SequenceNumberT SeqNo, Error Err) {
397 0 : if (Err)
398 0 : return Err;
399 0 : if (auto Err2 = C.startSendMessage(ResponseId, SeqNo))
400 0 : return Err2;
401 0 : return C.endSendMessage();
402 0 : }
403 0 :
404 2 : };
405 0 :
406 :
407 2 : // Send a response of the given wire return type (WireRetT) over the
408 : // channel, with the given sequence number.
409 : template <typename WireRetT, typename HandlerRetT, typename ChannelT,
410 : typename FunctionIdT, typename SequenceNumberT>
411 4 : Error respond(ChannelT &C, const FunctionIdT &ResponseId,
412 : SequenceNumberT SeqNo, Expected<HandlerRetT> ResultOrErr) {
413 : return RespondHelper<SupportsErrorReturn<WireRetT>::value>::
414 : template sendResult<WireRetT>(C, ResponseId, SeqNo, std::move(ResultOrErr));
415 4 : }
416 :
417 : // Send an empty response message on the given channel to indicate that
418 : // the handler ran.
419 : template <typename WireRetT, typename ChannelT, typename FunctionIdT,
420 : typename SequenceNumberT>
421 : Error respond(ChannelT &C, const FunctionIdT &ResponseId, SequenceNumberT SeqNo,
422 : Error Err) {
423 : return RespondHelper<SupportsErrorReturn<WireRetT>::value>::
424 : sendResult(C, ResponseId, SeqNo, std::move(Err));
425 : }
426 2 :
427 : // Converts a given type to the equivalent error return type.
428 2 : template <typename T> class WrappedHandlerReturn {
429 : public:
430 4 : using Type = Expected<T>;
431 : };
432 2 :
433 0 : template <typename T> class WrappedHandlerReturn<Expected<T>> {
434 0 : public:
435 0 : using Type = Expected<T>;
436 0 : };
437 15 :
438 0 : template <> class WrappedHandlerReturn<void> {
439 0 : public:
440 15 : using Type = Error;
441 0 : };
442 :
443 : template <> class WrappedHandlerReturn<Error> {
444 30 : public:
445 : using Type = Error;
446 24 : };
447 :
448 30 : template <> class WrappedHandlerReturn<ErrorSuccess> {
449 24 : public:
450 : using Type = Error;
451 : };
452 :
453 48 : // Traits class that strips the response function from the list of handler
454 : // arguments.
455 : template <typename FnT> class AsyncHandlerTraits;
456 :
457 34 : template <typename ResultT, typename... ArgTs>
458 : class AsyncHandlerTraits<Error(std::function<Error(Expected<ResultT>)>, ArgTs...)> {
459 : public:
460 10 : using Type = Error(ArgTs...);
461 : using ResultType = Expected<ResultT>;
462 : };
463 :
464 20 : template <typename... ArgTs>
465 6 : class AsyncHandlerTraits<Error(std::function<Error(Error)>, ArgTs...)> {
466 : public:
467 : using Type = Error(ArgTs...);
468 26 : using ResultType = Error;
469 : };
470 :
471 : template <typename... ArgTs>
472 12 : class AsyncHandlerTraits<ErrorSuccess(std::function<Error(Error)>, ArgTs...)> {
473 : public:
474 : using Type = Error(ArgTs...);
475 : using ResultType = Error;
476 6 : };
477 5 :
478 : template <typename... ArgTs>
479 : class AsyncHandlerTraits<void(std::function<Error(Error)>, ArgTs...)> {
480 5 : public:
481 : using Type = Error(ArgTs...);
482 : using ResultType = Error;
483 : };
484 28 :
485 : template <typename ResponseHandlerT, typename... ArgTs>
486 : class AsyncHandlerTraits<Error(ResponseHandlerT, ArgTs...)> :
487 18 : public AsyncHandlerTraits<Error(typename std::decay<ResponseHandlerT>::type,
488 10 : ArgTs...)> {};
489 :
490 : // This template class provides utilities related to RPC function handlers.
491 36 : // The base case applies to non-function types (the template class is
492 : // specialized for function types) and inherits from the appropriate
493 : // speciilization for the given non-function type's call operator.
494 : template <typename HandlerT>
495 18 : class HandlerTraits : public HandlerTraits<decltype(
496 : &std::remove_reference<HandlerT>::type::operator())> {
497 : };
498 :
499 4 : // Traits for handlers with a given function type.
500 : template <typename RetT, typename... ArgTs>
501 4 : class HandlerTraits<RetT(ArgTs...)> {
502 : public:
503 8 : // Function type of the handler.
504 : using Type = RetT(ArgTs...);
505 12 :
506 : // Return type of the handler.
507 8 : using ReturnType = RetT;
508 :
509 16 : // Call the given handler with the given arguments.
510 : template <typename HandlerT, typename... TArgTs>
511 : static typename WrappedHandlerReturn<RetT>::Type
512 : unpackAndRun(HandlerT &Handler, std::tuple<TArgTs...> &Args) {
513 : return unpackAndRunHelper(Handler, Args,
514 : llvm::index_sequence_for<TArgTs...>());
515 : }
516 :
517 : // Call the given handler with the given arguments.
518 : template <typename HandlerT, typename ResponderT, typename... TArgTs>
519 24 : static Error unpackAndRunAsync(HandlerT &Handler, ResponderT &Responder,
520 : std::tuple<TArgTs...> &Args) {
521 26 : return unpackAndRunAsyncHelper(Handler, Responder, Args,
522 24 : llvm::index_sequence_for<TArgTs...>());
523 : }
524 26 :
525 : // Call the given handler with the given arguments.
526 50 : template <typename HandlerT>
527 : static typename std::enable_if<
528 0 : std::is_void<typename HandlerTraits<HandlerT>::ReturnType>::value,
529 2 : Error>::type
530 24 : run(HandlerT &Handler, ArgTs &&... Args) {
531 6 : Handler(std::move(Args)...);
532 : return Error::success();
533 : }
534 6 :
535 0 : template <typename HandlerT, typename... TArgTs>
536 18 : static typename std::enable_if<
537 : !std::is_void<typename HandlerTraits<HandlerT>::ReturnType>::value,
538 : typename HandlerTraits<HandlerT>::ReturnType>::type
539 18 : run(HandlerT &Handler, TArgTs... Args) {
540 8 : return Handler(std::move(Args)...);
541 : }
542 8 :
543 : // Serialize arguments to the channel.
544 16 : template <typename ChannelT, typename... CArgTs>
545 : static Error serializeArgs(ChannelT &C, const CArgTs... CArgs) {
546 10 : return SequenceSerialization<ChannelT, ArgTs...>::serialize(C, CArgs...);
547 0 : }
548 :
549 10 : // Deserialize arguments from the channel.
550 0 : template <typename ChannelT, typename... CArgTs>
551 2 : static Error deserializeArgs(ChannelT &C, std::tuple<CArgTs...> &Args) {
552 : return deserializeArgsHelper(C, Args,
553 : llvm::index_sequence_for<CArgTs...>());
554 2 : }
555 :
556 41 : private:
557 : template <typename ChannelT, typename... CArgTs, size_t... Indexes>
558 0 : static Error deserializeArgsHelper(ChannelT &C, std::tuple<CArgTs...> &Args,
559 41 : llvm::index_sequence<Indexes...> _) {
560 : return SequenceSerialization<ChannelT, ArgTs...>::deserialize(
561 16 : C, std::get<Indexes>(Args)...);
562 : }
563 :
564 343 : template <typename HandlerT, typename ArgTuple, size_t... Indexes>
565 : static typename WrappedHandlerReturn<
566 5 : typename HandlerTraits<HandlerT>::ReturnType>::Type
567 327 : unpackAndRunHelper(HandlerT &Handler, ArgTuple &Args,
568 : llvm::index_sequence<Indexes...>) {
569 5 : return run(Handler, std::move(std::get<Indexes>(Args))...);
570 : }
571 678 :
572 :
573 0 : template <typename HandlerT, typename ResponderT, typename ArgTuple,
574 24 : size_t... Indexes>
575 327 : static typename WrappedHandlerReturn<
576 : typename HandlerTraits<HandlerT>::ReturnType>::Type
577 0 : unpackAndRunAsyncHelper(HandlerT &Handler, ResponderT &Responder,
578 : ArgTuple &Args,
579 : llvm::index_sequence<Indexes...>) {
580 : return run(Handler, Responder, std::move(std::get<Indexes>(Args))...);
581 12 : }
582 : };
583 24 :
584 12 : // Handler traits for free functions.
585 : template <typename RetT, typename... ArgTs>
586 28 : class HandlerTraits<RetT(*)(ArgTs...)>
587 : : public HandlerTraits<RetT(ArgTs...)> {};
588 :
589 4 : // Handler traits for class methods (especially call operators for lambdas).
590 48 : template <typename Class, typename RetT, typename... ArgTs>
591 8 : class HandlerTraits<RetT (Class::*)(ArgTs...)>
592 : : public HandlerTraits<RetT(ArgTs...)> {};
593 :
594 32 : // Handler traits for const class methods (especially call operators for
595 : // lambdas).
596 : template <typename Class, typename RetT, typename... ArgTs>
597 : class HandlerTraits<RetT (Class::*)(ArgTs...) const>
598 : : public HandlerTraits<RetT(ArgTs...)> {};
599 :
600 : // Utility to peel the Expected wrapper off a response handler error type.
601 : template <typename HandlerT> class ResponseHandlerArg;
602 0 :
603 0 : template <typename ArgT> class ResponseHandlerArg<Error(Expected<ArgT>)> {
604 : public:
605 0 : using ArgType = Expected<ArgT>;
606 0 : using UnwrappedArgType = ArgT;
607 : };
608 0 :
609 0 : template <typename ArgT>
610 : class ResponseHandlerArg<ErrorSuccess(Expected<ArgT>)> {
611 0 : public:
612 : using ArgType = Expected<ArgT>;
613 0 : using UnwrappedArgType = ArgT;
614 : };
615 :
616 0 : template <> class ResponseHandlerArg<Error(Error)> {
617 : public:
618 : using ArgType = Error;
619 : };
620 :
621 0 : template <> class ResponseHandlerArg<ErrorSuccess(Error)> {
622 : public:
623 : using ArgType = Error;
624 0 : };
625 :
626 : // ResponseHandler represents a handler for a not-yet-received function call
627 : // result.
628 0 : template <typename ChannelT> class ResponseHandler {
629 : public:
630 : virtual ~ResponseHandler() {}
631 :
632 0 : // Reads the function result off the wire and acts on it. The meaning of
633 : // "act" will depend on how this method is implemented in any given
634 : // ResponseHandler subclass but could, for example, mean running a
635 : // user-specified handler or setting a promise value.
636 : virtual Error handleResponse(ChannelT &C) = 0;
637 :
638 : // Abandons this outstanding result.
639 : virtual void abandon() = 0;
640 78 :
641 : // Create an error instance representing an abandoned response.
642 : static Error createAbandonedResponseError() {
643 78 : return make_error<ResponseAbandoned>();
644 : }
645 : };
646 :
647 156 : // ResponseHandler subclass for RPC functions with non-void returns.
648 : template <typename ChannelT, typename FuncRetT, typename HandlerT>
649 : class ResponseHandlerImpl : public ResponseHandler<ChannelT> {
650 : public:
651 78 : ResponseHandlerImpl(HandlerT Handler) : Handler(std::move(Handler)) {}
652 0 :
653 : // Handle the result by deserializing it from the channel then passing it
654 0 : // to the user defined handler.
655 : Error handleResponse(ChannelT &C) override {
656 0 : using UnwrappedArgType = typename ResponseHandlerArg<
657 : typename HandlerTraits<HandlerT>::Type>::UnwrappedArgType;
658 0 : UnwrappedArgType Result;
659 0 : if (auto Err =
660 0 : SerializationTraits<ChannelT, FuncRetT,
661 : UnwrappedArgType>::deserialize(C, Result))
662 0 : return Err;
663 : if (auto Err = C.endReceiveMessage())
664 0 : return Err;
665 : return Handler(std::move(Result));
666 0 : }
667 :
668 0 : // Abandon this response by calling the handler with an 'abandoned response'
669 : // error.
670 0 : void abandon() override {
671 : if (auto Err = Handler(this->createAbandonedResponseError())) {
672 0 : // Handlers should not fail when passed an abandoned response error.
673 : report_fatal_error(std::move(Err));
674 0 : }
675 : }
676 0 :
677 : private:
678 24 : HandlerT Handler;
679 : };
680 0 :
681 24 : // ResponseHandler subclass for RPC functions with void returns.
682 0 : template <typename ChannelT, typename HandlerT>
683 : class ResponseHandlerImpl<ChannelT, void, HandlerT>
684 0 : : public ResponseHandler<ChannelT> {
685 48 : public:
686 0 : ResponseHandlerImpl(HandlerT Handler) : Handler(std::move(Handler)) {}
687 :
688 0 : // Handle the result (no actual value, just a notification that the function
689 24 : // has completed on the remote end) by calling the user-defined handler with
690 0 : // Error::success().
691 : Error handleResponse(ChannelT &C) override {
692 0 : if (auto Err = C.endReceiveMessage())
693 : return Err;
694 0 : return Handler(Error::success());
695 : }
696 0 :
697 201 : // Abandon this response by calling the handler with an 'abandoned response'
698 0 : // error.
699 : void abandon() override {
700 201 : if (auto Err = Handler(this->createAbandonedResponseError())) {
701 : // Handlers should not fail when passed an abandoned response error.
702 0 : report_fatal_error(std::move(Err));
703 : }
704 402 : }
705 :
706 0 : private:
707 : HandlerT Handler;
708 201 : };
709 :
710 0 : template <typename ChannelT, typename FuncRetT, typename HandlerT>
711 0 : class ResponseHandlerImpl<ChannelT, Expected<FuncRetT>, HandlerT>
712 0 : : public ResponseHandler<ChannelT> {
713 : public:
714 0 : ResponseHandlerImpl(HandlerT Handler) : Handler(std::move(Handler)) {}
715 :
716 0 : // Handle the result by deserializing it from the channel then passing it
717 : // to the user defined handler.
718 199 : Error handleResponse(ChannelT &C) override {
719 0 : using HandlerArgType = typename ResponseHandlerArg<
720 199 : typename HandlerTraits<HandlerT>::Type>::ArgType;
721 0 : HandlerArgType Result((typename HandlerArgType::value_type()));
722 398 :
723 : if (auto Err =
724 0 : SerializationTraits<ChannelT, Expected<FuncRetT>,
725 : HandlerArgType>::deserialize(C, Result))
726 : return Err;
727 : if (auto Err = C.endReceiveMessage())
728 : return Err;
729 : return Handler(std::move(Result));
730 : }
731 :
732 0 : // Abandon this response by calling the handler with an 'abandoned response'
733 0 : // error.
734 327 : void abandon() override {
735 : if (auto Err = Handler(this->createAbandonedResponseError())) {
736 0 : // Handlers should not fail when passed an abandoned response error.
737 327 : report_fatal_error(std::move(Err));
738 0 : }
739 24 : }
740 0 :
741 0 : private:
742 24 : HandlerT Handler;
743 : };
744 0 :
745 : template <typename ChannelT, typename HandlerT>
746 0 : class ResponseHandlerImpl<ChannelT, Error, HandlerT>
747 0 : : public ResponseHandler<ChannelT> {
748 28 : public:
749 0 : ResponseHandlerImpl(HandlerT Handler) : Handler(std::move(Handler)) {}
750 0 :
751 0 : // Handle the result by deserializing it from the channel then passing it
752 0 : // to the user defined handler.
753 0 : Error handleResponse(ChannelT &C) override {
754 78 : Error Result = Error::success();
755 0 : if (auto Err =
756 0 : SerializationTraits<ChannelT, Error, Error>::deserialize(C, Result))
757 78 : return Err;
758 0 : if (auto Err = C.endReceiveMessage())
759 0 : return Err;
760 0 : return Handler(std::move(Result));
761 0 : }
762 0 :
763 0 : // Abandon this response by calling the handler with an 'abandoned response'
764 24 : // error.
765 0 : void abandon() override {
766 0 : if (auto Err = Handler(this->createAbandonedResponseError())) {
767 24 : // Handlers should not fail when passed an abandoned response error.
768 0 : report_fatal_error(std::move(Err));
769 201 : }
770 0 : }
771 :
772 201 : private:
773 0 : HandlerT Handler;
774 0 : };
775 0 :
776 : // Create a ResponseHandler from a given user handler.
777 2 : template <typename ChannelT, typename FuncRetT, typename HandlerT>
778 5 : std::unique_ptr<ResponseHandler<ChannelT>> createResponseHandler(HandlerT H) {
779 199 : return llvm::make_unique<ResponseHandlerImpl<ChannelT, FuncRetT, HandlerT>>(
780 0 : std::move(H));
781 0 : }
782 199 :
783 0 : // Helper for wrapping member functions up as functors. This is useful for
784 0 : // installing methods as result handlers.
785 0 : template <typename ClassT, typename RetT, typename... ArgTs>
786 0 : class MemberFnWrapper {
787 0 : public:
788 0 : using MethodT = RetT (ClassT::*)(ArgTs...);
789 0 : MemberFnWrapper(ClassT &Instance, MethodT Method)
790 0 : : Instance(Instance), Method(Method) {}
791 : RetT operator()(ArgTs &&... Args) {
792 0 : return (Instance.*Method)(std::move(Args)...);
793 0 : }
794 0 :
795 0 : private:
796 0 : ClassT &Instance;
797 : MethodT Method;
798 0 : };
799 0 :
800 0 : // Helper that provides a Functor for deserializing arguments.
801 1 : template <typename... ArgTs> class ReadArgs {
802 3 : public:
803 0 : Error operator()() { return Error::success(); }
804 0 : };
805 0 :
806 : template <typename ArgT, typename... ArgTs>
807 1 : class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
808 2 : public:
809 0 : ReadArgs(ArgT &Arg, ArgTs &... Args)
810 0 : : ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
811 0 :
812 : Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
813 0 : this->Arg = std::move(ArgVal);
814 : return ReadArgs<ArgTs...>::operator()(ArgVals...);
815 0 : }
816 0 :
817 1 : private:
818 : ArgT &Arg;
819 0 : };
820 0 :
821 0 : // Manage sequence numbers.
822 0 : template <typename SequenceNumberT> class SequenceNumberManager {
823 0 : public:
824 : // Reset, making all sequence numbers available.
825 0 : void reset() {
826 0 : std::lock_guard<std::mutex> Lock(SeqNoLock);
827 0 : NextSequenceNumber = 0;
828 0 : FreeSequenceNumbers.clear();
829 0 : }
830 :
831 0 : // Get the next available sequence number. Will re-use numbers that have
832 : // been released.
833 0 : SequenceNumberT getSequenceNumber() {
834 0 : std::lock_guard<std::mutex> Lock(SeqNoLock);
835 0 : if (FreeSequenceNumbers.empty())
836 0 : return NextSequenceNumber++;
837 0 : auto SequenceNumber = FreeSequenceNumbers.back();
838 0 : FreeSequenceNumbers.pop_back();
839 0 : return SequenceNumber;
840 0 : }
841 0 :
842 0 : // Release a sequence number, making it available for re-use.
843 0 : void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
844 0 : std::lock_guard<std::mutex> Lock(SeqNoLock);
845 0 : FreeSequenceNumbers.push_back(SequenceNumber);
846 0 : }
847 0 :
848 0 : private:
849 0 : std::mutex SeqNoLock;
850 0 : SequenceNumberT NextSequenceNumber = 0;
851 0 : std::vector<SequenceNumberT> FreeSequenceNumbers;
852 0 : };
853 0 :
854 : // Checks that predicate P holds for each corresponding pair of type arguments
855 0 : // from T1 and T2 tuple.
856 : template <template <class, class> class P, typename T1Tuple, typename T2Tuple>
857 0 : class RPCArgTypeCheckHelper;
858 :
859 0 : template <template <class, class> class P>
860 0 : class RPCArgTypeCheckHelper<P, std::tuple<>, std::tuple<>> {
861 0 : public:
862 0 : static const bool value = true;
863 0 : };
864 :
865 0 : template <template <class, class> class P, typename T, typename... Ts,
866 : typename U, typename... Us>
867 0 : class RPCArgTypeCheckHelper<P, std::tuple<T, Ts...>, std::tuple<U, Us...>> {
868 : public:
869 0 : static const bool value =
870 0 : P<T, U>::value &&
871 0 : RPCArgTypeCheckHelper<P, std::tuple<Ts...>, std::tuple<Us...>>::value;
872 0 : };
873 0 :
874 0 : template <template <class, class> class P, typename T1Sig, typename T2Sig>
875 0 : class RPCArgTypeCheck {
876 0 : public:
877 0 : using T1Tuple = typename FunctionArgsTuple<T1Sig>::Type;
878 0 : using T2Tuple = typename FunctionArgsTuple<T2Sig>::Type;
879 :
880 327 : static_assert(std::tuple_size<T1Tuple>::value >=
881 : std::tuple_size<T2Tuple>::value,
882 0 : "Too many arguments to RPC call");
883 : static_assert(std::tuple_size<T1Tuple>::value <=
884 327 : std::tuple_size<T2Tuple>::value,
885 0 : "Too few arguments to RPC call");
886 :
887 0 : static const bool value = RPCArgTypeCheckHelper<P, T1Tuple, T2Tuple>::value;
888 630 : };
889 :
890 0 : template <typename ChannelT, typename WireT, typename ConcreteT>
891 : class CanSerialize {
892 0 : private:
893 : using S = SerializationTraits<ChannelT, WireT, ConcreteT>;
894 630 :
895 0 : template <typename T>
896 24 : static std::true_type
897 0 : check(typename std::enable_if<
898 : std::is_same<decltype(T::serialize(std::declval<ChannelT &>(),
899 : std::declval<const ConcreteT &>())),
900 48 : Error>::value,
901 : void *>::type);
902 0 :
903 : template <typename> static std::false_type check(...);
904 :
905 0 : public:
906 48 : static const bool value = decltype(check<S>(0))::value;
907 : };
908 0 :
909 : template <typename ChannelT, typename WireT, typename ConcreteT>
910 0 : class CanDeserialize {
911 0 : private:
912 0 : using S = SerializationTraits<ChannelT, WireT, ConcreteT>;
913 0 :
914 : template <typename T>
915 0 : static std::true_type
916 : check(typename std::enable_if<
917 0 : std::is_same<decltype(T::deserialize(std::declval<ChannelT &>(),
918 0 : std::declval<ConcreteT &>())),
919 0 : Error>::value,
920 20 : void *>::type);
921 0 :
922 : template <typename> static std::false_type check(...);
923 0 :
924 40 : public:
925 0 : static const bool value = decltype(check<S>(0))::value;
926 : };
927 0 :
928 : /// Contains primitive utilities for defining, calling and handling calls to
929 0 : /// remote procedures. ChannelT is a bidirectional stream conforming to the
930 40 : /// RPCChannel interface (see RPCChannel.h), FunctionIdT is a procedure
931 0 : /// identifier type that must be serializable on ChannelT, and SequenceNumberT
932 24 : /// is an integral type that will be used to number in-flight function calls.
933 0 : ///
934 : /// These utilities support the construction of very primitive RPC utilities.
935 0 : /// Their intent is to ensure correct serialization and deserialization of
936 24 : /// procedure arguments, and to keep the client and server's view of the API in
937 0 : /// sync.
938 : template <typename ImplT, typename ChannelT, typename FunctionIdT,
939 0 : typename SequenceNumberT>
940 0 : class RPCEndpointBase {
941 0 : protected:
942 24 : class OrcRPCInvalid : public Function<OrcRPCInvalid, void()> {
943 0 : public:
944 0 : static const char *getName() { return "__orc_rpc$invalid"; }
945 0 : };
946 :
947 0 : class OrcRPCResponse : public Function<OrcRPCResponse, void()> {
948 0 : public:
949 0 : static const char *getName() { return "__orc_rpc$response"; }
950 0 : };
951 0 :
952 : class OrcRPCNegotiate
953 0 : : public Function<OrcRPCNegotiate, FunctionIdT(std::string)> {
954 0 : public:
955 0 : static const char *getName() { return "__orc_rpc$negotiate"; }
956 0 : };
957 24 :
958 0 : // Helper predicate for testing for the presence of SerializeTraits
959 0 : // serializers.
960 0 : template <typename WireT, typename ConcreteT>
961 24 : class CanSerializeCheck : detail::CanSerialize<ChannelT, WireT, ConcreteT> {
962 : public:
963 0 : using detail::CanSerialize<ChannelT, WireT, ConcreteT>::value;
964 :
965 48 : static_assert(value, "Missing serializer for argument (Can't serialize the "
966 0 : "first template type argument of CanSerializeCheck "
967 0 : "from the second)");
968 0 : };
969 0 :
970 0 : // Helper predicate for testing for the presence of SerializeTraits
971 48 : // deserializers.
972 0 : template <typename WireT, typename ConcreteT>
973 0 : class CanDeserializeCheck
974 : : detail::CanDeserialize<ChannelT, WireT, ConcreteT> {
975 0 : public:
976 0 : using detail::CanDeserialize<ChannelT, WireT, ConcreteT>::value;
977 0 :
978 0 : static_assert(value, "Missing deserializer for argument (Can't deserialize "
979 0 : "the second template type argument of "
980 58 : "CanDeserializeCheck from the first)");
981 0 : };
982 :
983 0 : public:
984 116 : /// Construct an RPC instance on a channel.
985 0 : RPCEndpointBase(ChannelT &C, bool LazyAutoNegotiation)
986 : : C(C), LazyAutoNegotiation(LazyAutoNegotiation) {
987 : // Hold ResponseId in a special variable, since we expect Response to be
988 0 : // called relatively frequently, and want to avoid the map lookup.
989 : ResponseId = FnIdAllocator.getResponseId();
990 116 : RemoteFunctionIds[OrcRPCResponse::getPrototype()] = ResponseId;
991 :
992 209 : // Register the negotiate function id and handler.
993 0 : auto NegotiateId = FnIdAllocator.getNegotiateId();
994 : RemoteFunctionIds[OrcRPCNegotiate::getPrototype()] = NegotiateId;
995 0 : Handlers[NegotiateId] = wrapHandler<OrcRPCNegotiate>(
996 402 : [this](const std::string &Name) { return handleNegotiate(Name); });
997 8 : }
998 0 :
999 :
1000 8 : /// Negotiate a function id for Func with the other end of the channel.
1001 0 : template <typename Func> Error negotiateFunction(bool Retry = false) {
1002 402 : return getRemoteFunctionId<Func>(true, Retry).takeError();
1003 0 : }
1004 :
1005 0 : /// Append a call Func, does not call send on the channel.
1006 0 : /// The first argument specifies a user-defined handler to be run when the
1007 0 : /// function returns. The handler should take an Expected<Func::ReturnType>,
1008 0 : /// or an Error (if Func::ReturnType is void). The handler will be called
1009 : /// with an error if the return value is abandoned due to a channel error.
1010 0 : template <typename Func, typename HandlerT, typename... ArgTs>
1011 0 : Error appendCallAsync(HandlerT Handler, const ArgTs &... Args) {
1012 0 :
1013 0 : static_assert(
1014 0 : detail::RPCArgTypeCheck<CanSerializeCheck, typename Func::Type,
1015 0 : void(ArgTs...)>::value,
1016 : "");
1017 :
1018 0 : // Look up the function ID.
1019 0 : FunctionIdT FnId;
1020 15 : if (auto FnIdOrErr = getRemoteFunctionId<Func>(LazyAutoNegotiation, false))
1021 : FnId = *FnIdOrErr;
1022 : else {
1023 : // Negotiation failed. Notify the handler then return the negotiate-failed
1024 35 : // error.
1025 0 : cantFail(Handler(make_error<ResponseAbandoned>()));
1026 20 : return FnIdOrErr.takeError();
1027 : }
1028 0 :
1029 30 : SequenceNumberT SeqNo; // initialized in locked scope below.
1030 0 : {
1031 0 : // Lock the pending responses map and sequence number manager.
1032 20 : std::lock_guard<std::mutex> Lock(ResponsesMutex);
1033 :
1034 20 : // Allocate a sequence number.
1035 30 : SeqNo = SequenceNumberMgr.getSequenceNumber();
1036 0 : assert(!PendingResponses.count(SeqNo) &&
1037 8 : "Sequence number already allocated");
1038 0 :
1039 : // Install the user handler.
1040 0 : PendingResponses[SeqNo] =
1041 : detail::createResponseHandler<ChannelT, typename Func::ReturnType>(
1042 16 : std::move(Handler));
1043 0 : }
1044 0 :
1045 : // Open the function call message.
1046 0 : if (auto Err = C.startSendMessage(FnId, SeqNo)) {
1047 : abandonPendingResponses();
1048 16 : return Err;
1049 0 : }
1050 3 :
1051 : // Serialize the call arguments.
1052 0 : if (auto Err = detail::HandlerTraits<typename Func::Type>::serializeArgs(
1053 : C, Args...)) {
1054 0 : abandonPendingResponses();
1055 6 : return Err;
1056 0 : }
1057 :
1058 0 : // Close the function call messagee.
1059 : if (auto Err = C.endSendMessage()) {
1060 0 : abandonPendingResponses();
1061 6 : return Err;
1062 0 : }
1063 2 :
1064 0 : return Error::success();
1065 : }
1066 0 :
1067 : Error sendAppendedCalls() { return C.send(); };
1068 4 :
1069 : template <typename Func, typename HandlerT, typename... ArgTs>
1070 0 : Error callAsync(HandlerT Handler, const ArgTs &... Args) {
1071 : if (auto Err = appendCallAsync<Func>(std::move(Handler), Args...))
1072 0 : return Err;
1073 : return C.send();
1074 4 : }
1075 :
1076 0 : /// Handle one incoming call.
1077 199 : Error handleOne() {
1078 0 : FunctionIdT FnId;
1079 : SequenceNumberT SeqNo;
1080 0 : if (auto Err = C.startReceiveMessage(FnId, SeqNo)) {
1081 0 : abandonPendingResponses();
1082 220 : return Err;
1083 : }
1084 0 : if (FnId == ResponseId)
1085 199 : return handleResponse(SeqNo);
1086 26 : auto I = Handlers.find(FnId);
1087 0 : if (I != Handlers.end())
1088 : return I->second(C, SeqNo);
1089 0 :
1090 48 : // else: No handler found. Report error to client?
1091 : return make_error<BadFunctionCall<FunctionIdT, SequenceNumberT>>(FnId,
1092 24 : SeqNo);
1093 : }
1094 0 :
1095 24 : /// Helper for handling setter procedures - this method returns a functor that
1096 47 : /// sets the variables referred to by Args... to values deserialized from the
1097 0 : /// channel.
1098 1 : /// E.g.
1099 : ///
1100 0 : /// typedef Function<0, bool, int> Func1;
1101 : ///
1102 4 : /// ...
1103 : /// bool B;
1104 : /// int I;
1105 0 : /// if (auto Err = expect<Func1>(Channel, readArgs(B, I)))
1106 : /// /* Handle Args */ ;
1107 28 : ///
1108 1 : template <typename... ArgTs>
1109 : static detail::ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
1110 25 : return detail::ReadArgs<ArgTs...>(Args...);
1111 : }
1112 5 :
1113 4 : /// Abandon all outstanding result handlers.
1114 2 : ///
1115 5 : /// This will call all currently registered result handlers to receive an
1116 : /// "abandoned" error as their argument. This is used internally by the RPC
1117 24 : /// in error situations, but can also be called directly by clients who are
1118 0 : /// disconnecting from the remote and don't or can't expect responses to their
1119 0 : /// outstanding calls. (Especially for outstanding blocking calls, calling
1120 25 : /// this function may be necessary to avoid dead threads).
1121 : void abandonPendingResponses() {
1122 1 : // Lock the pending responses map and sequence number manager.
1123 0 : std::lock_guard<std::mutex> Lock(ResponsesMutex);
1124 0 :
1125 0 : for (auto &KV : PendingResponses)
1126 2 : KV.second->abandon();
1127 58 : PendingResponses.clear();
1128 : SequenceNumberMgr.reset();
1129 0 : }
1130 58 :
1131 0 : /// Remove the handler for the given function.
1132 65 : /// A handler must currently be registered for this function.
1133 : template <typename Func>
1134 1 : void removeHandler() {
1135 64 : auto IdItr = LocalFunctionIds.find(Func::getPrototype());
1136 0 : assert(IdItr != LocalFunctionIds.end() &&
1137 0 : "Function does not have a registered handler");
1138 : auto HandlerItr = Handlers.find(IdItr->second);
1139 : assert(HandlerItr != Handlers.end() &&
1140 0 : "Function does not have a registered handler");
1141 0 : Handlers.erase(HandlerItr);
1142 0 : }
1143 0 :
1144 1 : /// Clear all handlers.
1145 0 : void clearHandlers() {
1146 1 : Handlers.clear();
1147 0 : }
1148 0 :
1149 0 : protected:
1150 0 :
1151 0 : FunctionIdT getInvalidFunctionId() const {
1152 0 : return FnIdAllocator.getInvalidId();
1153 0 : }
1154 0 :
1155 0 : /// Add the given handler to the handler map and make it available for
1156 1 : /// autonegotiation and execution.
1157 0 : template <typename Func, typename HandlerT>
1158 1 : void addHandlerImpl(HandlerT Handler) {
1159 0 :
1160 : static_assert(detail::RPCArgTypeCheck<
1161 : CanDeserializeCheck, typename Func::Type,
1162 2 : typename detail::HandlerTraits<HandlerT>::Type>::value,
1163 0 : "");
1164 0 :
1165 : FunctionIdT NewFnId = FnIdAllocator.template allocate<Func>();
1166 : LocalFunctionIds[Func::getPrototype()] = NewFnId;
1167 : Handlers[NewFnId] = wrapHandler<Func>(std::move(Handler));
1168 2 : }
1169 4 :
1170 1 : template <typename Func, typename HandlerT>
1171 : void addAsyncHandlerImpl(HandlerT Handler) {
1172 0 :
1173 4 : static_assert(detail::RPCArgTypeCheck<
1174 2 : CanDeserializeCheck, typename Func::Type,
1175 8 : typename detail::AsyncHandlerTraits<
1176 0 : typename detail::HandlerTraits<HandlerT>::Type
1177 : >::Type>::value,
1178 : "");
1179 :
1180 6 : FunctionIdT NewFnId = FnIdAllocator.template allocate<Func>();
1181 0 : LocalFunctionIds[Func::getPrototype()] = NewFnId;
1182 3 : Handlers[NewFnId] = wrapAsyncHandler<Func>(std::move(Handler));
1183 : }
1184 4 :
1185 : Error handleResponse(SequenceNumberT SeqNo) {
1186 2 : using Handler = typename decltype(PendingResponses)::mapped_type;
1187 0 : Handler PRHandler;
1188 0 :
1189 2 : {
1190 : // Lock the pending responses map and sequence number manager.
1191 2 : std::unique_lock<std::mutex> Lock(ResponsesMutex);
1192 2 : auto I = PendingResponses.find(SeqNo);
1193 4 :
1194 18 : if (I != PendingResponses.end()) {
1195 : PRHandler = std::move(I->second);
1196 0 : PendingResponses.erase(I);
1197 : SequenceNumberMgr.releaseSequenceNumber(SeqNo);
1198 38 : } else {
1199 0 : // Unlock the pending results map to prevent recursive lock.
1200 0 : Lock.unlock();
1201 : abandonPendingResponses();
1202 0 : return make_error<
1203 : InvalidSequenceNumberForResponse<SequenceNumberT>>(SeqNo);
1204 36 : }
1205 0 : }
1206 0 :
1207 0 : assert(PRHandler &&
1208 : "If we didn't find a response handler we should have bailed out");
1209 0 :
1210 0 : if (auto Err = PRHandler->handleResponse(C)) {
1211 0 : abandonPendingResponses();
1212 0 : return Err;
1213 0 : }
1214 0 :
1215 0 : return Error::success();
1216 0 : }
1217 0 :
1218 0 : FunctionIdT handleNegotiate(const std::string &Name) {
1219 0 : auto I = LocalFunctionIds.find(Name);
1220 0 : if (I == LocalFunctionIds.end())
1221 0 : return getInvalidFunctionId();
1222 0 : return I->second;
1223 0 : }
1224 0 :
1225 0 : // Find the remote FunctionId for the given function.
1226 0 : template <typename Func>
1227 0 : Expected<FunctionIdT> getRemoteFunctionId(bool NegotiateIfNotInMap,
1228 0 : bool NegotiateIfInvalid) {
1229 0 : bool DoNegotiate;
1230 0 :
1231 0 : // Check if we already have a function id...
1232 0 : auto I = RemoteFunctionIds.find(Func::getPrototype());
1233 0 : if (I != RemoteFunctionIds.end()) {
1234 0 : // If it's valid there's nothing left to do.
1235 0 : if (I->second != getInvalidFunctionId())
1236 0 : return I->second;
1237 : DoNegotiate = NegotiateIfInvalid;
1238 0 : } else
1239 0 : DoNegotiate = NegotiateIfNotInMap;
1240 0 :
1241 : // We don't have a function id for Func yet, but we're allowed to try to
1242 0 : // negotiate one.
1243 : if (DoNegotiate) {
1244 0 : auto &Impl = static_cast<ImplT &>(*this);
1245 0 : if (auto RemoteIdOrErr =
1246 0 : Impl.template callB<OrcRPCNegotiate>(Func::getPrototype())) {
1247 : RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
1248 0 : if (*RemoteIdOrErr == getInvalidFunctionId())
1249 : return make_error<CouldNotNegotiate>(Func::getPrototype());
1250 0 : return *RemoteIdOrErr;
1251 0 : } else
1252 0 : return RemoteIdOrErr.takeError();
1253 : }
1254 0 :
1255 : // No key was available in the map and we weren't allowed to try to
1256 8 : // negotiate one, so return an unknown function error.
1257 16 : return make_error<CouldNotNegotiate>(Func::getPrototype());
1258 0 : }
1259 0 :
1260 0 : using WrappedHandlerFn = std::function<Error(ChannelT &, SequenceNumberT)>;
1261 :
1262 0 : // Wrap the given user handler in the necessary argument-deserialization code,
1263 0 : // result-serialization code, and call to the launch policy (if present).
1264 0 : template <typename Func, typename HandlerT>
1265 0 : WrappedHandlerFn wrapHandler(HandlerT Handler) {
1266 0 : return [this, Handler](ChannelT &Channel,
1267 : SequenceNumberT SeqNo) mutable -> Error {
1268 0 : // Start by deserializing the arguments.
1269 0 : using ArgsTuple =
1270 : typename detail::FunctionArgsTuple<
1271 0 : typename detail::HandlerTraits<HandlerT>::Type>::Type;
1272 0 : auto Args = std::make_shared<ArgsTuple>();
1273 :
1274 8 : if (auto Err =
1275 16 : detail::HandlerTraits<typename Func::Type>::deserializeArgs(
1276 0 : Channel, *Args))
1277 0 : return Err;
1278 0 :
1279 3 : // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
1280 : // for RPCArgs. Void cast RPCArgs to work around this for now.
1281 : // FIXME: Remove this workaround once we can assume a working GCC version.
1282 : (void)Args;
1283 :
1284 6 : // End receieve message, unlocking the channel for reading.
1285 : if (auto Err = Channel.endReceiveMessage())
1286 : return Err;
1287 6 :
1288 : using HTraits = detail::HandlerTraits<HandlerT>;
1289 1 : using FuncReturn = typename Func::ReturnType;
1290 : return detail::respond<FuncReturn>(Channel, ResponseId, SeqNo,
1291 : HTraits::unpackAndRun(Handler, *Args));
1292 1 : };
1293 : }
1294 1 :
1295 : // Wrap the given user handler in the necessary argument-deserialization code,
1296 : // result-serialization code, and call to the launch policy (if present).
1297 1 : template <typename Func, typename HandlerT>
1298 : WrappedHandlerFn wrapAsyncHandler(HandlerT Handler) {
1299 1 : return [this, Handler](ChannelT &Channel,
1300 : SequenceNumberT SeqNo) mutable -> Error {
1301 : // Start by deserializing the arguments.
1302 1 : using AHTraits = detail::AsyncHandlerTraits<
1303 : typename detail::HandlerTraits<HandlerT>::Type>;
1304 1 : using ArgsTuple =
1305 : typename detail::FunctionArgsTuple<typename AHTraits::Type>::Type;
1306 : auto Args = std::make_shared<ArgsTuple>();
1307 1 :
1308 16 : if (auto Err =
1309 1 : detail::HandlerTraits<typename Func::Type>::deserializeArgs(
1310 : Channel, *Args))
1311 0 : return Err;
1312 1 :
1313 0 : // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
1314 1 : // for RPCArgs. Void cast RPCArgs to work around this for now.
1315 0 : // FIXME: Remove this workaround once we can assume a working GCC version.
1316 : (void)Args;
1317 1 :
1318 : // End receieve message, unlocking the channel for reading.
1319 87 : if (auto Err = Channel.endReceiveMessage())
1320 87 : return Err;
1321 87 :
1322 25 : using HTraits = detail::HandlerTraits<HandlerT>;
1323 62 : using FuncReturn = typename Func::ReturnType;
1324 : auto Responder =
1325 62 : [this, SeqNo](typename AHTraits::ResultType RetVal) -> Error {
1326 : return detail::respond<FuncReturn>(C, ResponseId, SeqNo,
1327 0 : std::move(RetVal));
1328 0 : };
1329 51 :
1330 51 : return HTraits::unpackAndRunAsync(Handler, Responder, *Args);
1331 51 : };
1332 51 : }
1333 0 :
1334 24 : ChannelT &C;
1335 0 :
1336 : bool LazyAutoNegotiation;
1337 0 :
1338 0 : RPCFunctionIdAllocator<FunctionIdT> FnIdAllocator;
1339 0 :
1340 0 : FunctionIdT ResponseId;
1341 0 : std::map<std::string, FunctionIdT> LocalFunctionIds;
1342 : std::map<const char *, FunctionIdT> RemoteFunctionIds;
1343 :
1344 0 : std::map<FunctionIdT, WrappedHandlerFn> Handlers;
1345 546 :
1346 526 : std::mutex ResponsesMutex;
1347 526 : detail::SequenceNumberManager<SequenceNumberT> SequenceNumberMgr;
1348 24 : std::map<SequenceNumberT, std::unique_ptr<detail::ResponseHandler<ChannelT>>>
1349 502 : PendingResponses;
1350 0 : };
1351 502 :
1352 0 : } // end namespace detail
1353 0 :
1354 0 : template <typename ChannelT, typename FunctionIdT = uint32_t,
1355 526 : typename SequenceNumberT = uint32_t>
1356 526 : class MultiThreadedRPCEndpoint
1357 526 : : public detail::RPCEndpointBase<
1358 526 : MultiThreadedRPCEndpoint<ChannelT, FunctionIdT, SequenceNumberT>,
1359 0 : ChannelT, FunctionIdT, SequenceNumberT> {
1360 0 : private:
1361 0 : using BaseClass =
1362 0 : detail::RPCEndpointBase<
1363 0 : MultiThreadedRPCEndpoint<ChannelT, FunctionIdT, SequenceNumberT>,
1364 : ChannelT, FunctionIdT, SequenceNumberT>;
1365 0 :
1366 0 : public:
1367 : MultiThreadedRPCEndpoint(ChannelT &C, bool LazyAutoNegotiation)
1368 : : BaseClass(C, LazyAutoNegotiation) {}
1369 :
1370 0 : /// Add a handler for the given RPC function.
1371 : /// This installs the given handler functor for the given RPC Function, and
1372 : /// makes the RPC function available for negotiation/calling from the remote.
1373 0 : template <typename Func, typename HandlerT>
1374 : void addHandler(HandlerT Handler) {
1375 : return this->template addHandlerImpl<Func>(std::move(Handler));
1376 : }
1377 2 :
1378 : /// Add a class-method as a handler.
1379 : template <typename Func, typename ClassT, typename RetT, typename... ArgTs>
1380 : void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
1381 : addHandler<Func>(
1382 4 : detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method));
1383 : }
1384 :
1385 : template <typename Func, typename HandlerT>
1386 : void addAsyncHandler(HandlerT Handler) {
1387 : return this->template addAsyncHandlerImpl<Func>(std::move(Handler));
1388 3 : }
1389 :
1390 1 : /// Add a class-method as a handler.
1391 : template <typename Func, typename ClassT, typename RetT, typename... ArgTs>
1392 : void addAsyncHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
1393 : addAsyncHandler<Func>(
1394 : detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method));
1395 2 : }
1396 24 :
1397 : /// Return type for non-blocking call primitives.
1398 : template <typename Func>
1399 0 : using NonBlockingCallResult = typename detail::ResultTraits<
1400 0 : typename Func::ReturnType>::ReturnFutureType;
1401 1 :
1402 : /// Call Func on Channel C. Does not block, does not call send. Returns a pair
1403 1 : /// of a future result and the sequence number assigned to the result.
1404 : ///
1405 : /// This utility function is primarily used for single-threaded mode support,
1406 : /// where the sequence number can be used to wait for the corresponding
1407 0 : /// result. In multi-threaded mode the appendCallNB method, which does not
1408 2 : /// return the sequence numeber, should be preferred.
1409 0 : template <typename Func, typename... ArgTs>
1410 0 : Expected<NonBlockingCallResult<Func>> appendCallNB(const ArgTs &... Args) {
1411 0 : using RTraits = detail::ResultTraits<typename Func::ReturnType>;
1412 : using ErrorReturn = typename RTraits::ErrorReturnType;
1413 0 : using ErrorReturnPromise = typename RTraits::ReturnPromiseType;
1414 2 :
1415 : // FIXME: Stack allocate and move this into the handler once LLVM builds
1416 : // with C++14.
1417 0 : auto Promise = std::make_shared<ErrorReturnPromise>();
1418 0 : auto FutureResult = Promise->get_future();
1419 0 :
1420 0 : if (auto Err = this->template appendCallAsync<Func>(
1421 : [Promise](ErrorReturn RetOrErr) {
1422 0 : Promise->set_value(std::move(RetOrErr));
1423 : return Error::success();
1424 0 : },
1425 0 : Args...)) {
1426 0 : RTraits::consumeAbandoned(FutureResult.get());
1427 : return std::move(Err);
1428 0 : }
1429 : return std::move(FutureResult);
1430 0 : }
1431 0 :
1432 0 : /// The same as appendCallNBWithSeq, except that it calls C.send() to
1433 : /// flush the channel after serializing the call.
1434 0 : template <typename Func, typename... ArgTs>
1435 : Expected<NonBlockingCallResult<Func>> callNB(const ArgTs &... Args) {
1436 0 : auto Result = appendCallNB<Func>(Args...);
1437 : if (!Result)
1438 : return Result;
1439 : if (auto Err = this->C.send()) {
1440 : this->abandonPendingResponses();
1441 : detail::ResultTraits<typename Func::ReturnType>::consumeAbandoned(
1442 : std::move(Result->get()));
1443 0 : return std::move(Err);
1444 : }
1445 : return Result;
1446 0 : }
1447 :
1448 : /// Call Func on Channel C. Blocks waiting for a result. Returns an Error
1449 : /// for void functions or an Expected<T> for functions returning a T.
1450 2 : ///
1451 : /// This function is for use in threaded code where another thread is
1452 4 : /// handling responses and incoming calls.
1453 : template <typename Func, typename... ArgTs,
1454 : typename AltRetT = typename Func::ReturnType>
1455 : typename detail::ResultTraits<AltRetT>::ErrorReturnType
1456 : callB(const ArgTs &... Args) {
1457 3 : if (auto FutureResOrErr = callNB<Func>(Args...))
1458 : return FutureResOrErr->get();
1459 1 : else
1460 : return FutureResOrErr.takeError();
1461 2 : }
1462 :
1463 : /// Handle incoming RPC calls.
1464 : Error handlerLoop() {
1465 : while (true)
1466 1 : if (auto Err = this->handleOne())
1467 : return Err;
1468 1 : return Error::success();
1469 : }
1470 2 : };
1471 16 :
1472 48 : template <typename ChannelT, typename FunctionIdT = uint32_t,
1473 : typename SequenceNumberT = uint32_t>
1474 : class SingleThreadedRPCEndpoint
1475 18 : : public detail::RPCEndpointBase<
1476 16 : SingleThreadedRPCEndpoint<ChannelT, FunctionIdT, SequenceNumberT>,
1477 : ChannelT, FunctionIdT, SequenceNumberT> {
1478 : private:
1479 16 : using BaseClass =
1480 16 : detail::RPCEndpointBase<
1481 16 : SingleThreadedRPCEndpoint<ChannelT, FunctionIdT, SequenceNumberT>,
1482 : ChannelT, FunctionIdT, SequenceNumberT>;
1483 16 :
1484 : public:
1485 0 : SingleThreadedRPCEndpoint(ChannelT &C, bool LazyAutoNegotiation)
1486 0 : : BaseClass(C, LazyAutoNegotiation) {}
1487 0 :
1488 : template <typename Func, typename HandlerT>
1489 0 : void addHandler(HandlerT Handler) {
1490 : return this->template addHandlerImpl<Func>(std::move(Handler));
1491 0 : }
1492 0 :
1493 0 : template <typename Func, typename ClassT, typename RetT, typename... ArgTs>
1494 : void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
1495 0 : addHandler<Func>(
1496 : detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method));
1497 75 : }
1498 72 :
1499 : template <typename Func, typename HandlerT>
1500 : void addAsyncHandler(HandlerT Handler) {
1501 24 : return this->template addAsyncHandlerImpl<Func>(std::move(Handler));
1502 24 : }
1503 :
1504 : /// Add a class-method as a handler.
1505 24 : template <typename Func, typename ClassT, typename RetT, typename... ArgTs>
1506 75 : void addAsyncHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
1507 75 : addAsyncHandler<Func>(
1508 : detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method));
1509 24 : }
1510 :
1511 0 : template <typename Func, typename... ArgTs,
1512 : typename AltRetT = typename Func::ReturnType>
1513 0 : typename detail::ResultTraits<AltRetT>::ErrorReturnType
1514 : callB(const ArgTs &... Args) {
1515 0 : bool ReceivedResponse = false;
1516 : using ResultType = typename detail::ResultTraits<AltRetT>::ErrorReturnType;
1517 0 : auto Result = detail::ResultTraits<AltRetT>::createBlankErrorReturnValue();
1518 51 :
1519 0 : // We have to 'Check' result (which we know is in a success state at this
1520 : // point) so that it can be overwritten in the async handler.
1521 51 : (void)!!Result;
1522 :
1523 526 : if (auto Err = this->template appendCallAsync<Func>(
1524 : [&](ResultType R) {
1525 0 : Result = std::move(R);
1526 51 : ReceivedResponse = true;
1527 0 : return Error::success();
1528 : },
1529 0 : Args...)) {
1530 : detail::ResultTraits<typename Func::ReturnType>::consumeAbandoned(
1531 0 : std::move(Result));
1532 628 : return std::move(Err);
1533 526 : }
1534 :
1535 0 : while (!ReceivedResponse) {
1536 : if (auto Err = this->handleOne()) {
1537 0 : detail::ResultTraits<typename Func::ReturnType>::consumeAbandoned(
1538 89 : std::move(Result));
1539 0 : return std::move(Err);
1540 0 : }
1541 0 : }
1542 :
1543 0 : return Result;
1544 526 : }
1545 43 : };
1546 :
1547 526 : /// Asynchronous dispatch for a function on an RPC endpoint.
1548 : template <typename RPCClass, typename Func>
1549 0 : class RPCAsyncDispatch {
1550 : public:
1551 0 : RPCAsyncDispatch(RPCClass &Endpoint) : Endpoint(Endpoint) {}
1552 528 :
1553 0 : template <typename HandlerT, typename... ArgTs>
1554 : Error operator()(HandlerT Handler, const ArgTs &... Args) const {
1555 0 : return Endpoint.template appendCallAsync<Func>(std::move(Handler), Args...);
1556 : }
1557 :
1558 1052 : private:
1559 24 : RPCClass &Endpoint;
1560 72 : };
1561 2 :
1562 2 : /// Construct an asynchronous dispatcher from an RPC endpoint and a Func.
1563 24 : template <typename Func, typename RPCEndpointT>
1564 843 : RPCAsyncDispatch<RPCEndpointT, Func> rpcAsyncDispatch(RPCEndpointT &Endpoint) {
1565 : return RPCAsyncDispatch<RPCEndpointT, Func>(Endpoint);
1566 0 : }
1567 24 :
1568 24 : /// Allows a set of asynchrounous calls to be dispatched, and then
1569 24 : /// waited on as a group.
1570 : class ParallelCallGroup {
1571 502 : public:
1572 :
1573 2 : ParallelCallGroup() = default;
1574 : ParallelCallGroup(const ParallelCallGroup &) = delete;
1575 : ParallelCallGroup &operator=(const ParallelCallGroup &) = delete;
1576 2 :
1577 : /// Make as asynchronous call.
1578 201 : template <typename AsyncDispatcher, typename HandlerT, typename... ArgTs>
1579 : Error call(const AsyncDispatcher &AsyncDispatch, HandlerT Handler,
1580 : const ArgTs &... Args) {
1581 2 : // Increment the count of outstanding calls. This has to happen before
1582 : // we invoke the call, as the handler may (depending on scheduling)
1583 : // be run immediately on another thread, and we don't want the decrement
1584 : // in the wrapped handler below to run before the increment.
1585 0 : {
1586 : std::unique_lock<std::mutex> Lock(M);
1587 205 : ++NumOutstandingCalls;
1588 201 : }
1589 :
1590 : // Wrap the user handler in a lambda that will decrement the
1591 : // outstanding calls count, then poke the condition variable.
1592 0 : using ArgType = typename detail::ResponseHandlerArg<
1593 4 : typename detail::HandlerTraits<HandlerT>::Type>::ArgType;
1594 0 : // FIXME: Move handler into wrapped handler once we have C++14.
1595 0 : auto WrappedHandler = [this, Handler](ArgType Arg) {
1596 : auto Err = Handler(std::move(Arg));
1597 33 : std::unique_lock<std::mutex> Lock(M);
1598 : --NumOutstandingCalls;
1599 201 : CV.notify_all();
1600 2 : return Err;
1601 0 : };
1602 201 :
1603 : return AsyncDispatch(std::move(WrappedHandler), Args...);
1604 0 : }
1605 :
1606 0 : /// Blocks until all calls have been completed and their return value
1607 201 : /// handlers run.
1608 0 : void wait() {
1609 0 : std::unique_lock<std::mutex> Lock(M);
1610 0 : while (NumOutstandingCalls > 0)
1611 0 : CV.wait(Lock);
1612 0 : }
1613 402 :
1614 0 : private:
1615 : std::mutex M;
1616 0 : std::condition_variable CV;
1617 0 : uint32_t NumOutstandingCalls = 0;
1618 36 : };
1619 438 :
1620 36 : /// Convenience class for grouping RPC Functions into APIs that can be
1621 36 : /// negotiated as a block.
1622 : ///
1623 : template <typename... Funcs>
1624 : class APICalls {
1625 : public:
1626 201 :
1627 : /// Test whether this API contains Function F.
1628 0 : template <typename F>
1629 : class Contains {
1630 : public:
1631 0 : static const bool value = false;
1632 : };
1633 0 :
1634 : /// Negotiate all functions in this API.
1635 : template <typename RPCEndpoint>
1636 0 : static Error negotiate(RPCEndpoint &R) {
1637 : return Error::success();
1638 : }
1639 : };
1640 0 :
1641 : template <typename Func, typename... Funcs>
1642 0 : class APICalls<Func, Funcs...> {
1643 0 : public:
1644 :
1645 : template <typename F>
1646 : class Contains {
1647 : public:
1648 0 : static const bool value = std::is_same<F, Func>::value |
1649 0 : APICalls<Funcs...>::template Contains<F>::value;
1650 0 : };
1651 :
1652 : template <typename RPCEndpoint>
1653 : static Error negotiate(RPCEndpoint &R) {
1654 0 : if (auto Err = R.template negotiateFunction<Func>())
1655 0 : return Err;
1656 : return APICalls<Funcs...>::negotiate(R);
1657 0 : }
1658 :
1659 : };
1660 :
1661 0 : template <typename... InnerFuncs, typename... Funcs>
1662 24 : class APICalls<APICalls<InnerFuncs...>, Funcs...> {
1663 : public:
1664 0 :
1665 : template <typename F>
1666 : class Contains {
1667 : public:
1668 0 : static const bool value =
1669 0 : APICalls<InnerFuncs...>::template Contains<F>::value |
1670 : APICalls<Funcs...>::template Contains<F>::value;
1671 24 : };
1672 24 :
1673 : template <typename RPCEndpoint>
1674 0 : static Error negotiate(RPCEndpoint &R) {
1675 0 : if (auto Err = APICalls<InnerFuncs...>::negotiate(R))
1676 0 : return Err;
1677 : return APICalls<Funcs...>::negotiate(R);
1678 : }
1679 :
1680 : };
1681 0 :
1682 : } // end namespace rpc
1683 24 : } // end namespace orc
1684 : } // end namespace llvm
1685 :
1686 24 : #endif
|