1 //===----- RPCUTils.h - Basic tilities 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 // Basic utilities for building RPC APIs. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H 15 #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H 16 17 #include <map> 18 #include <vector> 19 20 #include "llvm/ADT/Optional.h" 21 #include "llvm/ADT/STLExtras.h" 22 #include "llvm/ExecutionEngine/Orc/OrcError.h" 23 24 #ifdef _MSC_VER 25 // concrt.h depends on eh.h for __uncaught_exception declaration 26 // even if we disable exceptions. 27 #include <eh.h> 28 29 // Disable warnings from ppltasks.h transitively included by <future>. 30 #pragma warning(push) 31 #pragma warning(disable : 4530) 32 #pragma warning(disable : 4062) 33 #endif 34 35 #include <future> 36 37 #ifdef _MSC_VER 38 #pragma warning(pop) 39 #endif 40 41 namespace llvm { 42 namespace orc { 43 namespace remote { 44 45 /// Describes reserved RPC Function Ids. 46 /// 47 /// The default implementation will serve for integer and enum function id 48 /// types. If you want to use a custom type as your FunctionId you can 49 /// specialize this class and provide unique values for InvalidId, 50 /// ResponseId and FirstValidId. 51 52 template <typename T> class RPCFunctionIdTraits { 53 public: 54 static const T InvalidId = static_cast<T>(0); 55 static const T ResponseId = static_cast<T>(1); 56 static const T FirstValidId = static_cast<T>(2); 57 }; 58 59 // Base class containing utilities that require partial specialization. 60 // These cannot be included in RPC, as template class members cannot be 61 // partially specialized. 62 class RPCBase { 63 protected: 64 // RPC Function description type. 65 // 66 // This class provides the information and operations needed to support the 67 // RPC primitive operations (call, expect, etc) for a given function. It 68 // is specialized for void and non-void functions to deal with the differences 69 // betwen the two. Both specializations have the same interface: 70 // 71 // Id - The function's unique identifier. 72 // OptionalReturn - The return type for asyncronous calls. 73 // ErrorReturn - The return type for synchronous calls. 74 // optionalToErrorReturn - Conversion from a valid OptionalReturn to an 75 // ErrorReturn. 76 // readResult - Deserialize a result from a channel. 77 // abandon - Abandon a promised (asynchronous) result. 78 // respond - Retun a result on the channel. 79 template <typename FunctionIdT, FunctionIdT FuncId, typename FnT> 80 class FunctionHelper {}; 81 82 // RPC Function description specialization for non-void functions. 83 template <typename FunctionIdT, FunctionIdT FuncId, typename RetT, 84 typename... ArgTs> 85 class FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> { 86 public: 87 static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId && 88 FuncId != RPCFunctionIdTraits<FunctionIdT>::ResponseId, 89 "Cannot define custom function with InvalidId or ResponseId. " 90 "Please use RPCFunctionTraits<FunctionIdT>::FirstValidId."); 91 92 static const FunctionIdT Id = FuncId; 93 94 typedef Optional<RetT> OptionalReturn; 95 96 typedef Expected<RetT> ErrorReturn; 97 optionalToErrorReturn(OptionalReturn && V)98 static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) { 99 assert(V && "Return value not available"); 100 return std::move(*V); 101 } 102 103 template <typename ChannelT> readResult(ChannelT & C,std::promise<OptionalReturn> & P)104 static Error readResult(ChannelT &C, std::promise<OptionalReturn> &P) { 105 RetT Val; 106 auto Err = deserialize(C, Val); 107 auto Err2 = endReceiveMessage(C); 108 Err = joinErrors(std::move(Err), std::move(Err2)); 109 110 if (Err) { 111 P.set_value(OptionalReturn()); 112 return Err; 113 } 114 P.set_value(std::move(Val)); 115 return Error::success(); 116 } 117 abandon(std::promise<OptionalReturn> & P)118 static void abandon(std::promise<OptionalReturn> &P) { 119 P.set_value(OptionalReturn()); 120 } 121 122 template <typename ChannelT, typename SequenceNumberT> respond(ChannelT & C,SequenceNumberT SeqNo,ErrorReturn & Result)123 static Error respond(ChannelT &C, SequenceNumberT SeqNo, 124 ErrorReturn &Result) { 125 FunctionIdT ResponseId = RPCFunctionIdTraits<FunctionIdT>::ResponseId; 126 127 // If the handler returned an error then bail out with that. 128 if (!Result) 129 return Result.takeError(); 130 131 // Otherwise open a new message on the channel and send the result. 132 if (auto Err = startSendMessage(C)) 133 return Err; 134 if (auto Err = serializeSeq(C, ResponseId, SeqNo, *Result)) 135 return Err; 136 return endSendMessage(C); 137 } 138 }; 139 140 // RPC Function description specialization for void functions. 141 template <typename FunctionIdT, FunctionIdT FuncId, typename... ArgTs> 142 class FunctionHelper<FunctionIdT, FuncId, void(ArgTs...)> { 143 public: 144 static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId && 145 FuncId != RPCFunctionIdTraits<FunctionIdT>::ResponseId, 146 "Cannot define custom function with InvalidId or ResponseId. " 147 "Please use RPCFunctionTraits<FunctionIdT>::FirstValidId."); 148 149 static const FunctionIdT Id = FuncId; 150 151 typedef bool OptionalReturn; 152 typedef Error ErrorReturn; 153 optionalToErrorReturn(OptionalReturn && V)154 static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) { 155 assert(V && "Return value not available"); 156 return Error::success(); 157 } 158 159 template <typename ChannelT> readResult(ChannelT & C,std::promise<OptionalReturn> & P)160 static Error readResult(ChannelT &C, std::promise<OptionalReturn> &P) { 161 // Void functions don't have anything to deserialize, so we're good. 162 P.set_value(true); 163 return endReceiveMessage(C); 164 } 165 abandon(std::promise<OptionalReturn> & P)166 static void abandon(std::promise<OptionalReturn> &P) { P.set_value(false); } 167 168 template <typename ChannelT, typename SequenceNumberT> respond(ChannelT & C,SequenceNumberT SeqNo,ErrorReturn & Result)169 static Error respond(ChannelT &C, SequenceNumberT SeqNo, 170 ErrorReturn &Result) { 171 const FunctionIdT ResponseId = 172 RPCFunctionIdTraits<FunctionIdT>::ResponseId; 173 174 // If the handler returned an error then bail out with that. 175 if (Result) 176 return std::move(Result); 177 178 // Otherwise open a new message on the channel and send the result. 179 if (auto Err = startSendMessage(C)) 180 return Err; 181 if (auto Err = serializeSeq(C, ResponseId, SeqNo)) 182 return Err; 183 return endSendMessage(C); 184 } 185 }; 186 187 // Helper for the call primitive. 188 template <typename ChannelT, typename SequenceNumberT, typename Func> 189 class CallHelper; 190 191 template <typename ChannelT, typename SequenceNumberT, typename FunctionIdT, 192 FunctionIdT FuncId, typename RetT, typename... ArgTs> 193 class CallHelper<ChannelT, SequenceNumberT, 194 FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)>> { 195 public: call(ChannelT & C,SequenceNumberT SeqNo,const ArgTs &...Args)196 static Error call(ChannelT &C, SequenceNumberT SeqNo, 197 const ArgTs &... Args) { 198 if (auto Err = startSendMessage(C)) 199 return Err; 200 if (auto Err = serializeSeq(C, FuncId, SeqNo, Args...)) 201 return Err; 202 return endSendMessage(C); 203 } 204 }; 205 206 // Helper for handle primitive. 207 template <typename ChannelT, typename SequenceNumberT, typename Func> 208 class HandlerHelper; 209 210 template <typename ChannelT, typename SequenceNumberT, typename FunctionIdT, 211 FunctionIdT FuncId, typename RetT, typename... ArgTs> 212 class HandlerHelper<ChannelT, SequenceNumberT, 213 FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)>> { 214 public: 215 template <typename HandlerT> handle(ChannelT & C,HandlerT Handler)216 static Error handle(ChannelT &C, HandlerT Handler) { 217 return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs...>()); 218 } 219 220 private: 221 typedef FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> Func; 222 223 template <typename HandlerT, size_t... Is> readAndHandle(ChannelT & C,HandlerT Handler,llvm::index_sequence<Is...> _)224 static Error readAndHandle(ChannelT &C, HandlerT Handler, 225 llvm::index_sequence<Is...> _) { 226 std::tuple<ArgTs...> RPCArgs; 227 SequenceNumberT SeqNo; 228 // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning 229 // for RPCArgs. Void cast RPCArgs to work around this for now. 230 // FIXME: Remove this workaround once we can assume a working GCC version. 231 (void)RPCArgs; 232 if (auto Err = deserializeSeq(C, SeqNo, std::get<Is>(RPCArgs)...)) 233 return Err; 234 235 // We've deserialized the arguments, so unlock the channel for reading 236 // before we call the handler. This allows recursive RPC calls. 237 if (auto Err = endReceiveMessage(C)) 238 return Err; 239 240 // Run the handler and get the result. 241 auto Result = Handler(std::get<Is>(RPCArgs)...); 242 243 // Return the result to the client. 244 return Func::template respond<ChannelT, SequenceNumberT>(C, SeqNo, 245 Result); 246 } 247 }; 248 249 // Helper for wrapping member functions up as functors. 250 template <typename ClassT, typename RetT, typename... ArgTs> 251 class MemberFnWrapper { 252 public: 253 typedef RetT (ClassT::*MethodT)(ArgTs...); MemberFnWrapper(ClassT & Instance,MethodT Method)254 MemberFnWrapper(ClassT &Instance, MethodT Method) 255 : Instance(Instance), Method(Method) {} operator()256 RetT operator()(ArgTs &... Args) { return (Instance.*Method)(Args...); } 257 258 private: 259 ClassT &Instance; 260 MethodT Method; 261 }; 262 263 // Helper that provides a Functor for deserializing arguments. 264 template <typename... ArgTs> class ReadArgs { 265 public: operator()266 Error operator()() { return Error::success(); } 267 }; 268 269 template <typename ArgT, typename... ArgTs> 270 class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> { 271 public: ReadArgs(ArgT & Arg,ArgTs &...Args)272 ReadArgs(ArgT &Arg, ArgTs &... Args) 273 : ReadArgs<ArgTs...>(Args...), Arg(Arg) {} 274 operator()275 Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) { 276 this->Arg = std::move(ArgVal); 277 return ReadArgs<ArgTs...>::operator()(ArgVals...); 278 } 279 280 private: 281 ArgT &Arg; 282 }; 283 }; 284 285 /// Contains primitive utilities for defining, calling and handling calls to 286 /// remote procedures. ChannelT is a bidirectional stream conforming to the 287 /// RPCChannel interface (see RPCChannel.h), and FunctionIdT is a procedure 288 /// identifier type that must be serializable on ChannelT. 289 /// 290 /// These utilities support the construction of very primitive RPC utilities. 291 /// Their intent is to ensure correct serialization and deserialization of 292 /// procedure arguments, and to keep the client and server's view of the API in 293 /// sync. 294 /// 295 /// These utilities do not support return values. These can be handled by 296 /// declaring a corresponding '.*Response' procedure and expecting it after a 297 /// call). They also do not support versioning: the client and server *must* be 298 /// compiled with the same procedure definitions. 299 /// 300 /// 301 /// 302 /// Overview (see comments individual types/methods for details): 303 /// 304 /// Function<Id, Args...> : 305 /// 306 /// associates a unique serializable id with an argument list. 307 /// 308 /// 309 /// call<Func>(Channel, Args...) : 310 /// 311 /// Calls the remote procedure 'Func' by serializing Func's id followed by its 312 /// arguments and sending the resulting bytes to 'Channel'. 313 /// 314 /// 315 /// handle<Func>(Channel, <functor matching Error(Args...)> : 316 /// 317 /// Handles a call to 'Func' by deserializing its arguments and calling the 318 /// given functor. This assumes that the id for 'Func' has already been 319 /// deserialized. 320 /// 321 /// expect<Func>(Channel, <functor matching Error(Args...)> : 322 /// 323 /// The same as 'handle', except that the procedure id should not have been 324 /// read yet. Expect will deserialize the id and assert that it matches Func's 325 /// id. If it does not, and unexpected RPC call error is returned. 326 template <typename ChannelT, typename FunctionIdT = uint32_t, 327 typename SequenceNumberT = uint16_t> 328 class RPC : public RPCBase { 329 public: 330 /// RPC default constructor. 331 RPC() = default; 332 333 /// RPC instances cannot be copied. 334 RPC(const RPC &) = delete; 335 336 /// RPC instances cannot be copied. 337 RPC &operator=(const RPC &) = delete; 338 339 /// RPC move constructor. 340 // FIXME: Remove once MSVC can synthesize move ops. RPC(RPC && Other)341 RPC(RPC &&Other) 342 : SequenceNumberMgr(std::move(Other.SequenceNumberMgr)), 343 OutstandingResults(std::move(Other.OutstandingResults)) {} 344 345 /// RPC move assignment. 346 // FIXME: Remove once MSVC can synthesize move ops. 347 RPC &operator=(RPC &&Other) { 348 SequenceNumberMgr = std::move(Other.SequenceNumberMgr); 349 OutstandingResults = std::move(Other.OutstandingResults); 350 return *this; 351 } 352 353 /// Utility class for defining/referring to RPC procedures. 354 /// 355 /// Typedefs of this utility are used when calling/handling remote procedures. 356 /// 357 /// FuncId should be a unique value of FunctionIdT (i.e. not used with any 358 /// other Function typedef in the RPC API being defined. 359 /// 360 /// the template argument Ts... gives the argument list for the remote 361 /// procedure. 362 /// 363 /// E.g. 364 /// 365 /// typedef Function<0, bool> Func1; 366 /// typedef Function<1, std::string, std::vector<int>> Func2; 367 /// 368 /// if (auto Err = call<Func1>(Channel, true)) 369 /// /* handle Err */; 370 /// 371 /// if (auto Err = expect<Func2>(Channel, 372 /// [](std::string &S, std::vector<int> &V) { 373 /// // Stuff. 374 /// return Error::success(); 375 /// }) 376 /// /* handle Err */; 377 /// 378 template <FunctionIdT FuncId, typename FnT> 379 using Function = FunctionHelper<FunctionIdT, FuncId, FnT>; 380 381 /// Return type for asynchronous call primitives. 382 template <typename Func> 383 using AsyncCallResult = std::future<typename Func::OptionalReturn>; 384 385 /// Return type for asynchronous call-with-seq primitives. 386 template <typename Func> 387 using AsyncCallWithSeqResult = 388 std::pair<std::future<typename Func::OptionalReturn>, SequenceNumberT>; 389 390 /// Serialize Args... to channel C, but do not call C.send(). 391 /// 392 /// Returns an error (on serialization failure) or a pair of: 393 /// (1) A future Optional<T> (or future<bool> for void functions), and 394 /// (2) A sequence number. 395 /// 396 /// This utility function is primarily used for single-threaded mode support, 397 /// where the sequence number can be used to wait for the corresponding 398 /// result. In multi-threaded mode the appendCallAsync method, which does not 399 /// return the sequence numeber, should be preferred. 400 template <typename Func, typename... ArgTs> 401 Expected<AsyncCallWithSeqResult<Func>> appendCallAsyncWithSeq(ChannelT & C,const ArgTs &...Args)402 appendCallAsyncWithSeq(ChannelT &C, const ArgTs &... Args) { 403 auto SeqNo = SequenceNumberMgr.getSequenceNumber(); 404 std::promise<typename Func::OptionalReturn> Promise; 405 auto Result = Promise.get_future(); 406 OutstandingResults[SeqNo] = 407 createOutstandingResult<Func>(std::move(Promise)); 408 409 if (auto Err = CallHelper<ChannelT, SequenceNumberT, Func>::call(C, SeqNo, 410 Args...)) { 411 abandonOutstandingResults(); 412 return std::move(Err); 413 } else 414 return AsyncCallWithSeqResult<Func>(std::move(Result), SeqNo); 415 } 416 417 /// The same as appendCallAsyncWithSeq, except that it calls C.send() to 418 /// flush the channel after serializing the call. 419 template <typename Func, typename... ArgTs> 420 Expected<AsyncCallWithSeqResult<Func>> callAsyncWithSeq(ChannelT & C,const ArgTs &...Args)421 callAsyncWithSeq(ChannelT &C, const ArgTs &... Args) { 422 auto Result = appendCallAsyncWithSeq<Func>(C, Args...); 423 if (!Result) 424 return Result; 425 if (auto Err = C.send()) { 426 abandonOutstandingResults(); 427 return std::move(Err); 428 } 429 return Result; 430 } 431 432 /// Serialize Args... to channel C, but do not call send. 433 /// Returns an error if serialization fails, otherwise returns a 434 /// std::future<Optional<T>> (or a future<bool> for void functions). 435 template <typename Func, typename... ArgTs> appendCallAsync(ChannelT & C,const ArgTs &...Args)436 Expected<AsyncCallResult<Func>> appendCallAsync(ChannelT &C, 437 const ArgTs &... Args) { 438 auto ResAndSeqOrErr = appendCallAsyncWithSeq<Func>(C, Args...); 439 if (ResAndSeqOrErr) 440 return std::move(ResAndSeqOrErr->first); 441 return ResAndSeqOrErr.getError(); 442 } 443 444 /// The same as appendCallAsync, except that it calls C.send to flush the 445 /// channel after serializing the call. 446 template <typename Func, typename... ArgTs> callAsync(ChannelT & C,const ArgTs &...Args)447 Expected<AsyncCallResult<Func>> callAsync(ChannelT &C, 448 const ArgTs &... Args) { 449 auto ResAndSeqOrErr = callAsyncWithSeq<Func>(C, Args...); 450 if (ResAndSeqOrErr) 451 return std::move(ResAndSeqOrErr->first); 452 return ResAndSeqOrErr.getError(); 453 } 454 455 /// This can be used in single-threaded mode. 456 template <typename Func, typename HandleFtor, typename... ArgTs> 457 typename Func::ErrorReturn callSTHandling(ChannelT & C,HandleFtor & HandleOther,const ArgTs &...Args)458 callSTHandling(ChannelT &C, HandleFtor &HandleOther, const ArgTs &... Args) { 459 if (auto ResultAndSeqNoOrErr = callAsyncWithSeq<Func>(C, Args...)) { 460 auto &ResultAndSeqNo = *ResultAndSeqNoOrErr; 461 if (auto Err = waitForResult(C, ResultAndSeqNo.second, HandleOther)) 462 return std::move(Err); 463 return Func::optionalToErrorReturn(ResultAndSeqNo.first.get()); 464 } else 465 return ResultAndSeqNoOrErr.takeError(); 466 } 467 468 // This can be used in single-threaded mode. 469 template <typename Func, typename... ArgTs> callST(ChannelT & C,const ArgTs &...Args)470 typename Func::ErrorReturn callST(ChannelT &C, const ArgTs &... Args) { 471 return callSTHandling<Func>(C, handleNone, Args...); 472 } 473 474 /// Start receiving a new function call. 475 /// 476 /// Calls startReceiveMessage on the channel, then deserializes a FunctionId 477 /// into Id. startReceivingFunction(ChannelT & C,FunctionIdT & Id)478 Error startReceivingFunction(ChannelT &C, FunctionIdT &Id) { 479 if (auto Err = startReceiveMessage(C)) 480 return Err; 481 482 return deserialize(C, Id); 483 } 484 485 /// Deserialize args for Func from C and call Handler. The signature of 486 /// handler must conform to 'Error(Args...)' where Args... matches 487 /// the arguments used in the Func typedef. 488 template <typename Func, typename HandlerT> handle(ChannelT & C,HandlerT Handler)489 static Error handle(ChannelT &C, HandlerT Handler) { 490 return HandlerHelper<ChannelT, SequenceNumberT, Func>::handle(C, Handler); 491 } 492 493 /// Helper version of 'handle' for calling member functions. 494 template <typename Func, typename ClassT, typename RetT, typename... ArgTs> handle(ChannelT & C,ClassT & Instance,RetT (ClassT::* HandlerMethod)(ArgTs...))495 static Error handle(ChannelT &C, ClassT &Instance, 496 RetT (ClassT::*HandlerMethod)(ArgTs...)) { 497 return handle<Func>( 498 C, MemberFnWrapper<ClassT, RetT, ArgTs...>(Instance, HandlerMethod)); 499 } 500 501 /// Deserialize a FunctionIdT from C and verify it matches the id for Func. 502 /// If the id does match, deserialize the arguments and call the handler 503 /// (similarly to handle). 504 /// If the id does not match, return an unexpect RPC call error and do not 505 /// deserialize any further bytes. 506 template <typename Func, typename HandlerT> expect(ChannelT & C,HandlerT Handler)507 Error expect(ChannelT &C, HandlerT Handler) { 508 FunctionIdT FuncId; 509 if (auto Err = startReceivingFunction(C, FuncId)) 510 return std::move(Err); 511 if (FuncId != Func::Id) 512 return orcError(OrcErrorCode::UnexpectedRPCCall); 513 return handle<Func>(C, Handler); 514 } 515 516 /// Helper version of expect for calling member functions. 517 template <typename Func, typename ClassT, typename... ArgTs> expect(ChannelT & C,ClassT & Instance,Error (ClassT::* HandlerMethod)(ArgTs...))518 static Error expect(ChannelT &C, ClassT &Instance, 519 Error (ClassT::*HandlerMethod)(ArgTs...)) { 520 return expect<Func>( 521 C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod)); 522 } 523 524 /// Helper for handling setter procedures - this method returns a functor that 525 /// sets the variables referred to by Args... to values deserialized from the 526 /// channel. 527 /// E.g. 528 /// 529 /// typedef Function<0, bool, int> Func1; 530 /// 531 /// ... 532 /// bool B; 533 /// int I; 534 /// if (auto Err = expect<Func1>(Channel, readArgs(B, I))) 535 /// /* Handle Args */ ; 536 /// 537 template <typename... ArgTs> readArgs(ArgTs &...Args)538 static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) { 539 return ReadArgs<ArgTs...>(Args...); 540 } 541 542 /// Read a response from Channel. 543 /// This should be called from the receive loop to retrieve results. 544 Error handleResponse(ChannelT &C, SequenceNumberT *SeqNoRet = nullptr) { 545 SequenceNumberT SeqNo; 546 if (auto Err = deserialize(C, SeqNo)) { 547 abandonOutstandingResults(); 548 return Err; 549 } 550 551 if (SeqNoRet) 552 *SeqNoRet = SeqNo; 553 554 auto I = OutstandingResults.find(SeqNo); 555 if (I == OutstandingResults.end()) { 556 abandonOutstandingResults(); 557 return orcError(OrcErrorCode::UnexpectedRPCResponse); 558 } 559 560 if (auto Err = I->second->readResult(C)) { 561 abandonOutstandingResults(); 562 // FIXME: Release sequence numbers? 563 return Err; 564 } 565 566 OutstandingResults.erase(I); 567 SequenceNumberMgr.releaseSequenceNumber(SeqNo); 568 569 return Error::success(); 570 } 571 572 // Loop waiting for a result with the given sequence number. 573 // This can be used as a receive loop if the user doesn't have a default. 574 template <typename HandleOtherFtor> 575 Error waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo, 576 HandleOtherFtor &HandleOther = handleNone) { 577 bool GotTgtResult = false; 578 579 while (!GotTgtResult) { 580 FunctionIdT Id = RPCFunctionIdTraits<FunctionIdT>::InvalidId; 581 if (auto Err = startReceivingFunction(C, Id)) 582 return Err; 583 if (Id == RPCFunctionIdTraits<FunctionIdT>::ResponseId) { 584 SequenceNumberT SeqNo; 585 if (auto Err = handleResponse(C, &SeqNo)) 586 return Err; 587 GotTgtResult = (SeqNo == TgtSeqNo); 588 } else if (auto Err = HandleOther(C, Id)) 589 return Err; 590 } 591 592 return Error::success(); 593 } 594 595 // Default handler for 'other' (non-response) functions when waiting for a 596 // result from the channel. handleNone(ChannelT &,FunctionIdT)597 static Error handleNone(ChannelT &, FunctionIdT) { 598 return orcError(OrcErrorCode::UnexpectedRPCCall); 599 }; 600 601 private: 602 // Manage sequence numbers. 603 class SequenceNumberManager { 604 public: 605 SequenceNumberManager() = default; 606 607 SequenceNumberManager(const SequenceNumberManager &) = delete; 608 SequenceNumberManager &operator=(const SequenceNumberManager &) = delete; 609 SequenceNumberManager(SequenceNumberManager && Other)610 SequenceNumberManager(SequenceNumberManager &&Other) 611 : NextSequenceNumber(std::move(Other.NextSequenceNumber)), 612 FreeSequenceNumbers(std::move(Other.FreeSequenceNumbers)) {} 613 614 SequenceNumberManager &operator=(SequenceNumberManager &&Other) { 615 NextSequenceNumber = std::move(Other.NextSequenceNumber); 616 FreeSequenceNumbers = std::move(Other.FreeSequenceNumbers); 617 } 618 reset()619 void reset() { 620 std::lock_guard<std::mutex> Lock(SeqNoLock); 621 NextSequenceNumber = 0; 622 FreeSequenceNumbers.clear(); 623 } 624 getSequenceNumber()625 SequenceNumberT getSequenceNumber() { 626 std::lock_guard<std::mutex> Lock(SeqNoLock); 627 if (FreeSequenceNumbers.empty()) 628 return NextSequenceNumber++; 629 auto SequenceNumber = FreeSequenceNumbers.back(); 630 FreeSequenceNumbers.pop_back(); 631 return SequenceNumber; 632 } 633 releaseSequenceNumber(SequenceNumberT SequenceNumber)634 void releaseSequenceNumber(SequenceNumberT SequenceNumber) { 635 std::lock_guard<std::mutex> Lock(SeqNoLock); 636 FreeSequenceNumbers.push_back(SequenceNumber); 637 } 638 639 private: 640 std::mutex SeqNoLock; 641 SequenceNumberT NextSequenceNumber = 0; 642 std::vector<SequenceNumberT> FreeSequenceNumbers; 643 }; 644 645 // Base class for results that haven't been returned from the other end of the 646 // RPC connection yet. 647 class OutstandingResult { 648 public: ~OutstandingResult()649 virtual ~OutstandingResult() {} 650 virtual Error readResult(ChannelT &C) = 0; 651 virtual void abandon() = 0; 652 }; 653 654 // Outstanding results for a specific function. 655 template <typename Func> 656 class OutstandingResultImpl : public OutstandingResult { 657 private: 658 public: OutstandingResultImpl(std::promise<typename Func::OptionalReturn> && P)659 OutstandingResultImpl(std::promise<typename Func::OptionalReturn> &&P) 660 : P(std::move(P)) {} 661 readResult(ChannelT & C)662 Error readResult(ChannelT &C) override { return Func::readResult(C, P); } 663 abandon()664 void abandon() override { Func::abandon(P); } 665 666 private: 667 std::promise<typename Func::OptionalReturn> P; 668 }; 669 670 // Create an outstanding result for the given function. 671 template <typename Func> 672 std::unique_ptr<OutstandingResult> createOutstandingResult(std::promise<typename Func::OptionalReturn> && P)673 createOutstandingResult(std::promise<typename Func::OptionalReturn> &&P) { 674 return llvm::make_unique<OutstandingResultImpl<Func>>(std::move(P)); 675 } 676 677 // Abandon all outstanding results. abandonOutstandingResults()678 void abandonOutstandingResults() { 679 for (auto &KV : OutstandingResults) 680 KV.second->abandon(); 681 OutstandingResults.clear(); 682 SequenceNumberMgr.reset(); 683 } 684 685 SequenceNumberManager SequenceNumberMgr; 686 std::map<SequenceNumberT, std::unique_ptr<OutstandingResult>> 687 OutstandingResults; 688 }; 689 690 } // end namespace remote 691 } // end namespace orc 692 } // end namespace llvm 693 694 #endif 695