18 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
19 #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
36 #pragma warning(disable : 4530)
37 #pragma warning(disable : 4062)
50 template <
typename DerivedFunc,
typename FnT>
class Function;
55 template <
typename DerivedFunc,
typename RetT,
typename... ArgTs>
59 using Type = RetT(ArgTs...);
66 std::lock_guard<std::mutex>
Lock(NameMutex);
75 static std::mutex NameMutex;
76 static std::string
Name;
79 template <
typename DerivedFunc,
typename RetT,
typename... ArgTs>
80 std::mutex
Function<DerivedFunc, RetT(ArgTs...)>::NameMutex;
82 template <
typename DerivedFunc,
typename RetT,
typename... ArgTs>
88 template <
typename RetT,
typename... ArgTs>
91 using Type = std::tuple<
typename std::decay<
92 typename std::remove_reference<ArgTs>::type>::type...>;
116 template <
typename T>
118 T, typename std::enable_if<std::is_integral<T>::value>::type> {
124 template <
typename Func>
T allocate() {
return NextId++; }
136 namespace msvc_hacks {
142 class MSVCPError :
public Error {
144 MSVCPError() { (void)!!*
this; }
148 MSVCPError &operator=(MSVCPError
Other) {
153 MSVCPError(
Error Err) :
Error(std::move(Err)) {}
157 template <
typename T>
class MSVCPExpected :
public Expected<T> {
166 MSVCPExpected &operator=(MSVCPExpected &&
Other) {
173 template <
typename OtherT>
176 typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
180 template <
class OtherT>
183 typename std::enable_if<std::is_convertible<OtherT, T>::value>::type * =
187 template <
class OtherT>
188 explicit MSVCPExpected(
190 typename std::enable_if<!std::is_convertible<OtherT, T>::value>::type * =
274 template <
typename RetT>
279 template <
typename WireRetT,
typename HandlerRetT,
typename ChannelT,
280 typename FunctionIdT,
typename SequenceNumberT>
290 if (
auto Err = C.startSendMessage(ResponseId, SeqNo))
300 return C.endSendMessage();
305 template <
typename WireRetT,
typename ChannelT,
typename FunctionIdT,
306 typename SequenceNumberT>
308 SequenceNumberT SeqNo,
Error Err) {
311 if (
auto Err2 = C.startSendMessage(ResponseId, SeqNo))
313 return C.endSendMessage();
346 template <
typename HandlerT>
348 &std::remove_reference<HandlerT>::type::operator())> {
352 template <
typename RetT,
typename... ArgTs>
365 template <
typename HandlerT>
368 return unpackAndRunHelper(Handler, Args,
373 template <
typename HandlerT>
374 static typename std::enable_if<
378 Handler(std::move(
Args)...);
382 template <
typename HandlerT>
383 static typename std::enable_if<
387 return Handler(std::move(
Args)...);
391 template <
typename ChannelT,
typename... CArgTs>
397 template <
typename ChannelT,
typename... CArgTs>
399 return deserializeArgsHelper(C, Args,
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)...);
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))...);
421 template <
typename Class,
typename RetT,
typename... ArgTs>
427 template <
typename Class,
typename RetT,
typename... ArgTs>
440 template <
typename ArgT>
479 template <
typename ChannelT,
typename FuncRetT,
typename HandlerT>
489 UnwrappedArgType Result;
492 UnwrappedArgType>::deserialize(C, Result))
494 if (
auto Err = C.endReceiveMessage())
496 return Handler(Result);
513 template <
typename ChannelT,
typename HandlerT>
523 if (
auto Err = C.endReceiveMessage())
542 template <
typename ChannelT,
typename FuncRetT,
typename HandlerT>
544 return llvm::make_unique<ResponseHandlerImpl<ChannelT, FuncRetT, HandlerT>>(
550 template <
typename ClassT,
typename RetT,
typename... ArgTs>
555 : Instance(Instance), Method(Method) {}
557 return (Instance.*Method)(std::move(Args)...);
571 template <
typename ArgT,
typename... ArgTs>
575 :
ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
578 this->Arg = std::move(ArgVal);
591 std::lock_guard<std::mutex>
Lock(SeqNoLock);
592 NextSequenceNumber = 0;
593 FreeSequenceNumbers.clear();
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;
609 std::lock_guard<std::mutex>
Lock(SeqNoLock);
610 FreeSequenceNumbers.push_back(SequenceNumber);
614 std::mutex SeqNoLock;
615 SequenceNumberT NextSequenceNumber = 0;
616 std::vector<SequenceNumberT> FreeSequenceNumbers;
621 template <
template <
class,
class>
class P,
typename T1Tuple,
typename T2Tuple>
624 template <
template <
class,
class>
class P>
627 static const bool value =
true;
630 template <
template <
class,
class>
class P,
typename T,
typename... Ts,
631 typename U,
typename... Us>
634 static const bool value =
639 template <
template <
class,
class>
class P,
typename T1Sig,
typename T2Sig>
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");
655 template <
typename ChannelT,
typename WireT,
typename ConcreteT>
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 &>())),
668 template <
typename>
static std::false_type check(...);
674 template <
typename ChannelT,
typename WireT,
typename ConcreteT>
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 &>())),
687 template <
typename>
static std::false_type check(...);
703 template <
typename ImplT,
typename ChannelT,
typename FunctionIdT,
704 typename SequenceNumberT>
709 static const char *
getName() {
return "__orc_rpc$invalid"; }
714 static const char *
getName() {
return "__orc_rpc$response"; }
718 :
public Function<OrcRPCNegotiate, FunctionIdT(std::string)> {
720 static const char *
getName() {
return "__orc_rpc$negotiate"; }
725 template <
typename WireT,
typename ConcreteT>
730 static_assert(
value,
"Missing serializer for argument (Can't serialize the "
731 "first template type argument of CanSerializeCheck "
737 template <
typename WireT,
typename ConcreteT>
743 static_assert(
value,
"Missing deserializer for argument (Can't deserialize "
744 "the second template type argument of "
745 "CanDeserializeCheck from the first)");
751 : C(C), LazyAutoNegotiation(LazyAutoNegotiation) {
760 Handlers[NegotiateId] = wrapHandler<OrcRPCNegotiate>(
770 template <
typename Func,
typename HandlerT,
typename... ArgTs>
775 void(ArgTs...)>::value,
780 if (
auto FnIdOrErr = getRemoteFunctionId<Func>())
788 return FnIdOrErr.takeError();
791 SequenceNumberT SeqNo;
799 "Sequence number already allocated");
803 detail::createResponseHandler<ChannelT, typename Func::ReturnType>(
808 if (
auto Err = C.startSendMessage(FnId, SeqNo)) {
810 return joinErrors(std::move(Err), C.endSendMessage());
817 return joinErrors(std::move(Err), C.endSendMessage());
821 if (
auto Err = C.endSendMessage()) {
823 return std::move(Err);
831 template <
typename Func,
typename HandlerT,
typename... ArgTs>
833 if (
auto Err = appendCallAsync<Func>(std::move(Handler), Args...))
841 SequenceNumberT SeqNo;
842 if (
auto Err = C.startReceiveMessage(FnId, SeqNo))
848 return I->second(C, SeqNo);
867 template <
typename... ArgTs>
885 KV.second->abandon();
886 PendingResponses.clear();
901 template <
typename Func,
typename HandlerT>
909 FunctionIdT NewFnId =
FnIdAllocator.template allocate<Func>();
912 wrapHandler<Func>(std::move(Handler), std::move(Launch));
925 PRHandler = std::move(
I->second);
937 "If we didn't find a response handler we should have bailed out");
939 if (
auto Err = PRHandler->handleResponse(C)) {
966 auto &Impl =
static_cast<ImplT &
>(*this);
967 if (
auto RemoteIdOrErr =
968 Impl.template callB<OrcRPCNegotiate>(Func::getPrototype())) {
969 auto &RemoteId = *RemoteIdOrErr;
982 return RemoteIdOrErr.takeError();
995 template <
typename Func,
typename HandlerT>
997 return [
this, Handler, Launch](ChannelT &Channel,
998 SequenceNumberT SeqNo)
mutable ->
Error {
1000 auto Args = std::make_shared<
1013 if (
auto Err = Channel.endReceiveMessage())
1017 auto Responder = [
this, Handler,
Args, &Channel,
1018 SeqNo]()
mutable ->
Error {
1021 return detail::respond<FuncReturn>(
1022 Channel,
ResponseId, SeqNo, HTraits::unpackAndRun(Handler, *Args));
1028 return Launch(std::move(Responder));
1049 std::map<SequenceNumberT, std::unique_ptr<detail::ResponseHandler<ChannelT>>>
1055 template <
typename ChannelT,
typename FunctionIdT =
uint32_t,
1056 typename SequenceNumberT =
uint32_t>
1059 MultiThreadedRPCEndpoint<ChannelT, FunctionIdT, SequenceNumberT>,
1060 ChannelT, FunctionIdT, SequenceNumberT> {
1065 ChannelT, FunctionIdT, SequenceNumberT>;
1092 template <
typename Func,
typename HandlerT>
1094 return this->
template addHandlerImpl<Func>(std::move(Handler),
1099 template <
typename Func,
typename ClassT,
typename RetT,
typename... ArgTs>
1100 void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...),
1109 using OrcRPCNegotiate =
typename BaseClass::OrcRPCNegotiate;
1115 if (
I->second != this->getInvalidFunctionId())
1124 if (
auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype())) {
1130 return RemoteIdOrErr.takeError();
1134 template <
typename Func>
1145 template <
typename Func,
typename... ArgTs>
1148 using ErrorReturn =
typename RTraits::ErrorReturnType;
1149 using ErrorReturnPromise =
typename RTraits::ReturnPromiseType;
1153 auto Promise = std::make_shared<ErrorReturnPromise>();
1154 auto FutureResult = Promise->get_future();
1156 if (
auto Err = this->
template appendCallAsync<Func>(
1157 [Promise](ErrorReturn RetOrErr) {
1158 Promise->set_value(std::move(RetOrErr));
1163 RTraits::consumeAbandoned(FutureResult.get());
1164 return std::move(Err);
1166 return std::move(FutureResult);
1171 template <
typename Func,
typename... ArgTs>
1173 auto Result = appendCallNB<Func>(Args...);
1176 if (
auto Err = this->C.send()) {
1179 std::move(Result->get()));
1180 return std::move(Err);
1190 template <
typename Func,
typename... ArgTs,
1194 if (
auto FutureResOrErr = callNB<Func>(Args...)) {
1195 if (
auto Err = this->C.send()) {
1198 std::move(FutureResOrErr->get()));
1199 return std::move(Err);
1201 return FutureResOrErr->get();
1203 return FutureResOrErr.takeError();
1215 template <
typename ChannelT,
typename FunctionIdT =
uint32_t,
1216 typename SequenceNumberT =
uint32_t>
1219 SingleThreadedRPCEndpoint<ChannelT, FunctionIdT, SequenceNumberT>,
1220 ChannelT, FunctionIdT, SequenceNumberT> {
1225 ChannelT, FunctionIdT, SequenceNumberT>;
1233 template <
typename Func,
typename HandlerT>
1235 return this->
template addHandlerImpl<Func>(std::move(Handler),
1239 template <
typename Func,
typename ClassT,
typename RetT,
typename... ArgTs>
1240 void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
1247 using OrcRPCNegotiate =
typename BaseClass::OrcRPCNegotiate;
1253 if (
I->second != this->getInvalidFunctionId())
1262 if (
auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype())) {
1268 return RemoteIdOrErr.takeError();
1271 template <
typename Func,
typename... ArgTs,
1275 bool ReceivedResponse =
false;
1283 if (
auto Err = this->
template appendCallAsync<Func>(
1285 Result = std::move(R);
1286 ReceivedResponse =
true;
1293 return std::move(Err);
1296 while (!ReceivedResponse) {
1301 return std::move(Err);
1325 template <
typename Func,
typename HandlerT,
typename... ArgTs>
1332 std::unique_lock<std::mutex>
Lock(M);
1333 ++NumOutstandingCalls;
1341 auto WrappedHandler = [
this, Handler](ArgType Arg) {
1342 auto Err = Handler(std::move(Arg));
1343 std::unique_lock<std::mutex>
Lock(M);
1344 --NumOutstandingCalls;
1349 return RPC.template appendCallAsync<Func>(std::move(WrappedHandler),
1358 template <
typename Func,
typename HandlerT,
typename... ArgTs>
1360 if (
auto Err =
appendCall(std::move(Handler), Args...))
1362 return RPC.sendAppendedCalls();
1368 if (
auto Err = RPC.sendAppendedCalls())
1370 std::unique_lock<std::mutex>
Lock(M);
1371 while (NumOutstandingCalls > 0)
1379 std::condition_variable CV;
1386 template <
typename... Funcs>
1391 template <
typename F>
1398 template <
typename RPCEndpo
int>
1404 template <
typename Func,
typename... Funcs>
1408 template <
typename F>
1411 static const bool value = std::is_same<F, Func>::value |
1412 APICalls<Funcs...>::template Contains<F>::value;
1415 template <
typename RPCEndpo
int>
1417 if (
auto Err = R.template negotiateFunction<Func>())
1424 template <
typename... InnerFuncs,
typename... Funcs>
1428 template <
typename F>
1432 APICalls<InnerFuncs...>::template Contains<F>::value |
1433 APICalls<Funcs...>::template Contains<F>::value;
1436 template <
typename RPCEndpo
int>
void addHandlerImpl(HandlerT Handler, LaunchPolicy Launch)
Add the given handler to the handler map and make it available for autonegotiation and execution...
std::promise< ErrorReturnType > ReturnPromiseType
MultiThreadedRPCEndpoint(ChannelT &C, bool LazyAutoNegotiation)
ParallelCallGroup(RPCClass &RPC)
Construct a parallel call group for the given RPC.
Expected< NonBlockingCallResult< Func > > callNB(const ArgTs &...Args)
The same as appendCallNBWithSeq, except that it calls C.send() to flush the channel after serializing...
void releaseSequenceNumber(SequenceNumberT SequenceNumber)
FunctionIdT handleNegotiate(const std::string &Name)
static T getNegotiateId()
Expected< NonBlockingCallResult< Func > > appendCallNB(const ArgTs &...Args)
Call Func on Channel C.
Error sendAppendedCalls()
static ErrorReturnType createBlankErrorReturnValue()
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
void addHandler(HandlerT Handler)
std::map< FunctionIdT, WrappedHandlerFn > Handlers
RetT operator()(ArgTs &&...Args)
SequenceNumberT getSequenceNumber()
std::future< ErrorReturnType > ReturnFutureType
Subclass of Error for the sole purpose of identifying the success path in the type system...
ResponseHandlerImpl(HandlerT Handler)
static Error respond(ChannelT &C, const FunctionIdT &ResponseId, SequenceNumberT SeqNo, Expected< HandlerRetT > ResultOrErr)
ParallelCallGroup & operator=(const ParallelCallGroup &)=delete
static void consumeAbandoned(ErrorReturnType Err)
static Error negotiate(RPCEndpoint &R)
static Error serializeArgs(ChannelT &C, const CArgTs...CArgs)
Allows a set of asynchrounous calls to be dispatched, and then waited on as a group.
FunctionIdT getInvalidFunctionId() const
typename FunctionArgsTuple< RetT(ArgTs...)>::Type ArgStorage
Error takeError()
Take ownership of the stored error.
virtual Error handleResponse(ChannelT &C)=0
Error handlerLoop()
Handle incoming RPC calls.
Error negotiateFunction(bool Retry=false)
Negotiate a function id for Func with the other end of the channel.
static std::enable_if< !std::is_void< typename HandlerTraits< HandlerT >::ReturnType >::value, typename HandlerTraits< HandlerT >::ReturnType >::type run(HandlerT &Handler, ArgTs...Args)
static Error negotiate(RPCEndpoint &R)
Negotiate all functions in this API.
typename BaseClass::LaunchPolicy LaunchPolicy
The LaunchPolicy type allows a launch policy to be specified when adding a function handler...
void abandonPendingResponses()
Abandon all outstanding result handlers.
typename FunctionArgsTuple< T2Sig >::Type T2Tuple
RetT(ClassT::*)(ArgTs...) MethodT
std::promise< ErrorReturnType > ReturnPromiseType
static ErrorReturnType createBlankErrorReturnValue()
static StringRef getName(Value *V)
MemberFnWrapper(ClassT &Instance, MethodT Method)
Tagged union holding either a T or a Error.
Alias for the common case of a sequence of size_ts.
static Error deserializeArgs(ChannelT &C, std::tuple< CArgTs...> &Args)
Error appendCall(HandlerT Handler, const ArgTs &...Args)
Make as asynchronous call.
**static detail::ReadArgs< ArgTs...> readArgs(ArgTs &...Args)
Helper for handling setter procedures - this method returns a functor that sets the variables referre...
Error negotiateFunction(bool Retry=false)
Negotiate a function id for Func with the other end of the channel.
ResponseHandlerImpl(HandlerT Handler)
Error handleOne()
Handle one incoming call.
Error handleResponse(ChannelT &C) override
Error operator()(ArgT &ArgVal, ArgTs &...ArgVals)
Expected< RetT > ErrorReturnType
Error callAsync(HandlerT Handler, const ArgTs &...Args)
RetT(ArgTs...) Type
User defined function type.
static const char * getName()
The SerializationTraits<ChannelT, T> class describes how to serialize and deserialize an instance of ...
WrappedHandlerFn wrapHandler(HandlerT Handler, LaunchPolicy Launch)
Error handleResponse(SequenceNumberT SeqNo)
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
std::function< Error(ChannelT &, SequenceNumberT)> WrappedHandlerFn
The instances of the Type class are immutable: once they are created, they are never changed...
Provides a typedef for a tuple containing the decayed argument types.
std::unique_ptr< ResponseHandler< ChannelT > > createResponseHandler(HandlerT H)
Allocates RPC function ids during autonegotiation.
detail::ResultTraits< AltRetT >::ErrorReturnType callB(const ArgTs &...Args)
Call Func on Channel C.
std::map< std::string, FunctionIdT > LocalFunctionIds
RetT ReturnType
Return type.
void consumeError(Error Err)
Consume a Error without doing anything.
static const char * getName()
void addHandler(ClassT &Object, RetT(ClassT::*Method)(ArgTs...), LaunchPolicy Launch=LaunchPolicy())
Add a class-method as a handler.
static const char * getName()
static std::enable_if< std::is_void< typename HandlerTraits< HandlerT >::ReturnType >::value, Error >::type run(HandlerT &Handler, ArgTs &&...Args)
static Error createAbandonedResponseError()
static ErrorSuccess success()
Create a success value.
static void consumeAbandoned(ErrorReturnType RetOrErr)
virtual ~ResponseHandler()
Creates a compile-time integer sequence for a parameter pack.
void addHandler(HandlerT Handler, LaunchPolicy Launch=LaunchPolicy())
Add a handler for the given RPC function.
Contains primitive utilities for defining, calling and handling calls to remote procedures.
ReadArgs(ArgT &Arg, ArgTs &...Args)
std::mutex ResponsesMutex
std::map< const char *, FunctionIdT > RemoteFunctionIds
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.
RPCEndpointBase(ChannelT &C, bool LazyAutoNegotiation)
Construct an RPC instance on a channel.
detail::SequenceNumberManager< SequenceNumberT > SequenceNumberMgr
Error joinErrors(Error E1, Error E2)
Concatenate errors.
std::future< ErrorReturnType > ReturnFutureType
std::tuple< typename std::decay< typename std::remove_reference< ArgTs >::type >::type...> Type
Expected< FunctionIdT > getRemoteFunctionId()
Error & operator=(const Error &Other)=delete
TypeNameSequence is a utility for rendering sequences of types to a string by rendering each type...
static Error negotiate(RPCEndpoint &R)
Error wait()
Blocks until all calls have been completed and their return value handlers run.
static const char * getPrototype()
Returns the full function prototype as a string.
static WrappedHandlerReturn< RetT >::Type unpackAndRun(HandlerT &Handler, ArgStorage &Args)
std::function< Error(std::function< Error()>)> LaunchPolicy
Utility class for serializing sequences of values of varying types.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Error handleResponse(ChannelT &C) override
A raw_ostream that writes to an std::string.
Lightweight error class with error context and mandatory checking.
void addHandler(ClassT &Object, RetT(ClassT::*Method)(ArgTs...))
typename detail::ResultTraits< typename Func::ReturnType >::ReturnFutureType NonBlockingCallResult
Return type for non-blocking call primitives.
Error orcError(OrcErrorCode ErrCode)
std::map< SequenceNumberT, std::unique_ptr< detail::ResponseHandler< ChannelT > > > PendingResponses
detail::ResultTraits< AltRetT >::ErrorReturnType callB(const ArgTs &...Args)
Error appendCallAsync(HandlerT Handler, const ArgTs &...Args)
Append a call Func, does not call send on the channel.
Convenience class for grouping RPC Functions into APIs that can be negotiated as a block...
SingleThreadedRPCEndpoint(ChannelT &C, bool LazyAutoNegotiation)
typename FunctionArgsTuple< T1Sig >::Type T1Tuple
Error call(HandlerT Handler, const ArgTs &...Args)
Make an asynchronous call.
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
RPCFunctionIdAllocator< FunctionIdT > FnIdAllocator