llvm.org GIT mirror llvm / d8314f0
[ORC] Refactor the ORC RPC utilities to add some new features. (1) Add support for function key negotiation. The previous version of the RPC required both sides to maintain the same enumeration for functions in the API. This means that any version skew between the client and server would result in communication failure. With this version of the patch functions (and serializable types) are defined with string names, and the derived function signature strings are used to negotiate the actual function keys (which are used for efficient call serialization). This allows clients to connect to any server that supports a superset of the API (based on the function signatures it supports). (2) Add a callAsync primitive. The callAsync primitive can be used to install a return value handler that will run as soon as the RPC function's return value is sent back from the remote. (3) Launch policies for RPC function handlers. The new addHandler method, which installs handlers for RPC functions, takes two arguments: (1) the handler itself, and (2) an optional "launch policy". When the RPC function is called, the launch policy (if present) is invoked to actually launch the handler. This allows the handler to be spawned on a background thread, or added to a work list. If no launch policy is used, the handler is run on the server thread itself. This should only be used for short-running handlers, or entirely synchronous RPC APIs. (4) Zero cost cross type serialization. You can now define serialization from any type to a different "wire" type. For example, this allows you to call an RPC function that's defined to take a std::string while passing a StringRef argument. If a serializer from StringRef to std::string has been defined for the channel type this will be used to serialize the argument without having to construct a std::string instance. This allows buffer reference types to be used as arguments to RPC calls without requiring a copy of the buffer to be made. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@286620 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 4 years ago
17 changed file(s) with 1894 addition(s) and 1500 deletion(s). Raw diff Collapse all Expand all
1313 #ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H
1414 #define LLVM_TOOLS_LLI_REMOTEJITUTILS_H
1515
16 #include "llvm/ExecutionEngine/Orc/RPCByteChannel.h"
16 #include "llvm/ExecutionEngine/Orc/RawByteChannel.h"
1717 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
1818 #include
1919
2424 #endif
2525
2626 /// RPC channel that reads from and writes from file descriptors.
27 class FDRPCChannel final : public llvm::orc::remote::RPCByteChannel {
27 class FDRPCChannel final : public llvm::orc::rpc::RawByteChannel {
2828 public:
2929 FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
3030
12641264 BinopPrecedence['*'] = 40; // highest.
12651265
12661266 auto TCPChannel = connect();
1267 MyRemote Remote = ExitOnErr(MyRemote::Create(*TCPChannel));
1268 TheJIT = llvm::make_unique(Remote);
1267 auto Remote = ExitOnErr(MyRemote::Create(*TCPChannel));
1268 TheJIT = llvm::make_unique(*Remote);
12691269
12701270 // Automatically inject a definition for 'printExprResult'.
12711271 FunctionProtos["printExprResult"] =
12871287 TheJIT = nullptr;
12881288
12891289 // Send a terminate message to the remote to tell it to exit cleanly.
1290 ExitOnErr(Remote.terminateSession());
1290 ExitOnErr(Remote->terminateSession());
12911291
12921292 return 0;
12931293 }
2828 RemoteIndirectStubsOwnerIdAlreadyInUse,
2929 UnexpectedRPCCall,
3030 UnexpectedRPCResponse,
31 UnknownRPCFunction
3132 };
3233
3334 Error orcError(OrcErrorCode ErrCode);
77 //===----------------------------------------------------------------------===//
88 //
99 // This file defines the OrcRemoteTargetClient class and helpers. This class
10 // can be used to communicate over an RPCByteChannel with an
10 // can be used to communicate over an RawByteChannel with an
1111 // OrcRemoteTargetServer instance to support remote-JITing.
1212 //
1313 //===----------------------------------------------------------------------===//
3535 template
3636 class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
3737 public:
38 // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
39
40 OrcRemoteTargetClient(const OrcRemoteTargetClient &) = delete;
41 OrcRemoteTargetClient &operator=(const OrcRemoteTargetClient &) = delete;
42
43 OrcRemoteTargetClient(OrcRemoteTargetClient &&Other)
44 : Channel(Other.Channel), ExistingError(std::move(Other.ExistingError)),
45 RemoteTargetTriple(std::move(Other.RemoteTargetTriple)),
46 RemotePointerSize(std::move(Other.RemotePointerSize)),
47 RemotePageSize(std::move(Other.RemotePageSize)),
48 RemoteTrampolineSize(std::move(Other.RemoteTrampolineSize)),
49 RemoteIndirectStubSize(std::move(Other.RemoteIndirectStubSize)),
50 AllocatorIds(std::move(Other.AllocatorIds)),
51 IndirectStubOwnerIds(std::move(Other.IndirectStubOwnerIds)),
52 CallbackManager(std::move(Other.CallbackManager)) {}
53
54 OrcRemoteTargetClient &operator=(OrcRemoteTargetClient &&) = delete;
5538
5639 /// Remote memory manager.
5740 class RCMemoryManager : public RuntimeDyld::MemoryManager {
6144 DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
6245 }
6346
64 RCMemoryManager(RCMemoryManager &&Other)
65 : Client(std::move(Other.Client)), Id(std::move(Other.Id)),
66 Unmapped(std::move(Other.Unmapped)),
67 Unfinalized(std::move(Other.Unfinalized)) {}
68
69 RCMemoryManager operator=(RCMemoryManager &&Other) {
70 Client = std::move(Other.Client);
71 Id = std::move(Other.Id);
72 Unmapped = std::move(Other.Unmapped);
73 Unfinalized = std::move(Other.Unfinalized);
74 return *this;
75 }
47 RCMemoryManager(const RCMemoryManager&) = delete;
48 RCMemoryManager& operator=(const RCMemoryManager&) = delete;
49 RCMemoryManager(RCMemoryManager&&) = default;
50 RCMemoryManager& operator=(RCMemoryManager&&) = default;
7651
7752 ~RCMemoryManager() override {
7853 Client.destroyRemoteAllocator(Id);
366341 Alloc(uint64_t Size, unsigned Align)
367342 : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
368343
369 Alloc(Alloc &&Other)
370 : Size(std::move(Other.Size)), Align(std::move(Other.Align)),
371 Contents(std::move(Other.Contents)),
372 RemoteAddr(std::move(Other.RemoteAddr)) {}
373
374 Alloc &operator=(Alloc &&Other) {
375 Size = std::move(Other.Size);
376 Align = std::move(Other.Align);
377 Contents = std::move(Other.Contents);
378 RemoteAddr = std::move(Other.RemoteAddr);
379 return *this;
380 }
344 Alloc(const Alloc&) = delete;
345 Alloc& operator=(const Alloc&) = delete;
346 Alloc(Alloc&&) = default;
347 Alloc& operator=(Alloc&&) = default;
381348
382349 uint64_t getSize() const { return Size; }
383350
404371
405372 struct ObjectAllocs {
406373 ObjectAllocs() = default;
407
408 ObjectAllocs(ObjectAllocs &&Other)
409 : RemoteCodeAddr(std::move(Other.RemoteCodeAddr)),
410 RemoteRODataAddr(std::move(Other.RemoteRODataAddr)),
411 RemoteRWDataAddr(std::move(Other.RemoteRWDataAddr)),
412 CodeAllocs(std::move(Other.CodeAllocs)),
413 RODataAllocs(std::move(Other.RODataAllocs)),
414 RWDataAllocs(std::move(Other.RWDataAllocs)) {}
415
416 ObjectAllocs &operator=(ObjectAllocs &&Other) {
417 RemoteCodeAddr = std::move(Other.RemoteCodeAddr);
418 RemoteRODataAddr = std::move(Other.RemoteRODataAddr);
419 RemoteRWDataAddr = std::move(Other.RemoteRWDataAddr);
420 CodeAllocs = std::move(Other.CodeAllocs);
421 RODataAllocs = std::move(Other.RODataAllocs);
422 RWDataAllocs = std::move(Other.RWDataAllocs);
423 return *this;
424 }
374 ObjectAllocs(const ObjectAllocs &) = delete;
375 ObjectAllocs& operator=(const ObjectAllocs &) = delete;
376 ObjectAllocs(ObjectAllocs&&) = default;
377 ObjectAllocs& operator=(ObjectAllocs&&) = default;
425378
426379 JITTargetAddress RemoteCodeAddr = 0;
427380 JITTargetAddress RemoteRODataAddr = 0;
587540 /// Create an OrcRemoteTargetClient.
588541 /// Channel is the ChannelT instance to communicate on. It is assumed that
589542 /// the channel is ready to be read from and written to.
590 static Expected<OrcRemoteTargetClient> Create(ChannelT &Channel) {
543 static Expected<std::unique_ptr>
544 Create(ChannelT &Channel) {
591545 Error Err = Error::success();
592 OrcRemoteTargetClient H(Channel, Err);
546 std::unique_ptr
547 Client(new OrcRemoteTargetClient(Channel, Err));
593548 if (Err)
594549 return std::move(Err);
595 return Expected(std::move(H));
550 return std::move(Client);
596551 }
597552
598553 /// Call the int(void) function at the given address in the target and return
599554 /// its result.
600555 Expected callIntVoid(JITTargetAddress Addr) {
601556 DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
602
603 auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
604 return listenForCompileRequests(C, Id);
605 };
606 return callSTHandling(Channel, Listen, Addr);
557 return callB(Addr);
607558 }
608559
609560 /// Call the int(int, char*[]) function at the given address in the target and
612563 const std::vector &Args) {
613564 DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
614565 << "\n");
615
616 auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
617 return listenForCompileRequests(C, Id);
618 };
619 return callSTHandling(Channel, Listen, Addr, Args);
566 return callB(Addr, Args);
620567 }
621568
622569 /// Call the void() function at the given address in the target and wait for
624571 Error callVoidVoid(JITTargetAddress Addr) {
625572 DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
626573 << "\n");
627
628 auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
629 return listenForCompileRequests(C, Id);
630 };
631 return callSTHandling(Channel, Listen, Addr);
574 return callB(Addr);
632575 }
633576
634577 /// Create an RCMemoryManager which will allocate its memory on the remote
637580 assert(!MM && "MemoryManager should be null before creation.");
638581
639582 auto Id = AllocatorIds.getNext();
640 if (auto Err = callST(Channel, Id))
583 if (auto Err = callB(Id))
641584 return Err;
642585 MM = llvm::make_unique(*this, Id);
643586 return Error::success();
648591 Error createIndirectStubsManager(std::unique_ptr &I) {
649592 assert(!I && "Indirect stubs manager should be null before creation.");
650593 auto Id = IndirectStubOwnerIds.getNext();
651 if (auto Err = callST(Channel, Id))
594 if (auto Err = callB(Id))
652595 return Err;
653596 I = llvm::make_unique(*this, Id);
654597 return Error::success();
661604 return std::move(ExistingError);
662605
663606 // Emit the resolver block on the JIT server.
664 if (auto Err = callST(Channel))
607 if (auto Err = callB())
665608 return std::move(Err);
666609
667610 // Create the callback manager.
678621 if (ExistingError)
679622 return std::move(ExistingError);
680623
681 return callST(Channel, Name);
624 return callB(Name);
682625 }
683626
684627 /// Get the triple for the remote target.
685628 const std::string &getTargetTriple() const { return RemoteTargetTriple; }
686629
687 Error terminateSession() { return callST(Channel); }
630 Error terminateSession() { return callB(); }
688631
689632 private:
690 OrcRemoteTargetClient(ChannelT &Channel, Error &Err) : Channel(Channel) {
633
634 OrcRemoteTargetClient(ChannelT &Channel, Error &Err)
635 : OrcRemoteTargetRPCAPI(Channel) {
691636 ErrorAsOutParameter EAO(&Err);
692 if (auto RIOrErr = callST(Channel)) {
637
638 addHandler(
639 [this](JITTargetAddress Addr) -> JITTargetAddress {
640 if (CallbackManager)
641 return CallbackManager->executeCompileCallback(Addr);
642 return 0;
643 });
644
645 if (auto RIOrErr = callB()) {
693646 std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
694647 RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
695648 Err = Error::success();
699652 }
700653
701654 Error deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
702 return callST(Channel, Addr, Size);
655 return callB(Addr, Size);
703656 }
704657
705658 void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
706 if (auto Err = callST(Channel, Id)) {
659 if (auto Err = callB(Id)) {
707660 // FIXME: This will be triggered by a removeModuleSet call: Propagate
708661 // error return up through that.
709662 llvm_unreachable("Failed to destroy remote allocator.");
713666
714667 Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
715668 IndirectStubOwnerIds.release(Id);
716 return callST(Channel, Id);
669 return callB(Id);
717670 }
718671
719672 Expected>
720673 emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
721 return callST(Channel, Id, NumStubsRequired);
674 return callB(Id, NumStubsRequired);
722675 }
723676
724677 Expected> emitTrampolineBlock() {
726679 if (ExistingError)
727680 return std::move(ExistingError);
728681
729 return callST(Channel);
682 return callB();
730683 }
731684
732685 uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
734687 uint32_t getPointerSize() const { return RemotePointerSize; }
735688
736689 uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
737
738 Error listenForCompileRequests(RPCByteChannel &C, uint32_t &Id) {
739 assert(CallbackManager &&
740 "No calback manager. enableCompileCallbacks must be called first");
741
742 // Check for an 'out-of-band' error, e.g. from an MM destructor.
743 if (ExistingError)
744 return std::move(ExistingError);
745
746 // FIXME: CompileCallback could be an anonymous lambda defined at the use
747 // site below, but that triggers a GCC 4.7 ICE. When we move off
748 // GCC 4.7, tidy this up.
749 auto CompileCallback =
750 [this](JITTargetAddress Addr) -> Expected {
751 return this->CallbackManager->executeCompileCallback(Addr);
752 };
753
754 if (Id == RequestCompileId) {
755 if (auto Err = handle(C, CompileCallback))
756 return Err;
757 return Error::success();
758 }
759 // else
760 return orcError(OrcErrorCode::UnexpectedRPCCall);
761 }
762690
763691 Expected> readMem(char *Dst, JITTargetAddress Src,
764692 uint64_t Size) {
766694 if (ExistingError)
767695 return std::move(ExistingError);
768696
769 return callST(Channel, Src, Size);
697 return callB(Src, Size);
770698 }
771699
772700 Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) {
773 return callST(Channel, RAddr, Size);
701 return callB(RAddr, Size);
774702 }
775703
776704 Expected reserveMem(ResourceIdMgr::ResourceId Id,
780708 if (ExistingError)
781709 return std::move(ExistingError);
782710
783 return callST(Channel, Id, Size, Align);
711 return callB(Id, Size, Align);
784712 }
785713
786714 Error setProtections(ResourceIdMgr::ResourceId Id,
787715 JITTargetAddress RemoteSegAddr, unsigned ProtFlags) {
788 return callST(Channel, Id, RemoteSegAddr, ProtFlags);
716 return callB(Id, RemoteSegAddr, ProtFlags);
789717 }
790718
791719 Error writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) {
793721 if (ExistingError)
794722 return std::move(ExistingError);
795723
796 return callST(Channel, DirectBufferWriter(Src, Addr, Size));
724 return callB(DirectBufferWriter(Src, Addr, Size));
797725 }
798726
799727 Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
801729 if (ExistingError)
802730 return std::move(ExistingError);
803731
804 return callST(Channel, Addr, PtrVal);
732 return callB(Addr, PtrVal);
805733 }
806734
807735 static Error doNothing() { return Error::success(); }
808736
809 ChannelT &Channel;
810737 Error ExistingError = Error::success();
811738 std::string RemoteTargetTriple;
812739 uint32_t RemotePointerSize = 0;
1515 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
1616 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
1717
18 #include "RPCByteChannel.h"
18 #include "RawByteChannel.h"
1919 #include "RPCUtils.h"
2020 #include "llvm/ExecutionEngine/JITSymbol.h"
2121
3939 uint64_t Size;
4040 };
4141
42 } // end namespace remote
43
44 namespace rpc {
45
4246 template <>
43 class SerializationTraits {
44 public:
45
46 static const char* getName() { return "DirectBufferWriter"; }
47
48 static Error serialize(RPCByteChannel &C, const DirectBufferWriter &DBW) {
47 class RPCTypeName {
48 public:
49 static const char *getName() { return "DirectBufferWriter"; }
50 };
51
52 template
53 class SerializationTraits
54 typename std::enable_if<
55 std::is_base_of::
56 value>::type> {
57 public:
58
59 static Error serialize(ChannelT &C, const remote::DirectBufferWriter &DBW) {
4960 if (auto EC = serializeSeq(C, DBW.getDst()))
5061 return EC;
5162 if (auto EC = serializeSeq(C, DBW.getSize()))
5364 return C.appendBytes(DBW.getSrc(), DBW.getSize());
5465 }
5566
56 static Error deserialize(RPCByteChannel &C, DirectBufferWriter &DBW) {
67 static Error deserialize(ChannelT &C, remote::DirectBufferWriter &DBW) {
5768 JITTargetAddress Dst;
5869 if (auto EC = deserializeSeq(C, Dst))
5970 return EC;
6273 return EC;
6374 char *Addr = reinterpret_cast(static_cast(Dst));
6475
65 DBW = DirectBufferWriter(0, Dst, Size);
76 DBW = remote::DirectBufferWriter(0, Dst, Size);
6677
6778 return C.readBytes(Addr, Size);
6879 }
6980 };
7081
71 class OrcRemoteTargetRPCAPI : public RPC {
82 } // end namespace rpc
83
84 namespace remote {
85
86 class OrcRemoteTargetRPCAPI
87 : public rpc::SingleThreadedRPC {
7288 protected:
7389 class ResourceIdMgr {
7490 public:
92108
93109 public:
94110 // FIXME: Remove constructors once MSVC supports synthesizing move-ops.
95 OrcRemoteTargetRPCAPI() = default;
96 OrcRemoteTargetRPCAPI(const OrcRemoteTargetRPCAPI &) = delete;
97 OrcRemoteTargetRPCAPI &operator=(const OrcRemoteTargetRPCAPI &) = delete;
98
99 OrcRemoteTargetRPCAPI(OrcRemoteTargetRPCAPI &&) {}
100 OrcRemoteTargetRPCAPI &operator=(OrcRemoteTargetRPCAPI &&) { return *this; }
101
102 enum JITFuncId : uint32_t {
103 InvalidId = RPCFunctionIdTraits::InvalidId,
104 CallIntVoidId = RPCFunctionIdTraits::FirstValidId,
105 CallMainId,
106 CallVoidVoidId,
107 CreateRemoteAllocatorId,
108 CreateIndirectStubsOwnerId,
109 DeregisterEHFramesId,
110 DestroyRemoteAllocatorId,
111 DestroyIndirectStubsOwnerId,
112 EmitIndirectStubsId,
113 EmitResolverBlockId,
114 EmitTrampolineBlockId,
115 GetSymbolAddressId,
116 GetRemoteInfoId,
117 ReadMemId,
118 RegisterEHFramesId,
119 ReserveMemId,
120 RequestCompileId,
121 SetProtectionsId,
122 TerminateSessionId,
123 WriteMemId,
124 WritePtrId
125 };
126
127 static const char *getJITFuncIdName(JITFuncId Id);
128
129 typedef Function CallIntVoid;
130
131 typedef Function
132 int32_t(JITTargetAddress Addr,
133 std::vector Args)>
134 CallMain;
135
136 typedef Function CallVoidVoid;
137
138 typedef Function
139 void(ResourceIdMgr::ResourceId AllocatorID)>
140 CreateRemoteAllocator;
141
142 typedef Function
143 void(ResourceIdMgr::ResourceId StubOwnerID)>
144 CreateIndirectStubsOwner;
145
146 typedef Function
147 void(JITTargetAddress Addr, uint32_t Size)>
148 DeregisterEHFrames;
149
150 typedef Function
151 void(ResourceIdMgr::ResourceId AllocatorID)>
152 DestroyRemoteAllocator;
153
154 typedef Function
155 void(ResourceIdMgr::ResourceId StubsOwnerID)>
156 DestroyIndirectStubsOwner;
111 OrcRemoteTargetRPCAPI(rpc::RawByteChannel &C)
112 : rpc::SingleThreadedRPC(C, true) {}
113
114 class CallIntVoid : public rpc::Function
115 int32_t(JITTargetAddress Addr)> {
116 public:
117 static const char* getName() { return "CallIntVoid"; }
118 };
119
120 class CallMain
121 : public rpc::Function
122 int32_t(JITTargetAddress Addr,
123 std::vector Args)> {
124 public:
125 static const char* getName() { return "CallMain"; }
126 };
127
128 class CallVoidVoid : public rpc::Function
129 void(JITTargetAddress FnAddr)> {
130 public:
131 static const char* getName() { return "CallVoidVoid"; }
132 };
133
134 class CreateRemoteAllocator
135 : public rpc::Function
136 void(ResourceIdMgr::ResourceId AllocatorID)> {
137 public:
138 static const char* getName() { return "CreateRemoteAllocator"; }
139 };
140
141 class CreateIndirectStubsOwner
142 : public rpc::Function
143 void(ResourceIdMgr::ResourceId StubOwnerID)> {
144 public:
145 static const char* getName() { return "CreateIndirectStubsOwner"; }
146 };
147
148 class DeregisterEHFrames
149 : public rpc::Function
150 void(JITTargetAddress Addr, uint32_t Size)> {
151 public:
152 static const char* getName() { return "DeregisterEHFrames"; }
153 };
154
155 class DestroyRemoteAllocator
156 : public rpc::Function
157 void(ResourceIdMgr::ResourceId AllocatorID)> {
158 public:
159 static const char* getName() { return "DestroyRemoteAllocator"; }
160 };
161
162 class DestroyIndirectStubsOwner
163 : public rpc::Function
164 void(ResourceIdMgr::ResourceId StubsOwnerID)> {
165 public:
166 static const char* getName() { return "DestroyIndirectStubsOwner"; }
167 };
157168
158169 /// EmitIndirectStubs result is (StubsBase, PtrsBase, NumStubsEmitted).
159 typedef Function
160 std::tuple(
161 ResourceIdMgr::ResourceId StubsOwnerID,
162 uint32_t NumStubsRequired)>
163 EmitIndirectStubs;
164
165 typedef Function EmitResolverBlock;
170 class EmitIndirectStubs
171 : public rpc::Function
172 std::tuple
173 uint32_t>(
174 ResourceIdMgr::ResourceId StubsOwnerID,
175 uint32_t NumStubsRequired)> {
176 public:
177 static const char* getName() { return "EmitIndirectStubs"; }
178 };
179
180 class EmitResolverBlock : public rpc::Function {
181 public:
182 static const char* getName() { return "EmitResolverBlock"; }
183 };
166184
167185 /// EmitTrampolineBlock result is (BlockAddr, NumTrampolines).
168 typedef Function
169 std::tuple()>
170 EmitTrampolineBlock;
171
172 typedef Function
173 GetSymbolAddress;
186 class EmitTrampolineBlock
187 : public rpc::Function
188 std::tuple()> {
189 public:
190 static const char* getName() { return "EmitTrampolineBlock"; }
191 };
192
193 class GetSymbolAddress
194 : public rpc::Function
195 JITTargetAddress(std::string SymbolName)> {
196 public:
197 static const char* getName() { return "GetSymbolAddress"; }
198 };
174199
175200 /// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize,
176201 /// IndirectStubsSize).
177 typedef Function
178 uint32_t, uint32_t>()>
179 GetRemoteInfo;
180
181 typedef Function
182 std::vector(JITTargetAddress Src, uint64_t Size)>
183 ReadMem;
184
185 typedef Function
186 RegisterEHFrames;
187
188 typedef Function
189 JITTargetAddress(ResourceIdMgr::ResourceId AllocID,
190 uint64_t Size, uint32_t Align)>
191 ReserveMem;
192
193 typedef Function
194 JITTargetAddress(JITTargetAddress TrampolineAddr)>
195 RequestCompile;
196
197 typedef Function
198 void(ResourceIdMgr::ResourceId AllocID, JITTargetAddress Dst,
199 uint32_t ProtFlags)>
200 SetProtections;
201
202 typedef Function TerminateSession;
203
204 typedef Function WriteMem;
205
206 typedef Function
207 WritePtr;
202 class GetRemoteInfo
203 : public rpc::Function
204 std::tuple
205 uint32_t, uint32_t>()> {
206 public:
207 static const char* getName() { return "GetRemoteInfo"; }
208 };
209
210 class ReadMem
211 : public rpc::Function
212 std::vector(JITTargetAddress Src,
213 uint64_t Size)> {
214 public:
215 static const char* getName() { return "ReadMem"; }
216 };
217
218 class RegisterEHFrames
219 : public rpc::Function
220 void(JITTargetAddress Addr, uint32_t Size)> {
221 public:
222 static const char* getName() { return "RegisterEHFrames"; }
223 };
224
225 class ReserveMem
226 : public rpc::Function
227 JITTargetAddress(ResourceIdMgr::ResourceId AllocID,
228 uint64_t Size, uint32_t Align)> {
229 public:
230 static const char* getName() { return "ReserveMem"; }
231 };
232
233 class RequestCompile
234 : public rpc::Function
235 JITTargetAddress(JITTargetAddress TrampolineAddr)> {
236 public:
237 static const char* getName() { return "RequestCompile"; }
238 };
239
240 class SetProtections
241 : public rpc::Function
242 void(ResourceIdMgr::ResourceId AllocID,
243 JITTargetAddress Dst,
244 uint32_t ProtFlags)> {
245 public:
246 static const char* getName() { return "SetProtections"; }
247 };
248
249 class TerminateSession : public rpc::Function {
250 public:
251 static const char* getName() { return "TerminateSession"; }
252 };
253
254 class WriteMem : public rpc::Function
255 void(remote::DirectBufferWriter DB)> {
256 public:
257 static const char* getName() { return "WriteMem"; }
258 };
259
260 class WritePtr
261 : public rpc::Function
262 void(JITTargetAddress Dst, JITTargetAddress Val)> {
263 public:
264 static const char* getName() { return "WritePtr"; }
265 };
266
208267 };
209268
210269 } // end namespace remote
4040 OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup,
4141 EHFrameRegistrationFtor EHFramesRegister,
4242 EHFrameRegistrationFtor EHFramesDeregister)
43 : Channel(Channel), SymbolLookup(std::move(SymbolLookup)),
43 : OrcRemoteTargetRPCAPI(Channel), SymbolLookup(std::move(SymbolLookup)),
4444 EHFramesRegister(std::move(EHFramesRegister)),
45 EHFramesDeregister(std::move(EHFramesDeregister)) {}
45 EHFramesDeregister(std::move(EHFramesDeregister)),
46 TerminateFlag(false) {
47
48 using ThisT = typename std::remove_reference::type;
49 addHandler(*this, &ThisT::handleCallIntVoid);
50 addHandler(*this, &ThisT::handleCallMain);
51 addHandler(*this, &ThisT::handleCallVoidVoid);
52 addHandler(*this,
53 &ThisT::handleCreateRemoteAllocator);
54 addHandler(*this,
55 &ThisT::handleCreateIndirectStubsOwner);
56 addHandler(*this, &ThisT::handleDeregisterEHFrames);
57 addHandler(*this,
58 &ThisT::handleDestroyRemoteAllocator);
59 addHandler(*this,
60 &ThisT::handleDestroyIndirectStubsOwner);
61 addHandler(*this, &ThisT::handleEmitIndirectStubs);
62 addHandler(*this, &ThisT::handleEmitResolverBlock);
63 addHandler(*this, &ThisT::handleEmitTrampolineBlock);
64 addHandler(*this, &ThisT::handleGetSymbolAddress);
65 addHandler(*this, &ThisT::handleGetRemoteInfo);
66 addHandler(*this, &ThisT::handleReadMem);
67 addHandler(*this, &ThisT::handleRegisterEHFrames);
68 addHandler(*this, &ThisT::handleReserveMem);
69 addHandler(*this, &ThisT::handleSetProtections);
70 addHandler(*this, &ThisT::handleTerminateSession);
71 addHandler(*this, &ThisT::handleWriteMem);
72 addHandler(*this, &ThisT::handleWritePtr);
73 }
4674
4775 // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
4876 OrcRemoteTargetServer(const OrcRemoteTargetServer &) = delete;
4977 OrcRemoteTargetServer &operator=(const OrcRemoteTargetServer &) = delete;
5078
51 OrcRemoteTargetServer(OrcRemoteTargetServer &&Other)
52 : Channel(Other.Channel), SymbolLookup(std::move(Other.SymbolLookup)),
53 EHFramesRegister(std::move(Other.EHFramesRegister)),
54 EHFramesDeregister(std::move(Other.EHFramesDeregister)) {}
55
79 OrcRemoteTargetServer(OrcRemoteTargetServer &&Other) = default;
5680 OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete;
5781
58 Error handleKnownFunction(JITFuncId Id) {
59 typedef OrcRemoteTargetServer ThisT;
60
61 DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) << "\n");
62
63 switch (Id) {
64 case CallIntVoidId:
65 return handle(Channel, *this, &ThisT::handleCallIntVoid);
66 case CallMainId:
67 return handle(Channel, *this, &ThisT::handleCallMain);
68 case CallVoidVoidId:
69 return handle(Channel, *this, &ThisT::handleCallVoidVoid);
70 case CreateRemoteAllocatorId:
71 return handle(Channel, *this,
72 &ThisT::handleCreateRemoteAllocator);
73 case CreateIndirectStubsOwnerId:
74 return handle(
75 Channel, *this, &ThisT::handleCreateIndirectStubsOwner);
76 case DeregisterEHFramesId:
77 return handle(Channel, *this,
78 &ThisT::handleDeregisterEHFrames);
79 case DestroyRemoteAllocatorId:
80 return handle(
81 Channel, *this, &ThisT::handleDestroyRemoteAllocator);
82 case DestroyIndirectStubsOwnerId:
83 return handle(
84 Channel, *this, &ThisT::handleDestroyIndirectStubsOwner);
85 case EmitIndirectStubsId:
86 return handle(Channel, *this,
87 &ThisT::handleEmitIndirectStubs);
88 case EmitResolverBlockId:
89 return handle(Channel, *this,
90 &ThisT::handleEmitResolverBlock);
91 case EmitTrampolineBlockId:
92 return handle(Channel, *this,
93 &ThisT::handleEmitTrampolineBlock);
94 case GetSymbolAddressId:
95 return handle(Channel, *this,
96 &ThisT::handleGetSymbolAddress);
97 case GetRemoteInfoId:
98 return handle(Channel, *this, &ThisT::handleGetRemoteInfo);
99 case ReadMemId:
100 return handle(Channel, *this, &ThisT::handleReadMem);
101 case RegisterEHFramesId:
102 return handle(Channel, *this,
103 &ThisT::handleRegisterEHFrames);
104 case ReserveMemId:
105 return handle(Channel, *this, &ThisT::handleReserveMem);
106 case SetProtectionsId:
107 return handle(Channel, *this,
108 &ThisT::handleSetProtections);
109 case WriteMemId:
110 return handle(Channel, *this, &ThisT::handleWriteMem);
111 case WritePtrId:
112 return handle(Channel, *this, &ThisT::handleWritePtr);
113 default:
114 return orcError(OrcErrorCode::UnexpectedRPCCall);
115 }
116
117 llvm_unreachable("Unhandled JIT RPC procedure Id.");
118 }
11982
12083 Expected requestCompile(JITTargetAddress TrampolineAddr) {
121 auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
122 return handleKnownFunction(static_cast(Id));
123 };
124
125 return callSTHandling(Channel, Listen, TrampolineAddr);
126 }
127
128 Error handleTerminateSession() {
129 return handle(Channel, []() { return Error::success(); });
130 }
84 return callB(TrampolineAddr);
85 }
86
87 bool receivedTerminate() const { return TerminateFlag; }
13188
13289 private:
13390 struct Allocator {
364321 IndirectStubSize);
365322 }
366323
367 Expected> handleReadMem(JITTargetAddress RSrc, uint64_t Size) {
368 char *Src = reinterpret_cast(static_cast(RSrc));
324 Expected> handleReadMem(JITTargetAddress RSrc,
325 uint64_t Size) {
326 uint8_t *Src = reinterpret_cast(static_cast(RSrc));
369327
370328 DEBUG(dbgs() << " Reading " << Size << " bytes from "
371329 << format("0x%016x", RSrc) << "\n");
372330
373 std::vector<char> Buffer;
331 std::vector<uint8_t> Buffer;
374332 Buffer.resize(Size);
375 for (char *P = Src; Size != 0; --Size)
333 for (uint8_t *P = Src; Size != 0; --Size)
376334 Buffer.push_back(*P++);
377335
378336 return Buffer;
420378 return Allocator.setProtections(LocalAddr, Flags);
421379 }
422380
381 Error handleTerminateSession() {
382 TerminateFlag = true;
383 return Error::success();
384 }
385
423386 Error handleWriteMem(DirectBufferWriter DBW) {
424387 DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to "
425388 << format("0x%016x", DBW.getDst()) << "\n");
435398 return Error::success();
436399 }
437400
438 ChannelT &Channel;
439401 SymbolLookupFtor SymbolLookup;
440402 EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister;
441403 std::map Allocators;
443405 std::map IndirectStubsOwners;
444406 sys::OwningMemoryBlock ResolverBlock;
445407 std::vector TrampolineBlocks;
408 bool TerminateFlag;
446409 };
447410
448411 } // end namespace remote
+0
-231
include/llvm/ExecutionEngine/Orc/RPCByteChannel.h less more
None //===- llvm/ExecutionEngine/Orc/RPCByteChannel.h ----------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCBYTECHANNEL_H
10 #define LLVM_EXECUTIONENGINE_ORC_RPCBYTECHANNEL_H
11
12 #include "OrcError.h"
13 #include "RPCSerialization.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/Endian.h"
18 #include "llvm/Support/Error.h"
19 #include
20 #include
21 #include
22 #include
23 #include
24 #include
25 #include
26
27 namespace llvm {
28 namespace orc {
29 namespace remote {
30
31 /// Interface for byte-streams to be used with RPC.
32 class RPCByteChannel {
33 public:
34 virtual ~RPCByteChannel() {}
35
36 /// Read Size bytes from the stream into *Dst.
37 virtual Error readBytes(char *Dst, unsigned Size) = 0;
38
39 /// Read size bytes from *Src and append them to the stream.
40 virtual Error appendBytes(const char *Src, unsigned Size) = 0;
41
42 /// Flush the stream if possible.
43 virtual Error send() = 0;
44
45 /// Get the lock for stream reading.
46 std::mutex &getReadLock() { return readLock; }
47
48 /// Get the lock for stream writing.
49 std::mutex &getWriteLock() { return writeLock; }
50
51 private:
52 std::mutex readLock, writeLock;
53 };
54
55 /// Notify the channel that we're starting a message send.
56 /// Locks the channel for writing.
57 inline Error startSendMessage(RPCByteChannel &C) {
58 C.getWriteLock().lock();
59 return Error::success();
60 }
61
62 /// Notify the channel that we're ending a message send.
63 /// Unlocks the channel for writing.
64 inline Error endSendMessage(RPCByteChannel &C) {
65 C.getWriteLock().unlock();
66 return Error::success();
67 }
68
69 /// Notify the channel that we're starting a message receive.
70 /// Locks the channel for reading.
71 inline Error startReceiveMessage(RPCByteChannel &C) {
72 C.getReadLock().lock();
73 return Error::success();
74 }
75
76 /// Notify the channel that we're ending a message receive.
77 /// Unlocks the channel for reading.
78 inline Error endReceiveMessage(RPCByteChannel &C) {
79 C.getReadLock().unlock();
80 return Error::success();
81 }
82
83 template
84 typename =
85 typename std::enable_if<
86 std::is_base_of::value>::
87 type>
88 class RPCByteChannelPrimitiveSerialization {
89 public:
90 static Error serialize(ChannelT &C, T V) {
91 support::endian::byte_swap(V);
92 return C.appendBytes(reinterpret_cast(&V), sizeof(T));
93 };
94
95 static Error deserialize(ChannelT &C, T &V) {
96 if (auto Err = C.readBytes(reinterpret_cast(&V), sizeof(T)))
97 return Err;
98 support::endian::byte_swap(V);
99 return Error::success();
100 };
101 };
102
103 template
104 class SerializationTraits
105 : public RPCByteChannelPrimitiveSerialization {
106 public:
107 static const char* getName() { return "uint64_t"; }
108 };
109
110 template
111 class SerializationTraits
112 : public RPCByteChannelPrimitiveSerialization {
113 public:
114 static const char* getName() { return "int64_t"; }
115 };
116
117 template
118 class SerializationTraits
119 : public RPCByteChannelPrimitiveSerialization {
120 public:
121 static const char* getName() { return "uint32_t"; }
122 };
123
124 template
125 class SerializationTraits
126 : public RPCByteChannelPrimitiveSerialization {
127 public:
128 static const char* getName() { return "int32_t"; }
129 };
130
131 template
132 class SerializationTraits
133 : public RPCByteChannelPrimitiveSerialization {
134 public:
135 static const char* getName() { return "uint16_t"; }
136 };
137
138 template
139 class SerializationTraits
140 : public RPCByteChannelPrimitiveSerialization {
141 public:
142 static const char* getName() { return "int16_t"; }
143 };
144
145 template
146 class SerializationTraits
147 : public RPCByteChannelPrimitiveSerialization {
148 public:
149 static const char* getName() { return "uint8_t"; }
150 };
151
152 template
153 class SerializationTraits
154 : public RPCByteChannelPrimitiveSerialization {
155 public:
156 static const char* getName() { return "int8_t"; }
157 };
158
159 template
160 class SerializationTraits
161 : public RPCByteChannelPrimitiveSerialization {
162 public:
163 static const char* getName() { return "char"; }
164
165 static Error serialize(RPCByteChannel &C, char V) {
166 return serializeSeq(C, static_cast(V));
167 };
168
169 static Error deserialize(RPCByteChannel &C, char &V) {
170 uint8_t VV;
171 if (auto Err = deserializeSeq(C, VV))
172 return Err;
173 V = static_cast(V);
174 return Error::success();
175 };
176 };
177
178 template
179 class SerializationTraits
180 typename std::enable_if<
181 std::is_base_of::value>::
182 type> {
183 public:
184 static const char* getName() { return "bool"; }
185
186 static Error serialize(ChannelT &C, bool V) {
187 return C.appendBytes(reinterpret_cast(&V), 1);
188 }
189
190 static Error deserialize(ChannelT &C, bool &V) {
191 return C.readBytes(reinterpret_cast(&V), 1);
192 }
193 };
194
195 template
196 class SerializationTraits
197 typename std::enable_if<
198 std::is_base_of::value>::
199 type> {
200 public:
201 static const char* getName() { return "std::string"; }
202
203 static Error serialize(RPCByteChannel &C, StringRef S) {
204 if (auto Err = SerializationTraits::
205 serialize(C, static_cast(S.size())))
206 return Err;
207 return C.appendBytes((const char *)S.bytes_begin(), S.size());
208 }
209
210 /// RPC channel serialization for std::strings.
211 static Error serialize(RPCByteChannel &C, const std::string &S) {
212 return serialize(C, StringRef(S));
213 }
214
215 /// RPC channel deserialization for std::strings.
216 static Error deserialize(RPCByteChannel &C, std::string &S) {
217 uint64_t Count = 0;
218 if (auto Err = SerializationTraits::
219 deserialize(C, Count))
220 return Err;
221 S.resize(Count);
222 return C.readBytes(&S[0], Count);
223 }
224 };
225
226 } // end namespace remote
227 } // end namespace orc
228 } // end namespace llvm
229
230 #endif // LLVM_EXECUTIONENGINE_ORC_RPCBYTECHANNEL_H
1616
1717 namespace llvm {
1818 namespace orc {
19 namespace remote {
19 namespace rpc {
20
21 template
22 class RPCTypeName;
23
24 /// TypeNameSequence is a utility for rendering sequences of types to a string
25 /// by rendering each type, separated by ", ".
26 template class RPCTypeNameSequence {};
27
28 /// Render an empty TypeNameSequence to an ostream.
29 template
30 OStream &operator<<(OStream &OS, const RPCTypeNameSequence<> &V) {
31 return OS;
32 }
33
34 /// Render a TypeNameSequence of a single type to an ostream.
35 template
36 OStream &operator<<(OStream &OS, const RPCTypeNameSequence &V) {
37 OS << RPCTypeName::getName();
38 return OS;
39 }
40
41 /// Render a TypeNameSequence of more than one type to an ostream.
42 template
43 OStream&
44 operator<<(OStream &OS, const RPCTypeNameSequence &V) {
45 OS << RPCTypeName::getName() << ", "
46 << RPCTypeNameSequence();
47 return OS;
48 }
49
50 template <>
51 class RPCTypeName {
52 public:
53 static const char* getName() { return "void"; }
54 };
55
56 template <>
57 class RPCTypeName {
58 public:
59 static const char* getName() { return "int8_t"; }
60 };
61
62 template <>
63 class RPCTypeName {
64 public:
65 static const char* getName() { return "uint8_t"; }
66 };
67
68 template <>
69 class RPCTypeName {
70 public:
71 static const char* getName() { return "int16_t"; }
72 };
73
74 template <>
75 class RPCTypeName {
76 public:
77 static const char* getName() { return "uint16_t"; }
78 };
79
80 template <>
81 class RPCTypeName {
82 public:
83 static const char* getName() { return "int32_t"; }
84 };
85
86 template <>
87 class RPCTypeName {
88 public:
89 static const char* getName() { return "uint32_t"; }
90 };
91
92 template <>
93 class RPCTypeName {
94 public:
95 static const char* getName() { return "int64_t"; }
96 };
97
98 template <>
99 class RPCTypeName {
100 public:
101 static const char* getName() { return "uint64_t"; }
102 };
103
104 template <>
105 class RPCTypeName {
106 public:
107 static const char* getName() { return "bool"; }
108 };
109
110 template <>
111 class RPCTypeName {
112 public:
113 static const char* getName() { return "std::string"; }
114 };
115
116 template
117 class RPCTypeName> {
118 public:
119 static const char* getName() {
120 std::lock_guard Lock(NameMutex);
121 if (Name.empty())
122 raw_string_ostream(Name) << "std::pair<" << RPCTypeNameSequence()
123 << ">";
124 return Name.data();
125 }
126 private:
127 static std::mutex NameMutex;
128 static std::string Name;
129 };
130
131 template
132 std::mutex RPCTypeName>::NameMutex;
133 template
134 std::string RPCTypeName>::Name;
135
136 template
137 class RPCTypeName> {
138 public:
139 static const char* getName() {
140 std::lock_guard Lock(NameMutex);
141 if (Name.empty())
142 raw_string_ostream(Name) << "std::tuple<"
143 << RPCTypeNameSequence() << ">";
144 return Name.data();
145 }
146 private:
147 static std::mutex NameMutex;
148 static std::string Name;
149 };
150
151 template
152 std::mutex RPCTypeName>::NameMutex;
153 template
154 std::string RPCTypeName>::Name;
155
156 template
157 class RPCTypeName> {
158 public:
159 static const char*getName() {
160 std::lock_guard Lock(NameMutex);
161 if (Name.empty())
162 raw_string_ostream(Name) << "std::vector<" << RPCTypeName::getName()
163 << ">";
164 return Name.data();
165 }
166
167 private:
168 static std::mutex NameMutex;
169 static std::string Name;
170 };
171
172 template
173 std::mutex RPCTypeName>::NameMutex;
174 template
175 std::string RPCTypeName>::Name;
176
20177
21178 /// The SerializationTraits class describes how to serialize and
22179 /// deserialize an instance of type T to/from an abstract channel of type
50207 /// }
51208 ///
52209 /// @endcode
53 template T, typename = void>
210 template WireType, typename From = WireType,
211 typename = void>
54212 class SerializationTraits {};
55213
56 /// TypeNameSequence is a utility for rendering sequences of types to a string
57 /// by rendering each type, separated by ", ".
58 template class TypeNameSequence {};
59
60 /// Render a TypeNameSequence of a single type to an ostream.
61 template
62 OStream &operator<<(OStream &OS, const TypeNameSequence &V) {
63 OS << SerializationTraits::getName();
64 return OS;
65 }
66
67 /// Render a TypeNameSequence of more than one type to an ostream.
68 template
69 typename... ArgTs>
70 OStream &
71 operator<<(OStream &OS,
72 const TypeNameSequence &V) {
73 OS << SerializationTraits::getName() << ", "
74 << TypeNameSequence();
75 return OS;
76 }
77
78 /// RPC channel serialization for a variadic list of arguments.
79 template
80 Error serializeSeq(ChannelT &C, const T &Arg, const Ts &... Args) {
81 if (auto Err = SerializationTraits::serialize(C, Arg))
82 return Err;
83 return serializeSeq(C, Args...);
84 }
85
86 /// RPC channel serialization for an (empty) variadic list of arguments.
87 template Error serializeSeq(ChannelT &C) {
88 return Error::success();
89 }
90
91 /// RPC channel deserialization for a variadic list of arguments.
92 template
93 Error deserializeSeq(ChannelT &C, T &Arg, Ts &... Args) {
94 if (auto Err = SerializationTraits::deserialize(C, Arg))
95 return Err;
96 return deserializeSeq(C, Args...);
97 }
98
99 /// RPC channel serialization for an (empty) variadic list of arguments.
100 template Error deserializeSeq(ChannelT &C) {
101 return Error::success();
214 template
215 class SequenceTraits {
216 public:
217 static Error emitSeparator(ChannelT &C) { return Error::success(); }
218 static Error consumeSeparator(ChannelT &C) { return Error::success(); }
219 };
220
221 /// Utility class for serializing sequences of values of varying types.
222 /// Specializations of this class contain 'serialize' and 'deserialize' methods
223 /// for the given channel. The ArgTs... list will determine the "over-the-wire"
224 /// types to be serialized. The serialize and deserialize methods take a list
225 /// CArgTs... ("caller arg types") which must be the same length as ArgTs...,
226 /// but may be different types from ArgTs, provided that for each CArgT there
227 /// is a SerializationTraits specialization
228 /// SerializeTraits with methods that can serialize the
229 /// caller argument to over-the-wire value.
230 template
231 class SequenceSerialization;
232
233 template
234 class SequenceSerialization {
235 public:
236 static Error serialize(ChannelT &C) { return Error::success(); }
237 static Error deserialize(ChannelT &C) { return Error::success(); }
238 };
239
240 template
241 class SequenceSerialization {
242 public:
243
244 template
245 static Error serialize(ChannelT &C, const CArgT &CArg) {
246 return SerializationTraits::serialize(C, CArg);
247 }
248
249 template
250 static Error deserialize(ChannelT &C, CArgT &CArg) {
251 return SerializationTraits::deserialize(C, CArg);
252 }
253 };
254
255 template
256 class SequenceSerialization {
257 public:
258
259 template
260 static Error serialize(ChannelT &C, const CArgT &CArg,
261 const CArgTs&... CArgs) {
262 if (auto Err =
263 SerializationTraits::serialize(C, CArg))
264 return Err;
265 if (auto Err = SequenceTraits::emitSeparator(C))
266 return Err;
267 return SequenceSerialization::serialize(C, CArgs...);
268 }
269
270 template
271 static Error deserialize(ChannelT &C, CArgT &CArg,
272 CArgTs&... CArgs) {
273 if (auto Err =
274 SerializationTraits::deserialize(C, CArg))
275 return Err;
276 if (auto Err = SequenceTraits::consumeSeparator(C))
277 return Err;
278 return SequenceSerialization::deserialize(C, CArgs...);
279 }
280 };
281
282 template
283 Error serializeSeq(ChannelT &C, const ArgTs &... Args) {
284 return SequenceSerialization::serialize(C, Args...);
285 }
286
287 template
288 Error deserializeSeq(ChannelT &C, ArgTs &... Args) {
289 return SequenceSerialization::deserialize(C, Args...);
102290 }
103291
104292 /// SerializationTraits default specialization for std::pair.
105293 template
106294 class SerializationTraits> {
107295 public:
108 static const char *getName() {
109 std::lock_guard Lock(NameMutex);
110 if (Name.empty())
111 Name = (std::ostringstream()
112 << "std::pair<" << TypeNameSequence() << ">")
113 .str();
114
115 return Name.data();
116 }
117
118296 static Error serialize(ChannelT &C, const std::pair &V) {
119297 return serializeSeq(C, V.first, V.second);
120298 }
122300 static Error deserialize(ChannelT &C, std::pair &V) {
123301 return deserializeSeq(C, V.first, V.second);
124302 }
125
126 private:
127 static std::mutex NameMutex;
128 static std::string Name;
129 };
130
131 template
132 std::mutex SerializationTraits>::NameMutex;
133
134 template
135 std::string SerializationTraits>::Name;
303 };
136304
137305 /// SerializationTraits default specialization for std::tuple.
138306 template
139307 class SerializationTraits> {
140308 public:
141 static const char *getName() {
142 std::lock_guard Lock(NameMutex);
143 if (Name.empty())
144 Name = (std::ostringstream()
145 << "std::tuple<" << TypeNameSequence() << ">")
146 .str();
147
148 return Name.data();
149 }
150309
151310 /// RPC channel serialization for std::tuple.
152311 static Error serialize(ChannelT &C, const std::tuple &V) {
172331 llvm::index_sequence _) {
173332 return deserializeSeq(C, std::get(V)...);
174333 }
175
176 static std::mutex NameMutex;
177 static std::string Name;
178 };
179
180 template
181 std::mutex SerializationTraits>::NameMutex;
182
183 template
184 std::string SerializationTraits>::Name;
334 };
185335
186336 /// SerializationTraits default specialization for std::vector.
187337 template
188338 class SerializationTraits> {
189339 public:
190 static const char *getName() {
191 std::lock_guard Lock(NameMutex);
192 if (Name.empty())
193 Name = (std::ostringstream() << "std::vector<"
194 << TypeNameSequence() << ">")
195 .str();
196 return Name.data();
197 }
198
340
341 /// Serialize a std::vector from std::vector.
199342 static Error serialize(ChannelT &C, const std::vector &V) {
200 if (auto Err = SerializationTraits::serialize(
201 C, static_cast(V.size())))
343 if (auto Err = serializeSeq(C, static_cast(V.size())))
202344 return Err;
203345
204346 for (const auto &E : V)
205 if (auto Err = SerializationTraits::serialize(C, E))
347 if (auto Err = serializeSeq(C, E))
206348 return Err;
207349
208350 return Error::success();
209351 }
210352
353 /// Deserialize a std::vector to a std::vector.
211354 static Error deserialize(ChannelT &C, std::vector &V) {
212355 uint64_t Count = 0;
213 if (auto Err =
214 SerializationTraits::deserialize(C, Count))
356 if (auto Err = deserializeSeq(C, Count))
215357 return Err;
216358
217359 V.resize(Count);
218360 for (auto &E : V)
219 if (auto Err = SerializationTraits::deserialize(C, E))
361 if (auto Err = deserializeSeq(C, E))
220362 return Err;
221363
222364 return Error::success();
223365 }
224
225 private:
226 static std::mutex NameMutex;
227 static std::string Name;
228 };
229
230 template
231 std::mutex SerializationTraits>::NameMutex;
232
233 template
234 std::string SerializationTraits>::Name;
235
236 } // end namespace remote
366 };
367
368 } // end namespace rpc
237369 } // end namespace orc
238370 } // end namespace llvm
239371
None //===----- RPCUTils.h - Basic tilities for building RPC APIs ----*- C++ -*-===//
0 //===------- RPCUTils.h - Utilities for building RPC APIs -------*- C++ -*-===//
11 //
22 // The LLVM Compiler Infrastructure
33 //
66 //
77 //===----------------------------------------------------------------------===//
88 //
9 // Basic utilities for building RPC APIs.
9 // Utilities to support construction of simple RPC APIs.
10 //
11 // The RPC utilities aim for ease of use (minimal conceptual overhead) for C++
12 // programmers, high performance, low memory overhead, and efficient use of the
13 // communications channel.
1014 //
1115 //===----------------------------------------------------------------------===//
1216
1418 #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
1519
1620 #include
21 #include
1722 #include
1823
1924 #include "llvm/ADT/STLExtras.h"
2025 #include "llvm/ExecutionEngine/Orc/OrcError.h"
26 #include "llvm/ExecutionEngine/Orc/RPCSerialization.h"
2127
2228 #ifdef _MSC_VER
2329 // concrt.h depends on eh.h for __uncaught_exception declaration
3844
3945 namespace llvm {
4046 namespace orc {
41 namespace remote {
42
43 /// Describes reserved RPC Function Ids.
47 namespace rpc {
48
49 template
50 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
56 class Function {
57 public:
58
59 /// User defined function type.
60 using Type = RetT(ArgTs...);
61
62 /// Return type.
63 using ReturnType = RetT;
64
65 /// Returns the full function prototype as a string.
66 static const char *getPrototype() {
67 std::lock_guard Lock(NameMutex);
68 if (Name.empty())
69 raw_string_ostream(Name)
70 << RPCTypeName::getName() << " " << DerivedFunc::getName()
71 << "(" << llvm::orc::rpc::RPCTypeNameSequence() << ")";
72 return Name.data();
73 }
74 private:
75 static std::mutex NameMutex;
76 static std::string Name;
77 };
78
79
80 template
81 std::mutex Function::NameMutex;
82
83 template
84 std::string Function::Name;
85
86 /// Allocates RPC function ids during autonegotiation.
87 /// Specializations of this class must provide four members:
4488 ///
45 /// The default implementation will serve for integer and enum function id
46 /// types. If you want to use a custom type as your FunctionId you can
47 /// specialize this class and provide unique values for InvalidId,
48 /// ResponseId and FirstValidId.
49
50 template class RPCFunctionIdTraits {
51 public:
52 static const T InvalidId = static_cast(0);
53 static const T ResponseId = static_cast(1);
54 static const T FirstValidId = static_cast(2);
55 };
56
57 // Base class containing utilities that require partial specialization.
58 // These cannot be included in RPC, as template class members cannot be
59 // partially specialized.
60 class RPCBase {
61 protected:
62
63 // FIXME: Remove MSVCPError/MSVCPExpected once MSVC's future implementation
64 // supports classes without default constructors.
89 /// static T getInvalidId():
90 /// Should return a reserved id that will be used to represent missing
91 /// functions during autonegotiation.
92 ///
93 /// static T getResponseId():
94 /// Should return a reserved id that will be used to send function responses
95 /// (return values).
96 ///
97 /// static T getNegotiateId():
98 /// Should return a reserved id for the negotiate function, which will be used
99 /// to negotiate ids for user defined functions.
100 ///
101 /// template T allocate():
102 /// Allocate a unique id for function Func.
103 template
104 class RPCFunctionIdAllocator;
105
106 /// This specialization of RPCFunctionIdAllocator provides a default
107 /// implementation for integral types.
108 template
109 class RPCFunctionIdAllocator
110 typename std::enable_if<
111 std::is_integral::value
112 >::type> {
113 public:
114
115 static T getInvalidId() { return T(0); }
116 static T getResponseId() { return T(1); }
117 static T getNegotiateId() { return T(2); }
118
119 template
120 T allocate(){ return NextId++; }
121 private:
122 T NextId = 3;
123 };
124
125 namespace detail {
126
127 // FIXME: Remove MSVCPError/MSVCPExpected once MSVC's future implementation
128 // supports classes without default constructors.
65129 #ifdef _MSC_VER
130
131 namespace msvc_hacks {
66132
67133 // Work around MSVC's future implementation's use of default constructors:
68134 // A default constructed value in the promise will be overwritten when the
85151 MSVCPError(Error Err) : Error(std::move(Err)) {}
86152 };
87153
88 // Likewise for Expected:
154 // Work around MSVC's future implementation, similar to MSVCPError.
89155 template
90156 class MSVCPExpected : public Expected {
91157 public:
122188 nullptr) : Expected(std::move(Other)) {}
123189 };
124190
191 } // end namespace msvc_hacks
192
125193 #endif // _MSC_VER
126194
127 // RPC Function description type.
128 //
129 // This class provides the information and operations needed to support the
130 // RPC primitive operations (call, expect, etc) for a given function. It
131 // is specialized for void and non-void functions to deal with the differences
132 // betwen the two. Both specializations have the same interface:
133 //
134 // Id - The function's unique identifier.
135 // ErrorReturn - The return type for blocking calls.
136 // readResult - Deserialize a result from a channel.
137 // abandon - Abandon a promised result.
138 // respond - Retun a result on the channel.
139 template
140 class FunctionHelper {};
141
142 // RPC Function description specialization for non-void functions.
143 template
144 typename... ArgTs>
145 class FunctionHelper {
146 public:
147 static_assert(FuncId != RPCFunctionIdTraits::InvalidId &&
148 FuncId != RPCFunctionIdTraits::ResponseId,
149 "Cannot define custom function with InvalidId or ResponseId. "
150 "Please use RPCFunctionTraits::FirstValidId.");
151
152 static const FunctionIdT Id = FuncId;
153
154 typedef Expected ErrorReturn;
155
156 // FIXME: Ditch PErrorReturn (replace it with plain ErrorReturn) once MSVC's
157 // std::future implementation supports types without default
158 // constructors.
195 // ResultTraits provides typedefs and utilities specific to the return type
196 // of functions.
197 template
198 class ResultTraits {
199 public:
200
201 // The return type wrapped in llvm::Expected.
202 using ErrorReturnType = Expected;
203
159204 #ifdef _MSC_VER
160 typedef MSVCPExpected PErrorReturn;
205 // The ErrorReturnType wrapped in a std::promise.
206 using ReturnPromiseType = std::promise>;
207
208 // The ErrorReturnType wrapped in a std::future.
209 using ReturnFutureType = std::future>;
161210 #else
162 typedef Expected PErrorReturn;
211 // The ErrorReturnType wrapped in a std::promise.
212 using ReturnPromiseType = std::promise;
213
214 // The ErrorReturnType wrapped in a std::future.
215 using ReturnFutureType = std::future;
163216 #endif
164217
165 template
166 static Error readResult(ChannelT &C, std::promise &P) {
167 RetT Val;
168 auto Err = deserializeSeq(C, Val);
169 auto Err2 = endReceiveMessage(C);
170 Err = joinErrors(std::move(Err), std::move(Err2));
171 if (Err)
172 return Err;
173
174 P.set_value(std::move(Val));
175 return Error::success();
176 }
177
178 static void abandon(std::promise &P) {
179 P.set_value(
180 make_error("RPC function call failed to return",
181 inconvertibleErrorCode()));
182 }
183
184 static void consumeAbandoned(std::future &P) {
185 consumeError(P.get().takeError());
186 }
187
188 template
189 static Error respond(ChannelT &C, SequenceNumberT SeqNo,
190 ErrorReturn &Result) {
191 FunctionIdT ResponseId = RPCFunctionIdTraits::ResponseId;
192
193 // If the handler returned an error then bail out with that.
194 if (!Result)
195 return Result.takeError();
196
197 // Otherwise open a new message on the channel and send the result.
198 if (auto Err = startSendMessage(C))
199 return Err;
200 if (auto Err = serializeSeq(C, ResponseId, SeqNo, *Result))
201 return Err;
202 return endSendMessage(C);
203 }
204 };
205
206 // RPC Function description specialization for void functions.
207 template
208 class FunctionHelper {
209 public:
210 static_assert(FuncId != RPCFunctionIdTraits::InvalidId &&
211 FuncId != RPCFunctionIdTraits::ResponseId,
212 "Cannot define custom function with InvalidId or ResponseId. "
213 "Please use RPCFunctionTraits::FirstValidId.");
214
215 static const FunctionIdT Id = FuncId;
216
217 typedef Error ErrorReturn;
218
219 // FIXME: Ditch PErrorReturn (replace it with plain ErrorReturn) once MSVC's
220 // std::future implementation supports types without default
221 // constructors.
218 // Create a 'blank' value of the ErrorReturnType, ready and safe to
219 // overwrite.
220 static ErrorReturnType createBlankErrorReturnValue() {
221 return ErrorReturnType(RetT());
222 }
223
224 // Consume an abandoned ErrorReturnType.
225 static void consumeAbandoned(ErrorReturnType RetOrErr) {
226 consumeError(RetOrErr.takeError());
227 }
228 };
229
230 // ResultTraits specialization for void functions.
231 template <>
232 class ResultTraits {
233 public:
234
235 // For void functions, ErrorReturnType is llvm::Error.
236 using ErrorReturnType = Error;
237
222238 #ifdef _MSC_VER
223 typedef MSVCPError PErrorReturn;
239 // The ErrorReturnType wrapped in a std::promise.
240 using ReturnPromiseType = std::promise;
241
242 // The ErrorReturnType wrapped in a std::future.
243 using ReturnFutureType = std::future;
224244 #else
225 typedef Error PErrorReturn;
245 // The ErrorReturnType wrapped in a std::promise.
246 using ReturnPromiseType = std::promise;
247
248 // The ErrorReturnType wrapped in a std::future.
249 using ReturnFutureType = std::future;
226250 #endif
227251
228 template
229 static Error readResult(ChannelT &C, std::promise &P) {
230 // Void functions don't have anything to deserialize, so we're good.
231 P.set_value(Error::success());
232 return endReceiveMessage(C);
233 }
234
235 static void abandon(std::promise &P) {
236 P.set_value(
237 make_error("RPC function call failed to return",
238 inconvertibleErrorCode()));
239 }
240
241 static void consumeAbandoned(std::future &P) {
242 consumeError(P.get());
243 }
244
245 template
246 static Error respond(ChannelT &C, SequenceNumberT SeqNo,
247 ErrorReturn &Result) {
248 const FunctionIdT ResponseId =
249 RPCFunctionIdTraits::ResponseId;
250
251 // If the handler returned an error then bail out with that.
252 if (Result)
253 return std::move(Result);
254
255 // Otherwise open a new message on the channel and send the result.
256 if (auto Err = startSendMessage(C))
257 return Err;
258 if (auto Err = serializeSeq(C, ResponseId, SeqNo))
259 return Err;
260 return endSendMessage(C);
261 }
262 };
263
264 // Helper for the call primitive.
265 template
266 class CallHelper;
267
268 template
269 FunctionIdT FuncId, typename RetT, typename... ArgTs>
270 class CallHelper
271 FunctionHelper> {
272 public:
273 static Error call(ChannelT &C, SequenceNumberT SeqNo,
274 const ArgTs &... Args) {
275 if (auto Err = startSendMessage(C))
276 return Err;
277 if (auto Err = serializeSeq(C, FuncId, SeqNo, Args...))
278 return Err;
279 return endSendMessage(C);
280 }
281 };
282
283 // Helper for handle primitive.
284 template
285 class HandlerHelper;
286
287 template
288 FunctionIdT FuncId, typename RetT, typename... ArgTs>
289 class HandlerHelper
290 FunctionHelper> {
291 public:
292 template
293 static Error handle(ChannelT &C, HandlerT Handler) {
294 return readAndHandle(C, Handler, llvm::index_sequence_for());
295 }
296
297 private:
298 typedef FunctionHelper Func;
299
300 template
301 static Error readAndHandle(ChannelT &C, HandlerT Handler,
302 llvm::index_sequence _) {
303 std::tuple RPCArgs;
304 SequenceNumberT SeqNo;
305 // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
306 // for RPCArgs. Void cast RPCArgs to work around this for now.
307 // FIXME: Remove this workaround once we can assume a working GCC version.
308 (void)RPCArgs;
309 if (auto Err = deserializeSeq(C, SeqNo, std::get(RPCArgs)...))
310 return Err;
311
312 // We've deserialized the arguments, so unlock the channel for reading
313 // before we call the handler. This allows recursive RPC calls.
314 if (auto Err = endReceiveMessage(C))
315 return Err;
316
317 // Run the handler and get the result.
318 auto Result = Handler(std::get(RPCArgs)...);
319
320 // Return the result to the client.
321 return Func::template respond(C, SeqNo,
322 Result);
323 }
324 };
325
326 // Helper for wrapping member functions up as functors.
327 template
328 class MemberFnWrapper {
329 public:
330 typedef RetT (ClassT::*MethodT)(ArgTs...);
331 MemberFnWrapper(ClassT &Instance, MethodT Method)
332 : Instance(Instance), Method(Method) {}
333 RetT operator()(ArgTs &... Args) { return (Instance.*Method)(Args...); }
334
335 private:
336 ClassT &Instance;
337 MethodT Method;
338 };
339
340 // Helper that provides a Functor for deserializing arguments.
341 template class ReadArgs {
342 public:
343 Error operator()() { return Error::success(); }
344 };
345
346 template
347 class ReadArgs : public ReadArgs {
348 public:
349 ReadArgs(ArgT &Arg, ArgTs &... Args)
350 : ReadArgs(Args...), Arg(Arg) {}
351
352 Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
353 this->Arg = std::move(ArgVal);
354 return ReadArgs::operator()(ArgVals...);
355 }
356
357 private:
358 ArgT &Arg;
359 };
252 // Create a 'blank' value of the ErrorReturnType, ready and safe to
253 // overwrite.
254 static ErrorReturnType createBlankErrorReturnValue() {
255 return ErrorReturnType::success();
256 }
257
258 // Consume an abandoned ErrorReturnType.
259 static void consumeAbandoned(ErrorReturnType Err) {
260 consumeError(std::move(Err));
261 }
262 };
263
264 // ResultTraits is equivalent to ResultTraits. 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 <>
269 class ResultTraits : public ResultTraits {};
270
271 // ResultTraits> is equivalent to ResultTraits. This allows
272 // handlers for RPC functions returning a T to return either a T (in which
273 // case they implicitly succeed) or Expected (in which case their error
274 // return is propagated). See usage in HandlerTraits::runHandlerHelper.
275 template
276 class ResultTraits> : public ResultTraits {};
277
278 // Send a response of the given wire return type (WireRetT) over the
279 // channel, with the given sequence number.
280 template
281 typename FunctionIdT, typename SequenceNumberT>
282 static Error respond(ChannelT &C, const FunctionIdT &ResponseId,
283 SequenceNumberT SeqNo, Expected ResultOrErr) {
284 // If this was an error bail out.
285 // FIXME: Send an "error" message to the client if this is not a channel
286 // failure?
287 if (auto Err = ResultOrErr.takeError())
288 return Err;
289
290 // Open the response message.
291 if (auto Err = C.startSendMessage(ResponseId, SeqNo))
292 return Err;
293
294 // Serialize the result.
295 if (auto Err = SerializationTraits::
296 serialize(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
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 // This template class provides utilities related to RPC function handlers.
317 // The base case applies to non-function types (the template class is
318 // specialized for function types) and inherits from the appropriate
319 // speciilization for the given non-function type's call operator.
320 template
321 class HandlerTraits
322 : public HandlerTraits
323 &std::remove_reference::type::operator())> {};
324
325 // Traits for handlers with a given function type.
326 template
327 class HandlerTraits {
328 public:
329
330 // Function type of the handler.
331 using Type = RetT(ArgTs...);
332
333 // Return type of the handler.
334 using ReturnType = RetT;
335
336 // A std::tuple wrapping the handler arguments.
337 using ArgStorage =
338 std::tuple<
339 typename std::decay<
340 typename std::remove_reference::type>::type...>;
341
342 // Call the given handler with the given arguments.
343 template
344 static typename ResultTraits::ErrorReturnType
345 runHandler(HandlerT &Handler, ArgStorage &Args) {
346 return runHandlerHelper(Handler, Args,
347 llvm::index_sequence_for());
348 }
349
350 // Serialize arguments to the channel.
351 template
352 static Error serializeArgs(ChannelT &C, const CArgTs... CArgs) {
353 return SequenceSerialization::serialize(C, CArgs...);
354 }
355
356 // Deserialize arguments from the channel.
357 template
358 static Error deserializeArgs(ChannelT &C, std::tuple &Args) {
359 return deserializeArgsHelper(C, Args,
360 llvm::index_sequence_for());
361 }
362
363 private:
364
365 // For non-void user handlers: unwrap the args tuple and call the handler,
366 // returning the result.
367 template
368 static typename std::enable_if<
369 !std::is_void::value,
370 typename ResultTraits::ErrorReturnType>::type
371 runHandlerHelper(HandlerT &Handler, ArgStorage &Args,
372 llvm::index_sequence) {
373 return Handler(std::move(std::get(Args))...);
374 }
375
376 // For void user handlers: unwrap the args tuple and call the handler, then
377 // return Error::success().
378 template
379 static typename std::enable_if<
380 std::is_void::value,
381 typename ResultTraits::ErrorReturnType>::type
382 runHandlerHelper(HandlerT &Handler, ArgStorage &Args,
383 llvm::index_sequence) {
384 Handler(std::move(std::get(Args))...);
385 return ResultTraits::ErrorReturnType::success();
386 }
387
388 template
389 static
390 Error deserializeArgsHelper(ChannelT &C, std::tuple &Args,
391 llvm::index_sequence _) {
392 return SequenceSerialization::
393 deserialize(C, std::get(Args)...);
394 }
395
396 };
397
398 // Handler traits for class methods (especially call operators for lambdas).
399 template
400 class HandlerTraits
401 : public HandlerTraits {};
402
403 // Handler traits for const class methods (especially call operators for
404 // lambdas).
405 template
406 class HandlerTraits
407 : public HandlerTraits {};
408
409 // Utility to peel the Expected wrapper off a response handler error type.
410 template
411 class UnwrapResponseHandlerArg;
412
413 template
414 class UnwrapResponseHandlerArg)> {
415 public:
416 using ArgType = ArgT;
417 };
418
419 // ResponseHandler represents a handler for a not-yet-received function call
420 // result.
421 template
422 class ResponseHandler {
423 public:
424 virtual ~ResponseHandler() {}
425
426 // Reads the function result off the wire and acts on it. The meaning of
427 // "act" will depend on how this method is implemented in any given
428 // ResponseHandler subclass but could, for example, mean running a
429 // user-specified handler or setting a promise value.
430 virtual Error handleResponse(ChannelT &C) = 0;
431
432 // Abandons this outstanding result.
433 virtual void abandon() = 0;
434
435 // Create an error instance representing an abandoned response.
436 static Error createAbandonedResponseError() {
437 return make_error("RPC function call failed to return",
438 inconvertibleErrorCode());
439 }
440 };
441
442 // ResponseHandler subclass for RPC functions with non-void returns.
443 template
444 class ResponseHandlerImpl : public ResponseHandler {
445 public:
446 ResponseHandlerImpl(HandlerT Handler)
447 : Handler(std::move(Handler)) {}
448
449 // Handle the result by deserializing it from the channel then passing it
450 // to the user defined handler.
451 Error handleResponse(ChannelT &C) override {
452 using ArgType = typename UnwrapResponseHandlerArg<
453 typename HandlerTraits::Type>::ArgType;
454 ArgType Result;
455 if (auto Err = SerializationTraits::
456 deserialize(C, Result))
457 return Err;
458 if (auto Err = C.endReceiveMessage())
459 return Err;
460 return Handler(Result);
461 }
462
463 // Abandon this response by calling the handler with an 'abandoned response'
464 // error.
465 void abandon() override {
466 if (auto Err = Handler(this->createAbandonedResponseError())) {
467 // Handlers should not fail when passed an abandoned response error.
468 report_fatal_error(std::move(Err));
469 }
470 }
471
472 private:
473 HandlerT Handler;
474 };
475
476 // ResponseHandler subclass for RPC functions with void returns.
477 template
478 class ResponseHandlerImpl
479 : public ResponseHandler {
480 public:
481 ResponseHandlerImpl(HandlerT Handler)
482 : Handler(std::move(Handler)) {}
483
484 // Handle the result (no actual value, just a notification that the function
485 // has completed on the remote end) by calling the user-defined handler with
486 // Error::success().
487 Error handleResponse(ChannelT &C) override {
488 if (auto Err = C.endReceiveMessage())
489 return Err;
490 return Handler(Error::success());
491 }
492
493 // Abandon this response by calling the handler with an 'abandoned response'
494 // error.
495 void abandon() override {
496 if (auto Err = Handler(this->createAbandonedResponseError())) {
497 // Handlers should not fail when passed an abandoned response error.
498 report_fatal_error(std::move(Err));
499 }
500 }
501
502 private:
503 HandlerT Handler;
504 };
505
506 // Create a ResponseHandler from a given user handler.
507 template
508 std::unique_ptr>
509 createResponseHandler(HandlerT H) {
510 return llvm::make_unique<
511 ResponseHandlerImpl>(std::move(H));
512 }
513
514 // Helper for wrapping member functions up as functors. This is useful for
515 // installing methods as result handlers.
516 template
517 class MemberFnWrapper {
518 public:
519 using MethodT = RetT(ClassT::*)(ArgTs...);
520 MemberFnWrapper(ClassT &Instance, MethodT Method)
521 : Instance(Instance), Method(Method) {}
522 RetT operator()(ArgTs &&... Args) {
523 return (Instance.*Method)(std::move(Args)...);
524 }
525 private:
526 ClassT &Instance;
527 MethodT Method;
528 };
529
530 // Helper that provides a Functor for deserializing arguments.
531 template class ReadArgs {
532 public:
533 Error operator()() { return Error::success(); }
534 };
535
536 template
537 class ReadArgs : public ReadArgs {
538 public:
539 ReadArgs(ArgT &Arg, ArgTs &... Args)
540 : ReadArgs(Args...), Arg(Arg) {}
541
542 Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
543 this->Arg = std::move(ArgVal);
544 return ReadArgs::operator()(ArgVals...);
545 }
546 private:
547 ArgT &Arg;
548 };
549
550 // Manage sequence numbers.
551 template
552 class SequenceNumberManager {
553 public:
554 // Reset, making all sequence numbers available.
555 void reset() {
556 std::lock_guard Lock(SeqNoLock);
557 NextSequenceNumber = 0;
558 FreeSequenceNumbers.clear();
559 }
560
561 // Get the next available sequence number. Will re-use numbers that have
562 // been released.
563 SequenceNumberT getSequenceNumber() {
564 std::lock_guard Lock(SeqNoLock);
565 if (FreeSequenceNumbers.empty())
566 return NextSequenceNumber++;
567 auto SequenceNumber = FreeSequenceNumbers.back();
568 FreeSequenceNumbers.pop_back();
569 return SequenceNumber;
570 }
571
572 // Release a sequence number, making it available for re-use.
573 void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
574 std::lock_guard Lock(SeqNoLock);
575 FreeSequenceNumbers.push_back(SequenceNumber);
576 }
577
578 private:
579 std::mutex SeqNoLock;
580 SequenceNumberT NextSequenceNumber = 0;
581 std::vector FreeSequenceNumbers;
360582 };
361583
362584 /// Contains primitive utilities for defining, calling and handling calls to
363585 /// remote procedures. ChannelT is a bidirectional stream conforming to the
364 /// RPCChannel interface (see RPCChannel.h), and FunctionIdT is a procedure
365 /// identifier type that must be serializable on ChannelT.
586 /// RPCChannel interface (see RPCChannel.h), FunctionIdT is a procedure
587 /// identifier type that must be serializable on ChannelT, and SequenceNumberT
588 /// is an integral type that will be used to number in-flight function calls.
366589 ///
367590 /// These utilities support the construction of very primitive RPC utilities.
368591 /// Their intent is to ensure correct serialization and deserialization of
369592 /// procedure arguments, and to keep the client and server's view of the API in
370593 /// sync.
371 ///
372 /// These utilities do not support return values. These can be handled by
373 /// declaring a corresponding '.*Response' procedure and expecting it after a
374 /// call). They also do not support versioning: the client and server *must* be
375 /// compiled with the same procedure definitions.
376 ///
377 ///
378 ///
379 /// Overview (see comments individual types/methods for details):
380 ///
381 /// Function :
382 ///
383 /// associates a unique serializable id with an argument list.
384 ///
385 ///
386 /// call(Channel, Args...) :
387 ///
388 /// Calls the remote procedure 'Func' by serializing Func's id followed by its
389 /// arguments and sending the resulting bytes to 'Channel'.
390 ///
391 ///
392 /// handle(Channel, :
393 ///
394 /// Handles a call to 'Func' by deserializing its arguments and calling the
395 /// given functor. This assumes that the id for 'Func' has already been
396 /// deserialized.
397 ///
398 /// expect(Channel, :
399 ///
400 /// The same as 'handle', except that the procedure id should not have been
401 /// read yet. Expect will deserialize the id and assert that it matches Func's
402 /// id. If it does not, and unexpected RPC call error is returned.
403 template
404 typename SequenceNumberT = uint16_t>
405 class RPC : public RPCBase {
406 public:
407 /// RPC default constructor.
408 RPC() = default;
409
410 /// RPC instances cannot be copied.
411 RPC(RPC &&) = default;
412 RPC &operator=(RPC &&) = default;
413
414 /// Utility class for defining/referring to RPC procedures.
415 ///
416 /// Typedefs of this utility are used when calling/handling remote procedures.
417 ///
418 /// FuncId should be a unique value of FunctionIdT (i.e. not used with any
419 /// other Function typedef in the RPC API being defined.
420 ///
421 /// the template argument Ts... gives the argument list for the remote
422 /// procedure.
423 ///
424 /// E.g.
425 ///
426 /// typedef Function<0, bool> Func1;
427 /// typedef Function<1, std::string, std::vector> Func2;
428 ///
429 /// if (auto Err = call(Channel, true))
430 /// /* handle Err */;
431 ///
432 /// if (auto Err = expect(Channel,
433 /// [](std::string &S, std::vector &V) {
434 /// // Stuff.
435 /// return Error::success();
436 /// })
437 /// /* handle Err */;
438 ///
439 template
440 using Function = FunctionHelper;
441
442 /// Return type for non-blocking call primitives.
443 template
444 using NonBlockingCallResult = std::future;
445
446 /// Return type for non-blocking call-with-seq primitives.
447 template
448 using NonBlockingCallWithSeqResult =
449 std::pair, SequenceNumberT>;
450
451 /// Call Func on Channel C. Does not block, does not call send. Returns a pair
452 /// of a future result and the sequence number assigned to the result.
453 ///
454 /// This utility function is primarily used for single-threaded mode support,
455 /// where the sequence number can be used to wait for the corresponding
456 /// result. In multi-threaded mode the appendCallNB method, which does not
457 /// return the sequence numeber, should be preferred.
458 template
459 Expected>
460 appendCallNBWithSeq(ChannelT &C, const ArgTs &... Args) {
594 template
595 typename SequenceNumberT>
596 class RPCBase {
597 protected:
598
599 class OrcRPCInvalid : public Function {
600 public:
601 static const char *getName() { return "__orc_rpc$invalid"; }
602 };
603
604 class OrcRPCResponse : public Function {
605 public:
606 static const char *getName() { return "__orc_rpc$response"; }
607 };
608
609 class OrcRPCNegotiate
610 : public Function {
611 public:
612 static const char *getName() { return "__orc_rpc$negotiate"; }
613 };
614
615 public:
616
617 /// Construct an RPC instance on a channel.
618 RPCBase(ChannelT &C, bool LazyAutoNegotiation)
619 : C(C), LazyAutoNegotiation(LazyAutoNegotiation) {
620 // Hold ResponseId in a special variable, since we expect Response to be
621 // called relatively frequently, and want to avoid the map lookup.
622 ResponseId = FnIdAllocator.getResponseId();
623 RemoteFunctionIds[OrcRPCResponse::getPrototype()] = ResponseId;
624
625 // Register the negotiate function id and handler.
626 auto NegotiateId = FnIdAllocator.getNegotiateId();
627 RemoteFunctionIds[OrcRPCNegotiate::getPrototype()] = NegotiateId;
628 Handlers[NegotiateId] =
629 wrapHandler([this](const std::string &Name) {
630 return handleNegotiate(Name);
631 }, LaunchPolicy());
632 }
633
634 /// Append a call Func, does not call send on the channel.
635 /// The first argument specifies a user-defined handler to be run when the
636 /// function returns. The handler should take an Expected,
637 /// or an Error (if Func::ReturnType is void). The handler will be called
638 /// with an error if the return value is abandoned due to a channel error.
639 template
640 Error appendCallAsync(HandlerT Handler, const ArgTs &... Args) {
641 // Look up the function ID.
642 FunctionIdT FnId;
643 if (auto FnIdOrErr = getRemoteFunctionId())
644 FnId = *FnIdOrErr;
645 else {
646 // This isn't a channel error so we don't want to abandon other pending
647 // responses, but we still need to run the user handler with an error to
648 // let them know the call failed.
649 if (auto Err = Handler(orcError(OrcErrorCode::UnknownRPCFunction)))
650 report_fatal_error(std::move(Err));
651 return FnIdOrErr.takeError();
652 }
653
654 // Allocate a sequence number.
461655 auto SeqNo = SequenceNumberMgr.getSequenceNumber();
462 std::promise Promise;
463 auto Result = Promise.get_future();
464 OutstandingResults[SeqNo] =
465 createOutstandingResult(std::move(Promise));
466
467 if (auto Err = CallHelper::call(C, SeqNo,
468 Args...)) {
469 abandonOutstandingResults();
470 Func::consumeAbandoned(Result);
656 assert(!PendingResponses.count(SeqNo) &&
657 "Sequence number already allocated");
658
659 // Install the user handler.
660 PendingResponses[SeqNo] =
661 detail::createResponseHandler(
662 std::move(Handler));
663
664 // Open the function call message.
665 if (auto Err = C.startSendMessage(FnId, SeqNo)) {
666 abandonPendingResponses();
667 return joinErrors(std::move(Err), C.endSendMessage());
668 }
669
670 // Serialize the call arguments.
671 if (auto Err =
672 detail::HandlerTraits::
673 serializeArgs(C, Args...)) {
674 abandonPendingResponses();
675 return joinErrors(std::move(Err), C.endSendMessage());
676 }
677
678 // Close the function call messagee.
679 if (auto Err = C.endSendMessage()) {
680 abandonPendingResponses();
471681 return std::move(Err);
472 } else
473 return NonBlockingCallWithSeqResult(std::move(Result), SeqNo);
474 }
475
476 /// The same as appendCallNBWithSeq, except that it calls C.send() to
477 /// flush the channel after serializing the call.
478 template
479 Expected>
480 callNBWithSeq(ChannelT &C, const ArgTs &... Args) {
481 auto Result = appendCallNBWithSeq(C, Args...);
482 if (!Result)
483 return Result;
484 if (auto Err = C.send()) {
485 abandonOutstandingResults();
486 Func::consumeAbandoned(Result->first);
487 return std::move(Err);
488 }
489 return Result;
490 }
491
492 /// Serialize Args... to channel C, but do not call send.
493 /// Returns an error if serialization fails, otherwise returns a
494 /// std::future> (or a future for void functions).
495 template
496 Expected> appendCallNB(ChannelT &C,
497 const ArgTs &... Args) {
498 auto FutureResAndSeqOrErr = appendCallNBWithSeq(C, Args...);
499 if (FutureResAndSeqOrErr)
500 return std::move(FutureResAndSeqOrErr->first);
501 return FutureResAndSeqOrErr.takeError();
502 }
503
504 /// The same as appendCallNB, except that it calls C.send to flush the
505 /// channel after serializing the call.
506 template
507 Expected> callNB(ChannelT &C,
508 const ArgTs &... Args) {
509 auto FutureResAndSeqOrErr = callNBWithSeq(C, Args...);
510 if (FutureResAndSeqOrErr)
511 return std::move(FutureResAndSeqOrErr->first);
512 return FutureResAndSeqOrErr.takeError();
513 }
514
515 /// Call Func on Channel C. Blocks waiting for a result. Returns an Error
516 /// for void functions or an Expected for functions returning a T.
517 ///
518 /// This function is for use in threaded code where another thread is
519 /// handling responses and incoming calls.
520 template
521 typename Func::ErrorReturn callB(ChannelT &C, const ArgTs &... Args) {
522 if (auto FutureResOrErr = callNBWithSeq(C, Args...)) {
523 if (auto Err = C.send()) {
524 abandonOutstandingResults();
525 Func::consumeAbandoned(FutureResOrErr->first);
526 return std::move(Err);
527 }
528 return FutureResOrErr->first.get();
529 } else
530 return FutureResOrErr.takeError();
531 }
532
533 /// Call Func on Channel C. Block waiting for a result. While blocked, run
534 /// HandleOther to handle incoming calls (Response calls will be handled
535 /// implicitly before calling HandleOther). Returns an Error for void
536 /// functions or an Expected for functions returning a T.
537 ///
538 /// This function is for use in single threaded mode when the calling thread
539 /// must act as both sender and receiver.
540 template
541 typename Func::ErrorReturn
542 callSTHandling(ChannelT &C, HandleFtor &HandleOther, const ArgTs &... Args) {
543 if (auto ResultAndSeqNoOrErr = callNBWithSeq(C, Args...)) {
544 auto &ResultAndSeqNo = *ResultAndSeqNoOrErr;
545 if (auto Err = waitForResult(C, ResultAndSeqNo.second, HandleOther))
546 return std::move(Err);
547 return ResultAndSeqNo.first.get();
548 } else
549 return ResultAndSeqNoOrErr.takeError();
550 }
551
552 /// Call Func on Channel C. Block waiting for a result. Returns an Error for
553 /// void functions or an Expected for functions returning a T.
554 template
555 typename Func::ErrorReturn callST(ChannelT &C, const ArgTs &... Args) {
556 return callSTHandling(C, handleNone, Args...);
557 }
558
559 /// Start receiving a new function call.
560 ///
561 /// Calls startReceiveMessage on the channel, then deserializes a FunctionId
562 /// into Id.
563 Error startReceivingFunction(ChannelT &C, FunctionIdT &Id) {
564 if (auto Err = startReceiveMessage(C))
682 }
683
684 return Error::success();
685 }
686
687
688 template
689 Error callAsync(HandlerT Handler, const ArgTs &... Args) {
690 if (auto Err = appendCallAsync(std::move(Handler), Args...))
565691 return Err;
566
567 return deserializeSeq(C, Id);
568 }
569
570 /// Deserialize args for Func from C and call Handler. The signature of
571 /// handler must conform to 'Error(Args...)' where Args... matches
572 /// the arguments used in the Func typedef.
573 template
574 static Error handle(ChannelT &C, HandlerT Handler) {
575 return HandlerHelper::handle(C, Handler);
576 }
577
578 /// Helper version of 'handle' for calling member functions.
579 template
580 static Error handle(ChannelT &C, ClassT &Instance,
581 RetT (ClassT::*HandlerMethod)(ArgTs...)) {
582 return handle(
583 C, MemberFnWrapper(Instance, HandlerMethod));
584 }
585
586 /// Deserialize a FunctionIdT from C and verify it matches the id for Func.
587 /// If the id does match, deserialize the arguments and call the handler
588 /// (similarly to handle).
589 /// If the id does not match, return an unexpect RPC call error and do not
590 /// deserialize any further bytes.
591 template
592 Error expect(ChannelT &C, HandlerT Handler) {
593 FunctionIdT FuncId;
594 if (auto Err = startReceivingFunction(C, FuncId))
595 return std::move(Err);
596 if (FuncId != Func::Id)
597 return orcError(OrcErrorCode::UnexpectedRPCCall);
598 return handle(C, Handler);
599 }
600
601 /// Helper version of expect for calling member functions.
602 template
603 static Error expect(ChannelT &C, ClassT &Instance,
604 Error (ClassT::*HandlerMethod)(ArgTs...)) {
605 return expect(
606 C, MemberFnWrapper(Instance, HandlerMethod));
692 return C.send();
693 }
694
695 /// Handle one incoming call.
696 Error handleOne() {
697 FunctionIdT FnId;
698 SequenceNumberT SeqNo;
699 if (auto Err = C.startReceiveMessage(FnId, SeqNo))
700 return Err;
701 if (FnId == ResponseId)
702 return handleResponse(SeqNo);
703 auto I = Handlers.find(FnId);
704 if (I != Handlers.end())
705 return I->second(C, SeqNo);
706
707 // else: No handler found. Report error to client?
708 return orcError(OrcErrorCode::UnexpectedRPCCall);
607709 }
608710
609711 /// Helper for handling setter procedures - this method returns a functor that
620722 /// /* Handle Args */ ;
621723 ///
622724 template
623 static ReadArgs readArgs(ArgTs &... Args) {
624 return ReadArgs(Args...);
625 }
626
627 /// Read a response from Channel.
628 /// This should be called from the receive loop to retrieve results.
629 Error handleResponse(ChannelT &C, SequenceNumberT *SeqNoRet = nullptr) {
630 SequenceNumberT SeqNo;
631 if (auto Err = deserializeSeq(C, SeqNo)) {
632 abandonOutstandingResults();
725 static detail::ReadArgs readArgs(ArgTs &... Args) {
726 return detail::ReadArgs(Args...);
727 }
728
729 protected:
730 // The LaunchPolicy type allows a launch policy to be specified when adding
731 // a function handler. See addHandlerImpl.
732 using LaunchPolicy = std::function)>;
733
734 /// Add the given handler to the handler map and make it available for
735 /// autonegotiation and execution.
736 template
737 void addHandlerImpl(HandlerT Handler, LaunchPolicy Launch) {
738 FunctionIdT NewFnId = FnIdAllocator.template allocate();
739 LocalFunctionIds[Func::getPrototype()] = NewFnId;
740 Handlers[NewFnId] = wrapHandler(std::move(Handler),
741 std::move(Launch));
742 }
743
744 // Abandon all outstanding results.
745 void abandonPendingResponses() {
746 for (auto &KV : PendingResponses)
747 KV.second->abandon();
748 PendingResponses.clear();
749 SequenceNumberMgr.reset();
750 }
751
752 Error handleResponse(SequenceNumberT SeqNo) {
753 auto I = PendingResponses.find(SeqNo);
754 if (I == PendingResponses.end()) {
755 abandonPendingResponses();
756 return orcError(OrcErrorCode::UnexpectedRPCResponse);
757 }
758
759 auto PRHandler = std::move(I->second);
760 PendingResponses.erase(I);
761 SequenceNumberMgr.releaseSequenceNumber(SeqNo);
762
763 if (auto Err = PRHandler->handleResponse(C)) {
764 abandonPendingResponses();
765 SequenceNumberMgr.reset();
633766 return Err;
634767 }
635768
636 if (SeqNoRet)
637 *SeqNoRet = SeqNo;
638
639 auto I = OutstandingResults.find(SeqNo);
640 if (I == OutstandingResults.end()) {
641 abandonOutstandingResults();
642 return orcError(OrcErrorCode::UnexpectedRPCResponse);
643 }
644
645 if (auto Err = I->second->readResult(C)) {
646 abandonOutstandingResults();
647 // FIXME: Release sequence numbers?
769 return Error::success();
770 }
771
772 FunctionIdT handleNegotiate(const std::string &Name) {
773 auto I = LocalFunctionIds.find(Name);
774 if (I == LocalFunctionIds.end())
775 return FnIdAllocator.getInvalidId();
776 return I->second;
777 }
778
779 // Find the remote FunctionId for the given function, which must be in the
780 // RemoteFunctionIds map.
781 template
782 Expected getRemoteFunctionId() {
783 // Try to find the id for the given function.
784 auto I = RemoteFunctionIds.find(Func::getPrototype());
785
786 // If we have it in the map, return it.
787 if (I != RemoteFunctionIds.end())
788 return I->second;
789
790 // Otherwise, if we have auto-negotiation enabled, try to negotiate it.
791 if (LazyAutoNegotiation) {
792 auto &Impl = static_cast(*this);
793 if (auto RemoteIdOrErr =
794 Impl.template callB(Func::getPrototype())) {
795 auto &RemoteId = *RemoteIdOrErr;
796
797 // If autonegotiation indicates that the remote end doesn't support this
798 // function, return an unknown function error.
799 if (RemoteId == FnIdAllocator.getInvalidId())
800 return orcError(OrcErrorCode::UnknownRPCFunction);
801
802 // Autonegotiation succeeded and returned a valid id. Update the map and
803 // return the id.
804 RemoteFunctionIds[Func::getPrototype()] = RemoteId;
805 return RemoteId;
806 } else {
807 // Autonegotiation failed. Return the error.
808 return RemoteIdOrErr.takeError();
809 }
810 }
811
812 // No key was available in the map and autonegotiation wasn't enabled.
813 // Return an unknown function error.
814 return orcError(OrcErrorCode::UnknownRPCFunction);
815 }
816
817 using WrappedHandlerFn = std::function;
818
819 // Wrap the given user handler in the necessary argument-deserialization code,
820 // result-serialization code, and call to the launch policy (if present).
821 template
822 WrappedHandlerFn wrapHandler(HandlerT Handler, LaunchPolicy Launch) {
823 return
824 [this, Handler, Launch](ChannelT &Channel, SequenceNumberT SeqNo) -> Error {
825 // Start by deserializing the arguments.
826 auto Args =
827 std::make_shared::ArgStorage>();
828 if (auto Err = detail::HandlerTraits::
829 deserializeArgs(Channel, *Args))
830 return Err;
831
832 // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
833 // for RPCArgs. Void cast RPCArgs to work around this for now.
834 // FIXME: Remove this workaround once we can assume a working GCC version.
835 (void)Args;
836
837 // End receieve message, unlocking the channel for reading.
838 if (auto Err = Channel.endReceiveMessage())
839 return Err;
840
841 // Build the handler/responder.
842 auto Responder =
843 [this, Handler, Args, &Channel, SeqNo]() mutable -> Error {
844 using HTraits = detail::HandlerTraits;
845 using FuncReturn = typename Func::ReturnType;
846 return detail::respond(Channel, ResponseId, SeqNo,
847 HTraits::runHandler(Handler,
848 *Args));
849 };
850
851 // If there is an explicit launch policy then use it to launch the
852 // handler.
853 if (Launch)
854 return Launch(std::move(Responder));
855
856 // Otherwise run the handler on the listener thread.
857 return Responder();
858 };
859 }
860
861 ChannelT &C;
862
863 bool LazyAutoNegotiation;
864
865 RPCFunctionIdAllocator FnIdAllocator;
866
867 FunctionIdT ResponseId;
868 std::map LocalFunctionIds;
869 std::map RemoteFunctionIds;
870
871 std::map Handlers;
872
873 detail::SequenceNumberManager SequenceNumberMgr;
874 std::map>>
875 PendingResponses;
876 };
877
878 } // end namespace detail
879
880
881 template
882 typename FunctionIdT = uint32_t,
883 typename SequenceNumberT = uint32_t>
884 class MultiThreadedRPC
885 : public detail::RPCBase
886 SequenceNumberT>,
887 ChannelT, FunctionIdT, SequenceNumberT> {
888 private:
889 using BaseClass =
890 detail::RPCBase,
891 ChannelT, FunctionIdT, SequenceNumberT>;
892
893 public:
894
895 MultiThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
896 : BaseClass(C, LazyAutoNegotiation) {}
897
898 /// The LaunchPolicy type allows a launch policy to be specified when adding
899 /// a function handler. See addHandler.
900 using LaunchPolicy = typename BaseClass::LaunchPolicy;
901
902 /// Add a handler for the given RPC function.
903 /// This installs the given handler functor for the given RPC Function, and
904 /// makes the RPC function available for negotiation/calling from the remote.
905 ///
906 /// The optional LaunchPolicy argument can be used to control how the handler
907 /// is run when called:
908 ///
909 /// * If no LaunchPolicy is given, the handler code will be run on the RPC
910 /// handler thread that is reading from the channel. This handler cannot
911 /// make blocking RPC calls (since it would be blocking the thread used to
912 /// get the result), but can make non-blocking calls.
913 ///
914 /// * If a LaunchPolicy is given, the user's handler will be wrapped in a
915 /// call to serialize and send the result, and the resulting functor (with
916 /// type 'Error()' will be passed to the LaunchPolicy. The user can then
917 /// choose to add the wrapped handler to a work queue, spawn a new thread,
918 /// or anything else.
919 template
920 void addHandler(HandlerT Handler, LaunchPolicy Launch = LaunchPolicy()) {
921 return this->template addHandlerImpl(std::move(Handler),
922 std::move(Launch));
923 }
924
925 /// Negotiate a function id for Func with the other end of the channel.
926 template
927 Error negotiateFunction() {
928 using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
929
930 if (auto RemoteIdOrErr = callB(Func::getPrototype())) {
931 this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
932 return Error::success();
933 } else
934 return RemoteIdOrErr.takeError();
935 }
936
937 /// Convenience method for negotiating multiple functions at once.
938 template
939 Error negotiateFunctions() {
940 return negotiateFunction();
941 }
942
943 /// Convenience method for negotiating multiple functions at once.
944 template
945 Error negotiateFunctions() {
946 if (auto Err = negotiateFunction())
648947 return Err;
649 }
650
651 OutstandingResults.erase(I);
652 SequenceNumberMgr.releaseSequenceNumber(SeqNo);
653
948 return negotiateFunctions();
949 }
950
951 /// Return type for non-blocking call primitives.
952 template
953 using NonBlockingCallResult =
954 typename detail::ResultTraits::ReturnFutureType;
955
956 /// Call Func on Channel C. Does not block, does not call send. Returns a pair
957 /// of a future result and the sequence number assigned to the result.
958 ///
959 /// This utility function is primarily used for single-threaded mode support,
960 /// where the sequence number can be used to wait for the corresponding
961 /// result. In multi-threaded mode the appendCallNB method, which does not
962 /// return the sequence numeber, should be preferred.
963 template
964 Expected>
965 appendCallNB(const ArgTs &... Args) {
966 using RTraits = detail::ResultTraits;
967 using ErrorReturn = typename RTraits::ErrorReturnType;
968 using ErrorReturnPromise = typename RTraits::ReturnPromiseType;
969
970 // FIXME: Stack allocate and move this into the handler once LLVM builds
971 // with C++14.
972 auto Promise = std::make_shared();
973 auto FutureResult = Promise->get_future();
974
975 if (auto Err = this->template appendCallAsync(
976 [Promise](ErrorReturn RetOrErr) {
977 Promise->set_value(std::move(RetOrErr));
978 return Error::success();
979 }, Args...)) {
980 this->abandonPendingResponses();
981 RTraits::consumeAbandoned(FutureResult.get());
982 return std::move(Err);
983 }
984 return std::move(FutureResult);
985 }
986
987 /// The same as appendCallNBWithSeq, except that it calls C.send() to
988 /// flush the channel after serializing the call.
989 template
990 Expected>
991 callNB(const ArgTs &... Args) {
992 auto Result = appendCallNB(Args...);
993 if (!Result)
994 return Result;
995 if (auto Err = this->C.send()) {
996 this->abandonPendingResponses();
997 detail::ResultTraits::
998 consumeAbandoned(std::move(Result->get()));
999 return std::move(Err);
1000 }
1001 return Result;
1002 }
1003
1004 /// Call Func on Channel C. Blocks waiting for a result. Returns an Error
1005 /// for void functions or an Expected for functions returning a T.
1006 ///
1007 /// This function is for use in threaded code where another thread is
1008 /// handling responses and incoming calls.
1009 template
1010 typename AltRetT = typename Func::ReturnType>
1011 typename detail::ResultTraits::ErrorReturnType
1012 callB(const ArgTs &... Args) {
1013 if (auto FutureResOrErr = callNB(Args...)) {
1014 if (auto Err = this->C.send()) {
1015 this->abandonPendingResponses();
1016 detail::ResultTraits::
1017 consumeAbandoned(std::move(FutureResOrErr->get()));
1018 return std::move(Err);
1019 }
1020 return FutureResOrErr->get();
1021 } else
1022 return FutureResOrErr.takeError();
1023 }
1024
1025 /// Handle incoming RPC calls.
1026 Error handlerLoop() {
1027 while (true)
1028 if (auto Err = this->handleOne())
1029 return Err;
6541030 return Error::success();
6551031 }
6561032
657 // Loop waiting for a result with the given sequence number.
658 // This can be used as a receive loop if the user doesn't have a default.
659 template
660 Error waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo,
661 HandleOtherFtor &HandleOther = handleNone) {
662 bool GotTgtResult = false;
663
664 while (!GotTgtResult) {
665 FunctionIdT Id = RPCFunctionIdTraits::InvalidId;
666 if (auto Err = startReceivingFunction(C, Id))
667 return Err;
668 if (Id == RPCFunctionIdTraits::ResponseId) {
669 SequenceNumberT SeqNo;
670 if (auto Err = handleResponse(C, &SeqNo))
671 return Err;
672 GotTgtResult = (SeqNo == TgtSeqNo);
673 } else if (auto Err = HandleOther(C, Id))
674 return Err;
675 }
676
677 return Error::success();
678 }
679
680 // Default handler for 'other' (non-response) functions when waiting for a
681 // result from the channel.
682 static Error handleNone(ChannelT &, FunctionIdT) {
683 return orcError(OrcErrorCode::UnexpectedRPCCall);
684 };
685
1033 };
1034
1035 template
1036 typename FunctionIdT = uint32_t,
1037 typename SequenceNumberT = uint32_t>
1038 class SingleThreadedRPC
1039 : public detail::RPCBase
1040 SequenceNumberT>,
1041 ChannelT, FunctionIdT,
1042 SequenceNumberT> {
6861043 private:
687 // Manage sequence numbers.
688 class SequenceNumberManager {
689 public:
690 SequenceNumberManager() = default;
691
692 SequenceNumberManager(const SequenceNumberManager &) = delete;
693 SequenceNumberManager &operator=(const SequenceNumberManager &) = delete;
694
695 SequenceNumberManager(SequenceNumberManager &&Other)
696 : NextSequenceNumber(std::move(Other.NextSequenceNumber)),
697 FreeSequenceNumbers(std::move(Other.FreeSequenceNumbers)) {}
698
699 SequenceNumberManager &operator=(SequenceNumberManager &&Other) {
700 NextSequenceNumber = std::move(Other.NextSequenceNumber);
701 FreeSequenceNumbers = std::move(Other.FreeSequenceNumbers);
702 return *this;
703 }
704
705 void reset() {
706 std::lock_guard Lock(SeqNoLock);
707 NextSequenceNumber = 0;
708 FreeSequenceNumbers.clear();
709 }
710
711 SequenceNumberT getSequenceNumber() {
712 std::lock_guard Lock(SeqNoLock);
713 if (FreeSequenceNumbers.empty())
714 return NextSequenceNumber++;
715 auto SequenceNumber = FreeSequenceNumbers.back();
716 FreeSequenceNumbers.pop_back();
717 return SequenceNumber;
718 }
719
720 void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
721 std::lock_guard Lock(SeqNoLock);
722 FreeSequenceNumbers.push_back(SequenceNumber);
723 }
724
725 private:
726 std::mutex SeqNoLock;
727 SequenceNumberT NextSequenceNumber = 0;
728 std::vector FreeSequenceNumbers;
729 };
730
731 // Base class for results that haven't been returned from the other end of the
732 // RPC connection yet.
733 class OutstandingResult {
734 public:
735 virtual ~OutstandingResult() {}
736 virtual Error readResult(ChannelT &C) = 0;
737 virtual void abandon() = 0;
738 };
739
740 // Outstanding results for a specific function.
1044
1045 using BaseClass = detail::RPCBase
1046 SequenceNumberT>,
1047 ChannelT, FunctionIdT, SequenceNumberT>;
1048
1049 using LaunchPolicy = typename BaseClass::LaunchPolicy;
1050
1051 public:
1052
1053 SingleThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
1054 : BaseClass(C, LazyAutoNegotiation) {}
1055
1056 template
1057 void addHandler(HandlerT Handler) {
1058 return this->template addHandlerImpl(std::move(Handler),
1059 LaunchPolicy());
1060 }
1061
1062 template
1063 void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
1064 addHandler(
1065 detail::MemberFnWrapper(Object, Method));
1066 }
1067
1068 /// Negotiate a function id for Func with the other end of the channel.
7411069 template
742 class OutstandingResultImpl : public OutstandingResult {
743 private:
744 public:
745 OutstandingResultImpl(std::promise &&P)
746 : P(std::move(P)) {}
747
748 Error readResult(ChannelT &C) override { return Func::readResult(C, P); }
749
750 void abandon() override { Func::abandon(P); }
751
752 private:
753 std::promise P;
754 };
755
756 // Create an outstanding result for the given function.
1070 Error negotiateFunction() {
1071 using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
1072
1073 if (auto RemoteIdOrErr = callB(Func::getPrototype())) {
1074 this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
1075 return Error::success();
1076 } else
1077 return RemoteIdOrErr.takeError();
1078 }
1079
1080 /// Convenience method for negotiating multiple functions at once.
7571081 template
758 std::unique_ptr
759 createOutstandingResult(std::promise &&P) {
760 return llvm::make_unique>(std::move(P));
761 }
762
763 // Abandon all outstanding results.
764 void abandonOutstandingResults() {
765 for (auto &KV : OutstandingResults)
766 KV.second->abandon();
767 OutstandingResults.clear();
768 SequenceNumberMgr.reset();
769 }
770
771 SequenceNumberManager SequenceNumberMgr;
772 std::map>
773 OutstandingResults;
774 };
775
776 } // end namespace remote
1082 Error negotiateFunctions() {
1083 return negotiateFunction();
1084 }
1085
1086 /// Convenience method for negotiating multiple functions at once.
1087 template
1088 Error negotiateFunctions() {
1089 if (auto Err = negotiateFunction())
1090 return Err;
1091 return negotiateFunctions();
1092 }
1093
1094 template
1095 typename AltRetT = typename Func::ReturnType>
1096 typename detail::ResultTraits::ErrorReturnType
1097 callB(const ArgTs &... Args) {
1098 bool ReceivedResponse = false;
1099 using ResultType =
1100 typename detail::ResultTraits::ErrorReturnType;
1101 auto Result = detail::ResultTraits::createBlankErrorReturnValue();
1102
1103 // We have to 'Check' result (which we know is in a success state at this
1104 // point) so that it can be overwritten in the async handler.
1105 (void)!!Result;
1106
1107 if (auto Err = this->template appendCallAsync(
1108 [&](ResultType R) {
1109 Result = std::move(R);
1110 ReceivedResponse = true;
1111 return Error::success();
1112 }, Args...)) {
1113 this->abandonPendingResponses();
1114 detail::ResultTraits::
1115 consumeAbandoned(std::move(Result));
1116 return std::move(Err);
1117 }
1118
1119 while (!ReceivedResponse) {
1120 if (auto Err = this->handleOne()) {
1121 this->abandonPendingResponses();
1122 detail::ResultTraits::
1123 consumeAbandoned(std::move(Result));
1124 return std::move(Err);
1125 }
1126 }
1127
1128 return Result;
1129 }
1130
1131 //using detail::RPCBase::handleOne;
1132
1133 };
1134
1135 } // end namespace rpc
7771136 } // end namespace orc
7781137 } // end namespace llvm
7791138
0 //===- llvm/ExecutionEngine/Orc/RawByteChannel.h ----------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_EXECUTIONENGINE_ORC_RAWBYTECHANNEL_H
10 #define LLVM_EXECUTIONENGINE_ORC_RAWBYTECHANNEL_H
11
12 #include "OrcError.h"
13 #include "RPCSerialization.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/Endian.h"
18 #include "llvm/Support/Error.h"
19 #include
20 #include
21 #include
22 #include
23 #include
24 #include
25 #include
26
27 namespace llvm {
28 namespace orc {
29 namespace rpc {
30
31 /// Interface for byte-streams to be used with RPC.
32 class RawByteChannel {
33 public:
34 virtual ~RawByteChannel() {}
35
36 /// Read Size bytes from the stream into *Dst.
37 virtual Error readBytes(char *Dst, unsigned Size) = 0;
38
39 /// Read size bytes from *Src and append them to the stream.
40 virtual Error appendBytes(const char *Src, unsigned Size) = 0;
41
42 /// Flush the stream if possible.
43 virtual Error send() = 0;
44
45 /// Notify the channel that we're starting a message send.
46 /// Locks the channel for writing.
47 template
48 Error startSendMessage(const FunctionIdT &FnId, const SequenceIdT &SeqNo) {
49 if (auto Err = serializeSeq(*this, FnId, SeqNo))
50 return Err;
51 writeLock.lock();
52 return Error::success();
53 }
54
55 /// Notify the channel that we're ending a message send.
56 /// Unlocks the channel for writing.
57 Error endSendMessage() {
58 writeLock.unlock();
59 return Error::success();
60 }
61
62 /// Notify the channel that we're starting a message receive.
63 /// Locks the channel for reading.
64 template
65 Error startReceiveMessage(FunctionIdT &FnId, SequenceNumberT &SeqNo) {
66 readLock.lock();
67 return deserializeSeq(*this, FnId, SeqNo);
68 }
69
70 /// Notify the channel that we're ending a message receive.
71 /// Unlocks the channel for reading.
72 Error endReceiveMessage() {
73 readLock.unlock();
74 return Error::success();
75 }
76
77 /// Get the lock for stream reading.
78 std::mutex &getReadLock() { return readLock; }
79
80 /// Get the lock for stream writing.
81 std::mutex &getWriteLock() { return writeLock; }
82
83 private:
84 std::mutex readLock, writeLock;
85 };
86
87 template
88 class SerializationTraits
89 typename std::enable_if<
90 std::is_base_of::value &&
91 (std::is_same::value ||
92 std::is_same::value ||
93 std::is_same::value ||
94 std::is_same::value ||
95 std::is_same::value ||
96 std::is_same::value ||
97 std::is_same::value ||
98 std::is_same::value ||
99 std::is_same::value)>::type> {
100 public:
101 static Error serialize(ChannelT &C, T V) {
102 support::endian::byte_swap(V);
103 return C.appendBytes(reinterpret_cast(&V), sizeof(T));
104 };
105
106 static Error deserialize(ChannelT &C, T &V) {
107 if (auto Err = C.readBytes(reinterpret_cast(&V), sizeof(T)))
108 return Err;
109 support::endian::byte_swap(V);
110 return Error::success();
111 };
112 };
113
114 template
115 class SerializationTraits
116 typename std::enable_if<
117 std::is_base_of::value>::
118 type> {
119 public:
120 static Error serialize(ChannelT &C, bool V) {
121 return C.appendBytes(reinterpret_cast(&V), 1);
122 }
123
124 static Error deserialize(ChannelT &C, bool &V) {
125 return C.readBytes(reinterpret_cast(&V), 1);
126 }
127 };
128
129 template
130 class SerializationTraits
131 typename std::enable_if<
132 std::is_base_of::value>::
133 type> {
134 public:
135 /// RPC channel serialization for std::strings.
136 static Error serialize(RawByteChannel &C, StringRef S) {
137 if (auto Err = serializeSeq(C, static_cast(S.size())))
138 return Err;
139 return C.appendBytes((const char *)S.data(), S.size());
140 }
141 };
142
143 template
144 class SerializationTraits
145 typename std::enable_if<
146 std::is_base_of::value>::
147 type> {
148 public:
149 static Error serialize(RawByteChannel &C, const char *S) {
150 return SerializationTraits::
151 serialize(C, S);
152 }
153 };
154
155 template
156 class SerializationTraits
157 typename std::enable_if<
158 std::is_base_of::value>::
159 type> {
160 public:
161 /// RPC channel serialization for std::strings.
162 static Error serialize(RawByteChannel &C, const std::string &S) {
163 return SerializationTraits::
164 serialize(C, S);
165 }
166
167 /// RPC channel deserialization for std::strings.
168 static Error deserialize(RawByteChannel &C, std::string &S) {
169 uint64_t Count = 0;
170 if (auto Err = deserializeSeq(C, Count))
171 return Err;
172 S.resize(Count);
173 return C.readBytes(&S[0], Count);
174 }
175 };
176
177 } // end namespace rpc
178 } // end namespace orc
179 } // end namespace llvm
180
181 #endif // LLVM_EXECUTIONENGINE_ORC_RAWBYTECHANNEL_H
55 OrcCBindings.cpp
66 OrcError.cpp
77 OrcMCJITReplacement.cpp
8 OrcRemoteTargetRPCAPI.cpp
98
109 ADDITIONAL_HEADER_DIRS
1110 ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
4242 return "Unexpected RPC call";
4343 case OrcErrorCode::UnexpectedRPCResponse:
4444 return "Unexpected RPC response";
45 case OrcErrorCode::UnknownRPCFunction:
46 return "Unknown RPC function";
4547 }
4648 llvm_unreachable("Unhandled error code");
4749 }
+0
-53
lib/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.cpp less more
None //===------- OrcRemoteTargetRPCAPI.cpp - ORC Remote API utilities ---------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
10
11 namespace llvm {
12 namespace orc {
13 namespace remote {
14
15 #define FUNCNAME(X) \
16 case X ## Id: \
17 return #X
18
19 const char *OrcRemoteTargetRPCAPI::getJITFuncIdName(JITFuncId Id) {
20 switch (Id) {
21 case InvalidId:
22 return "*** Invalid JITFuncId ***";
23 FUNCNAME(CallIntVoid);
24 FUNCNAME(CallMain);
25 FUNCNAME(CallVoidVoid);
26 FUNCNAME(CreateRemoteAllocator);
27 FUNCNAME(CreateIndirectStubsOwner);
28 FUNCNAME(DeregisterEHFrames);
29 FUNCNAME(DestroyRemoteAllocator);
30 FUNCNAME(DestroyIndirectStubsOwner);
31 FUNCNAME(EmitIndirectStubs);
32 FUNCNAME(EmitResolverBlock);
33 FUNCNAME(EmitTrampolineBlock);
34 FUNCNAME(GetSymbolAddress);
35 FUNCNAME(GetRemoteInfo);
36 FUNCNAME(ReadMem);
37 FUNCNAME(RegisterEHFrames);
38 FUNCNAME(ReserveMem);
39 FUNCNAME(RequestCompile);
40 FUNCNAME(SetProtections);
41 FUNCNAME(TerminateSession);
42 FUNCNAME(WriteMem);
43 FUNCNAME(WritePtr);
44 };
45 return nullptr;
46 }
47
48 #undef FUNCNAME
49
50 } // end namespace remote
51 } // end namespace orc
52 } // end namespace llvm