llvm.org GIT mirror llvm / b35b701
[ORC] Revert r286620 while I investigate a bot failure. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@286621 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 2 years ago
17 changed file(s) with 1493 addition(s) and 1887 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/RawByteChannel.h"
16 #include "llvm/ExecutionEngine/Orc/RPCByteChannel.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::rpc::RawByteChannel {
27 class FDRPCChannel final : public llvm::orc::remote::RPCByteChannel {
2828 public:
2929 FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
3030
12641264 BinopPrecedence['*'] = 40; // highest.
12651265
12661266 auto TCPChannel = connect();
1267 auto Remote = ExitOnErr(MyRemote::Create(*TCPChannel));
1268 TheJIT = llvm::make_unique(*Remote);
1267 MyRemote 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
3231 };
3332
3433 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 RawByteChannel with an
10 // can be used to communicate over an RPCByteChannel 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;
3855
3956 /// Remote memory manager.
4057 class RCMemoryManager : public RuntimeDyld::MemoryManager {
4461 DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
4562 }
4663
47 RCMemoryManager(const RCMemoryManager&) = delete;
48 RCMemoryManager& operator=(const RCMemoryManager&) = delete;
49 RCMemoryManager(RCMemoryManager&&) = default;
50 RCMemoryManager& operator=(RCMemoryManager&&) = default;
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 }
5176
5277 ~RCMemoryManager() override {
5378 Client.destroyRemoteAllocator(Id);
341366 Alloc(uint64_t Size, unsigned Align)
342367 : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
343368
344 Alloc(const Alloc&) = delete;
345 Alloc& operator=(const Alloc&) = delete;
346 Alloc(Alloc&&) = default;
347 Alloc& operator=(Alloc&&) = default;
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 }
348381
349382 uint64_t getSize() const { return Size; }
350383
371404
372405 struct ObjectAllocs {
373406 ObjectAllocs() = default;
374 ObjectAllocs(const ObjectAllocs &) = delete;
375 ObjectAllocs& operator=(const ObjectAllocs &) = delete;
376 ObjectAllocs(ObjectAllocs&&) = default;
377 ObjectAllocs& operator=(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 }
378425
379426 JITTargetAddress RemoteCodeAddr = 0;
380427 JITTargetAddress RemoteRODataAddr = 0;
540587 /// Create an OrcRemoteTargetClient.
541588 /// Channel is the ChannelT instance to communicate on. It is assumed that
542589 /// the channel is ready to be read from and written to.
543 static Expected>
544 Create(ChannelT &Channel) {
590 static Expected Create(ChannelT &Channel) {
545591 Error Err = Error::success();
546 std::unique_ptr
547 Client(new OrcRemoteTargetClient(Channel, Err));
592 OrcRemoteTargetClient H(Channel, Err);
548593 if (Err)
549594 return std::move(Err);
550 return std::move(Client);
595 return Expected(std::move(H));
551596 }
552597
553598 /// Call the int(void) function at the given address in the target and return
554599 /// its result.
555600 Expected callIntVoid(JITTargetAddress Addr) {
556601 DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
557 return callB(Addr);
602
603 auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
604 return listenForCompileRequests(C, Id);
605 };
606 return callSTHandling(Channel, Listen, Addr);
558607 }
559608
560609 /// Call the int(int, char*[]) function at the given address in the target and
563612 const std::vector &Args) {
564613 DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
565614 << "\n");
566 return callB(Addr, Args);
615
616 auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
617 return listenForCompileRequests(C, Id);
618 };
619 return callSTHandling(Channel, Listen, Addr, Args);
567620 }
568621
569622 /// Call the void() function at the given address in the target and wait for
571624 Error callVoidVoid(JITTargetAddress Addr) {
572625 DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
573626 << "\n");
574 return callB(Addr);
627
628 auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
629 return listenForCompileRequests(C, Id);
630 };
631 return callSTHandling(Channel, Listen, Addr);
575632 }
576633
577634 /// Create an RCMemoryManager which will allocate its memory on the remote
580637 assert(!MM && "MemoryManager should be null before creation.");
581638
582639 auto Id = AllocatorIds.getNext();
583 if (auto Err = callB(Id))
640 if (auto Err = callST(Channel, Id))
584641 return Err;
585642 MM = llvm::make_unique(*this, Id);
586643 return Error::success();
591648 Error createIndirectStubsManager(std::unique_ptr &I) {
592649 assert(!I && "Indirect stubs manager should be null before creation.");
593650 auto Id = IndirectStubOwnerIds.getNext();
594 if (auto Err = callB(Id))
651 if (auto Err = callST(Channel, Id))
595652 return Err;
596653 I = llvm::make_unique(*this, Id);
597654 return Error::success();
604661 return std::move(ExistingError);
605662
606663 // Emit the resolver block on the JIT server.
607 if (auto Err = callB())
664 if (auto Err = callST(Channel))
608665 return std::move(Err);
609666
610667 // Create the callback manager.
621678 if (ExistingError)
622679 return std::move(ExistingError);
623680
624 return callB(Name);
681 return callST(Channel, Name);
625682 }
626683
627684 /// Get the triple for the remote target.
628685 const std::string &getTargetTriple() const { return RemoteTargetTriple; }
629686
630 Error terminateSession() { return callB(); }
687 Error terminateSession() { return callST(Channel); }
631688
632689 private:
633
634 OrcRemoteTargetClient(ChannelT &Channel, Error &Err)
635 : OrcRemoteTargetRPCAPI(Channel) {
690 OrcRemoteTargetClient(ChannelT &Channel, Error &Err) : Channel(Channel) {
636691 ErrorAsOutParameter EAO(&Err);
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()) {
692 if (auto RIOrErr = callST(Channel)) {
646693 std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
647694 RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
648695 Err = Error::success();
652699 }
653700
654701 Error deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
655 return callB(Addr, Size);
702 return callST(Channel, Addr, Size);
656703 }
657704
658705 void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
659 if (auto Err = callB(Id)) {
706 if (auto Err = callST(Channel, Id)) {
660707 // FIXME: This will be triggered by a removeModuleSet call: Propagate
661708 // error return up through that.
662709 llvm_unreachable("Failed to destroy remote allocator.");
666713
667714 Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
668715 IndirectStubOwnerIds.release(Id);
669 return callB(Id);
716 return callST(Channel, Id);
670717 }
671718
672719 Expected>
673720 emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
674 return callB(Id, NumStubsRequired);
721 return callST(Channel, Id, NumStubsRequired);
675722 }
676723
677724 Expected> emitTrampolineBlock() {
679726 if (ExistingError)
680727 return std::move(ExistingError);
681728
682 return callB();
729 return callST(Channel);
683730 }
684731
685732 uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
687734 uint32_t getPointerSize() const { return RemotePointerSize; }
688735
689736 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 }
690762
691763 Expected> readMem(char *Dst, JITTargetAddress Src,
692764 uint64_t Size) {
694766 if (ExistingError)
695767 return std::move(ExistingError);
696768
697 return callB(Src, Size);
769 return callST(Channel, Src, Size);
698770 }
699771
700772 Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) {
701 return callB(RAddr, Size);
773 return callST(Channel, RAddr, Size);
702774 }
703775
704776 Expected reserveMem(ResourceIdMgr::ResourceId Id,
708780 if (ExistingError)
709781 return std::move(ExistingError);
710782
711 return callB(Id, Size, Align);
783 return callST(Channel, Id, Size, Align);
712784 }
713785
714786 Error setProtections(ResourceIdMgr::ResourceId Id,
715787 JITTargetAddress RemoteSegAddr, unsigned ProtFlags) {
716 return callB(Id, RemoteSegAddr, ProtFlags);
788 return callST(Channel, Id, RemoteSegAddr, ProtFlags);
717789 }
718790
719791 Error writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) {
721793 if (ExistingError)
722794 return std::move(ExistingError);
723795
724 return callB(DirectBufferWriter(Src, Addr, Size));
796 return callST(Channel, DirectBufferWriter(Src, Addr, Size));
725797 }
726798
727799 Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
729801 if (ExistingError)
730802 return std::move(ExistingError);
731803
732 return callB(Addr, PtrVal);
804 return callST(Channel, Addr, PtrVal);
733805 }
734806
735807 static Error doNothing() { return Error::success(); }
736808
809 ChannelT &Channel;
737810 Error ExistingError = Error::success();
738811 std::string RemoteTargetTriple;
739812 uint32_t RemotePointerSize = 0;
1515 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
1616 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
1717
18 #include "RawByteChannel.h"
18 #include "RPCByteChannel.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
4642 template <>
47 class RPCTypeNameDirectBufferWriter> {
43 class SerializationTraitsDirectBufferWriter> {
4844 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) {
45
46 static const char* getName() { return "DirectBufferWriter"; }
47
48 static Error serialize(RPCByteChannel &C, const DirectBufferWriter &DBW) {
6049 if (auto EC = serializeSeq(C, DBW.getDst()))
6150 return EC;
6251 if (auto EC = serializeSeq(C, DBW.getSize()))
6453 return C.appendBytes(DBW.getSrc(), DBW.getSize());
6554 }
6655
67 static Error deserialize(ChannelT &C, remote::DirectBufferWriter &DBW) {
56 static Error deserialize(RPCByteChannel &C, DirectBufferWriter &DBW) {
6857 JITTargetAddress Dst;
6958 if (auto EC = deserializeSeq(C, Dst))
7059 return EC;
7362 return EC;
7463 char *Addr = reinterpret_cast(static_cast(Dst));
7564
76 DBW = remote::DirectBufferWriter(0, Dst, Size);
65 DBW = DirectBufferWriter(0, Dst, Size);
7766
7867 return C.readBytes(Addr, Size);
7968 }
8069 };
8170
82 } // end namespace rpc
83
84 namespace remote {
85
86 class OrcRemoteTargetRPCAPI
87 : public rpc::SingleThreadedRPCByteChannel> {
71 class OrcRemoteTargetRPCAPI : public RPCByteChannel> {
8872 protected:
8973 class ResourceIdMgr {
9074 public:
10892
10993 public:
11094 // FIXME: Remove constructors once MSVC supports synthesizing move-ops.
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"; }
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
118125 };
119126
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 };
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;
168157
169158 /// EmitIndirectStubs result is (StubsBase, PtrsBase, NumStubsEmitted).
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 };
159 typedef Function
160 std::tuple(
161 ResourceIdMgr::ResourceId StubsOwnerID,
162 uint32_t NumStubsRequired)>
163 EmitIndirectStubs;
164
165 typedef Function EmitResolverBlock;
184166
185167 /// EmitTrampolineBlock result is (BlockAddr, NumTrampolines).
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 };
168 typedef Function
169 std::tuple()>
170 EmitTrampolineBlock;
171
172 typedef Function
173 GetSymbolAddress;
199174
200175 /// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize,
201176 /// IndirectStubsSize).
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
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;
267208 };
268209
269210 } // end namespace remote
4040 OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup,
4141 EHFrameRegistrationFtor EHFramesRegister,
4242 EHFrameRegistrationFtor EHFramesDeregister)
43 : OrcRemoteTargetRPCAPI(Channel), SymbolLookup(std::move(SymbolLookup)),
43 : Channel(Channel), SymbolLookup(std::move(SymbolLookup)),
4444 EHFramesRegister(std::move(EHFramesRegister)),
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 }
45 EHFramesDeregister(std::move(EHFramesDeregister)) {}
7446
7547 // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
7648 OrcRemoteTargetServer(const OrcRemoteTargetServer &) = delete;
7749 OrcRemoteTargetServer &operator=(const OrcRemoteTargetServer &) = delete;
7850
79 OrcRemoteTargetServer(OrcRemoteTargetServer &&Other) = default;
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
8056 OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete;
8157
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 }
82119
83120 Expected requestCompile(JITTargetAddress TrampolineAddr) {
84 return callB(TrampolineAddr);
85 }
86
87 bool receivedTerminate() const { return TerminateFlag; }
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 }
88131
89132 private:
90133 struct Allocator {
321364 IndirectStubSize);
322365 }
323366
324 Expected> handleReadMem(JITTargetAddress RSrc,
325 uint64_t Size) {
326 uint8_t *Src = reinterpret_cast(static_cast(RSrc));
367 Expected> handleReadMem(JITTargetAddress RSrc, uint64_t Size) {
368 char *Src = reinterpret_cast(static_cast(RSrc));
327369
328370 DEBUG(dbgs() << " Reading " << Size << " bytes from "
329371 << format("0x%016x", RSrc) << "\n");
330372
331 std::vector<uint8_t> Buffer;
373 std::vector<char> Buffer;
332374 Buffer.resize(Size);
333 for (uint8_t *P = Src; Size != 0; --Size)
375 for (char *P = Src; Size != 0; --Size)
334376 Buffer.push_back(*P++);
335377
336378 return Buffer;
378420 return Allocator.setProtections(LocalAddr, Flags);
379421 }
380422
381 Error handleTerminateSession() {
382 TerminateFlag = true;
383 return Error::success();
384 }
385
386423 Error handleWriteMem(DirectBufferWriter DBW) {
387424 DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to "
388425 << format("0x%016x", DBW.getDst()) << "\n");
398435 return Error::success();
399436 }
400437
438 ChannelT &Channel;
401439 SymbolLookupFtor SymbolLookup;
402440 EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister;
403441 std::map Allocators;
405443 std::map IndirectStubsOwners;
406444 sys::OwningMemoryBlock ResolverBlock;
407445 std::vector TrampolineBlocks;
408 bool TerminateFlag;
409446 };
410447
411448 } // end namespace remote
0 //===- 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 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
19 namespace remote {
17720
17821 /// The SerializationTraits class describes how to serialize and
17922 /// deserialize an instance of type T to/from an abstract channel of type
20750 /// }
20851 ///
20952 /// @endcode
210 template
211 typename = void>
53 template typename = void>
21254 class SerializationTraits {};
21355
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...);
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();
290102 }
291103
292104 /// SerializationTraits default specialization for std::pair.
293105 template
294106 class SerializationTraits> {
295107 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
296118 static Error serialize(ChannelT &C, const std::pair &V) {
297119 return serializeSeq(C, V.first, V.second);
298120 }
300122 static Error deserialize(ChannelT &C, std::pair &V) {
301123 return deserializeSeq(C, V.first, V.second);
302124 }
125
126 private:
127 static std::mutex NameMutex;
128 static std::string Name;
303129 };
130
131 template
132 std::mutex SerializationTraits>::NameMutex;
133
134 template
135 std::string SerializationTraits>::Name;
304136
305137 /// SerializationTraits default specialization for std::tuple.
306138 template
307139 class SerializationTraits> {
308140 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 }
309150
310151 /// RPC channel serialization for std::tuple.
311152 static Error serialize(ChannelT &C, const std::tuple &V) {
331172 llvm::index_sequence _) {
332173 return deserializeSeq(C, std::get(V)...);
333174 }
175
176 static std::mutex NameMutex;
177 static std::string Name;
334178 };
179
180 template
181 std::mutex SerializationTraits>::NameMutex;
182
183 template
184 std::string SerializationTraits>::Name;
335185
336186 /// SerializationTraits default specialization for std::vector.
337187 template
338188 class SerializationTraits> {
339189 public:
340
341 /// Serialize a std::vector from std::vector.
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
342199 static Error serialize(ChannelT &C, const std::vector &V) {
343 if (auto Err = serializeSeq(C, static_cast(V.size())))
200 if (auto Err = SerializationTraits::serialize(
201 C, static_cast(V.size())))
344202 return Err;
345203
346204 for (const auto &E : V)
347 if (auto Err = serializeSeq(C, E))
205 if (auto Err = SerializationTraits::serialize(C, E))
348206 return Err;
349207
350208 return Error::success();
351209 }
352210
353 /// Deserialize a std::vector to a std::vector.
354211 static Error deserialize(ChannelT &C, std::vector &V) {
355212 uint64_t Count = 0;
356 if (auto Err = deserializeSeq(C, Count))
213 if (auto Err =
214 SerializationTraits::deserialize(C, Count))
357215 return Err;
358216
359217 V.resize(Count);
360218 for (auto &E : V)
361 if (auto Err = deserializeSeq(C, E))
219 if (auto Err = SerializationTraits::deserialize(C, E))
362220 return Err;
363221
364222 return Error::success();
365223 }
224
225 private:
226 static std::mutex NameMutex;
227 static std::string Name;
366228 };
367229
368 } // end namespace rpc
230 template
231 std::mutex SerializationTraits>::NameMutex;
232
233 template
234 std::string SerializationTraits>::Name;
235
236 } // end namespace remote
369237 } // end namespace orc
370238 } // end namespace llvm
371239
None //===------- RPCUTils.h - Utilities for building RPC APIs -------*- C++ -*-===//
0 //===----- RPCUTils.h - Basic tilities for building RPC APIs ----*- C++ -*-===//
11 //
22 // The LLVM Compiler Infrastructure
33 //
66 //
77 //===----------------------------------------------------------------------===//
88 //
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.
9 // Basic utilities for building RPC APIs.
1410 //
1511 //===----------------------------------------------------------------------===//
1612
1814 #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
1915
2016 #include
21 #include
2217 #include
2318
2419 #include "llvm/ADT/STLExtras.h"
2520 #include "llvm/ExecutionEngine/Orc/OrcError.h"
26 #include "llvm/ExecutionEngine/Orc/RPCSerialization.h"
2721
2822 #ifdef _MSC_VER
2923 // concrt.h depends on eh.h for __uncaught_exception declaration
4438
4539 namespace llvm {
4640 namespace orc {
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 {
41 namespace remote {
42
43 /// Describes reserved RPC Function Ids.
44 ///
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 {
5751 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;
52 static const T InvalidId = static_cast(0);
53 static const T ResponseId = static_cast(1);
54 static const T FirstValidId = static_cast(2);
7755 };
7856
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:
88 ///
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.
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.
12965 #ifdef _MSC_VER
130
131 namespace msvc_hacks {
13266
13367 // Work around MSVC's future implementation's use of default constructors:
13468 // A default constructed value in the promise will be overwritten when the
15185 MSVCPError(Error Err) : Error(std::move(Err)) {}
15286 };
15387
154 // Work around MSVC's future implementation, similar to MSVCPError.
88 // Likewise for Expected:
15589 template
15690 class MSVCPExpected : public Expected {
15791 public:
188122 nullptr) : Expected(std::move(Other)) {}
189123 };
190124
191 } // end namespace msvc_hacks
192
193125 #endif // _MSC_VER
194126
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
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.
204159 #ifdef _MSC_VER
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>;
160 typedef MSVCPExpected PErrorReturn;
210161 #else
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;
162 typedef Expected PErrorReturn;
216163 #endif
217164
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
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.
238222 #ifdef _MSC_VER
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;
223 typedef MSVCPError PErrorReturn;
244224 #else
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;
225 typedef Error PErrorReturn;
250226 #endif
251227
252 // Create a 'blank' value of the ErrorReturnType, ready and safe to
253 // overwrite.
254 static ErrorReturnType createBlankErrorReturnValue() {
255 return ErrorReturnType::success();
256 }
257
258 // Consume an abandoned ErrorReturnType.
259 static void consumeAbandoned(ErrorReturnType Err) {
260 consumeError(std::move(Err));
261 }
262 };
263
264 // ResultTraits is equivalent to ResultTraits. This allows
265 // handlers for void RPC functions to return either void (in which case they
266 // implicitly succeed) or Error (in which case their error return is
267 // propagated). See usage in HandlerTraits::runHandlerHelper.
268 template <>
269 class ResultTraits : public ResultTraits {};
270
271 // ResultTraits> is equivalent to ResultTraits. This allows
272 // handlers for RPC functions returning a T to return either a T (in which
273 // case they implicitly succeed) or Expected (in which case their error
274 // return is propagated). See usage in HandlerTraits::runHandlerHelper.
275 template
276 class ResultTraits> : public ResultTraits {};
277
278 // Send a response of the given wire return type (WireRetT) over the
279 // channel, with the given sequence number.
280 template
281 typename FunctionIdT, typename SequenceNumberT>
282 static Error respond(ChannelT &C, const FunctionIdT &ResponseId,
283 SequenceNumberT SeqNo, Expected ResultOrErr) {
284 // If this was an error bail out.
285 // FIXME: Send an "error" message to the client if this is not a channel
286 // failure?
287 if (auto Err = ResultOrErr.takeError())
288 return Err;
289
290 // Open the response message.
291 if (auto Err = C.startSendMessage(ResponseId, SeqNo))
292 return Err;
293
294 // Serialize the result.
295 if (auto Err = SerializationTraits::
296 serialize(C, *ResultOrErr))
297 return Err;
298
299 // Close the response message.
300 return C.endSendMessage();
301 }
302
303 // Send an empty response message on the given channel to indicate that
304 // the handler ran.
305 template
306 typename SequenceNumberT>
307 static Error respond(ChannelT &C, const FunctionIdT &ResponseId,
308 SequenceNumberT SeqNo, Error Err) {
309 if (Err)
310 return Err;
311 if (auto Err2 = C.startSendMessage(ResponseId, SeqNo))
312 return Err2;
313 return C.endSendMessage();
314 }
315
316 // This template class provides utilities related to RPC function handlers.
317 // The base case applies to non-function types (the template class is
318 // specialized for function types) and inherits from the appropriate
319 // speciilization for the given non-function type's call operator.
320 template
321 class HandlerTraits
322 : public HandlerTraits
323 &std::remove_reference::type::operator())> {};
324
325 // Traits for handlers with a given function type.
326 template
327 class HandlerTraits {
328 public:
329
330 // Function type of the handler.
331 using Type = RetT(ArgTs...);
332
333 // Return type of the handler.
334 using ReturnType = RetT;
335
336 // A std::tuple wrapping the handler arguments.
337 using ArgStorage =
338 std::tuple<
339 typename std::decay<
340 typename std::remove_reference::type>::type...>;
341
342 // Call the given handler with the given arguments.
343 template
344 static typename ResultTraits::ErrorReturnType
345 runHandler(HandlerT &Handler, ArgStorage &Args) {
346 return runHandlerHelper(Handler, Args,
347 llvm::index_sequence_for());
348 }
349
350 // Serialize arguments to the channel.
351 template
352 static Error serializeArgs(ChannelT &C, const CArgTs... CArgs) {
353 return SequenceSerialization::serialize(C, CArgs...);
354 }
355
356 // Deserialize arguments from the channel.
357 template
358 static Error deserializeArgs(ChannelT &C, std::tuple &Args) {
359 return deserializeArgsHelper(C, Args,
360 llvm::index_sequence_for());
361 }
362
363 private:
364
365 // For non-void user handlers: unwrap the args tuple and call the handler,
366 // returning the result.
367 template
368 static typename std::enable_if<
369 !std::is_void::value,
370 typename ResultTraits::ErrorReturnType>::type
371 runHandlerHelper(HandlerT &Handler, ArgStorage &Args,
372 llvm::index_sequence) {
373 return Handler(std::move(std::get(Args))...);
374 }
375
376 // For void user handlers: unwrap the args tuple and call the handler, then
377 // return Error::success().
378 template
379 static typename std::enable_if<
380 std::is_void::value,
381 typename ResultTraits::ErrorReturnType>::type
382 runHandlerHelper(HandlerT &Handler, ArgStorage &Args,
383 llvm::index_sequence) {
384 Handler(std::move(std::get(Args))...);
385 return ResultTraits::ErrorReturnType::success();
386 }
387
388 template
389 static
390 Error deserializeArgsHelper(ChannelT &C, std::tuple &Args,
391 llvm::index_sequence _) {
392 return SequenceSerialization::
393 deserialize(C, std::get(Args)...);
394 }
395
396 };
397
398 // Handler traits for class methods (especially call operators for lambdas).
399 template
400 class HandlerTraits
401 : public HandlerTraits {};
402
403 // Handler traits for const class methods (especially call operators for
404 // lambdas).
405 template
406 class HandlerTraits
407 : public HandlerTraits {};
408
409 // Utility to peel the Expected wrapper off a response handler error type.
410 template
411 class UnwrapResponseHandlerArg;
412
413 template
414 class UnwrapResponseHandlerArg)> {
415 public:
416 using ArgType = ArgT;
417 };
418
419 // ResponseHandler represents a handler for a not-yet-received function call
420 // result.
421 template
422 class ResponseHandler {
423 public:
424 virtual ~ResponseHandler() {}
425
426 // Reads the function result off the wire and acts on it. The meaning of
427 // "act" will depend on how this method is implemented in any given
428 // ResponseHandler subclass but could, for example, mean running a
429 // user-specified handler or setting a promise value.
430 virtual Error handleResponse(ChannelT &C) = 0;
431
432 // Abandons this outstanding result.
433 virtual void abandon() = 0;
434
435 // Create an error instance representing an abandoned response.
436 static Error createAbandonedResponseError() {
437 return make_error("RPC function call failed to return",
438 inconvertibleErrorCode());
439 }
440 };
441
442 // ResponseHandler subclass for RPC functions with non-void returns.
443 template
444 class ResponseHandlerImpl : public ResponseHandler {
445 public:
446 ResponseHandlerImpl(HandlerT Handler)
447 : Handler(std::move(Handler)) {}
448
449 // Handle the result by deserializing it from the channel then passing it
450 // to the user defined handler.
451 Error handleResponse(ChannelT &C) override {
452 using ArgType = typename UnwrapResponseHandlerArg<
453 typename HandlerTraits::Type>::ArgType;
454 ArgType Result;
455 if (auto Err = SerializationTraits::
456 deserialize(C, Result))
457 return Err;
458 if (auto Err = C.endReceiveMessage())
459 return Err;
460 return Handler(Result);
461 }
462
463 // Abandon this response by calling the handler with an 'abandoned response'
464 // error.
465 void abandon() override {
466 if (auto Err = Handler(this->createAbandonedResponseError())) {
467 // Handlers should not fail when passed an abandoned response error.
468 report_fatal_error(std::move(Err));
469 }
470 }
471
472 private:
473 HandlerT Handler;
474 };
475
476 // ResponseHandler subclass for RPC functions with void returns.
477 template
478 class ResponseHandlerImpl
479 : public ResponseHandler {
480 public:
481 ResponseHandlerImpl(HandlerT Handler)
482 : Handler(std::move(Handler)) {}
483
484 // Handle the result (no actual value, just a notification that the function
485 // has completed on the remote end) by calling the user-defined handler with
486 // Error::success().
487 Error handleResponse(ChannelT &C) override {
488 if (auto Err = C.endReceiveMessage())
489 return Err;
490 return Handler(Error::success());
491 }
492
493 // Abandon this response by calling the handler with an 'abandoned response'
494 // error.
495 void abandon() override {
496 if (auto Err = Handler(this->createAbandonedResponseError())) {
497 // Handlers should not fail when passed an abandoned response error.
498 report_fatal_error(std::move(Err));
499 }
500 }
501
502 private:
503 HandlerT Handler;
504 };
505
506 // Create a ResponseHandler from a given user handler.
507 template
508 std::unique_ptr>
509 createResponseHandler(HandlerT H) {
510 return llvm::make_unique<
511 ResponseHandlerImpl>(std::move(H));
512 }
513
514 // Helper for wrapping member functions up as functors. This is useful for
515 // installing methods as result handlers.
516 template
517 class MemberFnWrapper {
518 public:
519 using MethodT = RetT(ClassT::*)(ArgTs...);
520 MemberFnWrapper(ClassT &Instance, MethodT Method)
521 : Instance(Instance), Method(Method) {}
522 RetT operator()(ArgTs &&... Args) {
523 return (Instance.*Method)(std::move(Args)...);
524 }
525 private:
526 ClassT &Instance;
527 MethodT Method;
528 };
529
530 // Helper that provides a Functor for deserializing arguments.
531 template class ReadArgs {
532 public:
533 Error operator()() { return Error::success(); }
534 };
535
536 template
537 class ReadArgs : public ReadArgs {
538 public:
539 ReadArgs(ArgT &Arg, ArgTs &... Args)
540 : ReadArgs(Args...), Arg(Arg) {}
541
542 Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
543 this->Arg = std::move(ArgVal);
544 return ReadArgs::operator()(ArgVals...);
545 }
546 private:
547 ArgT &Arg;
548 };
549
550 // Manage sequence numbers.
551 template
552 class SequenceNumberManager {
553 public:
554 // Reset, making all sequence numbers available.
555 void reset() {
556 std::lock_guard Lock(SeqNoLock);
557 NextSequenceNumber = 0;
558 FreeSequenceNumbers.clear();
559 }
560
561 // Get the next available sequence number. Will re-use numbers that have
562 // been released.
563 SequenceNumberT getSequenceNumber() {
564 std::lock_guard Lock(SeqNoLock);
565 if (FreeSequenceNumbers.empty())
566 return NextSequenceNumber++;
567 auto SequenceNumber = FreeSequenceNumbers.back();
568 FreeSequenceNumbers.pop_back();
569 return SequenceNumber;
570 }
571
572 // Release a sequence number, making it available for re-use.
573 void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
574 std::lock_guard Lock(SeqNoLock);
575 FreeSequenceNumbers.push_back(SequenceNumber);
576 }
577
578 private:
579 std::mutex SeqNoLock;
580 SequenceNumberT NextSequenceNumber = 0;
581 std::vector FreeSequenceNumbers;
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 };
582360 };
583361
584362 /// Contains primitive utilities for defining, calling and handling calls to
585363 /// remote procedures. ChannelT is a bidirectional stream conforming to the
586 /// RPCChannel interface (see RPCChannel.h), FunctionIdT is a procedure
587 /// identifier type that must be serializable on ChannelT, and SequenceNumberT
588 /// is an integral type that will be used to number in-flight function calls.
364 /// RPCChannel interface (see RPCChannel.h), and FunctionIdT is a procedure
365 /// identifier type that must be serializable on ChannelT.
589366 ///
590367 /// These utilities support the construction of very primitive RPC utilities.
591368 /// Their intent is to ensure correct serialization and deserialization of
592369 /// procedure arguments, and to keep the client and server's view of the API in
593370 /// sync.
594 template
595 typename SequenceNumberT>
596 class RPCBase {
597 protected:
598
599 class OrcRPCInvalid : public Function {
600 public:
601 static const char *getName() { return "__orc_rpc$invalid"; }
602 };
603
604 class OrcRPCResponse : public Function {
605 public:
606 static const char *getName() { return "__orc_rpc$response"; }
607 };
608
609 class OrcRPCNegotiate
610 : public Function {
611 public:
612 static const char *getName() { return "__orc_rpc$negotiate"; }
613 };
614
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 {
615406 public:
616
617 /// Construct an RPC instance on a channel.
618 RPCBase(ChannelT &C, bool LazyAutoNegotiation)
619 : C(C), LazyAutoNegotiation(LazyAutoNegotiation) {
620 // Hold ResponseId in a special variable, since we expect Response to be
621 // called relatively frequently, and want to avoid the map lookup.
622 ResponseId = FnIdAllocator.getResponseId();
623 RemoteFunctionIds[OrcRPCResponse::getPrototype()] = ResponseId;
624
625 // Register the negotiate function id and handler.
626 auto NegotiateId = FnIdAllocator.getNegotiateId();
627 RemoteFunctionIds[OrcRPCNegotiate::getPrototype()] = NegotiateId;
628 Handlers[NegotiateId] =
629 wrapHandler([this](const std::string &Name) {
630 return handleNegotiate(Name);
631 }, LaunchPolicy());
632 }
633
634 /// Append a call Func, does not call send on the channel.
635 /// The first argument specifies a user-defined handler to be run when the
636 /// function returns. The handler should take an Expected,
637 /// or an Error (if Func::ReturnType is void). The handler will be called
638 /// with an error if the return value is abandoned due to a channel error.
639 template
640 Error appendCallAsync(HandlerT Handler, const ArgTs &... Args) {
641 // Look up the function ID.
642 FunctionIdT FnId;
643 if (auto FnIdOrErr = getRemoteFunctionId())
644 FnId = *FnIdOrErr;
645 else {
646 // This isn't a channel error so we don't want to abandon other pending
647 // responses, but we still need to run the user handler with an error to
648 // let them know the call failed.
649 if (auto Err = Handler(orcError(OrcErrorCode::UnknownRPCFunction)))
650 report_fatal_error(std::move(Err));
651 return FnIdOrErr.takeError();
652 }
653
654 // Allocate a sequence number.
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) {
655461 auto SeqNo = SequenceNumberMgr.getSequenceNumber();
656 assert(!PendingResponses.count(SeqNo) &&
657 "Sequence number already allocated");
658
659 // Install the user handler.
660 PendingResponses[SeqNo] =
661 detail::createResponseHandler(
662 std::move(Handler));
663
664 // Open the function call message.
665 if (auto Err = C.startSendMessage(FnId, SeqNo)) {
666 abandonPendingResponses();
667 return joinErrors(std::move(Err), C.endSendMessage());
668 }
669
670 // Serialize the call arguments.
671 if (auto Err =
672 detail::HandlerTraits::
673 serializeArgs(C, Args...)) {
674 abandonPendingResponses();
675 return joinErrors(std::move(Err), C.endSendMessage());
676 }
677
678 // Close the function call messagee.
679 if (auto Err = C.endSendMessage()) {
680 abandonPendingResponses();
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);
681471 return std::move(Err);
682 }
683
684 return Error::success();
685 }
686
687
688 template
689 Error callAsync(HandlerT Handler, const ArgTs &... Args) {
690 if (auto Err = appendCallAsync(std::move(Handler), Args...))
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))
691565 return Err;
692 return C.send();
693 }
694
695 /// Handle one incoming call.
696 Error handleOne() {
697 FunctionIdT FnId;
698 SequenceNumberT SeqNo;
699 if (auto Err = C.startReceiveMessage(FnId, SeqNo))
700 return Err;
701 if (FnId == ResponseId)
702 return handleResponse(SeqNo);
703 auto I = Handlers.find(FnId);
704 if (I != Handlers.end())
705 return I->second(C, SeqNo);
706
707 // else: No handler found. Report error to client?
708 return orcError(OrcErrorCode::UnexpectedRPCCall);
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));
709607 }
710608
711609 /// Helper for handling setter procedures - this method returns a functor that
722620 /// /* Handle Args */ ;
723621 ///
724622 template
725 static detail::ReadArgs readArgs(ArgTs &... Args) {
726 return detail::ReadArgs(Args...);
727 }
728
729 protected:
730 // The LaunchPolicy type allows a launch policy to be specified when adding
731 // a function handler. See addHandlerImpl.
732 using LaunchPolicy = std::function)>;
733
734 /// Add the given handler to the handler map and make it available for
735 /// autonegotiation and execution.
736 template
737 void addHandlerImpl(HandlerT Handler, LaunchPolicy Launch) {
738 FunctionIdT NewFnId = FnIdAllocator.template allocate();
739 LocalFunctionIds[Func::getPrototype()] = NewFnId;
740 Handlers[NewFnId] = wrapHandler(std::move(Handler),
741 std::move(Launch));
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();
633 return Err;
634 }
635
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?
648 return Err;
649 }
650
651 OutstandingResults.erase(I);
652 SequenceNumberMgr.releaseSequenceNumber(SeqNo);
653
654 return Error::success();
655 }
656
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
686 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.
741 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.
757 template
758 std::unique_ptr
759 createOutstandingResult(std::promise &&P) {
760 return llvm::make_unique>(std::move(P));
742761 }
743762
744763 // Abandon all outstanding results.
745 void abandonPendingResponses() {
746 for (auto &KV : PendingResponses)
764 void abandonOutstandingResults() {
765 for (auto &KV : OutstandingResults)
747766 KV.second->abandon();
748 PendingResponses.clear();
767 OutstandingResults.clear();
749768 SequenceNumberMgr.reset();
750769 }
751770
752 Error handleResponse(SequenceNumberT SeqNo) {
753 auto I = PendingResponses.find(SeqNo);
754 if (I == PendingResponses.end()) {
755 abandonPendingResponses();
756 return orcError(OrcErrorCode::UnexpectedRPCResponse);
757 }
758
759 auto PRHandler = std::move(I->second);
760 PendingResponses.erase(I);
761 SequenceNumberMgr.releaseSequenceNumber(SeqNo);
762
763 if (auto Err = PRHandler->handleResponse(C)) {
764 abandonPendingResponses();
765 SequenceNumberMgr.reset();
766 return Err;
767 }
768
769 return Error::success();
770 }
771
772 FunctionIdT handleNegotiate(const std::string &Name) {
773 auto I = LocalFunctionIds.find(Name);
774 if (I == LocalFunctionIds.end())
775 return FnIdAllocator.getInvalidId();
776 return I->second;
777 }
778
779 // Find the remote FunctionId for the given function, which must be in the
780 // RemoteFunctionIds map.
781 template
782 Expected getRemoteFunctionId() {
783 // Try to find the id for the given function.
784 auto I = RemoteFunctionIds.find(Func::getPrototype());
785
786 // If we have it in the map, return it.
787 if (I != RemoteFunctionIds.end())
788 return I->second;
789
790 // Otherwise, if we have auto-negotiation enabled, try to negotiate it.
791 if (LazyAutoNegotiation) {
792 auto &Impl = static_cast(*this);
793 if (auto RemoteIdOrErr =
794 Impl.template callB(Func::getPrototype())) {
795 auto &RemoteId = *RemoteIdOrErr;
796
797 // If autonegotiation indicates that the remote end doesn't support this
798 // function, return an unknown function error.
799 if (RemoteId == FnIdAllocator.getInvalidId())
800 return orcError(OrcErrorCode::UnknownRPCFunction);
801
802 // Autonegotiation succeeded and returned a valid id. Update the map and
803 // return the id.
804 RemoteFunctionIds[Func::getPrototype()] = RemoteId;
805 return RemoteId;
806 } else {
807 // Autonegotiation failed. Return the error.
808 return RemoteIdOrErr.takeError();
809 }
810 }
811
812 // No key was available in the map and autonegotiation wasn't enabled.
813 // Return an unknown function error.
814 return orcError(OrcErrorCode::UnknownRPCFunction);
815 }
816
817 using WrappedHandlerFn = std::function;
818
819 // Wrap the given user handler in the necessary argument-deserialization code,
820 // result-serialization code, and call to the launch policy (if present).
821 template
822 WrappedHandlerFn wrapHandler(HandlerT Handler, LaunchPolicy Launch) {
823 return
824 [this, Handler, Launch](ChannelT &Channel, SequenceNumberT SeqNo) -> Error {
825 // Start by deserializing the arguments.
826 auto Args =
827 std::make_shared::ArgStorage>();
828 if (auto Err = detail::HandlerTraits::
829 deserializeArgs(Channel, *Args))
830 return Err;
831
832 // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
833 // for RPCArgs. Void cast RPCArgs to work around this for now.
834 // FIXME: Remove this workaround once we can assume a working GCC version.
835 (void)Args;
836
837 // End receieve message, unlocking the channel for reading.
838 if (auto Err = Channel.endReceiveMessage())
839 return Err;
840
841 // Build the handler/responder.
842 auto Responder =
843 [this, Handler, Args, &Channel, SeqNo]() mutable -> Error {
844 using HTraits = detail::HandlerTraits;
845 using FuncReturn = typename Func::ReturnType;
846 return detail::respond(Channel, ResponseId, SeqNo,
847 HTraits::runHandler(Handler,
848 *Args));
849 };
850
851 // If there is an explicit launch policy then use it to launch the
852 // handler.
853 if (Launch)
854 return Launch(std::move(Responder));
855
856 // Otherwise run the handler on the listener thread.
857 return Responder();
858 };
859 }
860
861 ChannelT &C;
862
863 bool LazyAutoNegotiation;
864
865 RPCFunctionIdAllocator FnIdAllocator;
866
867 FunctionIdT ResponseId;
868 std::map LocalFunctionIds;
869 std::map RemoteFunctionIds;
870
871 std::map Handlers;
872
873 detail::SequenceNumberManager SequenceNumberMgr;
874 std::map>>
875 PendingResponses;
771 SequenceNumberManager SequenceNumberMgr;
772 std::map>
773 OutstandingResults;
876774 };
877775
878 } // end namespace detail
879
880
881 template
882 typename FunctionIdT = uint32_t,
883 typename SequenceNumberT = uint32_t>
884 class MultiThreadedRPC
885 : public detail::RPCBase
886 SequenceNumberT>,
887 ChannelT, FunctionIdT, SequenceNumberT> {
888 private:
889 using BaseClass =
890 detail::RPCBase,
891 ChannelT, FunctionIdT, SequenceNumberT>;
892
893 public:
894
895 MultiThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
896 : BaseClass(C, LazyAutoNegotiation) {}
897
898 /// The LaunchPolicy type allows a launch policy to be specified when adding
899 /// a function handler. See addHandler.
900 using LaunchPolicy = typename BaseClass::LaunchPolicy;
901
902 /// Add a handler for the given RPC function.
903 /// This installs the given handler functor for the given RPC Function, and
904 /// makes the RPC function available for negotiation/calling from the remote.
905 ///
906 /// The optional LaunchPolicy argument can be used to control how the handler
907 /// is run when called:
908 ///
909 /// * If no LaunchPolicy is given, the handler code will be run on the RPC
910 /// handler thread that is reading from the channel. This handler cannot
911 /// make blocking RPC calls (since it would be blocking the thread used to
912 /// get the result), but can make non-blocking calls.
913 ///
914 /// * If a LaunchPolicy is given, the user's handler will be wrapped in a
915 /// call to serialize and send the result, and the resulting functor (with
916 /// type 'Error()' will be passed to the LaunchPolicy. The user can then
917 /// choose to add the wrapped handler to a work queue, spawn a new thread,
918 /// or anything else.
919 template
920 void addHandler(HandlerT Handler, LaunchPolicy Launch = LaunchPolicy()) {
921 return this->template addHandlerImpl(std::move(Handler),
922 std::move(Launch));
923 }
924
925 /// Negotiate a function id for Func with the other end of the channel.
926 template
927 Error negotiateFunction() {
928 using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
929
930 if (auto RemoteIdOrErr = callB(Func::getPrototype())) {
931 this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
932 return Error::success();
933 } else
934 return RemoteIdOrErr.takeError();
935 }
936
937 /// Convenience method for negotiating multiple functions at once.
938 template
939 Error negotiateFunctions() {
940 return negotiateFunction();
941 }
942
943 /// Convenience method for negotiating multiple functions at once.
944 template
945 Error negotiateFunctions() {
946 if (auto Err = negotiateFunction())
947 return Err;
948 return negotiateFunctions();
949 }
950
951 /// Return type for non-blocking call primitives.
952 template
953 using NonBlockingCallResult =
954 typename detail::ResultTraits::ReturnFutureType;
955
956 /// Call Func on Channel C. Does not block, does not call send. Returns a pair
957 /// of a future result and the sequence number assigned to the result.
958 ///
959 /// This utility function is primarily used for single-threaded mode support,
960 /// where the sequence number can be used to wait for the corresponding
961 /// result. In multi-threaded mode the appendCallNB method, which does not
962 /// return the sequence numeber, should be preferred.
963 template
964 Expected>
965 appendCallNB(const ArgTs &... Args) {
966 using RTraits = detail::ResultTraits;
967 using ErrorReturn = typename RTraits::ErrorReturnType;
968 using ErrorReturnPromise = typename RTraits::ReturnPromiseType;
969
970 // FIXME: Stack allocate and move this into the handler once LLVM builds
971 // with C++14.
972 auto Promise = std::make_shared();
973 auto FutureResult = Promise->get_future();
974
975 if (auto Err = this->template appendCallAsync(
976 [Promise](ErrorReturn RetOrErr) {
977 Promise->set_value(std::move(RetOrErr));
978 return Error::success();
979 }, Args...)) {
980 this->abandonPendingResponses();
981 RTraits::consumeAbandoned(FutureResult.get());
982 return std::move(Err);
983 }
984 return std::move(FutureResult);
985 }
986
987 /// The same as appendCallNBWithSeq, except that it calls C.send() to
988 /// flush the channel after serializing the call.
989 template
990 Expected>
991 callNB(const ArgTs &... Args) {
992 auto Result = appendCallNB(Args...);
993 if (!Result)
994 return Result;
995 if (auto Err = this->C.send()) {
996 this->abandonPendingResponses();
997 detail::ResultTraits::
998 consumeAbandoned(std::move(Result->get()));
999 return std::move(Err);
1000 }
1001 return Result;
1002 }
1003
1004 /// Call Func on Channel C. Blocks waiting for a result. Returns an Error
1005 /// for void functions or an Expected for functions returning a T.
1006 ///
1007 /// This function is for use in threaded code where another thread is
1008 /// handling responses and incoming calls.
1009 template
1010 typename AltRetT = typename Func::ReturnType>
1011 typename detail::ResultTraits::ErrorReturnType
1012 callB(const ArgTs &... Args) {
1013 if (auto FutureResOrErr = callNB(Args...)) {
1014 if (auto Err = this->C.send()) {
1015 this->abandonPendingResponses();
1016 detail::ResultTraits::
1017 consumeAbandoned(std::move(FutureResOrErr->get()));
1018 return std::move(Err);
1019 }
1020 return FutureResOrErr->get();
1021 } else
1022 return FutureResOrErr.takeError();
1023 }
1024
1025 /// Handle incoming RPC calls.
1026 Error handlerLoop() {
1027 while (true)
1028 if (auto Err = this->handleOne())
1029 return Err;
1030 return Error::success();
1031 }
1032
1033 };
1034
1035 template
1036 typename FunctionIdT = uint32_t,
1037 typename SequenceNumberT = uint32_t>
1038 class SingleThreadedRPC
1039 : public detail::RPCBase
1040 SequenceNumberT>,
1041 ChannelT, FunctionIdT,
1042 SequenceNumberT> {
1043 private:
1044
1045 using BaseClass = detail::RPCBase
1046 SequenceNumberT>,
1047 ChannelT, FunctionIdT, SequenceNumberT>;
1048
1049 using LaunchPolicy = typename BaseClass::LaunchPolicy;
1050
1051 public:
1052
1053 SingleThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
1054 : BaseClass(C, LazyAutoNegotiation) {}
1055
1056 template
1057 void addHandler(HandlerT Handler) {
1058 return this->template addHandlerImpl(std::move(Handler),
1059 LaunchPolicy());
1060 }
1061
1062 template
1063 void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
1064 addHandler(
1065 detail::MemberFnWrapper(Object, Method));
1066 }
1067
1068 /// Negotiate a function id for Func with the other end of the channel.
1069 template
1070 Error negotiateFunction() {
1071 using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
1072
1073 if (auto RemoteIdOrErr = callB(Func::getPrototype())) {
1074 this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
1075 return Error::success();
1076 } else
1077 return RemoteIdOrErr.takeError();
1078 }
1079
1080 /// Convenience method for negotiating multiple functions at once.
1081 template
1082 Error negotiateFunctions() {
1083 return negotiateFunction();
1084 }
1085
1086 /// Convenience method for negotiating multiple functions at once.
1087 template
1088 Error negotiateFunctions() {
1089 if (auto Err = negotiateFunction())
1090 return Err;
1091 return negotiateFunctions();
1092 }
1093
1094 template
1095 typename AltRetT = typename Func::ReturnType>
1096 typename detail::ResultTraits::ErrorReturnType
1097 callB(const ArgTs &... Args) {
1098 bool ReceivedResponse = false;
1099 using ResultType =
1100 typename detail::ResultTraits::ErrorReturnType;
1101 auto Result = detail::ResultTraits::createBlankErrorReturnValue();
1102
1103 // We have to 'Check' result (which we know is in a success state at this
1104 // point) so that it can be overwritten in the async handler.
1105 (void)!!Result;
1106
1107 if (auto Err = this->template appendCallAsync(
1108 [&](ResultType R) {
1109 Result = std::move(R);
1110 ReceivedResponse = true;
1111 return Error::success();
1112 }, Args...)) {
1113 this->abandonPendingResponses();
1114 detail::ResultTraits::
1115 consumeAbandoned(std::move(Result));
1116 return std::move(Err);
1117 }
1118
1119 while (!ReceivedResponse) {
1120 if (auto Err = this->handleOne()) {
1121 this->abandonPendingResponses();
1122 detail::ResultTraits::
1123 consumeAbandoned(std::move(Result));
1124 return std::move(Err);
1125 }
1126 }
1127
1128 return Result;
1129 }
1130
1131 //using detail::RPCBase::handleOne;
1132
1133 };
1134
1135 } // end namespace rpc
776 } // end namespace remote
1136777 } // end namespace orc
1137778 } // end namespace llvm
1138779
+0
-182
include/llvm/ExecutionEngine/Orc/RawByteChannel.h less more
None //===- 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
89
910 ADDITIONAL_HEADER_DIRS
1011 ${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";
4745 }
4846 llvm_unreachable("Unhandled error code");
4947 }
0 //===------- 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
5252 RTDyldMemoryManager::deregisterEHFramesInProcess(Addr, Size);
5353 };
5454
55 FDRawChannel Channel(InFD, OutFD);
56 typedef remote::OrcRemoteTargetServer JITServer;
55 FDRPCChannel Channel(InFD, OutFD);
56 typedef remote::OrcRemoteTargetServer JITServer;
5757 JITServer Server(Channel, SymbolLookup, RegisterEHFrames, DeregisterEHFrames);
5858
59 while (!Server.receivedTerminate())
60 ExitOnErr(Server.handleOne());
59 while (1) {
60 uint32_t RawId;
61 ExitOnErr(Server.startReceivingFunction(Channel, RawId));
62 auto Id = static_cast(RawId);
63 switch (Id) {
64 case JITServer::TerminateSessionId:
65 ExitOnErr(Server.handleTerminateSession());
66 return 0;
67 default:
68 ExitOnErr(Server.handleKnownFunction(Id));
69 break;
70 }
71 }
6172
6273 close(InFD);
6374 close(OutFD);