llvm.org GIT mirror llvm / 085827f
[ORC] Re-apply 286620 with fixes for the ErrorSuccess class. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@286639 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 2 years ago
17 changed file(s) with 1901 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 template
420 class UnwrapResponseHandlerArg)> {
421 public:
422 using ArgType = ArgT;
423 };
424
425
426 // ResponseHandler represents a handler for a not-yet-received function call
427 // result.
428 template
429 class ResponseHandler {
430 public:
431 virtual ~ResponseHandler() {}
432
433 // Reads the function result off the wire and acts on it. The meaning of
434 // "act" will depend on how this method is implemented in any given
435 // ResponseHandler subclass but could, for example, mean running a
436 // user-specified handler or setting a promise value.
437 virtual Error handleResponse(ChannelT &C) = 0;
438
439 // Abandons this outstanding result.
440 virtual void abandon() = 0;
441
442 // Create an error instance representing an abandoned response.
443 static Error createAbandonedResponseError() {
444 return make_error("RPC function call failed to return",
445 inconvertibleErrorCode());
446 }
447 };
448
449 // ResponseHandler subclass for RPC functions with non-void returns.
450 template
451 class ResponseHandlerImpl : public ResponseHandler {
452 public:
453 ResponseHandlerImpl(HandlerT Handler)
454 : Handler(std::move(Handler)) {}
455
456 // Handle the result by deserializing it from the channel then passing it
457 // to the user defined handler.
458 Error handleResponse(ChannelT &C) override {
459 using ArgType = typename UnwrapResponseHandlerArg<
460 typename HandlerTraits::Type>::ArgType;
461 ArgType Result;
462 if (auto Err = SerializationTraits::
463 deserialize(C, Result))
464 return Err;
465 if (auto Err = C.endReceiveMessage())
466 return Err;
467 return Handler(Result);
468 }
469
470 // Abandon this response by calling the handler with an 'abandoned response'
471 // error.
472 void abandon() override {
473 if (auto Err = Handler(this->createAbandonedResponseError())) {
474 // Handlers should not fail when passed an abandoned response error.
475 report_fatal_error(std::move(Err));
476 }
477 }
478
479 private:
480 HandlerT Handler;
481 };
482
483 // ResponseHandler subclass for RPC functions with void returns.
484 template
485 class ResponseHandlerImpl
486 : public ResponseHandler {
487 public:
488 ResponseHandlerImpl(HandlerT Handler)
489 : Handler(std::move(Handler)) {}
490
491 // Handle the result (no actual value, just a notification that the function
492 // has completed on the remote end) by calling the user-defined handler with
493 // Error::success().
494 Error handleResponse(ChannelT &C) override {
495 if (auto Err = C.endReceiveMessage())
496 return Err;
497 return Handler(Error::success());
498 }
499
500 // Abandon this response by calling the handler with an 'abandoned response'
501 // error.
502 void abandon() override {
503 if (auto Err = Handler(this->createAbandonedResponseError())) {
504 // Handlers should not fail when passed an abandoned response error.
505 report_fatal_error(std::move(Err));
506 }
507 }
508
509 private:
510 HandlerT Handler;
511 };
512
513 // Create a ResponseHandler from a given user handler.
514 template
515 std::unique_ptr>
516 createResponseHandler(HandlerT H) {
517 return llvm::make_unique<
518 ResponseHandlerImpl>(std::move(H));
519 }
520
521 // Helper for wrapping member functions up as functors. This is useful for
522 // installing methods as result handlers.
523 template
524 class MemberFnWrapper {
525 public:
526 using MethodT = RetT(ClassT::*)(ArgTs...);
527 MemberFnWrapper(ClassT &Instance, MethodT Method)
528 : Instance(Instance), Method(Method) {}
529 RetT operator()(ArgTs &&... Args) {
530 return (Instance.*Method)(std::move(Args)...);
531 }
532 private:
533 ClassT &Instance;
534 MethodT Method;
535 };
536
537 // Helper that provides a Functor for deserializing arguments.
538 template class ReadArgs {
539 public:
540 Error operator()() { return Error::success(); }
541 };
542
543 template
544 class ReadArgs : public ReadArgs {
545 public:
546 ReadArgs(ArgT &Arg, ArgTs &... Args)
547 : ReadArgs(Args...), Arg(Arg) {}
548
549 Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
550 this->Arg = std::move(ArgVal);
551 return ReadArgs::operator()(ArgVals...);
552 }
553 private:
554 ArgT &Arg;
555 };
556
557 // Manage sequence numbers.
558 template
559 class SequenceNumberManager {
560 public:
561 // Reset, making all sequence numbers available.
562 void reset() {
563 std::lock_guard Lock(SeqNoLock);
564 NextSequenceNumber = 0;
565 FreeSequenceNumbers.clear();
566 }
567
568 // Get the next available sequence number. Will re-use numbers that have
569 // been released.
570 SequenceNumberT getSequenceNumber() {
571 std::lock_guard Lock(SeqNoLock);
572 if (FreeSequenceNumbers.empty())
573 return NextSequenceNumber++;
574 auto SequenceNumber = FreeSequenceNumbers.back();
575 FreeSequenceNumbers.pop_back();
576 return SequenceNumber;
577 }
578
579 // Release a sequence number, making it available for re-use.
580 void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
581 std::lock_guard Lock(SeqNoLock);
582 FreeSequenceNumbers.push_back(SequenceNumber);
583 }
584
585 private:
586 std::mutex SeqNoLock;
587 SequenceNumberT NextSequenceNumber = 0;
588 std::vector FreeSequenceNumbers;
360589 };
361590
362591 /// Contains primitive utilities for defining, calling and handling calls to
363592 /// 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.
593 /// RPCChannel interface (see RPCChannel.h), FunctionIdT is a procedure
594 /// identifier type that must be serializable on ChannelT, and SequenceNumberT
595 /// is an integral type that will be used to number in-flight function calls.
366596 ///
367597 /// These utilities support the construction of very primitive RPC utilities.
368598 /// Their intent is to ensure correct serialization and deserialization of
369599 /// procedure arguments, and to keep the client and server's view of the API in
370600 /// 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) {
601 template
602 typename SequenceNumberT>
603 class RPCBase {
604 protected:
605
606 class OrcRPCInvalid : public Function {
607 public:
608 static const char *getName() { return "__orc_rpc$invalid"; }
609 };
610
611 class OrcRPCResponse : public Function {
612 public:
613 static const char *getName() { return "__orc_rpc$response"; }
614 };
615
616 class OrcRPCNegotiate
617 : public Function {
618 public:
619 static const char *getName() { return "__orc_rpc$negotiate"; }
620 };
621
622 public:
623
624 /// Construct an RPC instance on a channel.
625 RPCBase(ChannelT &C, bool LazyAutoNegotiation)
626 : C(C), LazyAutoNegotiation(LazyAutoNegotiation) {
627 // Hold ResponseId in a special variable, since we expect Response to be
628 // called relatively frequently, and want to avoid the map lookup.
629 ResponseId = FnIdAllocator.getResponseId();
630 RemoteFunctionIds[OrcRPCResponse::getPrototype()] = ResponseId;
631
632 // Register the negotiate function id and handler.
633 auto NegotiateId = FnIdAllocator.getNegotiateId();
634 RemoteFunctionIds[OrcRPCNegotiate::getPrototype()] = NegotiateId;
635 Handlers[NegotiateId] =
636 wrapHandler([this](const std::string &Name) {
637 return handleNegotiate(Name);
638 }, LaunchPolicy());
639 }
640
641 /// Append a call Func, does not call send on the channel.
642 /// The first argument specifies a user-defined handler to be run when the
643 /// function returns. The handler should take an Expected,
644 /// or an Error (if Func::ReturnType is void). The handler will be called
645 /// with an error if the return value is abandoned due to a channel error.
646 template
647 Error appendCallAsync(HandlerT Handler, const ArgTs &... Args) {
648 // Look up the function ID.
649 FunctionIdT FnId;
650 if (auto FnIdOrErr = getRemoteFunctionId())
651 FnId = *FnIdOrErr;
652 else {
653 // This isn't a channel error so we don't want to abandon other pending
654 // responses, but we still need to run the user handler with an error to
655 // let them know the call failed.
656 if (auto Err = Handler(orcError(OrcErrorCode::UnknownRPCFunction)))
657 report_fatal_error(std::move(Err));
658 return FnIdOrErr.takeError();
659 }
660
661 // Allocate a sequence number.
461662 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);
663 assert(!PendingResponses.count(SeqNo) &&
664 "Sequence number already allocated");
665
666 // Install the user handler.
667 PendingResponses[SeqNo] =
668 detail::createResponseHandler(
669 std::move(Handler));
670
671 // Open the function call message.
672 if (auto Err = C.startSendMessage(FnId, SeqNo)) {
673 abandonPendingResponses();
674 return joinErrors(std::move(Err), C.endSendMessage());
675 }
676
677 // Serialize the call arguments.
678 if (auto Err =
679 detail::HandlerTraits::
680 serializeArgs(C, Args...)) {
681 abandonPendingResponses();
682 return joinErrors(std::move(Err), C.endSendMessage());
683 }
684
685 // Close the function call messagee.
686 if (auto Err = C.endSendMessage()) {
687 abandonPendingResponses();
471688 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))
689 }
690
691 return Error::success();
692 }
693
694
695 template
696 Error callAsync(HandlerT Handler, const ArgTs &... Args) {
697 if (auto Err = appendCallAsync(std::move(Handler), Args...))
565698 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));
699 return C.send();
700 }
701
702 /// Handle one incoming call.
703 Error handleOne() {
704 FunctionIdT FnId;
705 SequenceNumberT SeqNo;
706 if (auto Err = C.startReceiveMessage(FnId, SeqNo))
707 return Err;
708 if (FnId == ResponseId)
709 return handleResponse(SeqNo);
710 auto I = Handlers.find(FnId);
711 if (I != Handlers.end())
712 return I->second(C, SeqNo);
713
714 // else: No handler found. Report error to client?
715 return orcError(OrcErrorCode::UnexpectedRPCCall);
607716 }
608717
609718 /// Helper for handling setter procedures - this method returns a functor that
620729 /// /* Handle Args */ ;
621730 ///
622731 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();
732 static detail::ReadArgs readArgs(ArgTs &... Args) {
733 return detail::ReadArgs(Args...);
734 }
735
736 protected:
737 // The LaunchPolicy type allows a launch policy to be specified when adding
738 // a function handler. See addHandlerImpl.
739 using LaunchPolicy = std::function)>;
740
741 /// Add the given handler to the handler map and make it available for
742 /// autonegotiation and execution.
743 template
744 void addHandlerImpl(HandlerT Handler, LaunchPolicy Launch) {
745 FunctionIdT NewFnId = FnIdAllocator.template allocate();
746 LocalFunctionIds[Func::getPrototype()] = NewFnId;
747 Handlers[NewFnId] = wrapHandler(std::move(Handler),
748 std::move(Launch));
749 }
750
751 // Abandon all outstanding results.
752 void abandonPendingResponses() {
753 for (auto &KV : PendingResponses)
754 KV.second->abandon();
755 PendingResponses.clear();
756 SequenceNumberMgr.reset();
757 }
758
759 Error handleResponse(SequenceNumberT SeqNo) {
760 auto I = PendingResponses.find(SeqNo);
761 if (I == PendingResponses.end()) {
762 abandonPendingResponses();
763 return orcError(OrcErrorCode::UnexpectedRPCResponse);
764 }
765
766 auto PRHandler = std::move(I->second);
767 PendingResponses.erase(I);
768 SequenceNumberMgr.releaseSequenceNumber(SeqNo);
769
770 if (auto Err = PRHandler->handleResponse(C)) {
771 abandonPendingResponses();
772 SequenceNumberMgr.reset();
633773 return Err;
634774 }
635775
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?
776 return Error::success();
777 }
778
779 FunctionIdT handleNegotiate(const std::string &Name) {
780 auto I = LocalFunctionIds.find(Name);
781 if (I == LocalFunctionIds.end())
782 return FnIdAllocator.getInvalidId();
783 return I->second;
784 }
785
786 // Find the remote FunctionId for the given function, which must be in the
787 // RemoteFunctionIds map.
788 template
789 Expected getRemoteFunctionId() {
790 // Try to find the id for the given function.
791 auto I = RemoteFunctionIds.find(Func::getPrototype());
792
793 // If we have it in the map, return it.
794 if (I != RemoteFunctionIds.end())
795 return I->second;
796
797 // Otherwise, if we have auto-negotiation enabled, try to negotiate it.
798 if (LazyAutoNegotiation) {
799 auto &Impl = static_cast(*this);
800 if (auto RemoteIdOrErr =
801 Impl.template callB(Func::getPrototype())) {
802 auto &RemoteId = *RemoteIdOrErr;
803
804 // If autonegotiation indicates that the remote end doesn't support this
805 // function, return an unknown function error.
806 if (RemoteId == FnIdAllocator.getInvalidId())
807 return orcError(OrcErrorCode::UnknownRPCFunction);
808
809 // Autonegotiation succeeded and returned a valid id. Update the map and
810 // return the id.
811 RemoteFunctionIds[Func::getPrototype()] = RemoteId;
812 return RemoteId;
813 } else {
814 // Autonegotiation failed. Return the error.
815 return RemoteIdOrErr.takeError();
816 }
817 }
818
819 // No key was available in the map and autonegotiation wasn't enabled.
820 // Return an unknown function error.
821 return orcError(OrcErrorCode::UnknownRPCFunction);
822 }
823
824 using WrappedHandlerFn = std::function;
825
826 // Wrap the given user handler in the necessary argument-deserialization code,
827 // result-serialization code, and call to the launch policy (if present).
828 template
829 WrappedHandlerFn wrapHandler(HandlerT Handler, LaunchPolicy Launch) {
830 return
831 [this, Handler, Launch](ChannelT &Channel, SequenceNumberT SeqNo) -> Error {
832 // Start by deserializing the arguments.
833 auto Args =
834 std::make_shared::ArgStorage>();
835 if (auto Err = detail::HandlerTraits::
836 deserializeArgs(Channel, *Args))
837 return Err;
838
839 // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
840 // for RPCArgs. Void cast RPCArgs to work around this for now.
841 // FIXME: Remove this workaround once we can assume a working GCC version.
842 (void)Args;
843
844 // End receieve message, unlocking the channel for reading.
845 if (auto Err = Channel.endReceiveMessage())
846 return Err;
847
848 // Build the handler/responder.
849 auto Responder =
850 [this, Handler, Args, &Channel, SeqNo]() mutable -> Error {
851 using HTraits = detail::HandlerTraits;
852 using FuncReturn = typename Func::ReturnType;
853 return detail::respond(Channel, ResponseId, SeqNo,
854 HTraits::runHandler(Handler,
855 *Args));
856 };
857
858 // If there is an explicit launch policy then use it to launch the
859 // handler.
860 if (Launch)
861 return Launch(std::move(Responder));
862
863 // Otherwise run the handler on the listener thread.
864 return Responder();
865 };
866 }
867
868 ChannelT &C;
869
870 bool LazyAutoNegotiation;
871
872 RPCFunctionIdAllocator FnIdAllocator;
873
874 FunctionIdT ResponseId;
875 std::map LocalFunctionIds;
876 std::map RemoteFunctionIds;
877
878 std::map Handlers;
879
880 detail::SequenceNumberManager SequenceNumberMgr;
881 std::map>>
882 PendingResponses;
883 };
884
885 } // end namespace detail
886
887
888 template
889 typename FunctionIdT = uint32_t,
890 typename SequenceNumberT = uint32_t>
891 class MultiThreadedRPC
892 : public detail::RPCBase
893 SequenceNumberT>,
894 ChannelT, FunctionIdT, SequenceNumberT> {
895 private:
896 using BaseClass =
897 detail::RPCBase,
898 ChannelT, FunctionIdT, SequenceNumberT>;
899
900 public:
901
902 MultiThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
903 : BaseClass(C, LazyAutoNegotiation) {}
904
905 /// The LaunchPolicy type allows a launch policy to be specified when adding
906 /// a function handler. See addHandler.
907 using LaunchPolicy = typename BaseClass::LaunchPolicy;
908
909 /// Add a handler for the given RPC function.
910 /// This installs the given handler functor for the given RPC Function, and
911 /// makes the RPC function available for negotiation/calling from the remote.
912 ///
913 /// The optional LaunchPolicy argument can be used to control how the handler
914 /// is run when called:
915 ///
916 /// * If no LaunchPolicy is given, the handler code will be run on the RPC
917 /// handler thread that is reading from the channel. This handler cannot
918 /// make blocking RPC calls (since it would be blocking the thread used to
919 /// get the result), but can make non-blocking calls.
920 ///
921 /// * If a LaunchPolicy is given, the user's handler will be wrapped in a
922 /// call to serialize and send the result, and the resulting functor (with
923 /// type 'Error()' will be passed to the LaunchPolicy. The user can then
924 /// choose to add the wrapped handler to a work queue, spawn a new thread,
925 /// or anything else.
926 template
927 void addHandler(HandlerT Handler, LaunchPolicy Launch = LaunchPolicy()) {
928 return this->template addHandlerImpl(std::move(Handler),
929 std::move(Launch));
930 }
931
932 /// Negotiate a function id for Func with the other end of the channel.
933 template
934 Error negotiateFunction() {
935 using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
936
937 if (auto RemoteIdOrErr = callB(Func::getPrototype())) {
938 this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
939 return Error::success();
940 } else
941 return RemoteIdOrErr.takeError();
942 }
943
944 /// Convenience method for negotiating multiple functions at once.
945 template
946 Error negotiateFunctions() {
947 return negotiateFunction();
948 }
949
950 /// Convenience method for negotiating multiple functions at once.
951 template
952 Error negotiateFunctions() {
953 if (auto Err = negotiateFunction())
648954 return Err;
649 }
650
651 OutstandingResults.erase(I);
652 SequenceNumberMgr.releaseSequenceNumber(SeqNo);
653
955 return negotiateFunctions();
956 }
957
958 /// Return type for non-blocking call primitives.
959 template
960 using NonBlockingCallResult =
961 typename detail::ResultTraits::ReturnFutureType;
962
963 /// Call Func on Channel C. Does not block, does not call send. Returns a pair
964 /// of a future result and the sequence number assigned to the result.
965 ///
966 /// This utility function is primarily used for single-threaded mode support,
967 /// where the sequence number can be used to wait for the corresponding
968 /// result. In multi-threaded mode the appendCallNB method, which does not
969 /// return the sequence numeber, should be preferred.
970 template
971 Expected>
972 appendCallNB(const ArgTs &... Args) {
973 using RTraits = detail::ResultTraits;
974 using ErrorReturn = typename RTraits::ErrorReturnType;
975 using ErrorReturnPromise = typename RTraits::ReturnPromiseType;
976
977 // FIXME: Stack allocate and move this into the handler once LLVM builds
978 // with C++14.
979 auto Promise = std::make_shared();
980 auto FutureResult = Promise->get_future();
981
982 if (auto Err = this->template appendCallAsync(
983 [Promise](ErrorReturn RetOrErr) {
984 Promise->set_value(std::move(RetOrErr));
985 return Error::success();
986 }, Args...)) {
987 this->abandonPendingResponses();
988 RTraits::consumeAbandoned(FutureResult.get());
989 return std::move(Err);
990 }
991 return std::move(FutureResult);
992 }
993
994 /// The same as appendCallNBWithSeq, except that it calls C.send() to
995 /// flush the channel after serializing the call.
996 template
997 Expected>
998 callNB(const ArgTs &... Args) {
999 auto Result = appendCallNB(Args...);
1000 if (!Result)
1001 return Result;
1002 if (auto Err = this->C.send()) {
1003 this->abandonPendingResponses();
1004 detail::ResultTraits::
1005 consumeAbandoned(std::move(Result->get()));
1006 return std::move(Err);
1007 }
1008 return Result;
1009 }
1010
1011 /// Call Func on Channel C. Blocks waiting for a result. Returns an Error
1012 /// for void functions or an Expected for functions returning a T.
1013 ///
1014 /// This function is for use in threaded code where another thread is
1015 /// handling responses and incoming calls.
1016 template
1017 typename AltRetT = typename Func::ReturnType>
1018 typename detail::ResultTraits::ErrorReturnType
1019 callB(const ArgTs &... Args) {
1020 if (auto FutureResOrErr = callNB(Args...)) {
1021 if (auto Err = this->C.send()) {
1022 this->abandonPendingResponses();
1023 detail::ResultTraits::
1024 consumeAbandoned(std::move(FutureResOrErr->get()));
1025 return std::move(Err);
1026 }
1027 return FutureResOrErr->get();
1028 } else
1029 return FutureResOrErr.takeError();
1030 }
1031
1032 /// Handle incoming RPC calls.
1033 Error handlerLoop() {
1034 while (true)
1035 if (auto Err = this->handleOne())
1036 return Err;
6541037 return Error::success();
6551038 }
6561039
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
1040 };
1041
1042 template
1043 typename FunctionIdT = uint32_t,
1044 typename SequenceNumberT = uint32_t>
1045 class SingleThreadedRPC
1046 : public detail::RPCBase
1047 SequenceNumberT>,
1048 ChannelT, FunctionIdT,
1049 SequenceNumberT> {
6861050 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.
1051
1052 using BaseClass = detail::RPCBase
1053 SequenceNumberT>,
1054 ChannelT, FunctionIdT, SequenceNumberT>;
1055
1056 using LaunchPolicy = typename BaseClass::LaunchPolicy;
1057
1058 public:
1059
1060 SingleThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
1061 : BaseClass(C, LazyAutoNegotiation) {}
1062
1063 template
1064 void addHandler(HandlerT Handler) {
1065 return this->template addHandlerImpl(std::move(Handler),
1066 LaunchPolicy());
1067 }
1068
1069 template
1070 void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
1071 addHandler(
1072 detail::MemberFnWrapper(Object, Method));
1073 }
1074
1075 /// Negotiate a function id for Func with the other end of the channel.
7411076 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.
1077 Error negotiateFunction() {
1078 using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
1079
1080 if (auto RemoteIdOrErr = callB(Func::getPrototype())) {
1081 this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
1082 return Error::success();
1083 } else
1084 return RemoteIdOrErr.takeError();
1085 }
1086
1087 /// Convenience method for negotiating multiple functions at once.
7571088 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
1089 Error negotiateFunctions() {
1090 return negotiateFunction();
1091 }
1092
1093 /// Convenience method for negotiating multiple functions at once.
1094 template
1095 Error negotiateFunctions() {
1096 if (auto Err = negotiateFunction())
1097 return Err;
1098 return negotiateFunctions();
1099 }
1100
1101 template
1102 typename AltRetT = typename Func::ReturnType>
1103 typename detail::ResultTraits::ErrorReturnType
1104 callB(const ArgTs &... Args) {
1105 bool ReceivedResponse = false;
1106 using ResultType =
1107 typename detail::ResultTraits::ErrorReturnType;
1108 auto Result = detail::ResultTraits::createBlankErrorReturnValue();
1109
1110 // We have to 'Check' result (which we know is in a success state at this
1111 // point) so that it can be overwritten in the async handler.
1112 (void)!!Result;
1113
1114 if (auto Err = this->template appendCallAsync(
1115 [&](ResultType R) {
1116 Result = std::move(R);
1117 ReceivedResponse = true;
1118 return Error::success();
1119 }, Args...)) {
1120 this->abandonPendingResponses();
1121 detail::ResultTraits::
1122 consumeAbandoned(std::move(Result));
1123 return std::move(Err);
1124 }
1125
1126 while (!ReceivedResponse) {
1127 if (auto Err = this->handleOne()) {
1128 this->abandonPendingResponses();
1129 detail::ResultTraits::
1130 consumeAbandoned(std::move(Result));
1131 return std::move(Err);
1132 }
1133 }
1134
1135 return Result;
1136 }
1137
1138 //using detail::RPCBase::handleOne;
1139
1140 };
1141
1142 } // end namespace rpc
7771143 } // end namespace orc
7781144 } // end namespace llvm
7791145
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