summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorLang Hames <lhames@gmail.com>2016-11-11 19:46:46 +0000
committerLang Hames <lhames@gmail.com>2016-11-11 19:46:46 +0000
commitb35b7016390450f6261216d059ee574956f44413 (patch)
treeff326949fa89b39254efdb202e1a7d62a330b027 /include
parentd8314f03b12580b2b644ac7ca8ada80ba7f1e1bc (diff)
[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
Diffstat (limited to 'include')
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcError.h1
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h171
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h265
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h125
-rw-r--r--include/llvm/ExecutionEngine/Orc/RPCByteChannel.h231
-rw-r--r--include/llvm/ExecutionEngine/Orc/RPCSerialization.h340
-rw-r--r--include/llvm/ExecutionEngine/Orc/RPCUtils.h1453
-rw-r--r--include/llvm/ExecutionEngine/Orc/RawByteChannel.h182
8 files changed, 1188 insertions, 1580 deletions
diff --git a/include/llvm/ExecutionEngine/Orc/OrcError.h b/include/llvm/ExecutionEngine/Orc/OrcError.h
index 8841aa77f62..1b3f25fae16 100644
--- a/include/llvm/ExecutionEngine/Orc/OrcError.h
+++ b/include/llvm/ExecutionEngine/Orc/OrcError.h
@@ -29,7 +29,6 @@ enum class OrcErrorCode : int {
RemoteIndirectStubsOwnerIdAlreadyInUse,
UnexpectedRPCCall,
UnexpectedRPCResponse,
- UnknownRPCFunction
};
Error orcError(OrcErrorCode ErrCode);
diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
index 5b2f8921fef..d549fc31deb 100644
--- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
+++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This file defines the OrcRemoteTargetClient class and helpers. This class
-// can be used to communicate over an RawByteChannel with an
+// can be used to communicate over an RPCByteChannel with an
// OrcRemoteTargetServer instance to support remote-JITing.
//
//===----------------------------------------------------------------------===//
@@ -36,6 +36,23 @@ namespace remote {
template <typename ChannelT>
class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
public:
+ // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
+
+ OrcRemoteTargetClient(const OrcRemoteTargetClient &) = delete;
+ OrcRemoteTargetClient &operator=(const OrcRemoteTargetClient &) = delete;
+
+ OrcRemoteTargetClient(OrcRemoteTargetClient &&Other)
+ : Channel(Other.Channel), ExistingError(std::move(Other.ExistingError)),
+ RemoteTargetTriple(std::move(Other.RemoteTargetTriple)),
+ RemotePointerSize(std::move(Other.RemotePointerSize)),
+ RemotePageSize(std::move(Other.RemotePageSize)),
+ RemoteTrampolineSize(std::move(Other.RemoteTrampolineSize)),
+ RemoteIndirectStubSize(std::move(Other.RemoteIndirectStubSize)),
+ AllocatorIds(std::move(Other.AllocatorIds)),
+ IndirectStubOwnerIds(std::move(Other.IndirectStubOwnerIds)),
+ CallbackManager(std::move(Other.CallbackManager)) {}
+
+ OrcRemoteTargetClient &operator=(OrcRemoteTargetClient &&) = delete;
/// Remote memory manager.
class RCMemoryManager : public RuntimeDyld::MemoryManager {
@@ -45,10 +62,18 @@ public:
DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
}
- RCMemoryManager(const RCMemoryManager&) = delete;
- RCMemoryManager& operator=(const RCMemoryManager&) = delete;
- RCMemoryManager(RCMemoryManager&&) = default;
- RCMemoryManager& operator=(RCMemoryManager&&) = default;
+ RCMemoryManager(RCMemoryManager &&Other)
+ : Client(std::move(Other.Client)), Id(std::move(Other.Id)),
+ Unmapped(std::move(Other.Unmapped)),
+ Unfinalized(std::move(Other.Unfinalized)) {}
+
+ RCMemoryManager operator=(RCMemoryManager &&Other) {
+ Client = std::move(Other.Client);
+ Id = std::move(Other.Id);
+ Unmapped = std::move(Other.Unmapped);
+ Unfinalized = std::move(Other.Unfinalized);
+ return *this;
+ }
~RCMemoryManager() override {
Client.destroyRemoteAllocator(Id);
@@ -342,10 +367,18 @@ public:
Alloc(uint64_t Size, unsigned Align)
: Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
- Alloc(const Alloc&) = delete;
- Alloc& operator=(const Alloc&) = delete;
- Alloc(Alloc&&) = default;
- Alloc& operator=(Alloc&&) = default;
+ Alloc(Alloc &&Other)
+ : Size(std::move(Other.Size)), Align(std::move(Other.Align)),
+ Contents(std::move(Other.Contents)),
+ RemoteAddr(std::move(Other.RemoteAddr)) {}
+
+ Alloc &operator=(Alloc &&Other) {
+ Size = std::move(Other.Size);
+ Align = std::move(Other.Align);
+ Contents = std::move(Other.Contents);
+ RemoteAddr = std::move(Other.RemoteAddr);
+ return *this;
+ }
uint64_t getSize() const { return Size; }
@@ -372,10 +405,24 @@ public:
struct ObjectAllocs {
ObjectAllocs() = default;
- ObjectAllocs(const ObjectAllocs &) = delete;
- ObjectAllocs& operator=(const ObjectAllocs &) = delete;
- ObjectAllocs(ObjectAllocs&&) = default;
- ObjectAllocs& operator=(ObjectAllocs&&) = default;
+
+ ObjectAllocs(ObjectAllocs &&Other)
+ : RemoteCodeAddr(std::move(Other.RemoteCodeAddr)),
+ RemoteRODataAddr(std::move(Other.RemoteRODataAddr)),
+ RemoteRWDataAddr(std::move(Other.RemoteRWDataAddr)),
+ CodeAllocs(std::move(Other.CodeAllocs)),
+ RODataAllocs(std::move(Other.RODataAllocs)),
+ RWDataAllocs(std::move(Other.RWDataAllocs)) {}
+
+ ObjectAllocs &operator=(ObjectAllocs &&Other) {
+ RemoteCodeAddr = std::move(Other.RemoteCodeAddr);
+ RemoteRODataAddr = std::move(Other.RemoteRODataAddr);
+ RemoteRWDataAddr = std::move(Other.RemoteRWDataAddr);
+ CodeAllocs = std::move(Other.CodeAllocs);
+ RODataAllocs = std::move(Other.RODataAllocs);
+ RWDataAllocs = std::move(Other.RWDataAllocs);
+ return *this;
+ }
JITTargetAddress RemoteCodeAddr = 0;
JITTargetAddress RemoteRODataAddr = 0;
@@ -541,21 +588,23 @@ public:
/// Create an OrcRemoteTargetClient.
/// Channel is the ChannelT instance to communicate on. It is assumed that
/// the channel is ready to be read from and written to.
- static Expected<std::unique_ptr<OrcRemoteTargetClient>>
- Create(ChannelT &Channel) {
+ static Expected<OrcRemoteTargetClient> Create(ChannelT &Channel) {
Error Err = Error::success();
- std::unique_ptr<OrcRemoteTargetClient>
- Client(new OrcRemoteTargetClient(Channel, Err));
+ OrcRemoteTargetClient H(Channel, Err);
if (Err)
return std::move(Err);
- return std::move(Client);
+ return Expected<OrcRemoteTargetClient>(std::move(H));
}
/// Call the int(void) function at the given address in the target and return
/// its result.
Expected<int> callIntVoid(JITTargetAddress Addr) {
DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
- return callB<CallIntVoid>(Addr);
+
+ auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
+ return listenForCompileRequests(C, Id);
+ };
+ return callSTHandling<CallIntVoid>(Channel, Listen, Addr);
}
/// Call the int(int, char*[]) function at the given address in the target and
@@ -564,7 +613,11 @@ public:
const std::vector<std::string> &Args) {
DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
<< "\n");
- return callB<CallMain>(Addr, Args);
+
+ auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
+ return listenForCompileRequests(C, Id);
+ };
+ return callSTHandling<CallMain>(Channel, Listen, Addr, Args);
}
/// Call the void() function at the given address in the target and wait for
@@ -572,7 +625,11 @@ public:
Error callVoidVoid(JITTargetAddress Addr) {
DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
<< "\n");
- return callB<CallVoidVoid>(Addr);
+
+ auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
+ return listenForCompileRequests(C, Id);
+ };
+ return callSTHandling<CallVoidVoid>(Channel, Listen, Addr);
}
/// Create an RCMemoryManager which will allocate its memory on the remote
@@ -581,7 +638,7 @@ public:
assert(!MM && "MemoryManager should be null before creation.");
auto Id = AllocatorIds.getNext();
- if (auto Err = callB<CreateRemoteAllocator>(Id))
+ if (auto Err = callST<CreateRemoteAllocator>(Channel, Id))
return Err;
MM = llvm::make_unique<RCMemoryManager>(*this, Id);
return Error::success();
@@ -592,7 +649,7 @@ public:
Error createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {
assert(!I && "Indirect stubs manager should be null before creation.");
auto Id = IndirectStubOwnerIds.getNext();
- if (auto Err = callB<CreateIndirectStubsOwner>(Id))
+ if (auto Err = callST<CreateIndirectStubsOwner>(Channel, Id))
return Err;
I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);
return Error::success();
@@ -605,7 +662,7 @@ public:
return std::move(ExistingError);
// Emit the resolver block on the JIT server.
- if (auto Err = callB<EmitResolverBlock>())
+ if (auto Err = callST<EmitResolverBlock>(Channel))
return std::move(Err);
// Create the callback manager.
@@ -622,28 +679,18 @@ public:
if (ExistingError)
return std::move(ExistingError);
- return callB<GetSymbolAddress>(Name);
+ return callST<GetSymbolAddress>(Channel, Name);
}
/// Get the triple for the remote target.
const std::string &getTargetTriple() const { return RemoteTargetTriple; }
- Error terminateSession() { return callB<TerminateSession>(); }
+ Error terminateSession() { return callST<TerminateSession>(Channel); }
private:
-
- OrcRemoteTargetClient(ChannelT &Channel, Error &Err)
- : OrcRemoteTargetRPCAPI(Channel) {
+ OrcRemoteTargetClient(ChannelT &Channel, Error &Err) : Channel(Channel) {
ErrorAsOutParameter EAO(&Err);
-
- addHandler<RequestCompile>(
- [this](JITTargetAddress Addr) -> JITTargetAddress {
- if (CallbackManager)
- return CallbackManager->executeCompileCallback(Addr);
- return 0;
- });
-
- if (auto RIOrErr = callB<GetRemoteInfo>()) {
+ if (auto RIOrErr = callST<GetRemoteInfo>(Channel)) {
std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
Err = Error::success();
@@ -653,11 +700,11 @@ private:
}
Error deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
- return callB<RegisterEHFrames>(Addr, Size);
+ return callST<RegisterEHFrames>(Channel, Addr, Size);
}
void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
- if (auto Err = callB<DestroyRemoteAllocator>(Id)) {
+ if (auto Err = callST<DestroyRemoteAllocator>(Channel, Id)) {
// FIXME: This will be triggered by a removeModuleSet call: Propagate
// error return up through that.
llvm_unreachable("Failed to destroy remote allocator.");
@@ -667,12 +714,12 @@ private:
Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
IndirectStubOwnerIds.release(Id);
- return callB<DestroyIndirectStubsOwner>(Id);
+ return callST<DestroyIndirectStubsOwner>(Channel, Id);
}
Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
- return callB<EmitIndirectStubs>(Id, NumStubsRequired);
+ return callST<EmitIndirectStubs>(Channel, Id, NumStubsRequired);
}
Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() {
@@ -680,7 +727,7 @@ private:
if (ExistingError)
return std::move(ExistingError);
- return callB<EmitTrampolineBlock>();
+ return callST<EmitTrampolineBlock>(Channel);
}
uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
@@ -689,17 +736,42 @@ private:
uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
+ Error listenForCompileRequests(RPCByteChannel &C, uint32_t &Id) {
+ assert(CallbackManager &&
+ "No calback manager. enableCompileCallbacks must be called first");
+
+ // Check for an 'out-of-band' error, e.g. from an MM destructor.
+ if (ExistingError)
+ return std::move(ExistingError);
+
+ // FIXME: CompileCallback could be an anonymous lambda defined at the use
+ // site below, but that triggers a GCC 4.7 ICE. When we move off
+ // GCC 4.7, tidy this up.
+ auto CompileCallback =
+ [this](JITTargetAddress Addr) -> Expected<JITTargetAddress> {
+ return this->CallbackManager->executeCompileCallback(Addr);
+ };
+
+ if (Id == RequestCompileId) {
+ if (auto Err = handle<RequestCompile>(C, CompileCallback))
+ return Err;
+ return Error::success();
+ }
+ // else
+ return orcError(OrcErrorCode::UnexpectedRPCCall);
+ }
+
Expected<std::vector<char>> readMem(char *Dst, JITTargetAddress Src,
uint64_t Size) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return std::move(ExistingError);
- return callB<ReadMem>(Src, Size);
+ return callST<ReadMem>(Channel, Src, Size);
}
Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) {
- return callB<RegisterEHFrames>(RAddr, Size);
+ return callST<RegisterEHFrames>(Channel, RAddr, Size);
}
Expected<JITTargetAddress> reserveMem(ResourceIdMgr::ResourceId Id,
@@ -709,12 +781,12 @@ private:
if (ExistingError)
return std::move(ExistingError);
- return callB<ReserveMem>(Id, Size, Align);
+ return callST<ReserveMem>(Channel, Id, Size, Align);
}
Error setProtections(ResourceIdMgr::ResourceId Id,
JITTargetAddress RemoteSegAddr, unsigned ProtFlags) {
- return callB<SetProtections>(Id, RemoteSegAddr, ProtFlags);
+ return callST<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);
}
Error writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) {
@@ -722,7 +794,7 @@ private:
if (ExistingError)
return std::move(ExistingError);
- return callB<WriteMem>(DirectBufferWriter(Src, Addr, Size));
+ return callST<WriteMem>(Channel, DirectBufferWriter(Src, Addr, Size));
}
Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
@@ -730,11 +802,12 @@ private:
if (ExistingError)
return std::move(ExistingError);
- return callB<WritePtr>(Addr, PtrVal);
+ return callST<WritePtr>(Channel, Addr, PtrVal);
}
static Error doNothing() { return Error::success(); }
+ ChannelT &Channel;
Error ExistingError = Error::success();
std::string RemoteTargetTriple;
uint32_t RemotePointerSize = 0;
diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
index 413e286a347..33d6b604c61 100644
--- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
+++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h
@@ -16,7 +16,7 @@
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
-#include "RawByteChannel.h"
+#include "RPCByteChannel.h"
#include "RPCUtils.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
@@ -40,24 +40,13 @@ private:
uint64_t Size;
};
-} // end namespace remote
-
-namespace rpc {
-
template <>
-class RPCTypeName<remote::DirectBufferWriter> {
+class SerializationTraits<RPCByteChannel, DirectBufferWriter> {
public:
- static const char *getName() { return "DirectBufferWriter"; }
-};
-template <typename ChannelT>
-class SerializationTraits<ChannelT, remote::DirectBufferWriter, remote::DirectBufferWriter,
- typename std::enable_if<
- std::is_base_of<RawByteChannel, ChannelT>::
- value>::type> {
-public:
+ static const char* getName() { return "DirectBufferWriter"; }
- static Error serialize(ChannelT &C, const remote::DirectBufferWriter &DBW) {
+ static Error serialize(RPCByteChannel &C, const DirectBufferWriter &DBW) {
if (auto EC = serializeSeq(C, DBW.getDst()))
return EC;
if (auto EC = serializeSeq(C, DBW.getSize()))
@@ -65,7 +54,7 @@ public:
return C.appendBytes(DBW.getSrc(), DBW.getSize());
}
- static Error deserialize(ChannelT &C, remote::DirectBufferWriter &DBW) {
+ static Error deserialize(RPCByteChannel &C, DirectBufferWriter &DBW) {
JITTargetAddress Dst;
if (auto EC = deserializeSeq(C, Dst))
return EC;
@@ -74,18 +63,13 @@ public:
return EC;
char *Addr = reinterpret_cast<char *>(static_cast<uintptr_t>(Dst));
- DBW = remote::DirectBufferWriter(0, Dst, Size);
+ DBW = DirectBufferWriter(0, Dst, Size);
return C.readBytes(Addr, Size);
}
};
-} // end namespace rpc
-
-namespace remote {
-
-class OrcRemoteTargetRPCAPI
- : public rpc::SingleThreadedRPC<rpc::RawByteChannel> {
+class OrcRemoteTargetRPCAPI : public RPC<RPCByteChannel> {
protected:
class ResourceIdMgr {
public:
@@ -109,162 +93,119 @@ protected:
public:
// FIXME: Remove constructors once MSVC supports synthesizing move-ops.
- OrcRemoteTargetRPCAPI(rpc::RawByteChannel &C)
- : rpc::SingleThreadedRPC<rpc::RawByteChannel>(C, true) {}
-
- class CallIntVoid : public rpc::Function<CallIntVoid,
- int32_t(JITTargetAddress Addr)> {
- public:
- static const char* getName() { return "CallIntVoid"; }
- };
-
- class CallMain
- : public rpc::Function<CallMain,
- int32_t(JITTargetAddress Addr,
- std::vector<std::string> Args)> {
- public:
- static const char* getName() { return "CallMain"; }
- };
-
- class CallVoidVoid : public rpc::Function<CallVoidVoid,
- void(JITTargetAddress FnAddr)> {
- public:
- static const char* getName() { return "CallVoidVoid"; }
- };
-
- class CreateRemoteAllocator
- : public rpc::Function<CreateRemoteAllocator,
- void(ResourceIdMgr::ResourceId AllocatorID)> {
- public:
- static const char* getName() { return "CreateRemoteAllocator"; }
- };
-
- class CreateIndirectStubsOwner
- : public rpc::Function<CreateIndirectStubsOwner,
- void(ResourceIdMgr::ResourceId StubOwnerID)> {
- public:
- static const char* getName() { return "CreateIndirectStubsOwner"; }
- };
-
- class DeregisterEHFrames
- : public rpc::Function<DeregisterEHFrames,
- void(JITTargetAddress Addr, uint32_t Size)> {
- public:
- static const char* getName() { return "DeregisterEHFrames"; }
- };
-
- class DestroyRemoteAllocator
- : public rpc::Function<DestroyRemoteAllocator,
- void(ResourceIdMgr::ResourceId AllocatorID)> {
- public:
- static const char* getName() { return "DestroyRemoteAllocator"; }
- };
-
- class DestroyIndirectStubsOwner
- : public rpc::Function<DestroyIndirectStubsOwner,
- void(ResourceIdMgr::ResourceId StubsOwnerID)> {
- public:
- static const char* getName() { return "DestroyIndirectStubsOwner"; }
- };
+ OrcRemoteTargetRPCAPI() = default;
+ OrcRemoteTargetRPCAPI(const OrcRemoteTargetRPCAPI &) = delete;
+ OrcRemoteTargetRPCAPI &operator=(const OrcRemoteTargetRPCAPI &) = delete;
+
+ OrcRemoteTargetRPCAPI(OrcRemoteTargetRPCAPI &&) {}
+ OrcRemoteTargetRPCAPI &operator=(OrcRemoteTargetRPCAPI &&) { return *this; }
+
+ enum JITFuncId : uint32_t {
+ InvalidId = RPCFunctionIdTraits<JITFuncId>::InvalidId,
+ CallIntVoidId = RPCFunctionIdTraits<JITFuncId>::FirstValidId,
+ CallMainId,
+ CallVoidVoidId,
+ CreateRemoteAllocatorId,
+ CreateIndirectStubsOwnerId,
+ DeregisterEHFramesId,
+ DestroyRemoteAllocatorId,
+ DestroyIndirectStubsOwnerId,
+ EmitIndirectStubsId,
+ EmitResolverBlockId,
+ EmitTrampolineBlockId,
+ GetSymbolAddressId,
+ GetRemoteInfoId,
+ ReadMemId,
+ RegisterEHFramesId,
+ ReserveMemId,
+ RequestCompileId,
+ SetProtectionsId,
+ TerminateSessionId,
+ WriteMemId,
+ WritePtrId
+ };
+
+ static const char *getJITFuncIdName(JITFuncId Id);
+
+ typedef Function<CallIntVoidId, int32_t(JITTargetAddress Addr)> CallIntVoid;
+
+ typedef Function<CallMainId,
+ int32_t(JITTargetAddress Addr,
+ std::vector<std::string> Args)>
+ CallMain;
+
+ typedef Function<CallVoidVoidId, void(JITTargetAddress FnAddr)> CallVoidVoid;
+
+ typedef Function<CreateRemoteAllocatorId,
+ void(ResourceIdMgr::ResourceId AllocatorID)>
+ CreateRemoteAllocator;
+
+ typedef Function<CreateIndirectStubsOwnerId,
+ void(ResourceIdMgr::ResourceId StubOwnerID)>
+ CreateIndirectStubsOwner;
+
+ typedef Function<DeregisterEHFramesId,
+ void(JITTargetAddress Addr, uint32_t Size)>
+ DeregisterEHFrames;
+
+ typedef Function<DestroyRemoteAllocatorId,
+ void(ResourceIdMgr::ResourceId AllocatorID)>
+ DestroyRemoteAllocator;
+
+ typedef Function<DestroyIndirectStubsOwnerId,
+ void(ResourceIdMgr::ResourceId StubsOwnerID)>
+ DestroyIndirectStubsOwner;
/// EmitIndirectStubs result is (StubsBase, PtrsBase, NumStubsEmitted).
- class EmitIndirectStubs
- : public rpc::Function<EmitIndirectStubs,
- std::tuple<JITTargetAddress, JITTargetAddress,
- uint32_t>(
- ResourceIdMgr::ResourceId StubsOwnerID,
- uint32_t NumStubsRequired)> {
- public:
- static const char* getName() { return "EmitIndirectStubs"; }
- };
+ typedef Function<EmitIndirectStubsId,
+ std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>(
+ ResourceIdMgr::ResourceId StubsOwnerID,
+ uint32_t NumStubsRequired)>
+ EmitIndirectStubs;
- class EmitResolverBlock : public rpc::Function<EmitResolverBlock, void()> {
- public:
- static const char* getName() { return "EmitResolverBlock"; }
- };
+ typedef Function<EmitResolverBlockId, void()> EmitResolverBlock;
/// EmitTrampolineBlock result is (BlockAddr, NumTrampolines).
- class EmitTrampolineBlock
- : public rpc::Function<EmitTrampolineBlock,
- std::tuple<JITTargetAddress, uint32_t>()> {
- public:
- static const char* getName() { return "EmitTrampolineBlock"; }
- };
+ typedef Function<EmitTrampolineBlockId,
+ std::tuple<JITTargetAddress, uint32_t>()>
+ EmitTrampolineBlock;
- class GetSymbolAddress
- : public rpc::Function<GetSymbolAddress,
- JITTargetAddress(std::string SymbolName)> {
- public:
- static const char* getName() { return "GetSymbolAddress"; }
- };
+ typedef Function<GetSymbolAddressId, JITTargetAddress(std::string SymbolName)>
+ GetSymbolAddress;
/// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize,
/// IndirectStubsSize).
- class GetRemoteInfo
- : public rpc::Function<GetRemoteInfo,
- std::tuple<std::string, uint32_t, uint32_t,
- uint32_t, uint32_t>()> {
- public:
- static const char* getName() { return "GetRemoteInfo"; }
- };
+ typedef Function<GetRemoteInfoId, std::tuple<std::string, uint32_t, uint32_t,
+ uint32_t, uint32_t>()>
+ GetRemoteInfo;
- class ReadMem
- : public rpc::Function<ReadMem,
- std::vector<uint8_t>(JITTargetAddress Src,
- uint64_t Size)> {
- public:
- static const char* getName() { return "ReadMem"; }
- };
+ typedef Function<ReadMemId,
+ std::vector<char>(JITTargetAddress Src, uint64_t Size)>
+ ReadMem;
- class RegisterEHFrames
- : public rpc::Function<RegisterEHFrames,
- void(JITTargetAddress Addr, uint32_t Size)> {
- public:
- static const char* getName() { return "RegisterEHFrames"; }
- };
+ typedef Function<RegisterEHFramesId, void(JITTargetAddress Addr, uint32_t Size)>
+ RegisterEHFrames;
- class ReserveMem
- : public rpc::Function<ReserveMem,
- JITTargetAddress(ResourceIdMgr::ResourceId AllocID,
- uint64_t Size, uint32_t Align)> {
- public:
- static const char* getName() { return "ReserveMem"; }
- };
+ typedef Function<ReserveMemId,
+ JITTargetAddress(ResourceIdMgr::ResourceId AllocID,
+ uint64_t Size, uint32_t Align)>
+ ReserveMem;
- class RequestCompile
- : public rpc::Function<RequestCompile,
- JITTargetAddress(JITTargetAddress TrampolineAddr)> {
- public:
- static const char* getName() { return "RequestCompile"; }
- };
-
- class SetProtections
- : public rpc::Function<SetProtections,
- void(ResourceIdMgr::ResourceId AllocID,
- JITTargetAddress Dst,
- uint32_t ProtFlags)> {
- public:
- static const char* getName() { return "SetProtections"; }
- };
+ typedef Function<RequestCompileId,
+ JITTargetAddress(JITTargetAddress TrampolineAddr)>
+ RequestCompile;
- class TerminateSession : public rpc::Function<TerminateSession, void()> {
- public:
- static const char* getName() { return "TerminateSession"; }
- };
+ typedef Function<SetProtectionsId,
+ void(ResourceIdMgr::ResourceId AllocID, JITTargetAddress Dst,
+ uint32_t ProtFlags)>
+ SetProtections;
- class WriteMem : public rpc::Function<WriteMem,
- void(remote::DirectBufferWriter DB)> {
- public:
- static const char* getName() { return "WriteMem"; }
- };
+ typedef Function<TerminateSessionId, void()> TerminateSession;
- class WritePtr
- : public rpc::Function<WritePtr,
- void(JITTargetAddress Dst, JITTargetAddress Val)> {
- public:
- static const char* getName() { return "WritePtr"; }
- };
+ typedef Function<WriteMemId, void(DirectBufferWriter DB)> WriteMem;
+ typedef Function<WritePtrId, void(JITTargetAddress Dst, JITTargetAddress Val)>
+ WritePtr;
};
} // end namespace remote
diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
index bda4cd15342..e3dfaf77566 100644
--- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
+++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
@@ -41,51 +41,94 @@ public:
OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup,
EHFrameRegistrationFtor EHFramesRegister,
EHFrameRegistrationFtor EHFramesDeregister)
- : OrcRemoteTargetRPCAPI(Channel), SymbolLookup(std::move(SymbolLookup)),
+ : Channel(Channel), SymbolLookup(std::move(SymbolLookup)),
EHFramesRegister(std::move(EHFramesRegister)),
- EHFramesDeregister(std::move(EHFramesDeregister)),
- TerminateFlag(false) {
-
- using ThisT = typename std::remove_reference<decltype(*this)>::type;
- addHandler<CallIntVoid>(*this, &ThisT::handleCallIntVoid);
- addHandler<CallMain>(*this, &ThisT::handleCallMain);
- addHandler<CallVoidVoid>(*this, &ThisT::handleCallVoidVoid);
- addHandler<CreateRemoteAllocator>(*this,
- &ThisT::handleCreateRemoteAllocator);
- addHandler<CreateIndirectStubsOwner>(*this,
- &ThisT::handleCreateIndirectStubsOwner);
- addHandler<DeregisterEHFrames>(*this, &ThisT::handleDeregisterEHFrames);
- addHandler<DestroyRemoteAllocator>(*this,
- &ThisT::handleDestroyRemoteAllocator);
- addHandler<DestroyIndirectStubsOwner>(*this,
- &ThisT::handleDestroyIndirectStubsOwner);
- addHandler<EmitIndirectStubs>(*this, &ThisT::handleEmitIndirectStubs);
- addHandler<EmitResolverBlock>(*this, &ThisT::handleEmitResolverBlock);
- addHandler<EmitTrampolineBlock>(*this, &ThisT::handleEmitTrampolineBlock);
- addHandler<GetSymbolAddress>(*this, &ThisT::handleGetSymbolAddress);
- addHandler<GetRemoteInfo>(*this, &ThisT::handleGetRemoteInfo);
- addHandler<ReadMem>(*this, &ThisT::handleReadMem);
- addHandler<RegisterEHFrames>(*this, &ThisT::handleRegisterEHFrames);
- addHandler<ReserveMem>(*this, &ThisT::handleReserveMem);
- addHandler<SetProtections>(*this, &ThisT::handleSetProtections);
- addHandler<TerminateSession>(*this, &ThisT::handleTerminateSession);
- addHandler<WriteMem>(*this, &ThisT::handleWriteMem);
- addHandler<WritePtr>(*this, &ThisT::handleWritePtr);
- }
+ EHFramesDeregister(std::move(EHFramesDeregister)) {}
// FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
OrcRemoteTargetServer(const OrcRemoteTargetServer &) = delete;
OrcRemoteTargetServer &operator=(const OrcRemoteTargetServer &) = delete;
- OrcRemoteTargetServer(OrcRemoteTargetServer &&Other) = default;
+ OrcRemoteTargetServer(OrcRemoteTargetServer &&Other)
+ : Channel(Other.Channel), SymbolLookup(std::move(Other.SymbolLookup)),
+ EHFramesRegister(std::move(Other.EHFramesRegister)),
+ EHFramesDeregister(std::move(Other.EHFramesDeregister)) {}
+
OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete;
+ Error handleKnownFunction(JITFuncId Id) {
+ typedef OrcRemoteTargetServer ThisT;
+
+ DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) << "\n");
+
+ switch (Id) {
+ case CallIntVoidId:
+ return handle<CallIntVoid>(Channel, *this, &ThisT::handleCallIntVoid);
+ case CallMainId:
+ return handle<CallMain>(Channel, *this, &ThisT::handleCallMain);
+ case CallVoidVoidId:
+ return handle<CallVoidVoid>(Channel, *this, &ThisT::handleCallVoidVoid);
+ case CreateRemoteAllocatorId:
+ return handle<CreateRemoteAllocator>(Channel, *this,
+ &ThisT::handleCreateRemoteAllocator);
+ case CreateIndirectStubsOwnerId:
+ return handle<CreateIndirectStubsOwner>(
+ Channel, *this, &ThisT::handleCreateIndirectStubsOwner);
+ case DeregisterEHFramesId:
+ return handle<DeregisterEHFrames>(Channel, *this,
+ &ThisT::handleDeregisterEHFrames);
+ case DestroyRemoteAllocatorId:
+ return handle<DestroyRemoteAllocator>(
+ Channel, *this, &ThisT::handleDestroyRemoteAllocator);
+ case DestroyIndirectStubsOwnerId:
+ return handle<DestroyIndirectStubsOwner>(
+ Channel, *this, &ThisT::handleDestroyIndirectStubsOwner);
+ case EmitIndirectStubsId:
+ return handle<EmitIndirectStubs>(Channel, *this,
+ &ThisT::handleEmitIndirectStubs);
+ case EmitResolverBlockId:
+ return handle<EmitResolverBlock>(Channel, *this,
+ &ThisT::handleEmitResolverBlock);
+ case EmitTrampolineBlockId:
+ return handle<EmitTrampolineBlock>(Channel, *this,
+ &ThisT::handleEmitTrampolineBlock);
+ case GetSymbolAddressId:
+ return handle<GetSymbolAddress>(Channel, *this,
+ &ThisT::handleGetSymbolAddress);
+ case GetRemoteInfoId:
+ return handle<GetRemoteInfo>(Channel, *this, &ThisT::handleGetRemoteInfo);
+ case ReadMemId:
+ return handle<ReadMem>(Channel, *this, &ThisT::handleReadMem);
+ case RegisterEHFramesId:
+ return handle<RegisterEHFrames>(Channel, *this,
+ &ThisT::handleRegisterEHFrames);
+ case ReserveMemId:
+ return handle<ReserveMem>(Channel, *this, &ThisT::handleReserveMem);
+ case SetProtectionsId:
+ return handle<SetProtections>(Channel, *this,
+ &ThisT::handleSetProtections);
+ case WriteMemId:
+ return handle<WriteMem>(Channel, *this, &ThisT::handleWriteMem);
+ case WritePtrId:
+ return handle<WritePtr>(Channel, *this, &ThisT::handleWritePtr);
+ default:
+ return orcError(OrcErrorCode::UnexpectedRPCCall);
+ }
+
+ llvm_unreachable("Unhandled JIT RPC procedure Id.");
+ }
Expected<JITTargetAddress> requestCompile(JITTargetAddress TrampolineAddr) {
- return callB<RequestCompile>(TrampolineAddr);
+ auto Listen = [&](RPCByteChannel &C, uint32_t Id) {
+ return handleKnownFunction(static_cast<JITFuncId>(Id));
+ };
+
+ return callSTHandling<RequestCompile>(Channel, Listen, TrampolineAddr);
}
- bool receivedTerminate() const { return TerminateFlag; }
+ Error handleTerminateSession() {
+ return handle<TerminateSession>(Channel, []() { return Error::success(); });
+ }
private:
struct Allocator {
@@ -322,16 +365,15 @@ private:
IndirectStubSize);
}
- Expected<std::vector<uint8_t>> handleReadMem(JITTargetAddress RSrc,
- uint64_t Size) {
- uint8_t *Src = reinterpret_cast<uint8_t*>(static_cast<uintptr_t>(RSrc));
+ Expected<std::vector<char>> handleReadMem(JITTargetAddress RSrc, uint64_t Size) {
+ char *Src = reinterpret_cast<char *>(static_cast<uintptr_t>(RSrc));
DEBUG(dbgs() << " Reading " << Size << " bytes from "
<< format("0x%016x", RSrc) << "\n");
- std::vector<uint8_t> Buffer;
+ std::vector<char> Buffer;
Buffer.resize(Size);
- for (uint8_t *P = Src; Size != 0; --Size)
+ for (char *P = Src; Size != 0; --Size)
Buffer.push_back(*P++);
return Buffer;
@@ -379,11 +421,6 @@ private:
return Allocator.setProtections(LocalAddr, Flags);
}
- Error handleTerminateSession() {
- TerminateFlag = true;
- return Error::success();
- }
-
Error handleWriteMem(DirectBufferWriter DBW) {
DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to "
<< format("0x%016x", DBW.getDst()) << "\n");
@@ -399,6 +436,7 @@ private:
return Error::success();
}
+ ChannelT &Channel;
SymbolLookupFtor SymbolLookup;
EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister;
std::map<ResourceIdMgr::ResourceId, Allocator> Allocators;
@@ -406,7 +444,6 @@ private:
std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList> IndirectStubsOwners;
sys::OwningMemoryBlock ResolverBlock;
std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
- bool TerminateFlag;
};
} // end namespace remote
diff --git a/include/llvm/ExecutionEngine/Orc/RPCByteChannel.h b/include/llvm/ExecutionEngine/Orc/RPCByteChannel.h
new file mode 100644
index 00000000000..c8cb42d5374
--- /dev/null
+++ b/include/llvm/ExecutionEngine/Orc/RPCByteChannel.h
@@ -0,0 +1,231 @@
+//===- llvm/ExecutionEngine/Orc/RPCByteChannel.h ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_RPCBYTECHANNEL_H
+#define LLVM_EXECUTIONENGINE_ORC_RPCBYTECHANNEL_H
+
+#include "OrcError.h"
+#include "RPCSerialization.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+#include <cstdint>
+#include <mutex>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <vector>
+
+namespace llvm {
+namespace orc {
+namespace remote {
+
+/// Interface for byte-streams to be used with RPC.
+class RPCByteChannel {
+public:
+ virtual ~RPCByteChannel() {}
+
+ /// Read Size bytes from the stream into *Dst.
+ virtual Error readBytes(char *Dst, unsigned Size) = 0;
+
+ /// Read size bytes from *Src and append them to the stream.
+ virtual Error appendBytes(const char *Src, unsigned Size) = 0;
+
+ /// Flush the stream if possible.
+ virtual Error send() = 0;
+
+ /// Get the lock for stream reading.
+ std::mutex &getReadLock() { return readLock; }
+
+ /// Get the lock for stream writing.
+ std::mutex &getWriteLock() { return writeLock; }
+
+private:
+ std::mutex readLock, writeLock;
+};
+
+/// Notify the channel that we're starting a message send.
+/// Locks the channel for writing.
+inline Error startSendMessage(RPCByteChannel &C) {
+ C.getWriteLock().lock();
+ return Error::success();
+}
+
+/// Notify the channel that we're ending a message send.
+/// Unlocks the channel for writing.
+inline Error endSendMessage(RPCByteChannel &C) {
+ C.getWriteLock().unlock();
+ return Error::success();
+}
+
+/// Notify the channel that we're starting a message receive.
+/// Locks the channel for reading.
+inline Error startReceiveMessage(RPCByteChannel &C) {
+ C.getReadLock().lock();
+ return Error::success();
+}
+
+/// Notify the channel that we're ending a message receive.
+/// Unlocks the channel for reading.
+inline Error endReceiveMessage(RPCByteChannel &C) {
+ C.getReadLock().unlock();
+ return Error::success();
+}
+
+template <typename ChannelT, typename T,
+ typename =
+ typename std::enable_if<
+ std::is_base_of<RPCByteChannel, ChannelT>::value>::
+ type>
+class RPCByteChannelPrimitiveSerialization {
+public:
+ static Error serialize(ChannelT &C, T V) {
+ support::endian::byte_swap<T, support::big>(V);
+ return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T));
+ };
+
+ static Error deserialize(ChannelT &C, T &V) {
+ if (auto Err = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T)))
+ return Err;
+ support::endian::byte_swap<T, support::big>(V);
+ return Error::success();
+ };
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, uint64_t>
+ : public RPCByteChannelPrimitiveSerialization<ChannelT, uint64_t> {
+public:
+ static const char* getName() { return "uint64_t"; }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, int64_t>
+ : public RPCByteChannelPrimitiveSerialization<ChannelT, int64_t> {
+public:
+ static const char* getName() { return "int64_t"; }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, uint32_t>
+ : public RPCByteChannelPrimitiveSerialization<ChannelT, uint32_t> {
+public:
+ static const char* getName() { return "uint32_t"; }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, int32_t>
+ : public RPCByteChannelPrimitiveSerialization<ChannelT, int32_t> {
+public:
+ static const char* getName() { return "int32_t"; }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, uint16_t>
+ : public RPCByteChannelPrimitiveSerialization<ChannelT, uint16_t> {
+public:
+ static const char* getName() { return "uint16_t"; }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, int16_t>
+ : public RPCByteChannelPrimitiveSerialization<ChannelT, int16_t> {
+public:
+ static const char* getName() { return "int16_t"; }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, uint8_t>
+ : public RPCByteChannelPrimitiveSerialization<ChannelT, uint8_t> {
+public:
+ static const char* getName() { return "uint8_t"; }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, int8_t>
+ : public RPCByteChannelPrimitiveSerialization<ChannelT, int8_t> {
+public:
+ static const char* getName() { return "int8_t"; }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, char>
+ : public RPCByteChannelPrimitiveSerialization<ChannelT, uint8_t> {
+public:
+ static const char* getName() { return "char"; }
+
+ static Error serialize(RPCByteChannel &C, char V) {
+ return serializeSeq(C, static_cast<uint8_t>(V));
+ };
+
+ static Error deserialize(RPCByteChannel &C, char &V) {
+ uint8_t VV;
+ if (auto Err = deserializeSeq(C, VV))
+ return Err;
+ V = static_cast<char>(V);
+ return Error::success();
+ };
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, bool,
+ typename std::enable_if<
+ std::is_base_of<RPCByteChannel, ChannelT>::value>::
+ type> {
+public:
+ static const char* getName() { return "bool"; }
+
+ static Error serialize(ChannelT &C, bool V) {
+ return C.appendBytes(reinterpret_cast<const char *>(&V), 1);
+ }
+
+ static Error deserialize(ChannelT &C, bool &V) {
+ return C.readBytes(reinterpret_cast<char *>(&V), 1);
+ }
+};
+
+template <typename ChannelT>
+class SerializationTraits<ChannelT, std::string,
+ typename std::enable_if<
+ std::is_base_of<RPCByteChannel, ChannelT>::value>::
+ type> {
+public:
+ static const char* getName() { return "std::string"; }
+
+ static Error serialize(RPCByteChannel &C, StringRef S) {
+ if (auto Err = SerializationTraits<RPCByteChannel, uint64_t>::
+ serialize(C, static_cast<uint64_t>(S.size())))
+ return Err;
+ return C.appendBytes((const char *)S.bytes_begin(), S.size());
+ }
+
+ /// RPC channel serialization for std::strings.
+ static Error serialize(RPCByteChannel &C, const std::string &S) {
+ return serialize(C, StringRef(S));
+ }
+
+ /// RPC channel deserialization for std::strings.
+ static Error deserialize(RPCByteChannel &C, std::string &S) {
+ uint64_t Count = 0;
+ if (auto Err = SerializationTraits<RPCByteChannel, uint64_t>::
+ deserialize(C, Count))
+ return Err;
+ S.resize(Count);
+ return C.readBytes(&S[0], Count);
+ }
+};
+
+} // end namespace remote
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_RPCBYTECHANNEL_H
diff --git a/include/llvm/ExecutionEngine/Orc/RPCSerialization.h b/include/llvm/ExecutionEngine/Orc/RPCSerialization.h
index d1503e91b4f..0e9f5157f29 100644
--- a/include/llvm/ExecutionEngine/Orc/RPCSerialization.h
+++ b/include/llvm/ExecutionEngine/Orc/RPCSerialization.h
@@ -17,164 +17,7 @@
namespace llvm {
namespace orc {
-namespace rpc {
-
-template <typename T>
-class RPCTypeName;
-
-/// TypeNameSequence is a utility for rendering sequences of types to a string
-/// by rendering each type, separated by ", ".
-template <typename... ArgTs> class RPCTypeNameSequence {};
-
-/// Render an empty TypeNameSequence to an ostream.
-template <typename OStream>
-OStream &operator<<(OStream &OS, const RPCTypeNameSequence<> &V) {
- return OS;
-}
-
-/// Render a TypeNameSequence of a single type to an ostream.
-template <typename OStream, typename ArgT>
-OStream &operator<<(OStream &OS, const RPCTypeNameSequence<ArgT> &V) {
- OS << RPCTypeName<ArgT>::getName();
- return OS;
-}
-
-/// Render a TypeNameSequence of more than one type to an ostream.
-template <typename OStream, typename ArgT1, typename ArgT2, typename... ArgTs>
-OStream&
-operator<<(OStream &OS, const RPCTypeNameSequence<ArgT1, ArgT2, ArgTs...> &V) {
- OS << RPCTypeName<ArgT1>::getName() << ", "
- << RPCTypeNameSequence<ArgT2, ArgTs...>();
- return OS;
-}
-
-template <>
-class RPCTypeName<void> {
-public:
- static const char* getName() { return "void"; }
-};
-
-template <>
-class RPCTypeName<int8_t> {
-public:
- static const char* getName() { return "int8_t"; }
-};
-
-template <>
-class RPCTypeName<uint8_t> {
-public:
- static const char* getName() { return "uint8_t"; }
-};
-
-template <>
-class RPCTypeName<int16_t> {
-public:
- static const char* getName() { return "int16_t"; }
-};
-
-template <>
-class RPCTypeName<uint16_t> {
-public:
- static const char* getName() { return "uint16_t"; }
-};
-
-template <>
-class RPCTypeName<int32_t> {
-public:
- static const char* getName() { return "int32_t"; }
-};
-
-template <>
-class RPCTypeName<uint32_t> {
-public:
- static const char* getName() { return "uint32_t"; }
-};
-
-template <>
-class RPCTypeName<int64_t> {
-public:
- static const char* getName() { return "int64_t"; }
-};
-
-template <>
-class RPCTypeName<uint64_t> {
-public:
- static const char* getName() { return "uint64_t"; }
-};
-
-template <>
-class RPCTypeName<bool> {
-public:
- static const char* getName() { return "bool"; }
-};
-
-template <>
-class RPCTypeName<std::string> {
-public:
- static const char* getName() { return "std::string"; }
-};
-
-template <typename T1, typename T2>
-class RPCTypeName<std::pair<T1, T2>> {
-public:
- static const char* getName() {
- std::lock_guard<std::mutex> Lock(NameMutex);
- if (Name.empty())
- raw_string_ostream(Name) << "std::pair<" << RPCTypeNameSequence<T1, T2>()
- << ">";
- return Name.data();
- }
-private:
- static std::mutex NameMutex;
- static std::string Name;
-};
-
-template <typename T1, typename T2>
-std::mutex RPCTypeName<std::pair<T1, T2>>::NameMutex;
-template <typename T1, typename T2>
-std::string RPCTypeName<std::pair<T1, T2>>::Name;
-
-template <typename... ArgTs>
-class RPCTypeName<std::tuple<ArgTs...>> {
-public:
- static const char* getName() {
- std::lock_guard<std::mutex> Lock(NameMutex);
- if (Name.empty())
- raw_string_ostream(Name) << "std::tuple<"
- << RPCTypeNameSequence<ArgTs...>() << ">";
- return Name.data();
- }
-private:
- static std::mutex NameMutex;
- static std::string Name;
-};
-
-template <typename... ArgTs>
-std::mutex RPCTypeName<std::tuple<ArgTs...>>::NameMutex;
-template <typename... ArgTs>
-std::string RPCTypeName<std::tuple<ArgTs...>>::Name;
-
-template <typename T>
-class RPCTypeName<std::vector<T>> {
-public:
- static const char*getName() {
- std::lock_guard<std::mutex> Lock(NameMutex);
- if (Name.empty())
- raw_string_ostream(Name) << "std::vector<" << RPCTypeName<T>::getName()
- << ">";
- return Name.data();
- }
-
-private:
- static std::mutex NameMutex;
- static std::string Name;
-};
-
-template <typename T>
-std::mutex RPCTypeName<std::vector<T>>::NameMutex;
-template <typename T>
-std::string RPCTypeName<std::vector<T>>::Name;
-
+namespace remote {
/// The SerializationTraits<ChannelT, T> class describes how to serialize and
/// deserialize an instance of type T to/from an abstract channel of type
@@ -208,92 +51,71 @@ std::string RPCTypeName<std::vector<T>>::Name;
/// }
///
/// @endcode
-template <typename ChannelT, typename WireType, typename From = WireType,
- typename = void>
+template <typename ChannelT, typename T, typename = void>
class SerializationTraits {};
-template <typename ChannelT>
-class SequenceTraits {
-public:
- static Error emitSeparator(ChannelT &C) { return Error::success(); }
- static Error consumeSeparator(ChannelT &C) { return Error::success(); }
-};
-
-/// Utility class for serializing sequences of values of varying types.
-/// Specializations of this class contain 'serialize' and 'deserialize' methods
-/// for the given channel. The ArgTs... list will determine the "over-the-wire"
-/// types to be serialized. The serialize and deserialize methods take a list
-/// CArgTs... ("caller arg types") which must be the same length as ArgTs...,
-/// but may be different types from ArgTs, provided that for each CArgT there
-/// is a SerializationTraits specialization
-/// SerializeTraits<ChannelT, ArgT, CArgT> with methods that can serialize the
-/// caller argument to over-the-wire value.
-template <typename ChannelT, typename... ArgTs>
-class SequenceSerialization;
-
-template <typename ChannelT>
-class SequenceSerialization<ChannelT> {
-public:
- static Error serialize(ChannelT &C) { return Error::success(); }
- static Error deserialize(ChannelT &C) { return Error::success(); }
-};
-
-template <typename ChannelT, typename ArgT>
-class SequenceSerialization<ChannelT, ArgT> {
-public:
-
- template <typename CArgT>
- static Error serialize(ChannelT &C, const CArgT &CArg) {
- return SerializationTraits<ChannelT, ArgT, CArgT>::serialize(C, CArg);
- }
+/// TypeNameSequence is a utility for rendering sequences of types to a string
+/// by rendering each type, separated by ", ".
+template <typename ChannelT, typename... ArgTs> class TypeNameSequence {};
- template <typename CArgT>
- static Error deserialize(ChannelT &C, CArgT &CArg) {
- return SerializationTraits<ChannelT, ArgT, CArgT>::deserialize(C, CArg);
- }
-};
+/// Render a TypeNameSequence of a single type to an ostream.
+template <typename OStream, typename ChannelT, typename ArgT>
+OStream &operator<<(OStream &OS, const TypeNameSequence<ChannelT, ArgT> &V) {
+ OS << SerializationTraits<ChannelT, ArgT>::getName();
+ return OS;
+}
-template <typename ChannelT, typename ArgT, typename... ArgTs>
-class SequenceSerialization<ChannelT, ArgT, ArgTs...> {
-public:
+/// Render a TypeNameSequence of more than one type to an ostream.
+template <typename OStream, typename ChannelT, typename ArgT1, typename ArgT2,
+ typename... ArgTs>
+OStream &
+operator<<(OStream &OS,
+ const TypeNameSequence<ChannelT, ArgT1, ArgT2, ArgTs...> &V) {
+ OS << SerializationTraits<ChannelT, ArgT1>::getName() << ", "
+ << TypeNameSequence<ChannelT, ArgT2, ArgTs...>();
+ return OS;
+}
- template <typename CArgT, typename... CArgTs>
- static Error serialize(ChannelT &C, const CArgT &CArg,
- const CArgTs&... CArgs) {
- if (auto Err =
- SerializationTraits<ChannelT, ArgT, CArgT>::serialize(C, CArg))
- return Err;
- if (auto Err = SequenceTraits<ChannelT>::emitSeparator(C))
- return Err;
- return SequenceSerialization<ChannelT, ArgTs...>::serialize(C, CArgs...);
- }
+/// RPC channel serialization for a variadic list of arguments.
+template <typename ChannelT, typename T, typename... Ts>
+Error serializeSeq(ChannelT &C, const T &Arg, const Ts &... Args) {
+ if (auto Err = SerializationTraits<ChannelT, T>::serialize(C, Arg))
+ return Err;
+ return serializeSeq(C, Args...);
+}
- template <typename CArgT, typename... CArgTs>
- static Error deserialize(ChannelT &C, CArgT &CArg,
- CArgTs&... CArgs) {
- if (auto Err =
- SerializationTraits<ChannelT, ArgT, CArgT>::deserialize(C, CArg))
- return Err;
- if (auto Err = SequenceTraits<ChannelT>::consumeSeparator(C))
- return Err;
- return SequenceSerialization<ChannelT, ArgTs...>::deserialize(C, CArgs...);
- }
-};
+/// RPC channel serialization for an (empty) variadic list of arguments.
+template <typename ChannelT> Error serializeSeq(ChannelT &C) {
+ return Error::success();
+}
-template <typename ChannelT, typename... ArgTs>
-Error serializeSeq(ChannelT &C, const ArgTs &... Args) {
- return SequenceSerialization<ChannelT, ArgTs...>::serialize(C, Args...);
+/// RPC channel deserialization for a variadic list of arguments.
+template <typename ChannelT, typename T, typename... Ts>
+Error deserializeSeq(ChannelT &C, T &Arg, Ts &... Args) {
+ if (auto Err = SerializationTraits<ChannelT, T>::deserialize(C, Arg))
+ return Err;
+ return deserializeSeq(C, Args...);
}
-template <typename ChannelT, typename... ArgTs>
-Error deserializeSeq(ChannelT &C, ArgTs &... Args) {
- return SequenceSerialization<ChannelT, ArgTs...>::deserialize(C, Args...);
+/// RPC channel serialization for an (empty) variadic list of arguments.
+template <typename ChannelT> Error deserializeSeq(ChannelT &C) {
+ return Error::success();
}
/// SerializationTraits default specialization for std::pair.
template <typename ChannelT, typename T1, typename T2>
class SerializationTraits<ChannelT, std::pair<T1, T2>> {
public:
+ static const char *getName() {
+ std::lock_guard<std::mutex> Lock(NameMutex);
+ if (Name.empty())
+ Name = (std::ostringstream()
+ << "std::pair<" << TypeNameSequence<ChannelT, T1, T2>() << ">")
+ .str();
+
+ return Name.data();
+ }
+
static Error serialize(ChannelT &C, const std::pair<T1, T2> &V) {
return serializeSeq(C, V.first, V.second);
}
@@ -301,12 +123,31 @@ public:
static Error deserialize(ChannelT &C, std::pair<T1, T2> &V) {
return deserializeSeq(C, V.first, V.second);
}
+
+private:
+ static std::mutex NameMutex;
+ static std::string Name;
};
+template <typename ChannelT, typename T1, typename T2>
+std::mutex SerializationTraits<ChannelT, std::pair<T1, T2>>::NameMutex;
+
+template <typename ChannelT, typename T1, typename T2>
+std::string SerializationTraits<ChannelT, std::pair<T1, T2>>::Name;
+
/// SerializationTraits default specialization for std::tuple.
template <typename ChannelT, typename... ArgTs>
class SerializationTraits<ChannelT, std::tuple<ArgTs...>> {
public:
+ static const char *getName() {
+ std::lock_guard<std::mutex> Lock(NameMutex);
+ if (Name.empty())
+ Name = (std::ostringstream()
+ << "std::tuple<" << TypeNameSequence<ChannelT, ArgTs...>() << ">")
+ .str();
+
+ return Name.data();
+ }
/// RPC channel serialization for std::tuple.
static Error serialize(ChannelT &C, const std::tuple<ArgTs...> &V) {
@@ -332,41 +173,68 @@ private:
llvm::index_sequence<Is...> _) {
return deserializeSeq(C, std::get<Is>(V)...);
}
+
+ static std::mutex NameMutex;
+ static std::string Name;
};
+template <typename ChannelT, typename... ArgTs>
+std::mutex SerializationTraits<ChannelT, std::tuple<ArgTs...>>::NameMutex;
+
+template <typename ChannelT, typename... ArgTs>
+std::string SerializationTraits<ChannelT, std::tuple<ArgTs...>>::Name;
+
/// SerializationTraits default specialization for std::vector.
template <typename ChannelT, typename T>
class SerializationTraits<ChannelT, std::vector<T>> {
public:
+ static const char *getName() {
+ std::lock_guard<std::mutex> Lock(NameMutex);
+ if (Name.empty())
+ Name = (std::ostringstream() << "std::vector<"
+ << TypeNameSequence<ChannelT, T>() << ">")
+ .str();
+ return Name.data();
+ }
- /// Serialize a std::vector<T> from std::vector<T>.
static Error serialize(ChannelT &C, const std::vector<T> &V) {
- if (auto Err = serializeSeq(C, static_cast<uint64_t>(V.size())))
+ if (auto Err = SerializationTraits<ChannelT, uint64_t>::serialize(
+ C, static_cast<uint64_t>(V.size())))
return Err;
for (const auto &E : V)
- if (auto Err = serializeSeq(C, E))
+ if (auto Err = SerializationTraits<ChannelT, T>::serialize(C, E))
return Err;
return Error::success();
}
- /// Deserialize a std::vector<T> to a std::vector<T>.
static Error deserialize(ChannelT &C, std::vector<T> &V) {
uint64_t Count = 0;
- if (auto Err = deserializeSeq(C, Count))
+ if (auto Err =
+ SerializationTraits<ChannelT, uint64_t>::deserialize(C, Count))
return Err;
V.resize(Count);
for (auto &E : V)
- if (auto Err = deserializeSeq(C, E))
+ if (auto Err = SerializationTraits<ChannelT, T>::deserialize(C, E))
return Err;
return Error::success();
}
+
+private:
+ static std::mutex NameMutex;
+ static std::string Name;
};
-} // end namespace rpc
+template <typename ChannelT, typename T>
+std::mutex SerializationTraits<ChannelT, std::vector<T>>::NameMutex;
+
+template <typename ChannelT, typename T>
+std::string SerializationTraits<ChannelT, std::vector<T>>::Name;
+
+} // end namespace remote
} // end namespace orc
} // end namespace llvm
diff --git a/include/llvm/ExecutionEngine/Orc/RPCUtils.h b/include/llvm/ExecutionEngine/Orc/RPCUtils.h
index a38d56b4c7d..436c037e920 100644
--- a/include/llvm/ExecutionEngine/Orc/RPCUtils.h
+++ b/include/llvm/ExecutionEngine/Orc/RPCUtils.h
@@ -1,4 +1,4 @@
-//===------- RPCUTils.h - Utilities for building RPC APIs -------*- C++ -*-===//
+//===----- RPCUTils.h - Basic tilities for building RPC APIs ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,11 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// Utilities to support construction of simple RPC APIs.
-//
-// The RPC utilities aim for ease of use (minimal conceptual overhead) for C++
-// programmers, high performance, low memory overhead, and efficient use of the
-// communications channel.
+// Basic utilities for building RPC APIs.
//
//===----------------------------------------------------------------------===//
@@ -19,12 +15,10 @@
#define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
#include <map>
-#include <thread>
#include <vector>
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/Orc/OrcError.h"
-#include "llvm/ExecutionEngine/Orc/RPCSerialization.h"
#ifdef _MSC_VER
// concrt.h depends on eh.h for __uncaught_exception declaration
@@ -45,92 +39,32 @@
namespace llvm {
namespace orc {
-namespace rpc {
-
-template <typename DerivedFunc, typename FnT>
-class Function;
-
-// RPC Function class.
-// DerivedFunc should be a user defined class with a static 'getName()' method
-// returning a const char* representing the function's name.
-template <typename DerivedFunc, typename RetT, typename... ArgTs>
-class Function<DerivedFunc, RetT(ArgTs...)> {
-public:
-
- /// User defined function type.
- using Type = RetT(ArgTs...);
-
- /// Return type.
- using ReturnType = RetT;
-
- /// Returns the full function prototype as a string.
- static const char *getPrototype() {
- std::lock_guard<std::mutex> Lock(NameMutex);
- if (Name.empty())
- raw_string_ostream(Name)
- << RPCTypeName<RetT>::getName() << " " << DerivedFunc::getName()
- << "(" << llvm::orc::rpc::RPCTypeNameSequence<ArgTs...>() << ")";
- return Name.data();
- }
-private:
- static std::mutex NameMutex;
- static std::string Name;
-};
-
-
-template <typename DerivedFunc, typename RetT, typename... ArgTs>
-std::mutex Function<DerivedFunc, RetT(ArgTs...)>::NameMutex;
+namespace remote {
-template <typename DerivedFunc, typename RetT, typename... ArgTs>
-std::string Function<DerivedFunc, RetT(ArgTs...)>::Name;
-
-/// Allocates RPC function ids during autonegotiation.
-/// Specializations of this class must provide four members:
-///
-/// static T getInvalidId():
-/// Should return a reserved id that will be used to represent missing
-/// functions during autonegotiation.
-///
-/// static T getResponseId():
-/// Should return a reserved id that will be used to send function responses
-/// (return values).
+/// Describes reserved RPC Function Ids.
///
-/// static T getNegotiateId():
-/// Should return a reserved id for the negotiate function, which will be used
-/// to negotiate ids for user defined functions.
-///
-/// template <typename Func> T allocate():
-/// Allocate a unique id for function Func.
-template <typename T, typename = void>
-class RPCFunctionIdAllocator;
-
-/// This specialization of RPCFunctionIdAllocator provides a default
-/// implementation for integral types.
-template <typename T>
-class RPCFunctionIdAllocator<T,
- typename std::enable_if<
- std::is_integral<T>::value
- >::type> {
-public:
-
- static T getInvalidId() { return T(0); }
- static T getResponseId() { return T(1); }
- static T getNegotiateId() { return T(2); }
+/// The default implementation will serve for integer and enum function id
+/// types. If you want to use a custom type as your FunctionId you can
+/// specialize this class and provide unique values for InvalidId,
+/// ResponseId and FirstValidId.
- template <typename Func>
- T allocate(){ return NextId++; }
-private:
- T NextId = 3;
+template <typename T> class RPCFunctionIdTraits {
+public:
+ static const T InvalidId = static_cast<T>(0);
+ static const T ResponseId = static_cast<T>(1);
+ static const T FirstValidId = static_cast<T>(2);
};
-namespace detail {
+// Base class containing utilities that require partial specialization.
+// These cannot be included in RPC, as template class members cannot be
+// partially specialized.
+class RPCBase {
+protected:
-// FIXME: Remove MSVCPError/MSVCPExpected once MSVC's future implementation
-// supports classes without default constructors.
+ // FIXME: Remove MSVCPError/MSVCPExpected once MSVC's future implementation
+ // supports classes without default constructors.
#ifdef _MSC_VER
-namespace msvc_hacks {
-
// Work around MSVC's future implementation's use of default constructors:
// A default constructed value in the promise will be overwritten when the
// real error is set - so the default constructed Error has to be checked
@@ -152,7 +86,7 @@ namespace msvc_hacks {
MSVCPError(Error Err) : Error(std::move(Err)) {}
};
- // Work around MSVC's future implementation, similar to MSVCPError.
+ // Likewise for Expected:
template <typename T>
class MSVCPExpected : public Expected<T> {
public:
@@ -189,524 +123,488 @@ namespace msvc_hacks {
nullptr) : Expected<T>(std::move(Other)) {}
};
-} // end namespace msvc_hacks
-
#endif // _MSC_VER
-// ResultTraits provides typedefs and utilities specific to the return type
-// of functions.
-template <typename RetT>
-class ResultTraits {
-public:
-
- // The return type wrapped in llvm::Expected.
- using ErrorReturnType = Expected<RetT>;
-
-#ifdef _MSC_VER
- // The ErrorReturnType wrapped in a std::promise.
- using ReturnPromiseType = std::promise<msvc_hacks::MSVCPExpected<RetT>>;
-
- // The ErrorReturnType wrapped in a std::future.
- using ReturnFutureType = std::future<msvc_hacks::MSVCPExpected<RetT>>;
-#else
- // The ErrorReturnType wrapped in a std::promise.
- using ReturnPromiseType = std::promise<ErrorReturnType>;
-
- // The ErrorReturnType wrapped in a std::future.
- using ReturnFutureType = std::future<ErrorReturnType>;
-#endif
-
- // Create a 'blank' value of the ErrorReturnType, ready and safe to
- // overwrite.
- static ErrorReturnType createBlankErrorReturnValue() {
- return ErrorReturnType(RetT());
- }
-
- // Consume an abandoned ErrorReturnType.
- static void consumeAbandoned(ErrorReturnType RetOrErr) {
- consumeError(RetOrErr.takeError());
- }
-};
+ // RPC Function description type.
+ //
+ // This class provides the information and operations needed to support the
+ // RPC primitive operations (call, expect, etc) for a given function. It
+ // is specialized for void and non-void functions to deal with the differences
+ // betwen the two. Both specializations have the same interface:
+ //
+ // Id - The function's unique identifier.
+ // ErrorReturn - The return type for blocking calls.
+ // readResult - Deserialize a result from a channel.
+ // abandon - Abandon a promised result.
+ // respond - Retun a result on the channel.
+ template <typename FunctionIdT, FunctionIdT FuncId, typename FnT>
+ class FunctionHelper {};
+
+ // RPC Function description specialization for non-void functions.
+ template <typename FunctionIdT, FunctionIdT FuncId, typename RetT,
+ typename... ArgTs>
+ class FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> {
+ public:
+ static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId &&
+ FuncId != RPCFunctionIdTraits<FunctionIdT>::ResponseId,
+ "Cannot define custom function with InvalidId or ResponseId. "
+ "Please use RPCFunctionTraits<FunctionIdT>::FirstValidId.");
-// ResultTraits specialization for void functions.
-template <>
-class ResultTraits<void> {
-public:
+ static const FunctionIdT Id = FuncId;
- // For void functions, ErrorReturnType is llvm::Error.
- using ErrorReturnType = Error;
+ typedef Expected<RetT> ErrorReturn;
+ // FIXME: Ditch PErrorReturn (replace it with plain ErrorReturn) once MSVC's
+ // std::future implementation supports types without default
+ // constructors.
#ifdef _MSC_VER
- // The ErrorReturnType wrapped in a std::promise.
- using ReturnPromiseType = std::promise<msvc_hacks::MSVCPError>;
-
- // The ErrorReturnType wrapped in a std::future.
- using ReturnFutureType = std::future<msvc_hacks::MSVCPError>;
+ typedef MSVCPExpected<RetT> PErrorReturn;
#else
- // The ErrorReturnType wrapped in a std::promise.
- using ReturnPromiseType = std::promise<ErrorReturnType>;
-
- // The ErrorReturnType wrapped in a std::future.
- using ReturnFutureType = std::future<ErrorReturnType>;
+ typedef Expected<RetT> PErrorReturn;
#endif
- // Create a 'blank' value of the ErrorReturnType, ready and safe to
- // overwrite.
- static ErrorReturnType createBlankErrorReturnValue() {
- return ErrorReturnType::success();
- }
-
- // Consume an abandoned ErrorReturnType.
- static void consumeAbandoned(ErrorReturnType Err) {
- consumeError(std::move(Err));
- }
-};
-
-// ResultTraits<Error> is equivalent to ResultTraits<void>. This allows
-// handlers for void RPC functions to return either void (in which case they
-// implicitly succeed) or Error (in which case their error return is
-// propagated). See usage in HandlerTraits::runHandlerHelper.
-template <>
-class ResultTraits<Error> : public ResultTraits<void> {};
-
-// ResultTraits<Expected<T>> is equivalent to ResultTraits<T>. This allows
-// handlers for RPC functions returning a T to return either a T (in which
-// case they implicitly succeed) or Expected<T> (in which case their error
-// return is propagated). See usage in HandlerTraits::runHandlerHelper.
-template <typename RetT>
-class ResultTraits<Expected<RetT>> : public ResultTraits<RetT> {};
-
-// Send a response of the given wire return type (WireRetT) over the
-// channel, with the given sequence number.
-template <typename WireRetT, typename HandlerRetT, typename ChannelT,
- typename FunctionIdT, typename SequenceNumberT>
-static Error respond(ChannelT &C, const FunctionIdT &ResponseId,
- SequenceNumberT SeqNo, Expected<HandlerRetT> ResultOrErr) {
- // If this was an error bail out.
- // FIXME: Send an "error" message to the client if this is not a channel
- // failure?
- if (auto Err = ResultOrErr.takeError())
- return Err;
-
- // Open the response message.
- if (auto Err = C.startSendMessage(ResponseId, SeqNo))
- return Err;
-
- // Serialize the result.
- if (auto Err = SerializationTraits<ChannelT, WireRetT, HandlerRetT>::
- serialize(C, *ResultOrErr))
- return Err;
-
- // Close the response message.
- return C.endSendMessage();
-}
-
-// Send an empty response message on the given channel to indicate that
-// the handler ran.
-template <typename WireRetT, typename ChannelT, typename FunctionIdT,
- typename SequenceNumberT>
-static Error respond(ChannelT &C, const FunctionIdT &ResponseId,
- SequenceNumberT SeqNo, Error Err) {
- if (Err)
- return Err;
- if (auto Err2 = C.startSendMessage(ResponseId, SeqNo))
- return Err2;
- return C.endSendMessage();
-}
-
-// This template class provides utilities related to RPC function handlers.
-// The base case applies to non-function types (the template class is
-// specialized for function types) and inherits from the appropriate
-// speciilization for the given non-function type's call operator.
-template <typename HandlerT>
-class HandlerTraits
- : public HandlerTraits<decltype(
- &std::remove_reference<HandlerT>::type::operator())> {};
-
-// Traits for handlers with a given function type.
-template <typename RetT, typename... ArgTs>
-class HandlerTraits<RetT(ArgTs...)> {
-public:
-
- // Function type of the handler.
- using Type = RetT(ArgTs...);
+ template <typename ChannelT>
+ static Error readResult(ChannelT &C, std::promise<PErrorReturn> &P) {
+ RetT Val;
+ auto Err = deserializeSeq(C, Val);
+ auto Err2 = endReceiveMessage(C);
+ Err = joinErrors(std::move(Err), std::move(Err2));
+ if (Err)
+ return Err;
- // Return type of the handler.
- using ReturnType = RetT;
+ P.set_value(std::move(Val));
+ return Error::success();
+ }
- // A std::tuple wrapping the handler arguments.
- using ArgStorage =
- std::tuple<
- typename std::decay<
- typename std::remove_reference<ArgTs>::type>::type...>;
+ static void abandon(std::promise<PErrorReturn> &P) {
+ P.set_value(
+ make_error<StringError>("RPC function call failed to return",
+ inconvertibleErrorCode()));
+ }
- // Call the given handler with the given arguments.
- template <typename HandlerT>
- static typename ResultTraits<RetT>::ErrorReturnType
- runHandler(HandlerT &Handler, ArgStorage &Args) {
- return runHandlerHelper<RetT>(Handler, Args,
- llvm::index_sequence_for<ArgTs...>());
- }
+ static void consumeAbandoned(std::future<PErrorReturn> &P) {
+ consumeError(P.get().takeError());
+ }
- // Serialize arguments to the channel.
- template <typename ChannelT, typename... CArgTs>
- static Error serializeArgs(ChannelT &C, const CArgTs... CArgs) {
- return SequenceSerialization<ChannelT, ArgTs...>::serialize(C, CArgs...);
- }
+ template <typename ChannelT, typename SequenceNumberT>
+ static Error respond(ChannelT &C, SequenceNumberT SeqNo,
+ ErrorReturn &Result) {
+ FunctionIdT ResponseId = RPCFunctionIdTraits<FunctionIdT>::ResponseId;
- // Deserialize arguments from the channel.
- template <typename ChannelT, typename... CArgTs>
- static Error deserializeArgs(ChannelT &C, std::tuple<CArgTs...> &Args) {
- return deserializeArgsHelper(C, Args,
- llvm::index_sequence_for<CArgTs...>());
- }
+ // If the handler returned an error then bail out with that.
+ if (!Result)
+ return Result.takeError();
-private:
-
- // For non-void user handlers: unwrap the args tuple and call the handler,
- // returning the result.
- template <typename RetTAlt, typename HandlerT, size_t... Indexes>
- static typename std::enable_if<
- !std::is_void<RetTAlt>::value,
- typename ResultTraits<RetT>::ErrorReturnType>::type
- runHandlerHelper(HandlerT &Handler, ArgStorage &Args,
- llvm::index_sequence<Indexes...>) {
- return Handler(std::move(std::get<Indexes>(Args))...);
- }
+ // Otherwise open a new message on the channel and send the result.
+ if (auto Err = startSendMessage(C))
+ return Err;
+ if (auto Err = serializeSeq(C, ResponseId, SeqNo, *Result))
+ return Err;
+ return endSendMessage(C);
+ }
+ };
- // For void user handlers: unwrap the args tuple and call the handler, then
- // return Error::success().
- template <typename RetTAlt, typename HandlerT, size_t... Indexes>
- static typename std::enable_if<
- std::is_void<RetTAlt>::value,
- typename ResultTraits<RetT>::ErrorReturnType>::type
- runHandlerHelper(HandlerT &Handler, ArgStorage &Args,
- llvm::index_sequence<Indexes...>) {
- Handler(std::move(std::get<Indexes>(Args))...);
- return ResultTraits<RetT>::ErrorReturnType::success();
- }
+ // RPC Function description specialization for void functions.
+ template <typename FunctionIdT, FunctionIdT FuncId, typename... ArgTs>
+ class FunctionHelper<FunctionIdT, FuncId, void(ArgTs...)> {
+ public:
+ static_assert(FuncId != RPCFunctionIdTraits<FunctionIdT>::InvalidId &&
+ FuncId != RPCFunctionIdTraits<FunctionIdT>::ResponseId,
+ "Cannot define custom function with InvalidId or ResponseId. "
+ "Please use RPCFunctionTraits<FunctionIdT>::FirstValidId.");
- template <typename ChannelT, typename... CArgTs, size_t... Indexes>
- static
- Error deserializeArgsHelper(ChannelT &C, std::tuple<CArgTs...> &Args,
- llvm::index_sequence<Indexes...> _) {
- return SequenceSerialization<ChannelT, ArgTs...>::
- deserialize(C, std::get<Indexes>(Args)...);
- }
+ static const FunctionIdT Id = FuncId;
-};
+ typedef Error ErrorReturn;
-// Handler traits for class methods (especially call operators for lambdas).
-template <typename Class, typename RetT, typename... ArgTs>
-class HandlerTraits<RetT (Class::*)(ArgTs...)>
- : public HandlerTraits<RetT(ArgTs...)> {};
-
-// Handler traits for const class methods (especially call operators for
-// lambdas).
-template <typename Class, typename RetT, typename... ArgTs>
-class HandlerTraits<RetT (Class::*)(ArgTs...) const>
- : public HandlerTraits<RetT(ArgTs...)> {};
+ // FIXME: Ditch PErrorReturn (replace it with plain ErrorReturn) once MSVC's
+ // std::future implementation supports types without default
+ // constructors.
+#ifdef _MSC_VER
+ typedef MSVCPError PErrorReturn;
+#else
+ typedef Error PErrorReturn;
+#endif
-// Utility to peel the Expected wrapper off a response handler error type.
-template <typename HandlerT>
-class UnwrapResponseHandlerArg;
+ template <typename ChannelT>
+ static Error readResult(ChannelT &C, std::promise<PErrorReturn> &P) {
+ // Void functions don't have anything to deserialize, so we're good.
+ P.set_value(Error::success());
+ return endReceiveMessage(C);
+ }
-template <typename ArgT>
-class UnwrapResponseHandlerArg<Error(Expected<ArgT>)> {
-public:
- using ArgType = ArgT;
-};
+ static void abandon(std::promise<PErrorReturn> &P) {
+ P.set_value(
+ make_error<StringError>("RPC function call failed to return",
+ inconvertibleErrorCode()));
+ }
-// ResponseHandler represents a handler for a not-yet-received function call
-// result.
-template <typename ChannelT>
-class ResponseHandler {
-public:
- virtual ~ResponseHandler() {}
+ static void consumeAbandoned(std::future<PErrorReturn> &P) {
+ consumeError(P.get());
+ }
- // Reads the function result off the wire and acts on it. The meaning of
- // "act" will depend on how this method is implemented in any given
- // ResponseHandler subclass but could, for example, mean running a
- // user-specified handler or setting a promise value.
- virtual Error handleResponse(ChannelT &C) = 0;
+ template <typename ChannelT, typename SequenceNumberT>
+ static Error respond(ChannelT &C, SequenceNumberT SeqNo,
+ ErrorReturn &Result) {
+ const FunctionIdT ResponseId =
+ RPCFunctionIdTraits<FunctionIdT>::ResponseId;
- // Abandons this outstanding result.
- virtual void abandon() = 0;
+ // If the handler returned an error then bail out with that.
+ if (Result)
+ return std::move(Result);
- // Create an error instance representing an abandoned response.
- static Error createAbandonedResponseError() {
- return make_error<StringError>("RPC function call failed to return",
- inconvertibleErrorCode());
- }
-};
+ // Otherwise open a new message on the channel and send the result.
+ if (auto Err = startSendMessage(C))
+ return Err;
+ if (auto Err = serializeSeq(C, ResponseId, SeqNo))
+ return Err;
+ return endSendMessage(C);
+ }
+ };
-// ResponseHandler subclass for RPC functions with non-void returns.
-template <typename ChannelT, typename FuncRetT, typename HandlerT>
-class ResponseHandlerImpl : public ResponseHandler<ChannelT> {
-public:
- ResponseHandlerImpl(HandlerT Handler)
- : Handler(std::move(Handler)) {}
-
- // Handle the result by deserializing it from the channel then passing it
- // to the user defined handler.
- Error handleResponse(ChannelT &C) override {
- using ArgType = typename UnwrapResponseHandlerArg<
- typename HandlerTraits<HandlerT>::Type>::ArgType;
- ArgType Result;
- if (auto Err = SerializationTraits<ChannelT, FuncRetT, ArgType>::
- deserialize(C, Result))
- return Err;
- if (auto Err = C.endReceiveMessage())
- return Err;
- return Handler(Result);
- }
+ // Helper for the call primitive.
+ template <typename ChannelT, typename SequenceNumberT, typename Func>
+ class CallHelper;
- // Abandon this response by calling the handler with an 'abandoned response'
- // error.
- void abandon() override {
- if (auto Err = Handler(this->createAbandonedResponseError())) {
- // Handlers should not fail when passed an abandoned response error.
- report_fatal_error(std::move(Err));
+ template <typename ChannelT, typename SequenceNumberT, typename FunctionIdT,
+ FunctionIdT FuncId, typename RetT, typename... ArgTs>
+ class CallHelper<ChannelT, SequenceNumberT,
+ FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)>> {
+ public:
+ static Error call(ChannelT &C, SequenceNumberT SeqNo,
+ const ArgTs &... Args) {
+ if (auto Err = startSendMessage(C))
+ return Err;
+ if (auto Err = serializeSeq(C, FuncId, SeqNo, Args...))
+ return Err;
+ return endSendMessage(C);
}
- }
-
-private:
- HandlerT Handler;
-};
+ };
-// ResponseHandler subclass for RPC functions with void returns.
-template <typename ChannelT, typename HandlerT>
-class ResponseHandlerImpl<ChannelT, void, HandlerT>
- : public ResponseHandler<ChannelT> {
-public:
- ResponseHandlerImpl(HandlerT Handler)
- : Handler(std::move(Handler)) {}
-
- // Handle the result (no actual value, just a notification that the function
- // has completed on the remote end) by calling the user-defined handler with
- // Error::success().
- Error handleResponse(ChannelT &C) override {
- if (auto Err = C.endReceiveMessage())
- return Err;
- return Handler(Error::success());
- }
+ // Helper for handle primitive.
+ template <typename ChannelT, typename SequenceNumberT, typename Func>
+ class HandlerHelper;
- // Abandon this response by calling the handler with an 'abandoned response'
- // error.
- void abandon() override {
- if (auto Err = Handler(this->createAbandonedResponseError())) {
- // Handlers should not fail when passed an abandoned response error.
- report_fatal_error(std::move(Err));
+ template <typename ChannelT, typename SequenceNumberT, typename FunctionIdT,
+ FunctionIdT FuncId, typename RetT, typename... ArgTs>
+ class HandlerHelper<ChannelT, SequenceNumberT,
+ FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)>> {
+ public:
+ template <typename HandlerT>
+ static Error handle(ChannelT &C, HandlerT Handler) {
+ return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs...>());
}
- }
-private:
- HandlerT Handler;
-};
+ private:
+ typedef FunctionHelper<FunctionIdT, FuncId, RetT(ArgTs...)> Func;
+
+ template <typename HandlerT, size_t... Is>
+ static Error readAndHandle(ChannelT &C, HandlerT Handler,
+ llvm::index_sequence<Is...> _) {
+ std::tuple<ArgTs...> RPCArgs;
+ SequenceNumberT SeqNo;
+ // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
+ // for RPCArgs. Void cast RPCArgs to work around this for now.
+ // FIXME: Remove this workaround once we can assume a working GCC version.
+ (void)RPCArgs;
+ if (auto Err = deserializeSeq(C, SeqNo, std::get<Is>(RPCArgs)...))
+ return Err;
-// Create a ResponseHandler from a given user handler.
-template <typename ChannelT, typename FuncRetT, typename HandlerT>
-std::unique_ptr<ResponseHandler<ChannelT>>
-createResponseHandler(HandlerT H) {
- return llvm::make_unique<
- ResponseHandlerImpl<ChannelT, FuncRetT, HandlerT>>(std::move(H));
-}
-
-// Helper for wrapping member functions up as functors. This is useful for
-// installing methods as result handlers.
-template <typename ClassT, typename RetT, typename... ArgTs>
-class MemberFnWrapper {
-public:
- using MethodT = RetT(ClassT::*)(ArgTs...);
- MemberFnWrapper(ClassT &Instance, MethodT Method)
- : Instance(Instance), Method(Method) {}
- RetT operator()(ArgTs &&... Args) {
- return (Instance.*Method)(std::move(Args)...);
- }
-private:
- ClassT &Instance;
- MethodT Method;
-};
+ // We've deserialized the arguments, so unlock the channel for reading
+ // before we call the handler. This allows recursive RPC calls.
+ if (auto Err = endReceiveMessage(C))
+ return Err;
-// Helper that provides a Functor for deserializing arguments.
-template <typename... ArgTs> class ReadArgs {
-public:
- Error operator()() { return Error::success(); }
-};
+ // Run the handler and get the result.
+ auto Result = Handler(std::get<Is>(RPCArgs)...);
-template <typename ArgT, typename... ArgTs>
-class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
-public:
- ReadArgs(ArgT &Arg, ArgTs &... Args)
- : ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
+ // Return the result to the client.
+ return Func::template respond<ChannelT, SequenceNumberT>(C, SeqNo,
+ Result);
+ }
+ };
- Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
- this->Arg = std::move(ArgVal);
- return ReadArgs<ArgTs...>::operator()(ArgVals...);
- }
-private:
- ArgT &Arg;
-};
+ // Helper for wrapping member functions up as functors.
+ template <typename ClassT, typename RetT, typename... ArgTs>
+ class MemberFnWrapper {
+ public:
+ typedef RetT (ClassT::*MethodT)(ArgTs...);
+ MemberFnWrapper(ClassT &Instance, MethodT Method)
+ : Instance(Instance), Method(Method) {}
+ RetT operator()(ArgTs &... Args) { return (Instance.*Method)(Args...); }
+
+ private:
+ ClassT &Instance;
+ MethodT Method;
+ };
-// Manage sequence numbers.
-template <typename SequenceNumberT>
-class SequenceNumberManager {
-public:
- // Reset, making all sequence numbers available.
- void reset() {
- std::lock_guard<std::mutex> Lock(SeqNoLock);
- NextSequenceNumber = 0;
- FreeSequenceNumbers.clear();
- }
+ // Helper that provides a Functor for deserializing arguments.
+ template <typename... ArgTs> class ReadArgs {
+ public:
+ Error operator()() { return Error::success(); }
+ };
- // Get the next available sequence number. Will re-use numbers that have
- // been released.
- SequenceNumberT getSequenceNumber() {
- std::lock_guard<std::mutex> Lock(SeqNoLock);
- if (FreeSequenceNumbers.empty())
- return NextSequenceNumber++;
- auto SequenceNumber = FreeSequenceNumbers.back();
- FreeSequenceNumbers.pop_back();
- return SequenceNumber;
- }
+ template <typename ArgT, typename... ArgTs>
+ class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
+ public:
+ ReadArgs(ArgT &Arg, ArgTs &... Args)
+ : ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
- // Release a sequence number, making it available for re-use.
- void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
- std::lock_guard<std::mutex> Lock(SeqNoLock);
- FreeSequenceNumbers.push_back(SequenceNumber);
- }
+ Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
+ this->Arg = std::move(ArgVal);
+ return ReadArgs<ArgTs...>::operator()(ArgVals...);
+ }
-private:
- std::mutex SeqNoLock;
- SequenceNumberT NextSequenceNumber = 0;
- std::vector<SequenceNumberT> FreeSequenceNumbers;
+ private:
+ ArgT &Arg;
+ };
};
/// Contains primitive utilities for defining, calling and handling calls to
/// remote procedures. ChannelT is a bidirectional stream conforming to the
-/// RPCChannel interface (see RPCChannel.h), FunctionIdT is a procedure
-/// identifier type that must be serializable on ChannelT, and SequenceNumberT
-/// is an integral type that will be used to number in-flight function calls.
+/// RPCChannel interface (see RPCChannel.h), and FunctionIdT is a procedure
+/// identifier type that must be serializable on ChannelT.
///
/// These utilities support the construction of very primitive RPC utilities.
/// Their intent is to ensure correct serialization and deserialization of
/// procedure arguments, and to keep the client and server's view of the API in
/// sync.
-template <typename ImplT, typename ChannelT, typename FunctionIdT,
- typename SequenceNumberT>
-class RPCBase {
-protected:
+///
+/// These utilities do not support return values. These can be handled by
+/// declaring a corresponding '.*Response' procedure and expecting it after a
+/// call). They also do not support versioning: the client and server *must* be
+/// compiled with the same procedure definitions.
+///
+///
+///
+/// Overview (see comments individual types/methods for details):
+///
+/// Function<Id, Args...> :
+///
+/// associates a unique serializable id with an argument list.
+///
+///
+/// call<Func>(Channel, Args...) :
+///
+/// Calls the remote procedure 'Func' by serializing Func's id followed by its
+/// arguments and sending the resulting bytes to 'Channel'.
+///
+///
+/// handle<Func>(Channel, <functor matching Error(Args...)> :
+///
+/// Handles a call to 'Func' by deserializing its arguments and calling the
+/// given functor. This assumes that the id for 'Func' has already been
+/// deserialized.
+///
+/// expect<Func>(Channel, <functor matching Error(Args...)> :
+///
+/// The same as 'handle', except that the procedure id should not have been
+/// read yet. Expect will deserialize the id and assert that it matches Func's
+/// id. If it does not, and unexpected RPC call error is returned.
+template <typename ChannelT, typename FunctionIdT = uint32_t,
+ typename SequenceNumberT = uint16_t>
+class RPC : public RPCBase {
+public:
+ /// RPC default constructor.
+ RPC() = default;
- class OrcRPCInvalid : public Function<OrcRPCInvalid, void()> {
- public:
- static const char *getName() { return "__orc_rpc$invalid"; }
- };
+ /// RPC instances cannot be copied.
+ RPC(RPC &&) = default;
+ RPC &operator=(RPC &&) = default;
- class OrcRPCResponse : public Function<OrcRPCResponse, void()> {
- public:
- static const char *getName() { return "__orc_rpc$response"; }
- };
+ /// Utility class for defining/referring to RPC procedures.
+ ///
+ /// Typedefs of this utility are used when calling/handling remote procedures.
+ ///
+ /// FuncId should be a unique value of FunctionIdT (i.e. not used with any
+ /// other Function typedef in the RPC API being defined.
+ ///
+ /// the template argument Ts... gives the argument list for the remote
+ /// procedure.
+ ///
+ /// E.g.
+ ///
+ /// typedef Function<0, bool> Func1;
+ /// typedef Function<1, std::string, std::vector<int>> Func2;
+ ///
+ /// if (auto Err = call<Func1>(Channel, true))
+ /// /* handle Err */;
+ ///
+ /// if (auto Err = expect<Func2>(Channel,
+ /// [](std::string &S, std::vector<int> &V) {
+ /// // Stuff.
+ /// return Error::success();
+ /// })
+ /// /* handle Err */;
+ ///
+ template <FunctionIdT FuncId, typename FnT>
+ using Function = FunctionHelper<FunctionIdT, FuncId, FnT>;
- class OrcRPCNegotiate
- : public Function<OrcRPCNegotiate, FunctionIdT(std::string)> {
- public:
- static const char *getName() { return "__orc_rpc$negotiate"; }
- };
+ /// Return type for non-blocking call primitives.
+ template <typename Func>
+ using NonBlockingCallResult = std::future<typename Func::PErrorReturn>;
-public:
+ /// Return type for non-blocking call-with-seq primitives.
+ template <typename Func>
+ using NonBlockingCallWithSeqResult =
+ std::pair<NonBlockingCallResult<Func>, SequenceNumberT>;
- /// Construct an RPC instance on a channel.
- RPCBase(ChannelT &C, bool LazyAutoNegotiation)
- : C(C), LazyAutoNegotiation(LazyAutoNegotiation) {
- // Hold ResponseId in a special variable, since we expect Response to be
- // called relatively frequently, and want to avoid the map lookup.
- ResponseId = FnIdAllocator.getResponseId();
- RemoteFunctionIds[OrcRPCResponse::getPrototype()] = ResponseId;
-
- // Register the negotiate function id and handler.
- auto NegotiateId = FnIdAllocator.getNegotiateId();
- RemoteFunctionIds[OrcRPCNegotiate::getPrototype()] = NegotiateId;
- Handlers[NegotiateId] =
- wrapHandler<OrcRPCNegotiate>([this](const std::string &Name) {
- return handleNegotiate(Name);
- }, LaunchPolicy());
+ /// Call Func on Channel C. Does not block, does not call send. Returns a pair
+ /// of a future result and the sequence number assigned to the result.
+ ///
+ /// This utility function is primarily used for single-threaded mode support,
+ /// where the sequence number can be used to wait for the corresponding
+ /// result. In multi-threaded mode the appendCallNB method, which does not
+ /// return the sequence numeber, should be preferred.
+ template <typename Func, typename... ArgTs>
+ Expected<NonBlockingCallWithSeqResult<Func>>
+ appendCallNBWithSeq(ChannelT &C, const ArgTs &... Args) {
+ auto SeqNo = SequenceNumberMgr.getSequenceNumber();
+ std::promise<typename Func::PErrorReturn> Promise;
+ auto Result = Promise.get_future();
+ OutstandingResults[SeqNo] =
+ createOutstandingResult<Func>(std::move(Promise));
+
+ if (auto Err = CallHelper<ChannelT, SequenceNumberT, Func>::call(C, SeqNo,
+ Args...)) {
+ abandonOutstandingResults();
+ Func::consumeAbandoned(Result);
+ return std::move(Err);
+ } else
+ return NonBlockingCallWithSeqResult<Func>(std::move(Result), SeqNo);
}
- /// Append a call Func, does not call send on the channel.
- /// The first argument specifies a user-defined handler to be run when the
- /// function returns. The handler should take an Expected<Func::ReturnType>,
- /// or an Error (if Func::ReturnType is void). The handler will be called
- /// with an error if the return value is abandoned due to a channel error.
- template <typename Func, typename HandlerT, typename... ArgTs>
- Error appendCallAsync(HandlerT Handler, const ArgTs &... Args) {
- // Look up the function ID.
- FunctionIdT FnId;
- if (auto FnIdOrErr = getRemoteFunctionId<Func>())
- FnId = *FnIdOrErr;
- else {
- // This isn't a channel error so we don't want to abandon other pending
- // responses, but we still need to run the user handler with an error to
- // let them know the call failed.
- if (auto Err = Handler(orcError(OrcErrorCode::UnknownRPCFunction)))
- report_fatal_error(std::move(Err));
- return FnIdOrErr.takeError();
+ /// The same as appendCallNBWithSeq, except that it calls C.send() to
+ /// flush the channel after serializing the call.
+ template <typename Func, typename... ArgTs>
+ Expected<NonBlockingCallWithSeqResult<Func>>
+ callNBWithSeq(ChannelT &C, const ArgTs &... Args) {
+ auto Result = appendCallNBWithSeq<Func>(C, Args...);
+ if (!Result)
+ return Result;
+ if (auto Err = C.send()) {
+ abandonOutstandingResults();
+ Func::consumeAbandoned(Result->first);
+ return std::move(Err);
}
+ return Result;
+ }
- // Allocate a sequence number.
- auto SeqNo = SequenceNumberMgr.getSequenceNumber();
- assert(!PendingResponses.count(SeqNo) &&
- "Sequence number already allocated");
-
- // Install the user handler.
- PendingResponses[SeqNo] =
- detail::createResponseHandler<ChannelT, typename Func::ReturnType>(
- std::move(Handler));
-
- // Open the function call message.
- if (auto Err = C.startSendMessage(FnId, SeqNo)) {
- abandonPendingResponses();
- return joinErrors(std::move(Err), C.endSendMessage());
- }
+ /// Serialize Args... to channel C, but do not call send.
+ /// Returns an error if serialization fails, otherwise returns a
+ /// std::future<Expected<T>> (or a future<Error> for void functions).
+ template <typename Func, typename... ArgTs>
+ Expected<NonBlockingCallResult<Func>> appendCallNB(ChannelT &C,
+ const ArgTs &... Args) {
+ auto FutureResAndSeqOrErr = appendCallNBWithSeq<Func>(C, Args...);
+ if (FutureResAndSeqOrErr)
+ return std::move(FutureResAndSeqOrErr->first);
+ return FutureResAndSeqOrErr.takeError();
+ }
- // Serialize the call arguments.
- if (auto Err =
- detail::HandlerTraits<typename Func::Type>::
- serializeArgs(C, Args...)) {
- abandonPendingResponses();
- return joinErrors(std::move(Err), C.endSendMessage());
- }
+ /// The same as appendCallNB, except that it calls C.send to flush the
+ /// channel after serializing the call.
+ template <typename Func, typename... ArgTs>
+ Expected<NonBlockingCallResult<Func>> callNB(ChannelT &C,
+ const ArgTs &... Args) {
+ auto FutureResAndSeqOrErr = callNBWithSeq<Func>(C, Args...);
+ if (FutureResAndSeqOrErr)
+ return std::move(FutureResAndSeqOrErr->first);
+ return FutureResAndSeqOrErr.takeError();
+ }
- // Close the function call messagee.
- if (auto Err = C.endSendMessage()) {
- abandonPendingResponses();
- return std::move(Err);
- }
+ /// Call Func on Channel C. Blocks waiting for a result. Returns an Error
+ /// for void functions or an Expected<T> for functions returning a T.
+ ///
+ /// This function is for use in threaded code where another thread is
+ /// handling responses and incoming calls.
+ template <typename Func, typename... ArgTs>
+ typename Func::ErrorReturn callB(ChannelT &C, const ArgTs &... Args) {
+ if (auto FutureResOrErr = callNBWithSeq<Func>(C, Args...)) {
+ if (auto Err = C.send()) {
+ abandonOutstandingResults();
+ Func::consumeAbandoned(FutureResOrErr->first);
+ return std::move(Err);
+ }
+ return FutureResOrErr->first.get();
+ } else
+ return FutureResOrErr.takeError();
+ }
- return Error::success();
+ /// Call Func on Channel C. Block waiting for a result. While blocked, run
+ /// HandleOther to handle incoming calls (Response calls will be handled
+ /// implicitly before calling HandleOther). Returns an Error for void
+ /// functions or an Expected<T> for functions returning a T.
+ ///
+ /// This function is for use in single threaded mode when the calling thread
+ /// must act as both sender and receiver.
+ template <typename Func, typename HandleFtor, typename... ArgTs>
+ typename Func::ErrorReturn
+ callSTHandling(ChannelT &C, HandleFtor &HandleOther, const ArgTs &... Args) {
+ if (auto ResultAndSeqNoOrErr = callNBWithSeq<Func>(C, Args...)) {
+ auto &ResultAndSeqNo = *ResultAndSeqNoOrErr;
+ if (auto Err = waitForResult(C, ResultAndSeqNo.second, HandleOther))
+ return std::move(Err);
+ return ResultAndSeqNo.first.get();
+ } else
+ return ResultAndSeqNoOrErr.takeError();
}
+ /// Call Func on Channel C. Block waiting for a result. Returns an Error for
+ /// void functions or an Expected<T> for functions returning a T.
+ template <typename Func, typename... ArgTs>
+ typename Func::ErrorReturn callST(ChannelT &C, const ArgTs &... Args) {
+ return callSTHandling<Func>(C, handleNone, Args...);
+ }
- template <typename Func, typename HandlerT, typename... ArgTs>
- Error callAsync(HandlerT Handler, const ArgTs &... Args) {
- if (auto Err = appendCallAsync<Func>(std::move(Handler), Args...))
+ /// Start receiving a new function call.
+ ///
+ /// Calls startReceiveMessage on the channel, then deserializes a FunctionId
+ /// into Id.
+ Error startReceivingFunction(ChannelT &C, FunctionIdT &Id) {
+ if (auto Err = startReceiveMessage(C))
return Err;
- return C.send();
+
+ return deserializeSeq(C, Id);
}
- /// Handle one incoming call.
- Error handleOne() {
- FunctionIdT FnId;
- SequenceNumberT SeqNo;
- if (auto Err = C.startReceiveMessage(FnId, SeqNo))
- return Err;
- if (FnId == ResponseId)
- return handleResponse(SeqNo);
- auto I = Handlers.find(FnId);
- if (I != Handlers.end())
- return I->second(C, SeqNo);
+ /// Deserialize args for Func from C and call Handler. The signature of
+ /// handler must conform to 'Error(Args...)' where Args... matches
+ /// the arguments used in the Func typedef.
+ template <typename Func, typename HandlerT>
+ static Error handle(ChannelT &C, HandlerT Handler) {
+ return HandlerHelper<ChannelT, SequenceNumberT, Func>::handle(C, Handler);
+ }
- // else: No handler found. Report error to client?
- return orcError(OrcErrorCode::UnexpectedRPCCall);
+ /// Helper version of 'handle' for calling member functions.
+ template <typename Func, typename ClassT, typename RetT, typename... ArgTs>
+ static Error handle(ChannelT &C, ClassT &Instance,
+ RetT (ClassT::*HandlerMethod)(ArgTs...)) {
+ return handle<Func>(
+ C, MemberFnWrapper<ClassT, RetT, ArgTs...>(Instance, HandlerMethod));
+ }
+
+ /// Deserialize a FunctionIdT from C and verify it matches the id for Func.
+ /// If the id does match, deserialize the arguments and call the handler
+ /// (similarly to handle).
+ /// If the id does not match, return an unexpect RPC call error and do not
+ /// deserialize any further bytes.
+ template <typename Func, typename HandlerT>
+ Error expect(ChannelT &C, HandlerT Handler) {
+ FunctionIdT FuncId;
+ if (auto Err = startReceivingFunction(C, FuncId))
+ return std::move(Err);
+ if (FuncId != Func::Id)
+ return orcError(OrcErrorCode::UnexpectedRPCCall);
+ return handle<Func>(C, Handler);
+ }
+
+ /// Helper version of expect for calling member functions.
+ template <typename Func, typename ClassT, typename... ArgTs>
+ static Error expect(ChannelT &C, ClassT &Instance,
+ Error (ClassT::*HandlerMethod)(ArgTs...)) {
+ return expect<Func>(
+ C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));
}
/// Helper for handling setter procedures - this method returns a functor that
@@ -723,417 +621,160 @@ public:
/// /* Handle Args */ ;
///
template <typename... ArgTs>
- static detail::ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
- return detail::ReadArgs<ArgTs...>(Args...);
+ static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
+ return ReadArgs<ArgTs...>(Args...);
}
-protected:
- // The LaunchPolicy type allows a launch policy to be specified when adding
- // a function handler. See addHandlerImpl.
- using LaunchPolicy = std::function<Error(std::function<Error()>)>;
-
- /// Add the given handler to the handler map and make it available for
- /// autonegotiation and execution.
- template <typename Func, typename HandlerT>
- void addHandlerImpl(HandlerT Handler, LaunchPolicy Launch) {
- FunctionIdT NewFnId = FnIdAllocator.template allocate<Func>();
- LocalFunctionIds[Func::getPrototype()] = NewFnId;
- Handlers[NewFnId] = wrapHandler<Func>(std::move(Handler),
- std::move(Launch));
- }
+ /// Read a response from Channel.
+ /// This should be called from the receive loop to retrieve results.
+ Error handleResponse(ChannelT &C, SequenceNumberT *SeqNoRet = nullptr) {
+ SequenceNumberT SeqNo;
+ if (auto Err = deserializeSeq(C, SeqNo)) {
+ abandonOutstandingResults();
+ return Err;
+ }
- // Abandon all outstanding results.
- void abandonPendingResponses() {
- for (auto &KV : PendingResponses)
- KV.second->abandon();
- PendingResponses.clear();
- SequenceNumberMgr.reset();
- }
+ if (SeqNoRet)
+ *SeqNoRet = SeqNo;
- Error handleResponse(SequenceNumberT SeqNo) {
- auto I = PendingResponses.find(SeqNo);
- if (I == PendingResponses.end()) {
- abandonPendingResponses();
+ auto I = OutstandingResults.find(SeqNo);
+ if (I == OutstandingResults.end()) {
+ abandonOutstandingResults();
return orcError(OrcErrorCode::UnexpectedRPCResponse);
}
- auto PRHandler = std::move(I->second);
- PendingResponses.erase(I);
- SequenceNumberMgr.releaseSequenceNumber(SeqNo);
-
- if (auto Err = PRHandler->handleResponse(C)) {
- abandonPendingResponses();
- SequenceNumberMgr.reset();
+ if (auto Err = I->second->readResult(C)) {
+ abandonOutstandingResults();
+ // FIXME: Release sequence numbers?
return Err;
}
- return Error::success();
- }
-
- FunctionIdT handleNegotiate(const std::string &Name) {
- auto I = LocalFunctionIds.find(Name);
- if (I == LocalFunctionIds.end())
- return FnIdAllocator.getInvalidId();
- return I->second;
- }
-
- // Find the remote FunctionId for the given function, which must be in the
- // RemoteFunctionIds map.
- template <typename Func>
- Expected<FunctionIdT> getRemoteFunctionId() {
- // Try to find the id for the given function.
- auto I = RemoteFunctionIds.find(Func::getPrototype());
-
- // If we have it in the map, return it.
- if (I != RemoteFunctionIds.end())
- return I->second;
-
- // Otherwise, if we have auto-negotiation enabled, try to negotiate it.
- if (LazyAutoNegotiation) {
- auto &Impl = static_cast<ImplT&>(*this);
- if (auto RemoteIdOrErr =
- Impl.template callB<OrcRPCNegotiate>(Func::getPrototype())) {
- auto &RemoteId = *RemoteIdOrErr;
-
- // If autonegotiation indicates that the remote end doesn't support this
- // function, return an unknown function error.
- if (RemoteId == FnIdAllocator.getInvalidId())
- return orcError(OrcErrorCode::UnknownRPCFunction);
-
- // Autonegotiation succeeded and returned a valid id. Update the map and
- // return the id.
- RemoteFunctionIds[Func::getPrototype()] = RemoteId;
- return RemoteId;
- } else {
- // Autonegotiation failed. Return the error.
- return RemoteIdOrErr.takeError();
- }
- }
+ OutstandingResults.erase(I);
+ SequenceNumberMgr.releaseSequenceNumber(SeqNo);
- // No key was available in the map and autonegotiation wasn't enabled.
- // Return an unknown function error.
- return orcError(OrcErrorCode::UnknownRPCFunction);
+ return Error::success();
}
- using WrappedHandlerFn = std::function<Error(ChannelT&, SequenceNumberT)>;
+ // Loop waiting for a result with the given sequence number.
+ // This can be used as a receive loop if the user doesn't have a default.
+ template <typename HandleOtherFtor>
+ Error waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo,
+ HandleOtherFtor &HandleOther = handleNone) {
+ bool GotTgtResult = false;
- // Wrap the given user handler in the necessary argument-deserialization code,
- // result-serialization code, and call to the launch policy (if present).
- template <typename Func, typename HandlerT>
- WrappedHandlerFn wrapHandler(HandlerT Handler, LaunchPolicy Launch) {
- return
- [this, Handler, Launch](ChannelT &Channel, SequenceNumberT SeqNo) -> Error {
- // Start by deserializing the arguments.
- auto Args =
- std::make_shared<typename detail::HandlerTraits<HandlerT>::ArgStorage>();
- if (auto Err = detail::HandlerTraits<typename Func::Type>::
- deserializeArgs(Channel, *Args))
- return Err;
-
- // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning
- // for RPCArgs. Void cast RPCArgs to work around this for now.
- // FIXME: Remove this workaround once we can assume a working GCC version.
- (void)Args;
-
- // End receieve message, unlocking the channel for reading.
- if (auto Err = Channel.endReceiveMessage())
+ while (!GotTgtResult) {
+ FunctionIdT Id = RPCFunctionIdTraits<FunctionIdT>::InvalidId;
+ if (auto Err = startReceivingFunction(C, Id))
+ return Err;
+ if (Id == RPCFunctionIdTraits<FunctionIdT>::ResponseId) {
+ SequenceNumberT SeqNo;
+ if (auto Err = handleResponse(C, &SeqNo))
return Err;
+ GotTgtResult = (SeqNo == TgtSeqNo);
+ } else if (auto Err = HandleOther(C, Id))
+ return Err;
+ }
- // Build the handler/responder.
- auto Responder =
- [this, Handler, Args, &Channel, SeqNo]() mutable -> Error {
- using HTraits = detail::HandlerTraits<HandlerT>;
- using FuncReturn = typename Func::ReturnType;
- return detail::respond<FuncReturn>(Channel, ResponseId, SeqNo,
- HTraits::runHandler(Handler,
- *Args));
- };
-
- // If there is an explicit launch policy then use it to launch the
- // handler.
- if (Launch)
- return Launch(std::move(Responder));
-
- // Otherwise run the handler on the listener thread.
- return Responder();
- };
+ return Error::success();
}
- ChannelT &C;
-
- bool LazyAutoNegotiation;
-
- RPCFunctionIdAllocator<FunctionIdT> FnIdAllocator;
-
- FunctionIdT ResponseId;
- std::map<std::string, FunctionIdT> LocalFunctionIds;
- std::map<const char*, FunctionIdT> RemoteFunctionIds;
-
- std::map<FunctionIdT, WrappedHandlerFn> Handlers;
-
- detail::SequenceNumberManager<SequenceNumberT> SequenceNumberMgr;
- std::map<SequenceNumberT, std::unique_ptr<detail::ResponseHandler<ChannelT>>>
- PendingResponses;
-};
-
-} // end namespace detail
-
+ // Default handler for 'other' (non-response) functions when waiting for a
+ // result from the channel.
+ static Error handleNone(ChannelT &, FunctionIdT) {
+ return orcError(OrcErrorCode::UnexpectedRPCCall);
+ };
-template <typename ChannelT,
- typename FunctionIdT = uint32_t,
- typename SequenceNumberT = uint32_t>
-class MultiThreadedRPC
- : public detail::RPCBase<MultiThreadedRPC<ChannelT, FunctionIdT,
- SequenceNumberT>,
- ChannelT, FunctionIdT, SequenceNumberT> {
private:
- using BaseClass =
- detail::RPCBase<MultiThreadedRPC<ChannelT, FunctionIdT, SequenceNumberT>,
- ChannelT, FunctionIdT, SequenceNumberT>;
-
-public:
-
- MultiThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
- : BaseClass(C, LazyAutoNegotiation) {}
-
- /// The LaunchPolicy type allows a launch policy to be specified when adding
- /// a function handler. See addHandler.
- using LaunchPolicy = typename BaseClass::LaunchPolicy;
-
- /// Add a handler for the given RPC function.
- /// This installs the given handler functor for the given RPC Function, and
- /// makes the RPC function available for negotiation/calling from the remote.
- ///
- /// The optional LaunchPolicy argument can be used to control how the handler
- /// is run when called:
- ///
- /// * If no LaunchPolicy is given, the handler code will be run on the RPC
- /// handler thread that is reading from the channel. This handler cannot
- /// make blocking RPC calls (since it would be blocking the thread used to
- /// get the result), but can make non-blocking calls.
- ///
- /// * If a LaunchPolicy is given, the user's handler will be wrapped in a
- /// call to serialize and send the result, and the resulting functor (with
- /// type 'Error()' will be passed to the LaunchPolicy. The user can then
- /// choose to add the wrapped handler to a work queue, spawn a new thread,
- /// or anything else.
- template <typename Func, typename HandlerT>
- void addHandler(HandlerT Handler, LaunchPolicy Launch = LaunchPolicy()) {
- return this->template addHandlerImpl<Func>(std::move(Handler),
- std::move(Launch));
- }
-
- /// Negotiate a function id for Func with the other end of the channel.
- template <typename Func>
- Error negotiateFunction() {
- using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
-
- if (auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype())) {
- this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
- return Error::success();
- } else
- return RemoteIdOrErr.takeError();
- }
-
- /// Convenience method for negotiating multiple functions at once.
- template <typename Func>
- Error negotiateFunctions() {
- return negotiateFunction<Func>();
- }
+ // Manage sequence numbers.
+ class SequenceNumberManager {
+ public:
+ SequenceNumberManager() = default;
- /// Convenience method for negotiating multiple functions at once.
- template <typename Func1, typename Func2, typename... Funcs>
- Error negotiateFunctions() {
- if (auto Err = negotiateFunction<Func1>())
- return Err;
- return negotiateFunctions<Func2, Funcs...>();
- }
+ SequenceNumberManager(const SequenceNumberManager &) = delete;
+ SequenceNumberManager &operator=(const SequenceNumberManager &) = delete;
- /// Return type for non-blocking call primitives.
- template <typename Func>
- using NonBlockingCallResult =
- typename detail::ResultTraits<typename Func::ReturnType>::ReturnFutureType;
+ SequenceNumberManager(SequenceNumberManager &&Other)
+ : NextSequenceNumber(std::move(Other.NextSequenceNumber)),
+ FreeSequenceNumbers(std::move(Other.FreeSequenceNumbers)) {}
- /// Call Func on Channel C. Does not block, does not call send. Returns a pair
- /// of a future result and the sequence number assigned to the result.
- ///
- /// This utility function is primarily used for single-threaded mode support,
- /// where the sequence number can be used to wait for the corresponding
- /// result. In multi-threaded mode the appendCallNB method, which does not
- /// return the sequence numeber, should be preferred.
- template <typename Func, typename... ArgTs>
- Expected<NonBlockingCallResult<Func>>
- appendCallNB(const ArgTs &... Args) {
- using RTraits = detail::ResultTraits<typename Func::ReturnType>;
- using ErrorReturn = typename RTraits::ErrorReturnType;
- using ErrorReturnPromise = typename RTraits::ReturnPromiseType;
-
- // FIXME: Stack allocate and move this into the handler once LLVM builds
- // with C++14.
- auto Promise = std::make_shared<ErrorReturnPromise>();
- auto FutureResult = Promise->get_future();
-
- if (auto Err = this->template appendCallAsync<Func>(
- [Promise](ErrorReturn RetOrErr) {
- Promise->set_value(std::move(RetOrErr));
- return Error::success();
- }, Args...)) {
- this->abandonPendingResponses();
- RTraits::consumeAbandoned(FutureResult.get());
- return std::move(Err);
+ SequenceNumberManager &operator=(SequenceNumberManager &&Other) {
+ NextSequenceNumber = std::move(Other.NextSequenceNumber);
+ FreeSequenceNumbers = std::move(Other.FreeSequenceNumbers);
+ return *this;
}
- return std::move(FutureResult);
- }
- /// The same as appendCallNBWithSeq, except that it calls C.send() to
- /// flush the channel after serializing the call.
- template <typename Func, typename... ArgTs>
- Expected<NonBlockingCallResult<Func>>
- callNB(const ArgTs &... Args) {
- auto Result = appendCallNB<Func>(Args...);
- if (!Result)
- return Result;
- if (auto Err = this->C.send()) {
- this->abandonPendingResponses();
- detail::ResultTraits<typename Func::ReturnType>::
- consumeAbandoned(std::move(Result->get()));
- return std::move(Err);
+ void reset() {
+ std::lock_guard<std::mutex> Lock(SeqNoLock);
+ NextSequenceNumber = 0;
+ FreeSequenceNumbers.clear();
}
- return Result;
- }
- /// Call Func on Channel C. Blocks waiting for a result. Returns an Error
- /// for void functions or an Expected<T> for functions returning a T.
- ///
- /// This function is for use in threaded code where another thread is
- /// handling responses and incoming calls.
- template <typename Func, typename... ArgTs,
- typename AltRetT = typename Func::ReturnType>
- typename detail::ResultTraits<AltRetT>::ErrorReturnType
- callB(const ArgTs &... Args) {
- if (auto FutureResOrErr = callNB<Func>(Args...)) {
- if (auto Err = this->C.send()) {
- this->abandonPendingResponses();
- detail::ResultTraits<typename Func::ReturnType>::
- consumeAbandoned(std::move(FutureResOrErr->get()));
- return std::move(Err);
- }
- return FutureResOrErr->get();
- } else
- return FutureResOrErr.takeError();
- }
-
- /// Handle incoming RPC calls.
- Error handlerLoop() {
- while (true)
- if (auto Err = this->handleOne())
- return Err;
- return Error::success();
- }
-
-};
-
-template <typename ChannelT,
- typename FunctionIdT = uint32_t,
- typename SequenceNumberT = uint32_t>
-class SingleThreadedRPC
- : public detail::RPCBase<SingleThreadedRPC<ChannelT, FunctionIdT,
- SequenceNumberT>,
- ChannelT, FunctionIdT,
- SequenceNumberT> {
-private:
-
- using BaseClass = detail::RPCBase<SingleThreadedRPC<ChannelT, FunctionIdT,
- SequenceNumberT>,
- ChannelT, FunctionIdT, SequenceNumberT>;
+ SequenceNumberT getSequenceNumber() {
+ std::lock_guard<std::mutex> Lock(SeqNoLock);
+ if (FreeSequenceNumbers.empty())
+ return NextSequenceNumber++;
+ auto SequenceNumber = FreeSequenceNumbers.back();
+ FreeSequenceNumbers.pop_back();
+ return SequenceNumber;
+ }
- using LaunchPolicy = typename BaseClass::LaunchPolicy;
+ void releaseSequenceNumber(SequenceNumberT SequenceNumber) {
+ std::lock_guard<std::mutex> Lock(SeqNoLock);
+ FreeSequenceNumbers.push_back(SequenceNumber);
+ }
-public:
+ private:
+ std::mutex SeqNoLock;
+ SequenceNumberT NextSequenceNumber = 0;
+ std::vector<SequenceNumberT> FreeSequenceNumbers;
+ };
- SingleThreadedRPC(ChannelT &C, bool LazyAutoNegotiation)
- : BaseClass(C, LazyAutoNegotiation) {}
+ // Base class for results that haven't been returned from the other end of the
+ // RPC connection yet.
+ class OutstandingResult {
+ public:
+ virtual ~OutstandingResult() {}
+ virtual Error readResult(ChannelT &C) = 0;
+ virtual void abandon() = 0;
+ };
- template <typename Func, typename HandlerT>
- void addHandler(HandlerT Handler) {
- return this->template addHandlerImpl<Func>(std::move(Handler),
- LaunchPolicy());
- }
+ // Outstanding results for a specific function.
+ template <typename Func>
+ class OutstandingResultImpl : public OutstandingResult {
+ private:
+ public:
+ OutstandingResultImpl(std::promise<typename Func::PErrorReturn> &&P)
+ : P(std::move(P)) {}
- template <typename Func, typename ClassT, typename RetT, typename... ArgTs>
- void addHandler(ClassT &Object, RetT (ClassT::*Method)(ArgTs...)) {
- addHandler<Func>(
- detail::MemberFnWrapper<ClassT, RetT, ArgTs...>(Object, Method));
- }
+ Error readResult(ChannelT &C) override { return Func::readResult(C, P); }
- /// Negotiate a function id for Func with the other end of the channel.
- template <typename Func>
- Error negotiateFunction() {
- using OrcRPCNegotiate = typename BaseClass::OrcRPCNegotiate;
+ void abandon() override { Func::abandon(P); }
- if (auto RemoteIdOrErr = callB<OrcRPCNegotiate>(Func::getPrototype())) {
- this->RemoteFunctionIds[Func::getPrototype()] = *RemoteIdOrErr;
- return Error::success();
- } else
- return RemoteIdOrErr.takeError();
- }
+ private:
+ std::promise<typename Func::PErrorReturn> P;
+ };
- /// Convenience method for negotiating multiple functions at once.
+ // Create an outstanding result for the given function.
template <typename Func>
- Error negotiateFunctions() {
- return negotiateFunction<Func>();
+ std::unique_ptr<OutstandingResult>
+ createOutstandingResult(std::promise<typename Func::PErrorReturn> &&P) {
+ return llvm::make_unique<OutstandingResultImpl<Func>>(std::move(P));
}
- /// Convenience method for negotiating multiple functions at once.
- template <typename Func1, typename Func2, typename... Funcs>
- Error negotiateFunctions() {
- if (auto Err = negotiateFunction<Func1>())
- return Err;
- return negotiateFunctions<Func2, Funcs...>();
- }
-
- template <typename Func, typename... ArgTs,
- typename AltRetT = typename Func::ReturnType>
- typename detail::ResultTraits<AltRetT>::ErrorReturnType
- callB(const ArgTs &... Args) {
- bool ReceivedResponse = false;
- using ResultType =
- typename detail::ResultTraits<AltRetT>::ErrorReturnType;
- auto Result = detail::ResultTraits<AltRetT>::createBlankErrorReturnValue();
-
- // We have to 'Check' result (which we know is in a success state at this
- // point) so that it can be overwritten in the async handler.
- (void)!!Result;
-
- if (auto Err = this->template appendCallAsync<Func>(
- [&](ResultType R) {
- Result = std::move(R);
- ReceivedResponse = true;
- return Error::success();
- }, Args...)) {
- this->abandonPendingResponses();
- detail::ResultTraits<typename Func::ReturnType>::
- consumeAbandoned(std::move(Result));
- return std::move(Err);
- }
-
- while (!ReceivedResponse) {
- if (auto Err = this->handleOne()) {
- this->abandonPendingResponses();
- detail::ResultTraits<typename Func::ReturnType>::
- consumeAbandoned(std::move(Result));
- return std::move(Err);
- }
- }
-
- return Result;
+ // Abandon all outstanding results.
+ void abandonOutstandingResults() {
+ for (auto &KV : OutstandingResults)
+ KV.second->abandon();
+ OutstandingResults.clear();
+ SequenceNumberMgr.reset();
}
- //using detail::RPCBase<ChannelT, FunctionIdT, SequenceNumberT>::handleOne;
-
+ SequenceNumberManager SequenceNumberMgr;
+ std::map<SequenceNumberT, std::unique_ptr<OutstandingResult>>
+ OutstandingResults;
};
-} // end namespace rpc
+} // end namespace remote
} // end namespace orc
} // end namespace llvm
diff --git a/include/llvm/ExecutionEngine/Orc/RawByteChannel.h b/include/llvm/ExecutionEngine/Orc/RawByteChannel.h
deleted file mode 100644
index c80074ffd7f..00000000000
--- a/include/llvm/ExecutionEngine/Orc/RawByteChannel.h
+++ /dev/null
@@ -1,182 +0,0 @@
-//===- llvm/ExecutionEngine/Orc/RawByteChannel.h ----------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_EXECUTIONENGINE_ORC_RAWBYTECHANNEL_H
-#define LLVM_EXECUTIONENGINE_ORC_RAWBYTECHANNEL_H
-
-#include "OrcError.h"
-#include "RPCSerialization.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/Error.h"
-#include <cstddef>
-#include <cstdint>
-#include <mutex>
-#include <string>
-#include <tuple>
-#include <type_traits>
-#include <vector>
-
-namespace llvm {
-namespace orc {
-namespace rpc {
-
-/// Interface for byte-streams to be used with RPC.
-class RawByteChannel {
-public:
- virtual ~RawByteChannel() {}
-
- /// Read Size bytes from the stream into *Dst.
- virtual Error readBytes(char *Dst, unsigned Size) = 0;
-
- /// Read size bytes from *Src and append them to the stream.
- virtual Error appendBytes(const char *Src, unsigned Size) = 0;
-
- /// Flush the stream if possible.
- virtual Error send() = 0;
-
- /// Notify the channel that we're starting a message send.
- /// Locks the channel for writing.
- template <typename FunctionIdT, typename SequenceIdT>
- Error startSendMessage(const FunctionIdT &FnId, const SequenceIdT &SeqNo) {
- if (auto Err = serializeSeq(*this, FnId, SeqNo))
- return Err;
- writeLock.lock();
- return Error::success();
- }
-
- /// Notify the channel that we're ending a message send.
- /// Unlocks the channel for writing.
- Error endSendMessage() {
- writeLock.unlock();
- return Error::success();
- }
-
- /// Notify the channel that we're starting a message receive.
- /// Locks the channel for reading.
- template <typename FunctionIdT, typename SequenceNumberT>
- Error startReceiveMessage(FunctionIdT &FnId, SequenceNumberT &SeqNo) {
- readLock.lock();
- return deserializeSeq(*this, FnId, SeqNo);
- }
-
- /// Notify the channel that we're ending a message receive.
- /// Unlocks the channel for reading.
- Error endReceiveMessage() {
- readLock.unlock();
- return Error::success();
- }
-
- /// Get the lock for stream reading.
- std::mutex &getReadLock() { return readLock; }
-
- /// Get the lock for stream writing.
- std::mutex &getWriteLock() { return writeLock; }
-
-private:
- std::mutex readLock, writeLock;
-};
-
-template <typename ChannelT, typename T>
-class SerializationTraits<ChannelT, T, T,
- typename std::enable_if<
- std::is_base_of<RawByteChannel, ChannelT>::value &&
- (std::is_same<T, uint8_t>::value ||
- std::is_same<T, int8_t>::value ||
- std::is_same<T, uint16_t>::value ||
- std::is_same<T, int16_t>::value ||
- std::is_same<T, uint32_t>::value ||
- std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value ||
- std::is_same<T, int64_t>::value ||
- std::is_same<T, char>::value)>::type> {
-public:
- static Error serialize(ChannelT &C, T V) {
- support::endian::byte_swap<T, support::big>(V);
- return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T));
- };
-
- static Error deserialize(ChannelT &C, T &V) {
- if (auto Err = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T)))
- return Err;
- support::endian::byte_swap<T, support::big>(V);
- return Error::success();
- };
-};
-
-template <typename ChannelT>
-class SerializationTraits<ChannelT, bool, bool,
- typename std::enable_if<
- std::is_base_of<RawByteChannel, ChannelT>::value>::
- type> {
-public:
- static Error serialize(ChannelT &C, bool V) {
- return C.appendBytes(reinterpret_cast<const char *>(&V), 1);
- }
-
- static Error deserialize(ChannelT &C, bool &V) {
- return C.readBytes(reinterpret_cast<char *>(&V), 1);
- }
-};
-
-template <typename ChannelT>
-class SerializationTraits<ChannelT, std::string, StringRef,
- typename std::enable_if<
- std::is_base_of<RawByteChannel, ChannelT>::value>::
- type> {
-public:
- /// RPC channel serialization for std::strings.
- static Error serialize(RawByteChannel &C, StringRef S) {
- if (auto Err = serializeSeq(C, static_cast<uint64_t>(S.size())))
- return Err;
- return C.appendBytes((const char *)S.data(), S.size());
- }
-};
-
-template <typename ChannelT>
-class SerializationTraits<ChannelT, std::string, const char*,
- typename std::enable_if<
- std::is_base_of<RawByteChannel, ChannelT>::value>::
- type> {
-public:
- static Error serialize(RawByteChannel &C, const char *S) {
- return SerializationTraits<ChannelT, std::string, StringRef>::
- serialize(C, S);
- }
-};
-
-template <typename ChannelT>
-class SerializationTraits<ChannelT, std::string, std::string,
- typename std::enable_if<
- std::is_base_of<RawByteChannel, ChannelT>::value>::
- type> {
-public:
- /// RPC channel serialization for std::strings.
- static Error serialize(RawByteChannel &C, const std::string &S) {
- return SerializationTraits<ChannelT, std::string, StringRef>::
- serialize(C, S);
- }
-
- /// RPC channel deserialization for std::strings.
- static Error deserialize(RawByteChannel &C, std::string &S) {
- uint64_t Count = 0;
- if (auto Err = deserializeSeq(C, Count))
- return Err;
- S.resize(Count);
- return C.readBytes(&S[0], Count);
- }
-};
-
-} // end namespace rpc
-} // end namespace orc
-} // end namespace llvm
-
-#endif // LLVM_EXECUTIONENGINE_ORC_RAWBYTECHANNEL_H