LLVM  4.0.0
RPCUtils.h
Go to the documentation of this file.
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"
28 
29 #ifdef _MSC_VER
30 // concrt.h depends on eh.h for __uncaught_exception declaration
31 // even if we disable exceptions.
32 #include <eh.h>
33 
34 // Disable warnings from ppltasks.h transitively included by <future>.
35 #pragma warning(push)
36 #pragma warning(disable : 4530)
37 #pragma warning(disable : 4062)
38 #endif
39 
40 #include <future>
41 
42 #ifdef _MSC_VER
43 #pragma warning(pop)
44 #endif
45 
46 namespace llvm {
47 namespace orc {
48 namespace rpc {
49 
50 template <typename DerivedFunc, typename FnT> class Function;
51 
52 // RPC Function class.
53 // DerivedFunc should be a user defined class with a static 'getName()' method
54 // returning a const char* representing the function's name.
55 template <typename DerivedFunc, typename RetT, typename... ArgTs>
56 class Function<DerivedFunc, RetT(ArgTs...)> {
57 public:
58  /// User defined function type.
59  using Type = RetT(ArgTs...);
60 
61  /// Return type.
62  using ReturnType = RetT;
63 
64  /// Returns the full function prototype as a string.
65  static const char *getPrototype() {
66  std::lock_guard<std::mutex> Lock(NameMutex);
67  if (Name.empty())
70  << "(" << llvm::orc::rpc::RPCTypeNameSequence<ArgTs...>() << ")";
71  return Name.data();
72  }
73 
74 private:
75  static std::mutex NameMutex;
76  static std::string Name;
77 };
78 
79 template <typename DerivedFunc, typename RetT, typename... ArgTs>
80 std::mutex Function<DerivedFunc, RetT(ArgTs...)>::NameMutex;
81 
82 template <typename DerivedFunc, typename RetT, typename... ArgTs>
83 std::string Function<DerivedFunc, RetT(ArgTs...)>::Name;
84 
85 /// Provides a typedef for a tuple containing the decayed argument types.
86 template <typename T> class FunctionArgsTuple;
87 
88 template <typename RetT, typename... ArgTs>
89 class FunctionArgsTuple<RetT(ArgTs...)> {
90 public:
91  using Type = std::tuple<typename std::decay<
92  typename std::remove_reference<ArgTs>::type>::type...>;
93 };
94 
95 /// Allocates RPC function ids during autonegotiation.
96 /// Specializations of this class must provide four members:
97 ///
98 /// static T getInvalidId():
99 /// Should return a reserved id that will be used to represent missing
100 /// functions during autonegotiation.
101 ///
102 /// static T getResponseId():
103 /// Should return a reserved id that will be used to send function responses
104 /// (return values).
105 ///
106 /// static T getNegotiateId():
107 /// Should return a reserved id for the negotiate function, which will be used
108 /// to negotiate ids for user defined functions.
109 ///
110 /// template <typename Func> T allocate():
111 /// Allocate a unique id for function Func.
112 template <typename T, typename = void> class RPCFunctionIdAllocator;
113 
114 /// This specialization of RPCFunctionIdAllocator provides a default
115 /// implementation for integral types.
116 template <typename T>
118  T, typename std::enable_if<std::is_integral<T>::value>::type> {
119 public:
120  static T getInvalidId() { return T(0); }
121  static T getResponseId() { return T(1); }
122  static T getNegotiateId() { return T(2); }
123 
124  template <typename Func> T allocate() { return NextId++; }
125 
126 private:
127  T NextId = 3;
128 };
129 
130 namespace detail {
131 
132 // FIXME: Remove MSVCPError/MSVCPExpected once MSVC's future implementation
133 // supports classes without default constructors.
134 #ifdef _MSC_VER
135 
136 namespace msvc_hacks {
137 
138 // Work around MSVC's future implementation's use of default constructors:
139 // A default constructed value in the promise will be overwritten when the
140 // real error is set - so the default constructed Error has to be checked
141 // already.
142 class MSVCPError : public Error {
143 public:
144  MSVCPError() { (void)!!*this; }
145 
146  MSVCPError(MSVCPError &&Other) : Error(std::move(Other)) {}
147 
148  MSVCPError &operator=(MSVCPError Other) {
149  Error::operator=(std::move(Other));
150  return *this;
151  }
152 
153  MSVCPError(Error Err) : Error(std::move(Err)) {}
154 };
155 
156 // Work around MSVC's future implementation, similar to MSVCPError.
157 template <typename T> class MSVCPExpected : public Expected<T> {
158 public:
159  MSVCPExpected()
160  : Expected<T>(make_error<StringError>("", inconvertibleErrorCode())) {
161  consumeError(this->takeError());
162  }
163 
164  MSVCPExpected(MSVCPExpected &&Other) : Expected<T>(std::move(Other)) {}
165 
166  MSVCPExpected &operator=(MSVCPExpected &&Other) {
167  Expected<T>::operator=(std::move(Other));
168  return *this;
169  }
170 
171  MSVCPExpected(Error Err) : Expected<T>(std::move(Err)) {}
172 
173  template <typename OtherT>
174  MSVCPExpected(
175  OtherT &&Val,
176  typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
177  nullptr)
178  : Expected<T>(std::move(Val)) {}
179 
180  template <class OtherT>
181  MSVCPExpected(
183  typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
184  nullptr)
185  : Expected<T>(std::move(Other)) {}
186 
187  template <class OtherT>
188  explicit MSVCPExpected(
190  typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
191  nullptr)
192  : Expected<T>(std::move(Other)) {}
193 };
194 
195 } // end namespace msvc_hacks
196 
197 #endif // _MSC_VER
198 
199 // ResultTraits provides typedefs and utilities specific to the return type
200 // of functions.
201 template <typename RetT> class ResultTraits {
202 public:
203  // The return type wrapped in llvm::Expected.
205 
206 #ifdef _MSC_VER
207  // The ErrorReturnType wrapped in a std::promise.
208  using ReturnPromiseType = std::promise<msvc_hacks::MSVCPExpected<RetT>>;
209 
210  // The ErrorReturnType wrapped in a std::future.
211  using ReturnFutureType = std::future<msvc_hacks::MSVCPExpected<RetT>>;
212 #else
213  // The ErrorReturnType wrapped in a std::promise.
214  using ReturnPromiseType = std::promise<ErrorReturnType>;
215 
216  // The ErrorReturnType wrapped in a std::future.
217  using ReturnFutureType = std::future<ErrorReturnType>;
218 #endif
219 
220  // Create a 'blank' value of the ErrorReturnType, ready and safe to
221  // overwrite.
223  return ErrorReturnType(RetT());
224  }
225 
226  // Consume an abandoned ErrorReturnType.
227  static void consumeAbandoned(ErrorReturnType RetOrErr) {
228  consumeError(RetOrErr.takeError());
229  }
230 };
231 
232 // ResultTraits specialization for void functions.
233 template <> class ResultTraits<void> {
234 public:
235  // For void functions, ErrorReturnType is llvm::Error.
237 
238 #ifdef _MSC_VER
239  // The ErrorReturnType wrapped in a std::promise.
240  using ReturnPromiseType = std::promise<msvc_hacks::MSVCPError>;
241 
242  // The ErrorReturnType wrapped in a std::future.
243  using ReturnFutureType = std::future<msvc_hacks::MSVCPError>;
244 #else
245  // The ErrorReturnType wrapped in a std::promise.
246  using ReturnPromiseType = std::promise<ErrorReturnType>;
247 
248  // The ErrorReturnType wrapped in a std::future.
249  using ReturnFutureType = std::future<ErrorReturnType>;
250 #endif
251 
252  // Create a 'blank' value of the ErrorReturnType, ready and safe to
253  // overwrite.
255  return ErrorReturnType::success();
256  }
257 
258  // Consume an abandoned ErrorReturnType.
260  consumeError(std::move(Err));
261  }
262 };
263 
264 // ResultTraits<Error> is equivalent to ResultTraits<void>. This allows
265 // handlers for void RPC functions to return either void (in which case they
266 // implicitly succeed) or Error (in which case their error return is
267 // propagated). See usage in HandlerTraits::runHandlerHelper.
268 template <> class ResultTraits<Error> : public ResultTraits<void> {};
269 
270 // ResultTraits<Expected<T>> is equivalent to ResultTraits<T>. This allows
271 // handlers for RPC functions returning a T to return either a T (in which
272 // case they implicitly succeed) or Expected<T> (in which case their error
273 // return is propagated). See usage in HandlerTraits::runHandlerHelper.
274 template <typename RetT>
275 class ResultTraits<Expected<RetT>> : public ResultTraits<RetT> {};
276 
277 // Send a response of the given wire return type (WireRetT) over the
278 // channel, with the given sequence number.
279 template <typename WireRetT, typename HandlerRetT, typename ChannelT,
280  typename FunctionIdT, typename SequenceNumberT>
281 static Error respond(ChannelT &C, const FunctionIdT &ResponseId,
282  SequenceNumberT SeqNo, Expected<HandlerRetT> ResultOrErr) {
283  // If this was an error bail out.
284  // FIXME: Send an "error" message to the client if this is not a channel
285  // failure?
286  if (auto Err = ResultOrErr.takeError())
287  return Err;
288 
289  // Open the response message.
290  if (auto Err = C.startSendMessage(ResponseId, SeqNo))
291  return Err;
292 
293  // Serialize the result.
294  if (auto Err =
296  C, *ResultOrErr))
297  return Err;
298 
299  // Close the response message.
300  return C.endSendMessage();
301 }
302 
303 // Send an empty response message on the given channel to indicate that
304 // the handler ran.
305 template <typename WireRetT, typename ChannelT, typename FunctionIdT,
306  typename SequenceNumberT>
307 static Error respond(ChannelT &C, const FunctionIdT &ResponseId,
308  SequenceNumberT SeqNo, Error Err) {
309  if (Err)
310  return Err;
311  if (auto Err2 = C.startSendMessage(ResponseId, SeqNo))
312  return Err2;
313  return C.endSendMessage();
314 }
315 
316 // Converts a given type to the equivalent error return type.
317 template <typename T> class WrappedHandlerReturn {
318 public:
319  using Type = Expected<T>;
320 };
321 
322 template <typename T> class WrappedHandlerReturn<Expected<T>> {
323 public:
324  using Type = Expected<T>;
325 };
326 
327 template <> class WrappedHandlerReturn<void> {
328 public:
329  using Type = Error;
330 };
331 
332 template <> class WrappedHandlerReturn<Error> {
333 public:
334  using Type = Error;
335 };
336 
337 template <> class WrappedHandlerReturn<ErrorSuccess> {
338 public:
339  using Type = Error;
340 };
341 
342 // This template class provides utilities related to RPC function handlers.
343 // The base case applies to non-function types (the template class is
344 // specialized for function types) and inherits from the appropriate
345 // speciilization for the given non-function type's call operator.
346 template <typename HandlerT>
347 class HandlerTraits : public HandlerTraits<decltype(
348  &std::remove_reference<HandlerT>::type::operator())> {
349 };
350 
351 // Traits for handlers with a given function type.
352 template <typename RetT, typename... ArgTs>
353 class HandlerTraits<RetT(ArgTs...)> {
354 public:
355  // Function type of the handler.
356  using Type = RetT(ArgTs...);
357 
358  // Return type of the handler.
359  using ReturnType = RetT;
360 
361  // A std::tuple wrapping the handler arguments.
362  using ArgStorage = typename FunctionArgsTuple<RetT(ArgTs...)>::Type;
363 
364  // Call the given handler with the given arguments.
365  template <typename HandlerT>
366  static typename WrappedHandlerReturn<RetT>::Type
367  unpackAndRun(HandlerT &Handler, ArgStorage &Args) {
368  return unpackAndRunHelper(Handler, Args,
370  }
371 
372  // Call the given handler with the given arguments.
373  template <typename HandlerT>
374  static typename std::enable_if<
376  Error>::type
377  run(HandlerT &Handler, ArgTs &&... Args) {
378  Handler(std::move(Args)...);
379  return Error::success();
380  }
381 
382  template <typename HandlerT>
383  static typename std::enable_if<
386  run(HandlerT &Handler, ArgTs... Args) {
387  return Handler(std::move(Args)...);
388  }
389 
390  // Serialize arguments to the channel.
391  template <typename ChannelT, typename... CArgTs>
392  static Error serializeArgs(ChannelT &C, const CArgTs... CArgs) {
394  }
395 
396  // Deserialize arguments from the channel.
397  template <typename ChannelT, typename... CArgTs>
398  static Error deserializeArgs(ChannelT &C, std::tuple<CArgTs...> &Args) {
399  return deserializeArgsHelper(C, Args,
401  }
402 
403 private:
404  template <typename ChannelT, typename... CArgTs, size_t... Indexes>
405  static Error deserializeArgsHelper(ChannelT &C, std::tuple<CArgTs...> &Args,
408  C, std::get<Indexes>(Args)...);
409  }
410 
411  template <typename HandlerT, size_t... Indexes>
412  static typename WrappedHandlerReturn<
414  unpackAndRunHelper(HandlerT &Handler, ArgStorage &Args,
416  return run(Handler, std::move(std::get<Indexes>(Args))...);
417  }
418 };
419 
420 // Handler traits for class methods (especially call operators for lambdas).
421 template <typename Class, typename RetT, typename... ArgTs>
422 class HandlerTraits<RetT (Class::*)(ArgTs...)>
423  : public HandlerTraits<RetT(ArgTs...)> {};
424 
425 // Handler traits for const class methods (especially call operators for
426 // lambdas).
427 template <typename Class, typename RetT, typename... ArgTs>
428 class HandlerTraits<RetT (Class::*)(ArgTs...) const>
429  : public HandlerTraits<RetT(ArgTs...)> {};
430 
431 // Utility to peel the Expected wrapper off a response handler error type.
432 template <typename HandlerT> class ResponseHandlerArg;
433 
434 template <typename ArgT> class ResponseHandlerArg<Error(Expected<ArgT>)> {
435 public:
437  using UnwrappedArgType = ArgT;
438 };
439 
440 template <typename ArgT>
442 public:
444  using UnwrappedArgType = ArgT;
445 };
446 
447 template <> class ResponseHandlerArg<Error(Error)> {
448 public:
449  using ArgType = Error;
450 };
451 
452 template <> class ResponseHandlerArg<ErrorSuccess(Error)> {
453 public:
454  using ArgType = Error;
455 };
456 
457 // ResponseHandler represents a handler for a not-yet-received function call
458 // result.
459 template <typename ChannelT> class ResponseHandler {
460 public:
461  virtual ~ResponseHandler() {}
462 
463  // Reads the function result off the wire and acts on it. The meaning of
464  // "act" will depend on how this method is implemented in any given
465  // ResponseHandler subclass but could, for example, mean running a
466  // user-specified handler or setting a promise value.
467  virtual Error handleResponse(ChannelT &C) = 0;
468 
469  // Abandons this outstanding result.
470  virtual void abandon() = 0;
471 
472  // Create an error instance representing an abandoned response.
475  }
476 };
477 
478 // ResponseHandler subclass for RPC functions with non-void returns.
479 template <typename ChannelT, typename FuncRetT, typename HandlerT>
480 class ResponseHandlerImpl : public ResponseHandler<ChannelT> {
481 public:
482  ResponseHandlerImpl(HandlerT Handler) : Handler(std::move(Handler)) {}
483 
484  // Handle the result by deserializing it from the channel then passing it
485  // to the user defined handler.
486  Error handleResponse(ChannelT &C) override {
487  using UnwrappedArgType = typename ResponseHandlerArg<
488  typename HandlerTraits<HandlerT>::Type>::UnwrappedArgType;
489  UnwrappedArgType Result;
490  if (auto Err =
491  SerializationTraits<ChannelT, FuncRetT,
492  UnwrappedArgType>::deserialize(C, Result))
493  return Err;
494  if (auto Err = C.endReceiveMessage())
495  return Err;
496  return Handler(Result);
497  }
498 
499  // Abandon this response by calling the handler with an 'abandoned response'
500  // error.
501  void abandon() override {
502  if (auto Err = Handler(this->createAbandonedResponseError())) {
503  // Handlers should not fail when passed an abandoned response error.
504  report_fatal_error(std::move(Err));
505  }
506  }
507 
508 private:
509  HandlerT Handler;
510 };
511 
512 // ResponseHandler subclass for RPC functions with void returns.
513 template <typename ChannelT, typename HandlerT>
514 class ResponseHandlerImpl<ChannelT, void, HandlerT>
515  : public ResponseHandler<ChannelT> {
516 public:
517  ResponseHandlerImpl(HandlerT Handler) : Handler(std::move(Handler)) {}
518 
519  // Handle the result (no actual value, just a notification that the function
520  // has completed on the remote end) by calling the user-defined handler with
521  // Error::success().
522  Error handleResponse(ChannelT &C) override {
523  if (auto Err = C.endReceiveMessage())
524  return Err;
525  return Handler(Error::success());
526  }
527 
528  // Abandon this response by calling the handler with an 'abandoned response'
529  // error.
530  void abandon() override {
531  if (auto Err = Handler(this->createAbandonedResponseError())) {
532  // Handlers should not fail when passed an abandoned response error.
533  report_fatal_error(std::move(Err));
534  }
535  }
536 
537 private:
538  HandlerT Handler;
539 };
540 
541 // Create a ResponseHandler from a given user handler.
542 template <typename ChannelT, typename FuncRetT, typename HandlerT>
543 std::unique_ptr<ResponseHandler<ChannelT>> createResponseHandler(HandlerT H) {
544  return llvm::make_unique<ResponseHandlerImpl<ChannelT, FuncRetT, HandlerT>>(
545  std::move(H));
546 }
547 
548 // Helper for wrapping member functions up as functors. This is useful for
549 // installing methods as result handlers.
550 template <typename ClassT, typename RetT, typename... ArgTs>
552 public:
553  using MethodT = RetT (ClassT::*)(ArgTs...);
554  MemberFnWrapper(ClassT &Instance, MethodT Method)
555  : Instance(Instance), Method(Method) {}
556  RetT operator()(ArgTs &&... Args) {
557  return (Instance.*Method)(std::move(Args)...);
558  }
559 
560 private:
561  ClassT &Instance;
562  MethodT Method;
563 };
564 
565 // Helper that provides a Functor for deserializing arguments.
566 template <typename... ArgTs> class ReadArgs {
567 public:
569 };
570 
571 template <typename ArgT, typename... ArgTs>
572 class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
573 public:
574  ReadArgs(ArgT &Arg, ArgTs &... Args)
575  : ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
576 
577  Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
578  this->Arg = std::move(ArgVal);
579  return ReadArgs<ArgTs...>::operator()(ArgVals...);
580  }
581 
582 private:
583  ArgT &Arg;
584 };
585 
586 // Manage sequence numbers.
587 template <typename SequenceNumberT> class SequenceNumberManager {
588 public:
589  // Reset, making all sequence numbers available.
590  void reset() {
591  std::lock_guard<std::mutex> Lock(SeqNoLock);
592  NextSequenceNumber = 0;
593  FreeSequenceNumbers.clear();
594  }
595 
596  // Get the next available sequence number. Will re-use numbers that have
597  // been released.
598  SequenceNumberT getSequenceNumber() {
599  std::lock_guard<std::mutex> Lock(SeqNoLock);
600  if (FreeSequenceNumbers.empty())
601  return NextSequenceNumber++;
602  auto SequenceNumber = FreeSequenceNumbers.back();
603  FreeSequenceNumbers.pop_back();
604  return SequenceNumber;
605  }
606 
607  // Release a sequence number, making it available for re-use.
608  void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
609  std::lock_guard<std::mutex> Lock(SeqNoLock);
610  FreeSequenceNumbers.push_back(SequenceNumber);
611  }
612 
613 private:
614  std::mutex SeqNoLock;
615  SequenceNumberT NextSequenceNumber = 0;
616  std::vector<SequenceNumberT> FreeSequenceNumbers;
617 };
618 
619 // Checks that predicate P holds for each corresponding pair of type arguments
620 // from T1 and T2 tuple.
621 template <template <class, class> class P, typename T1Tuple, typename T2Tuple>
623 
624 template <template <class, class> class P>
625 class RPCArgTypeCheckHelper<P, std::tuple<>, std::tuple<>> {
626 public:
627  static const bool value = true;
628 };
629 
630 template <template <class, class> class P, typename T, typename... Ts,
631  typename U, typename... Us>
632 class RPCArgTypeCheckHelper<P, std::tuple<T, Ts...>, std::tuple<U, Us...>> {
633 public:
634  static const bool value =
635  P<T, U>::value &&
636  RPCArgTypeCheckHelper<P, std::tuple<Ts...>, std::tuple<Us...>>::value;
637 };
638 
639 template <template <class, class> class P, typename T1Sig, typename T2Sig>
641 public:
644 
645  static_assert(std::tuple_size<T1Tuple>::value >=
646  std::tuple_size<T2Tuple>::value,
647  "Too many arguments to RPC call");
648  static_assert(std::tuple_size<T1Tuple>::value <=
649  std::tuple_size<T2Tuple>::value,
650  "Too few arguments to RPC call");
651 
653 };
654 
655 template <typename ChannelT, typename WireT, typename ConcreteT>
657 private:
659 
660  template <typename T>
661  static std::true_type
662  check(typename std::enable_if<
663  std::is_same<decltype(T::serialize(std::declval<ChannelT &>(),
664  std::declval<const ConcreteT &>())),
665  Error>::value,
666  void *>::type);
667 
668  template <typename> static std::false_type check(...);
669 
670 public:
671  static const bool value = decltype(check<S>(0))::value;
672 };
673 
674 template <typename ChannelT, typename WireT, typename ConcreteT>
676 private:
678 
679  template <typename T>
680  static std::true_type
681  check(typename std::enable_if<
682  std::is_same<decltype(T::deserialize(std::declval<ChannelT &>(),
683  std::declval<ConcreteT &>())),
684  Error>::value,
685  void *>::type);
686 
687  template <typename> static std::false_type check(...);
688 
689 public:
690  static const bool value = decltype(check<S>(0))::value;
691 };
692 
693 /// Contains primitive utilities for defining, calling and handling calls to
694 /// remote procedures. ChannelT is a bidirectional stream conforming to the
695 /// RPCChannel interface (see RPCChannel.h), FunctionIdT is a procedure
696 /// identifier type that must be serializable on ChannelT, and SequenceNumberT
697 /// is an integral type that will be used to number in-flight function calls.
698 ///
699 /// These utilities support the construction of very primitive RPC utilities.
700 /// Their intent is to ensure correct serialization and deserialization of
701 /// procedure arguments, and to keep the client and server's view of the API in
702 /// sync.
703 template <typename ImplT, typename ChannelT, typename FunctionIdT,
704  typename SequenceNumberT>
706 protected:
707  class OrcRPCInvalid : public Function<OrcRPCInvalid, void()> {
708  public:
709  static const char *getName() { return "__orc_rpc$invalid"; }
710  };
711 
712  class OrcRPCResponse : public Function<OrcRPCResponse, void()> {
713  public:
714  static const char *getName() { return "__orc_rpc$response"; }
715  };
716 
718  : public Function<OrcRPCNegotiate, FunctionIdT(std::string)> {
719  public:
720  static const char *getName() { return "__orc_rpc$negotiate"; }
721  };
722 
723  // Helper predicate for testing for the presence of SerializeTraits
724  // serializers.
725  template <typename WireT, typename ConcreteT>
726  class CanSerializeCheck : detail::CanSerialize<ChannelT, WireT, ConcreteT> {
727  public:
729 
730  static_assert(value, "Missing serializer for argument (Can't serialize the "
731  "first template type argument of CanSerializeCheck "
732  "from the second)");
733  };
734 
735  // Helper predicate for testing for the presence of SerializeTraits
736  // deserializers.
737  template <typename WireT, typename ConcreteT>
739  : detail::CanDeserialize<ChannelT, WireT, ConcreteT> {
740  public:
742 
743  static_assert(value, "Missing deserializer for argument (Can't deserialize "
744  "the second template type argument of "
745  "CanDeserializeCheck from the first)");
746  };
747 
748 public:
749  /// Construct an RPC instance on a channel.
751  : C(C), LazyAutoNegotiation(LazyAutoNegotiation) {
752  // Hold ResponseId in a special variable, since we expect Response to be
753  // called relatively frequently, and want to avoid the map lookup.
754  ResponseId = FnIdAllocator.getResponseId();
755  RemoteFunctionIds[OrcRPCResponse::getPrototype()] = ResponseId;
756 
757  // Register the negotiate function id and handler.
758  auto NegotiateId = FnIdAllocator.getNegotiateId();
759  RemoteFunctionIds[OrcRPCNegotiate::getPrototype()] = NegotiateId;
760  Handlers[NegotiateId] = wrapHandler<OrcRPCNegotiate>(
761  [this](const std::string &Name) { return handleNegotiate(Name); },
762  LaunchPolicy());
763  }
764 
765  /// Append a call Func, does not call send on the channel.
766  /// The first argument specifies a user-defined handler to be run when the
767  /// function returns. The handler should take an Expected<Func::ReturnType>,
768  /// or an Error (if Func::ReturnType is void). The handler will be called
769  /// with an error if the return value is abandoned due to a channel error.
770  template <typename Func, typename HandlerT, typename... ArgTs>
771  Error appendCallAsync(HandlerT Handler, const ArgTs &... Args) {
772 
773  static_assert(
774  detail::RPCArgTypeCheck<CanSerializeCheck, typename Func::Type,
775  void(ArgTs...)>::value,
776  "");
777 
778  // Look up the function ID.
779  FunctionIdT FnId;
780  if (auto FnIdOrErr = getRemoteFunctionId<Func>())
781  FnId = *FnIdOrErr;
782  else {
783  // This isn't a channel error so we don't want to abandon other pending
784  // responses, but we still need to run the user handler with an error to
785  // let them know the call failed.
786  if (auto Err = Handler(orcError(OrcErrorCode::UnknownRPCFunction)))
787  report_fatal_error(std::move(Err));
788  return FnIdOrErr.takeError();
789  }
790 
791  SequenceNumberT SeqNo; // initialized in locked scope below.
792  {
793  // Lock the pending responses map and sequence number manager.
794  std::lock_guard<std::mutex> Lock(ResponsesMutex);
795 
796  // Allocate a sequence number.
797  SeqNo = SequenceNumberMgr.getSequenceNumber();
798  assert(!PendingResponses.count(SeqNo) &&
799  "Sequence number already allocated");
800 
801  // Install the user handler.
802  PendingResponses[SeqNo] =
803  detail::createResponseHandler<ChannelT, typename Func::ReturnType>(
804  std::move(Handler));
805  }
806 
807  // Open the function call message.
808  if (auto Err = C.startSendMessage(FnId, SeqNo)) {
810  return joinErrors(std::move(Err), C.endSendMessage());
811  }
812 
813  // Serialize the call arguments.
815  C, Args...)) {
817  return joinErrors(std::move(Err), C.endSendMessage());
818  }
819 
820  // Close the function call messagee.
821  if (auto Err = C.endSendMessage()) {
823  return std::move(Err);
824  }
825 
826  return Error::success();
827  }
828 
829  Error sendAppendedCalls() { return C.send(); };
830 
831  template <typename Func, typename HandlerT, typename... ArgTs>
832  Error callAsync(HandlerT Handler, const ArgTs &... Args) {
833  if (auto Err = appendCallAsync<Func>(std::move(Handler), Args...))
834  return Err;
835  return C.send();
836  }
837 
838  /// Handle one incoming call.
840  FunctionIdT FnId;
841  SequenceNumberT SeqNo;
842  if (auto Err = C.startReceiveMessage(FnId, SeqNo))
843  return Err;
844  if (FnId == ResponseId)
845  return handleResponse(SeqNo);
846  auto I = Handlers.find(FnId);
847  if (I != Handlers.end())
848  return I->second(C, SeqNo);
849 
850  // else: No handler found. Report error to client?
852  }
853 
854  /// Helper for handling setter procedures - this method returns a functor that
855  /// sets the variables referred to by Args... to values deserialized from the
856  /// channel.
857  /// E.g.
858  ///
859  /// typedef Function<0, bool, int> Func1;
860  ///
861  /// ...
862  /// bool B;
863  /// int I;
864  /// if (auto Err = expect<Func1>(Channel, readArgs(B, I)))
865  /// /* Handle Args */ ;
866  ///
867  template <typename... ArgTs>
868  static detail::ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
869  return detail::ReadArgs<ArgTs...>(Args...);
870  }
871 
872  /// Abandon all outstanding result handlers.
873  ///
874  /// This will call all currently registered result handlers to receive an
875  /// "abandoned" error as their argument. This is used internally by the RPC
876  /// in error situations, but can also be called directly by clients who are
877  /// disconnecting from the remote and don't or can't expect responses to their
878  /// outstanding calls. (Especially for outstanding blocking calls, calling
879  /// this function may be necessary to avoid dead threads).
881  // Lock the pending responses map and sequence number manager.
882  std::lock_guard<std::mutex> Lock(ResponsesMutex);
883 
884  for (auto &KV : PendingResponses)
885  KV.second->abandon();
886  PendingResponses.clear();
887  SequenceNumberMgr.reset();
888  }
889 
890 protected:
891  // The LaunchPolicy type allows a launch policy to be specified when adding
892  // a function handler. See addHandlerImpl.
893  using LaunchPolicy = std::function<Error(std::function<Error()>)>;
894 
895  FunctionIdT getInvalidFunctionId() const {
896  return FnIdAllocator.getInvalidId();
897  }
898 
899  /// Add the given handler to the handler map and make it available for
900  /// autonegotiation and execution.
901  template <typename Func, typename HandlerT>
902  void addHandlerImpl(HandlerT Handler, LaunchPolicy Launch) {
903 
904  static_assert(detail::RPCArgTypeCheck<
905  CanDeserializeCheck, typename Func::Type,
906  typename detail::HandlerTraits<HandlerT>::Type>::value,
907  "");
908 
909  FunctionIdT NewFnId = FnIdAllocator.template allocate<Func>();
910  LocalFunctionIds[Func::getPrototype()] = NewFnId;
911  Handlers[NewFnId] =
912  wrapHandler<Func>(std::move(Handler), std::move(Launch));
913  }
914 
915  Error handleResponse(SequenceNumberT SeqNo) {
916  using Handler = typename decltype(PendingResponses)::mapped_type;
917  Handler PRHandler;
918 
919  {
920  // Lock the pending responses map and sequence number manager.
921  std::unique_lock<std::mutex> Lock(ResponsesMutex);
922  auto I = PendingResponses.find(SeqNo);
923 
924  if (I != PendingResponses.end()) {
925  PRHandler = std::move(I->second);
926  PendingResponses.erase(I);
927  SequenceNumberMgr.releaseSequenceNumber(SeqNo);
928  } else {
929  // Unlock the pending results map to prevent recursive lock.
930  Lock.unlock();
933  }
934  }
935 
936  assert(PRHandler &&
937  "If we didn't find a response handler we should have bailed out");
938 
939  if (auto Err = PRHandler->handleResponse(C)) {
941  return Err;
942  }
943 
944  return Error::success();
945  }
946 
947  FunctionIdT handleNegotiate(const std::string &Name) {
948  auto I = LocalFunctionIds.find(Name);
949  if (I == LocalFunctionIds.end())
950  return getInvalidFunctionId();
951  return I->second;
952  }
953 
954  // Find the remote FunctionId for the given function, which must be in the
955  // RemoteFunctionIds map.
956  template <typename Func> Expected<FunctionIdT> getRemoteFunctionId() {
957  // Try to find the id for the given function.
958  auto I = RemoteFunctionIds.find(Func::getPrototype());
959 
960  // If we have it in the map, return it.
961  if (I != RemoteFunctionIds.end())
962  return I->second;
963 
964  // Otherwise, if we have auto-negotiation enabled, try to negotiate it.
966  auto &Impl = static_cast<ImplT &>(*this);
967  if (auto RemoteIdOrErr =
968  Impl.template callB<OrcRPCNegotiate>(Func::getPrototype())) {
969  auto &RemoteId = *RemoteIdOrErr;
970 
971  // If autonegotiation indicates that the remote end doesn't support this
972  // function, return an unknown function error.
973  if (RemoteId == getInvalidFunctionId())
975 
976  // Autonegotiation succeeded and returned a valid id. Update the map and
977  // return the id.
978  RemoteFunctionIds[Func::getPrototype()] = RemoteId;
979  return RemoteId;
980  } else {
981  // Autonegotiation failed. Return the error.
982  return RemoteIdOrErr.takeError();
983  }
984  }
985 
986  // No key was available in the map and autonegotiation wasn't enabled.
987  // Return an unknown function error.
989  }
990 
991  using WrappedHandlerFn = std::function<Error(ChannelT &, SequenceNumberT)>;
992 
993  // Wrap the given user handler in the necessary argument-deserialization code,
994  // result-serialization code, and call to the launch policy (if present).
995  template <typename Func, typename HandlerT>
996  WrappedHandlerFn wrapHandler(HandlerT Handler, LaunchPolicy Launch) {
997  return [this, Handler, Launch](ChannelT &Channel,
998  SequenceNumberT SeqNo) mutable -> Error {
999  // Start by deserializing the arguments.
1000  auto Args = std::make_shared<
1002  if (auto Err =
1004  Channel, *Args))
1005  return Err;
1006 
1007  // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
1008  // for RPCArgs. Void cast RPCArgs to work around this for now.
1009  // FIXME: Remove this workaround once we can assume a working GCC version.
1010  (void)Args;
1011 
1012  // End receieve message, unlocking the channel for reading.
1013  if (auto Err = Channel.endReceiveMessage())
1014  return Err;
1015 
1016  // Build the handler/responder.
1017  auto Responder = [this, Handler, Args, &Channel,
1018  SeqNo]() mutable -> Error {
1019  using HTraits = detail::HandlerTraits<HandlerT>;
1020  using FuncReturn = typename Func::ReturnType;
1021  return detail::respond<FuncReturn>(
1022  Channel, ResponseId, SeqNo, HTraits::unpackAndRun(Handler, *Args));
1023  };
1024 
1025  // If there is an explicit launch policy then use it to launch the
1026  // handler.
1027  if (Launch)
1028  return Launch(std::move(Responder));
1029 
1030  // Otherwise run the handler on the listener thread.
1031  return Responder();
1032  };
1033  }
1034 
1035  ChannelT &C;
1036 
1038 
1040 
1041  FunctionIdT ResponseId;
1042  std::map<std::string, FunctionIdT> LocalFunctionIds;
1043  std::map<const char *, FunctionIdT> RemoteFunctionIds;
1044 
1045  std::map<FunctionIdT, WrappedHandlerFn> Handlers;
1046 
1047  std::mutex ResponsesMutex;
1049  std::map<SequenceNumberT, std::unique_ptr<detail::ResponseHandler<ChannelT>>>
1051 };
1052 
1053 } // end namespace detail
1054 
1055 template <typename ChannelT, typename FunctionIdT = uint32_t,
1056  typename SequenceNumberT = uint32_t>
1058  : public detail::RPCEndpointBase<
1059  MultiThreadedRPCEndpoint<ChannelT, FunctionIdT, SequenceNumberT>,
1060  ChannelT, FunctionIdT, SequenceNumberT> {
1061 private:
1062  using BaseClass =
1065  ChannelT, FunctionIdT, SequenceNumberT>;
1066 
1067 public:
1069  : BaseClass(C, LazyAutoNegotiation) {}
1070 
1071  /// The LaunchPolicy type allows a launch policy to be specified when adding
1072  /// a function handler. See addHandler.
1074 
1075  /// Add a handler for the given RPC function.
1076  /// This installs the given handler functor for the given RPC Function, and
1077  /// makes the RPC function available for negotiation/calling from the remote.
1078  ///
1079  /// The optional LaunchPolicy argument can be used to control how the handler
1080  /// is run when called:
1081  ///
1082  /// * If no LaunchPolicy is given, the handler code will be run on the RPC
1083  /// handler thread that is reading from the channel. This handler cannot
1084  /// make blocking RPC calls (since it would be blocking the thread used to
1085  /// get the result), but can make non-blocking calls.
1086  ///
1087  /// * If a LaunchPolicy is given, the user's handler will be wrapped in a
1088  /// call to serialize and send the result, and the resulting functor (with
1089  /// type 'Error()' will be passed to the LaunchPolicy. The user can then
1090  /// choose to add the wrapped handler to a work queue, spawn a new thread,
1091  /// or anything else.
1092  template <typename Func, typename HandlerT>
1093  void addHandler(HandlerT Handler, LaunchPolicy Launch = LaunchPolicy()) {
1094  return this->template addHandlerImpl<Func>(std::move(Handler),
1095  std::move(Launch));
1096  }
1097 
1098  /// Add a class-method as a handler.
1099  template <typename Func, typename ClassT, typename RetT, typename... ArgTs>
1100  void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...),
1101  LaunchPolicy Launch = LaunchPolicy()) {
1102  addHandler<Func>(
1103  detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method),
1104  Launch);
1105  }
1106 
1107  /// Negotiate a function id for Func with the other end of the channel.
1108  template <typename Func> Error negotiateFunction(bool Retry = false) {
1109  using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
1110 
1111  // Check if we already have a function id...
1112  auto I = this->RemoteFunctionIds.find(Func::getPrototype());
1113  if (I != this->RemoteFunctionIds.end()) {
1114  // If it's valid there's nothing left to do.
1115  if (I->second != this->getInvalidFunctionId())
1116  return Error::success();
1117  // If it's invalid and we can't re-attempt negotiation, throw an error.
1118  if (!Retry)
1120  }
1121 
1122  // We don't have a function id for Func yet, call the remote to try to
1123  // negotiate one.
1124  if (auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype())) {
1125  this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
1126  if (*RemoteIdOrErr == this->getInvalidFunctionId())
1128  return Error::success();
1129  } else
1130  return RemoteIdOrErr.takeError();
1131  }
1132 
1133  /// Return type for non-blocking call primitives.
1134  template <typename Func>
1136  typename Func::ReturnType>::ReturnFutureType;
1137 
1138  /// Call Func on Channel C. Does not block, does not call send. Returns a pair
1139  /// of a future result and the sequence number assigned to the result.
1140  ///
1141  /// This utility function is primarily used for single-threaded mode support,
1142  /// where the sequence number can be used to wait for the corresponding
1143  /// result. In multi-threaded mode the appendCallNB method, which does not
1144  /// return the sequence numeber, should be preferred.
1145  template <typename Func, typename... ArgTs>
1148  using ErrorReturn = typename RTraits::ErrorReturnType;
1149  using ErrorReturnPromise = typename RTraits::ReturnPromiseType;
1150 
1151  // FIXME: Stack allocate and move this into the handler once LLVM builds
1152  // with C++14.
1153  auto Promise = std::make_shared<ErrorReturnPromise>();
1154  auto FutureResult = Promise->get_future();
1155 
1156  if (auto Err = this->template appendCallAsync<Func>(
1157  [Promise](ErrorReturn RetOrErr) {
1158  Promise->set_value(std::move(RetOrErr));
1159  return Error::success();
1160  },
1161  Args...)) {
1162  this->abandonPendingResponses();
1163  RTraits::consumeAbandoned(FutureResult.get());
1164  return std::move(Err);
1165  }
1166  return std::move(FutureResult);
1167  }
1168 
1169  /// The same as appendCallNBWithSeq, except that it calls C.send() to
1170  /// flush the channel after serializing the call.
1171  template <typename Func, typename... ArgTs>
1173  auto Result = appendCallNB<Func>(Args...);
1174  if (!Result)
1175  return Result;
1176  if (auto Err = this->C.send()) {
1177  this->abandonPendingResponses();
1179  std::move(Result->get()));
1180  return std::move(Err);
1181  }
1182  return Result;
1183  }
1184 
1185  /// Call Func on Channel C. Blocks waiting for a result. Returns an Error
1186  /// for void functions or an Expected<T> for functions returning a T.
1187  ///
1188  /// This function is for use in threaded code where another thread is
1189  /// handling responses and incoming calls.
1190  template <typename Func, typename... ArgTs,
1191  typename AltRetT = typename Func::ReturnType>
1193  callB(const ArgTs &... Args) {
1194  if (auto FutureResOrErr = callNB<Func>(Args...)) {
1195  if (auto Err = this->C.send()) {
1196  this->abandonPendingResponses();
1198  std::move(FutureResOrErr->get()));
1199  return std::move(Err);
1200  }
1201  return FutureResOrErr->get();
1202  } else
1203  return FutureResOrErr.takeError();
1204  }
1205 
1206  /// Handle incoming RPC calls.
1208  while (true)
1209  if (auto Err = this->handleOne())
1210  return Err;
1211  return Error::success();
1212  }
1213 };
1214 
1215 template <typename ChannelT, typename FunctionIdT = uint32_t,
1216  typename SequenceNumberT = uint32_t>
1218  : public detail::RPCEndpointBase<
1219  SingleThreadedRPCEndpoint<ChannelT, FunctionIdT, SequenceNumberT>,
1220  ChannelT, FunctionIdT, SequenceNumberT> {
1221 private:
1222  using BaseClass =
1225  ChannelT, FunctionIdT, SequenceNumberT>;
1226 
1227  using LaunchPolicy = typename BaseClass::LaunchPolicy;
1228 
1229 public:
1231  : BaseClass(C, LazyAutoNegotiation) {}
1232 
1233  template <typename Func, typename HandlerT>
1234  void addHandler(HandlerT Handler) {
1235  return this->template addHandlerImpl<Func>(std::move(Handler),
1236  LaunchPolicy());
1237  }
1238 
1239  template <typename Func, typename ClassT, typename RetT, typename... ArgTs>
1240  void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
1241  addHandler<Func>(
1242  detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method));
1243  }
1244 
1245  /// Negotiate a function id for Func with the other end of the channel.
1246  template <typename Func> Error negotiateFunction(bool Retry = false) {
1247  using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
1248 
1249  // Check if we already have a function id...
1250  auto I = this->RemoteFunctionIds.find(Func::getPrototype());
1251  if (I != this->RemoteFunctionIds.end()) {
1252  // If it's valid there's nothing left to do.
1253  if (I->second != this->getInvalidFunctionId())
1254  return Error::success();
1255  // If it's invalid and we can't re-attempt negotiation, throw an error.
1256  if (!Retry)
1258  }
1259 
1260  // We don't have a function id for Func yet, call the remote to try to
1261  // negotiate one.
1262  if (auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype())) {
1263  this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
1264  if (*RemoteIdOrErr == this->getInvalidFunctionId())
1266  return Error::success();
1267  } else
1268  return RemoteIdOrErr.takeError();
1269  }
1270 
1271  template <typename Func, typename... ArgTs,
1272  typename AltRetT = typename Func::ReturnType>
1274  callB(const ArgTs &... Args) {
1275  bool ReceivedResponse = false;
1276  using ResultType = typename detail::ResultTraits<AltRetT>::ErrorReturnType;
1278 
1279  // We have to 'Check' result (which we know is in a success state at this
1280  // point) so that it can be overwritten in the async handler.
1281  (void)!!Result;
1282 
1283  if (auto Err = this->template appendCallAsync<Func>(
1284  [&](ResultType R) {
1285  Result = std::move(R);
1286  ReceivedResponse = true;
1287  return Error::success();
1288  },
1289  Args...)) {
1290  this->abandonPendingResponses();
1292  std::move(Result));
1293  return std::move(Err);
1294  }
1295 
1296  while (!ReceivedResponse) {
1297  if (auto Err = this->handleOne()) {
1298  this->abandonPendingResponses();
1300  std::move(Result));
1301  return std::move(Err);
1302  }
1303  }
1304 
1305  return Result;
1306  }
1307 };
1308 
1309 /// \brief Allows a set of asynchrounous calls to be dispatched, and then
1310 /// waited on as a group.
1311 template <typename RPCClass> class ParallelCallGroup {
1312 public:
1313 
1314  /// \brief Construct a parallel call group for the given RPC.
1315  ParallelCallGroup(RPCClass &RPC) : RPC(RPC), NumOutstandingCalls(0) {}
1316 
1317  ParallelCallGroup(const ParallelCallGroup &) = delete;
1318  ParallelCallGroup &operator=(const ParallelCallGroup &) = delete;
1319 
1320  /// \brief Make as asynchronous call.
1321  ///
1322  /// Does not issue a send call to the RPC's channel. The channel may use this
1323  /// to batch up subsequent calls. A send will automatically be sent when wait
1324  /// is called.
1325  template <typename Func, typename HandlerT, typename... ArgTs>
1326  Error appendCall(HandlerT Handler, const ArgTs &... Args) {
1327  // Increment the count of outstanding calls. This has to happen before
1328  // we invoke the call, as the handler may (depending on scheduling)
1329  // be run immediately on another thread, and we don't want the decrement
1330  // in the wrapped handler below to run before the increment.
1331  {
1332  std::unique_lock<std::mutex> Lock(M);
1333  ++NumOutstandingCalls;
1334  }
1335 
1336  // Wrap the user handler in a lambda that will decrement the
1337  // outstanding calls count, then poke the condition variable.
1338  using ArgType = typename detail::ResponseHandlerArg<
1339  typename detail::HandlerTraits<HandlerT>::Type>::ArgType;
1340  // FIXME: Move handler into wrapped handler once we have C++14.
1341  auto WrappedHandler = [this, Handler](ArgType Arg) {
1342  auto Err = Handler(std::move(Arg));
1343  std::unique_lock<std::mutex> Lock(M);
1344  --NumOutstandingCalls;
1345  CV.notify_all();
1346  return Err;
1347  };
1348 
1349  return RPC.template appendCallAsync<Func>(std::move(WrappedHandler),
1350  Args...);
1351  }
1352 
1353  /// \brief Make an asynchronous call.
1354  ///
1355  /// The same as appendCall, but also calls send on the channel immediately.
1356  /// Prefer appendCall if you are about to issue a "wait" call shortly, as
1357  /// this may allow the channel to better batch the calls.
1358  template <typename Func, typename HandlerT, typename... ArgTs>
1359  Error call(HandlerT Handler, const ArgTs &... Args) {
1360  if (auto Err = appendCall(std::move(Handler), Args...))
1361  return Err;
1362  return RPC.sendAppendedCalls();
1363  }
1364 
1365  /// \brief Blocks until all calls have been completed and their return value
1366  /// handlers run.
1368  if (auto Err = RPC.sendAppendedCalls())
1369  return Err;
1370  std::unique_lock<std::mutex> Lock(M);
1371  while (NumOutstandingCalls > 0)
1372  CV.wait(Lock);
1373  return Error::success();
1374  }
1375 
1376 private:
1377  RPCClass &RPC;
1378  std::mutex M;
1379  std::condition_variable CV;
1380  uint32_t NumOutstandingCalls;
1381 };
1382 
1383 /// @brief Convenience class for grouping RPC Functions into APIs that can be
1384 /// negotiated as a block.
1385 ///
1386 template <typename... Funcs>
1387 class APICalls {
1388 public:
1389 
1390  /// @brief Test whether this API contains Function F.
1391  template <typename F>
1392  class Contains {
1393  public:
1394  static const bool value = false;
1395  };
1396 
1397  /// @brief Negotiate all functions in this API.
1398  template <typename RPCEndpoint>
1399  static Error negotiate(RPCEndpoint &R) {
1400  return Error::success();
1401  }
1402 };
1403 
1404 template <typename Func, typename... Funcs>
1405 class APICalls<Func, Funcs...> {
1406 public:
1407 
1408  template <typename F>
1409  class Contains {
1410  public:
1411  static const bool value = std::is_same<F, Func>::value |
1412  APICalls<Funcs...>::template Contains<F>::value;
1413  };
1414 
1415  template <typename RPCEndpoint>
1416  static Error negotiate(RPCEndpoint &R) {
1417  if (auto Err = R.template negotiateFunction<Func>())
1418  return Err;
1420  }
1421 
1422 };
1423 
1424 template <typename... InnerFuncs, typename... Funcs>
1425 class APICalls<APICalls<InnerFuncs...>, Funcs...> {
1426 public:
1427 
1428  template <typename F>
1429  class Contains {
1430  public:
1431  static const bool value =
1432  APICalls<InnerFuncs...>::template Contains<F>::value |
1433  APICalls<Funcs...>::template Contains<F>::value;
1434  };
1435 
1436  template <typename RPCEndpoint>
1437  static Error negotiate(RPCEndpoint &R) {
1438  if (auto Err = APICalls<InnerFuncs...>::negotiate(R))
1439  return Err;
1441  }
1442 
1443 };
1444 
1445 } // end namespace rpc
1446 } // end namespace orc
1447 } // end namespace llvm
1448 
1449 #endif
void addHandlerImpl(HandlerT Handler, LaunchPolicy Launch)
Add the given handler to the handler map and make it available for autonegotiation and execution...
Definition: RPCUtils.h:902
std::promise< ErrorReturnType > ReturnPromiseType
Definition: RPCUtils.h:214
MultiThreadedRPCEndpoint(ChannelT &C, bool LazyAutoNegotiation)
Definition: RPCUtils.h:1068
ParallelCallGroup(RPCClass &RPC)
Construct a parallel call group for the given RPC.
Definition: RPCUtils.h:1315
Expected< NonBlockingCallResult< Func > > callNB(const ArgTs &...Args)
The same as appendCallNBWithSeq, except that it calls C.send() to flush the channel after serializing...
Definition: RPCUtils.h:1172
void releaseSequenceNumber(SequenceNumberT SequenceNumber)
Definition: RPCUtils.h:608
FunctionIdT handleNegotiate(const std::string &Name)
Definition: RPCUtils.h:947
Expected< NonBlockingCallResult< Func > > appendCallNB(const ArgTs &...Args)
Call Func on Channel C.
Definition: RPCUtils.h:1146
static ErrorReturnType createBlankErrorReturnValue()
Definition: RPCUtils.h:222
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
std::map< FunctionIdT, WrappedHandlerFn > Handlers
Definition: RPCUtils.h:1045
RetT operator()(ArgTs &&...Args)
Definition: RPCUtils.h:556
std::future< ErrorReturnType > ReturnFutureType
Definition: RPCUtils.h:217
Subclass of Error for the sole purpose of identifying the success path in the type system...
static Error respond(ChannelT &C, const FunctionIdT &ResponseId, SequenceNumberT SeqNo, Expected< HandlerRetT > ResultOrErr)
Definition: RPCUtils.h:281
ParallelCallGroup & operator=(const ParallelCallGroup &)=delete
static void consumeAbandoned(ErrorReturnType Err)
Definition: RPCUtils.h:259
static sys::Mutex Lock
static Error negotiate(RPCEndpoint &R)
Definition: RPCUtils.h:1416
static Error serializeArgs(ChannelT &C, const CArgTs...CArgs)
Definition: RPCUtils.h:392
Allows a set of asynchrounous calls to be dispatched, and then waited on as a group.
Definition: RPCUtils.h:1311
FunctionIdT getInvalidFunctionId() const
Definition: RPCUtils.h:895
typename FunctionArgsTuple< RetT(ArgTs...)>::Type ArgStorage
Definition: RPCUtils.h:362
Error takeError()
Take ownership of the stored error.
virtual Error handleResponse(ChannelT &C)=0
Error handlerLoop()
Handle incoming RPC calls.
Definition: RPCUtils.h:1207
Error negotiateFunction(bool Retry=false)
Negotiate a function id for Func with the other end of the channel.
Definition: RPCUtils.h:1246
static std::enable_if< !std::is_void< typename HandlerTraits< HandlerT >::ReturnType >::value, typename HandlerTraits< HandlerT >::ReturnType >::type run(HandlerT &Handler, ArgTs...Args)
Definition: RPCUtils.h:386
static Error negotiate(RPCEndpoint &R)
Negotiate all functions in this API.
Definition: RPCUtils.h:1399
typename BaseClass::LaunchPolicy LaunchPolicy
The LaunchPolicy type allows a launch policy to be specified when adding a function handler...
Definition: RPCUtils.h:1073
void abandonPendingResponses()
Abandon all outstanding result handlers.
Definition: RPCUtils.h:880
typename FunctionArgsTuple< T2Sig >::Type T2Tuple
Definition: RPCUtils.h:643
RetT(ClassT::*)(ArgTs...) MethodT
Definition: RPCUtils.h:553
std::promise< ErrorReturnType > ReturnPromiseType
Definition: RPCUtils.h:246
static ErrorReturnType createBlankErrorReturnValue()
Definition: RPCUtils.h:254
static StringRef getName(Value *V)
MemberFnWrapper(ClassT &Instance, MethodT Method)
Definition: RPCUtils.h:554
Tagged union holding either a T or a Error.
Alias for the common case of a sequence of size_ts.
Definition: STLExtras.h:354
static Error deserializeArgs(ChannelT &C, std::tuple< CArgTs...> &Args)
Definition: RPCUtils.h:398
ELFYAML::ELF_STO Other
Definition: ELFYAML.cpp:662
Error appendCall(HandlerT Handler, const ArgTs &...Args)
Make as asynchronous call.
Definition: RPCUtils.h:1326
**static detail::ReadArgs< ArgTs...> readArgs(ArgTs &...Args)
Helper for handling setter procedures - this method returns a functor that sets the variables referre...
Definition: RPCUtils.h:868
Error negotiateFunction(bool Retry=false)
Negotiate a function id for Func with the other end of the channel.
Definition: RPCUtils.h:1108
#define T
Error handleOne()
Handle one incoming call.
Definition: RPCUtils.h:839
Error handleResponse(ChannelT &C) override
Definition: RPCUtils.h:486
Error operator()(ArgT &ArgVal, ArgTs &...ArgVals)
Definition: RPCUtils.h:577
Error callAsync(HandlerT Handler, const ArgTs &...Args)
Definition: RPCUtils.h:832
RetT(ArgTs...) Type
User defined function type.
Definition: RPCUtils.h:59
#define P(N)
The SerializationTraits<ChannelT, T> class describes how to serialize and deserialize an instance of ...
WrappedHandlerFn wrapHandler(HandlerT Handler, LaunchPolicy Launch)
Definition: RPCUtils.h:996
Error handleResponse(SequenceNumberT SeqNo)
Definition: RPCUtils.h:915
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
Provides a typedef for a tuple containing the decayed argument types.
Definition: RPCUtils.h:86
#define H(x, y, z)
Definition: MD5.cpp:53
std::unique_ptr< ResponseHandler< ChannelT > > createResponseHandler(HandlerT H)
Definition: RPCUtils.h:543
Allocates RPC function ids during autonegotiation.
Definition: RPCUtils.h:112
detail::ResultTraits< AltRetT >::ErrorReturnType callB(const ArgTs &...Args)
Call Func on Channel C.
Definition: RPCUtils.h:1193
std::map< std::string, FunctionIdT > LocalFunctionIds
Definition: RPCUtils.h:1042
void consumeError(Error Err)
Consume a Error without doing anything.
void addHandler(ClassT &Object, RetT(ClassT::*Method)(ArgTs...), LaunchPolicy Launch=LaunchPolicy())
Add a class-method as a handler.
Definition: RPCUtils.h:1100
static std::enable_if< std::is_void< typename HandlerTraits< HandlerT >::ReturnType >::value, Error >::type run(HandlerT &Handler, ArgTs &&...Args)
Definition: RPCUtils.h:377
static ErrorSuccess success()
Create a success value.
static void consumeAbandoned(ErrorReturnType RetOrErr)
Definition: RPCUtils.h:227
Creates a compile-time integer sequence for a parameter pack.
Definition: STLExtras.h:356
void addHandler(HandlerT Handler, LaunchPolicy Launch=LaunchPolicy())
Add a handler for the given RPC function.
Definition: RPCUtils.h:1093
Contains primitive utilities for defining, calling and handling calls to remote procedures.
Definition: RPCUtils.h:705
std::map< const char *, FunctionIdT > RemoteFunctionIds
Definition: RPCUtils.h:1043
Expected & operator=(Expected &&Other)
Move-assign from another Expected<T>.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
Test whether this API contains Function F.
Definition: RPCUtils.h:1392
RPCEndpointBase(ChannelT &C, bool LazyAutoNegotiation)
Construct an RPC instance on a channel.
Definition: RPCUtils.h:750
detail::SequenceNumberManager< SequenceNumberT > SequenceNumberMgr
Definition: RPCUtils.h:1048
Error joinErrors(Error E1, Error E2)
Concatenate errors.
std::future< ErrorReturnType > ReturnFutureType
Definition: RPCUtils.h:249
#define I(x, y, z)
Definition: MD5.cpp:54
std::tuple< typename std::decay< typename std::remove_reference< ArgTs >::type >::type...> Type
Definition: RPCUtils.h:92
Expected< FunctionIdT > getRemoteFunctionId()
Definition: RPCUtils.h:956
Error & operator=(const Error &Other)=delete
TypeNameSequence is a utility for rendering sequences of types to a string by rendering each type...
Error wait()
Blocks until all calls have been completed and their return value handlers run.
Definition: RPCUtils.h:1367
static const char * getPrototype()
Returns the full function prototype as a string.
Definition: RPCUtils.h:65
static WrappedHandlerReturn< RetT >::Type unpackAndRun(HandlerT &Handler, ArgStorage &Args)
Definition: RPCUtils.h:367
std::function< Error(std::function< Error()>)> LaunchPolicy
Definition: RPCUtils.h:893
Utility class for serializing sequences of values of varying types.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:463
aarch64 promote const
Lightweight error class with error context and mandatory checking.
void addHandler(ClassT &Object, RetT(ClassT::*Method)(ArgTs...))
Definition: RPCUtils.h:1240
typename detail::ResultTraits< typename Func::ReturnType >::ReturnFutureType NonBlockingCallResult
Return type for non-blocking call primitives.
Definition: RPCUtils.h:1136
Error orcError(OrcErrorCode ErrCode)
Definition: OrcError.cpp:61
std::map< SequenceNumberT, std::unique_ptr< detail::ResponseHandler< ChannelT > > > PendingResponses
Definition: RPCUtils.h:1050
detail::ResultTraits< AltRetT >::ErrorReturnType callB(const ArgTs &...Args)
Definition: RPCUtils.h:1274
Error appendCallAsync(HandlerT Handler, const ArgTs &...Args)
Append a call Func, does not call send on the channel.
Definition: RPCUtils.h:771
Convenience class for grouping RPC Functions into APIs that can be negotiated as a block...
Definition: RPCUtils.h:1387
SingleThreadedRPCEndpoint(ChannelT &C, bool LazyAutoNegotiation)
Definition: RPCUtils.h:1230
typename FunctionArgsTuple< T1Sig >::Type T1Tuple
Definition: RPCUtils.h:642
Error call(HandlerT Handler, const ArgTs &...Args)
Make an asynchronous call.
Definition: RPCUtils.h:1359
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
RPCFunctionIdAllocator< FunctionIdT > FnIdAllocator
Definition: RPCUtils.h:1039