Re-apply bb27e456435 and 5629afea910 with fixes.
This reapplies bb27e4564355243e479cab40885d6e0f7f640572 (SimpleRemoteEPC support) and 2269a941a450a0d395161cfb792be58870b2875b (#include <mutex> fix) with further fixes to support building with LLVM_ENABLE_THREADS=Off.
This commit is contained in:
parent
15e9575fb5
commit
bb72f07380
@ -1302,7 +1302,8 @@ public:
|
||||
/// object.
|
||||
ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC);
|
||||
|
||||
/// End the session. Closes all JITDylibs.
|
||||
/// End the session. Closes all JITDylibs and disconnects from the
|
||||
/// executor.
|
||||
Error endSession();
|
||||
|
||||
/// Get the ExecutorProcessControl object associated with this
|
||||
|
||||
@ -38,11 +38,6 @@ public:
|
||||
EPCGenericJITLinkMemoryManager(ExecutorProcessControl &EPC, FuncAddrs FAs)
|
||||
: EPC(EPC), FAs(FAs) {}
|
||||
|
||||
/// Create using the standard memory allocation function names from the
|
||||
/// ORCTargetProcess library.
|
||||
static Expected<std::unique_ptr<EPCGenericJITLinkMemoryManager>>
|
||||
CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC);
|
||||
|
||||
Expected<std::unique_ptr<Allocation>>
|
||||
allocate(const jitlink::JITLinkDylib *JD,
|
||||
const SegmentsRequestMap &Request) override;
|
||||
|
||||
@ -39,11 +39,6 @@ public:
|
||||
EPCGenericMemoryAccess(ExecutorProcessControl &EPC, FuncAddrs FAs)
|
||||
: EPC(EPC), FAs(FAs) {}
|
||||
|
||||
/// Create using the standard memory access function names from the
|
||||
/// ORCTargetProcess library.
|
||||
static Expected<std::unique_ptr<EPCGenericMemoryAccess>>
|
||||
CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC);
|
||||
|
||||
void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
using namespace shared;
|
||||
|
||||
@ -0,0 +1,250 @@
|
||||
//===--- SimpleRemoteEPCUtils.h - Utils for Simple Remote EPC ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Message definitions and other utilities for SimpleRemoteEPC and
|
||||
// SimpleRemoteEPCServer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
|
||||
extern const char *ExecutorSessionObjectName;
|
||||
extern const char *DispatchFnName;
|
||||
} // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
|
||||
|
||||
enum class SimpleRemoteEPCOpcode : uint8_t {
|
||||
FirstOpC,
|
||||
Setup = FirstOpC,
|
||||
Hangup,
|
||||
Result,
|
||||
CallWrapper,
|
||||
LastOpC = CallWrapper
|
||||
};
|
||||
|
||||
struct SimpleRemoteEPCExecutorInfo {
|
||||
std::string TargetTriple;
|
||||
uint64_t PageSize;
|
||||
StringMap<ExecutorAddress> BootstrapSymbols;
|
||||
|
||||
Expected<ExecutorAddress> getBootstrapSymbol(StringRef Name) const {
|
||||
auto I = BootstrapSymbols.find(Name);
|
||||
if (I == BootstrapSymbols.end())
|
||||
return make_error<StringError>("Symbol \"" + Name +
|
||||
"\" not found in "
|
||||
"bootstrap symbols map",
|
||||
inconvertibleErrorCode());
|
||||
return I->second;
|
||||
}
|
||||
|
||||
Error getBootstrapSymbols(
|
||||
ArrayRef<std::pair<ExecutorAddress &, StringRef>> Pairs) const {
|
||||
for (auto &KV : Pairs) {
|
||||
if (auto A = getBootstrapSymbol(KV.second))
|
||||
KV.first = *A;
|
||||
else
|
||||
return A.takeError();
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
using SimpleRemoteEPCArgBytesVector = SmallVector<char, 128>;
|
||||
|
||||
class SimpleRemoteEPCTransportClient {
|
||||
public:
|
||||
enum HandleMessageAction { ContinueSession, EndSession };
|
||||
|
||||
virtual ~SimpleRemoteEPCTransportClient();
|
||||
|
||||
/// Handle receipt of a message.
|
||||
///
|
||||
/// Returns an Error if the message cannot be handled, 'EndSession' if the
|
||||
/// client will not accept any further messages, and 'ContinueSession'
|
||||
/// otherwise.
|
||||
virtual Expected<HandleMessageAction>
|
||||
handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
|
||||
ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) = 0;
|
||||
|
||||
/// Handle a disconnection from the underlying transport. No further messages
|
||||
/// should be sent to handleMessage after this is called.
|
||||
/// Err may contain an Error value indicating unexpected disconnection. This
|
||||
/// allows clients to log such errors, but no attempt should be made at
|
||||
/// recovery (which should be handled inside the transport class, if it is
|
||||
/// supported at all).
|
||||
virtual void handleDisconnect(Error Err) = 0;
|
||||
};
|
||||
|
||||
class SimpleRemoteEPCTransport {
|
||||
public:
|
||||
virtual ~SimpleRemoteEPCTransport();
|
||||
|
||||
/// Send a SimpleRemoteEPC message.
|
||||
///
|
||||
/// This function may be called concurrently. Subclasses should implement
|
||||
/// locking if required for the underlying transport.
|
||||
virtual Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
|
||||
ExecutorAddress TagAddr,
|
||||
ArrayRef<char> ArgBytes) = 0;
|
||||
|
||||
/// Trigger disconnection from the transport. The implementation should
|
||||
/// respond by calling handleDisconnect on the client once disconnection
|
||||
/// is complete.
|
||||
virtual void disconnect() = 0;
|
||||
};
|
||||
|
||||
/// Uses read/write on FileDescriptors for transport.
|
||||
class FDSimpleRemoteEPCTransport : public SimpleRemoteEPCTransport {
|
||||
public:
|
||||
/// Create a FDSimpleRemoteEPCTransport using the given FDs for
|
||||
/// reading (InFD) and writing (OutFD).
|
||||
static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
|
||||
Create(SimpleRemoteEPCTransportClient &C, int InFD, int OutFD);
|
||||
|
||||
/// Create a FDSimpleRemoteEPCTransport using the given FD for both
|
||||
/// reading and writing.
|
||||
static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
|
||||
Create(SimpleRemoteEPCTransportClient &C, int FD) {
|
||||
return Create(C, FD, FD);
|
||||
}
|
||||
|
||||
~FDSimpleRemoteEPCTransport() override;
|
||||
|
||||
Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
|
||||
ExecutorAddress TagAddr, ArrayRef<char> ArgBytes) override;
|
||||
|
||||
void disconnect() override;
|
||||
|
||||
private:
|
||||
FDSimpleRemoteEPCTransport(SimpleRemoteEPCTransportClient &C, int InFD,
|
||||
int OutFD);
|
||||
|
||||
Error readBytes(char *Dst, size_t Size, bool *IsEOF = nullptr);
|
||||
int writeBytes(const char *Src, size_t Size);
|
||||
void listenLoop();
|
||||
|
||||
std::mutex M;
|
||||
SimpleRemoteEPCTransportClient &C;
|
||||
std::thread ListenerThread;
|
||||
int InFD, OutFD;
|
||||
};
|
||||
|
||||
struct RemoteSymbolLookupSetElement {
|
||||
std::string Name;
|
||||
bool Required;
|
||||
};
|
||||
|
||||
using RemoteSymbolLookupSet = std::vector<RemoteSymbolLookupSetElement>;
|
||||
|
||||
struct RemoteSymbolLookup {
|
||||
uint64_t H;
|
||||
RemoteSymbolLookupSet Symbols;
|
||||
};
|
||||
|
||||
namespace shared {
|
||||
|
||||
using SPSRemoteSymbolLookupSetElement = SPSTuple<SPSString, bool>;
|
||||
|
||||
using SPSRemoteSymbolLookupSet = SPSSequence<SPSRemoteSymbolLookupSetElement>;
|
||||
|
||||
using SPSRemoteSymbolLookup = SPSTuple<uint64_t, SPSRemoteSymbolLookupSet>;
|
||||
|
||||
/// Tuple containing target triple, page size, and bootstrap symbols.
|
||||
using SPSSimpleRemoteEPCExecutorInfo =
|
||||
SPSTuple<SPSString, uint64_t,
|
||||
SPSSequence<SPSTuple<SPSString, SPSExecutorAddress>>>;
|
||||
|
||||
template <>
|
||||
class SPSSerializationTraits<SPSRemoteSymbolLookupSetElement,
|
||||
RemoteSymbolLookupSetElement> {
|
||||
public:
|
||||
static size_t size(const RemoteSymbolLookupSetElement &V) {
|
||||
return SPSArgList<SPSString, bool>::size(V.Name, V.Required);
|
||||
}
|
||||
|
||||
static size_t serialize(SPSOutputBuffer &OB,
|
||||
const RemoteSymbolLookupSetElement &V) {
|
||||
return SPSArgList<SPSString, bool>::serialize(OB, V.Name, V.Required);
|
||||
}
|
||||
|
||||
static size_t deserialize(SPSInputBuffer &IB,
|
||||
RemoteSymbolLookupSetElement &V) {
|
||||
return SPSArgList<SPSString, bool>::deserialize(IB, V.Name, V.Required);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class SPSSerializationTraits<SPSRemoteSymbolLookup, RemoteSymbolLookup> {
|
||||
public:
|
||||
static size_t size(const RemoteSymbolLookup &V) {
|
||||
return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::size(V.H, V.Symbols);
|
||||
}
|
||||
|
||||
static size_t serialize(SPSOutputBuffer &OB, const RemoteSymbolLookup &V) {
|
||||
return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::serialize(OB, V.H,
|
||||
V.Symbols);
|
||||
}
|
||||
|
||||
static size_t deserialize(SPSInputBuffer &IB, RemoteSymbolLookup &V) {
|
||||
return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::deserialize(
|
||||
IB, V.H, V.Symbols);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class SPSSerializationTraits<SPSSimpleRemoteEPCExecutorInfo,
|
||||
SimpleRemoteEPCExecutorInfo> {
|
||||
public:
|
||||
static size_t size(const SimpleRemoteEPCExecutorInfo &SI) {
|
||||
return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::size(
|
||||
SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
|
||||
}
|
||||
|
||||
static bool serialize(SPSOutputBuffer &OB,
|
||||
const SimpleRemoteEPCExecutorInfo &SI) {
|
||||
return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::serialize(
|
||||
OB, SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
|
||||
}
|
||||
|
||||
static bool deserialize(SPSInputBuffer &IB, SimpleRemoteEPCExecutorInfo &SI) {
|
||||
return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::deserialize(
|
||||
IB, SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
|
||||
}
|
||||
};
|
||||
|
||||
using SPSRunAsMainSignature = int64_t(SPSExecutorAddress,
|
||||
SPSSequence<SPSString>);
|
||||
|
||||
using SPSLoadDylibSignature =
|
||||
SPSExpected<SPSExecutorAddress>(SPSExecutorAddress, SPSString, uint64_t);
|
||||
|
||||
using SPSLookupSymbolsSignature =
|
||||
SPSExpected<SPSSequence<SPSSequence<SPSExecutorAddress>>>(
|
||||
SPSExecutorAddress, SPSSequence<SPSRemoteSymbolLookup>);
|
||||
|
||||
} // end namespace shared
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
|
||||
136
llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
Normal file
136
llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
Normal file
@ -0,0 +1,136 @@
|
||||
//===---- SimpleRemoteEPC.h - Simple remote executor control ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Simple remote executor process control.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEEPC_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEEPC_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FunctionExtras.h"
|
||||
#include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MSVCErrorWorkarounds.h"
|
||||
|
||||
#include <future>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
class SimpleRemoteEPC : public ExecutorProcessControl,
|
||||
public SimpleRemoteEPCTransportClient {
|
||||
public:
|
||||
/// Create a SimpleRemoteEPC using the given transport type and args.
|
||||
template <typename TransportT, typename... TransportTCtorArgTs>
|
||||
static Expected<std::unique_ptr<SimpleRemoteEPC>>
|
||||
Create(TransportTCtorArgTs &&...TransportTCtorArgs) {
|
||||
std::unique_ptr<SimpleRemoteEPC> SREPC(
|
||||
new SimpleRemoteEPC(std::make_shared<SymbolStringPool>()));
|
||||
|
||||
// Prepare for setup packet.
|
||||
std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
|
||||
auto EIF = EIP.get_future();
|
||||
SREPC->prepareToReceiveSetupMessage(EIP);
|
||||
auto T = TransportT::Create(
|
||||
*SREPC, std::forward<TransportTCtorArgTs>(TransportTCtorArgs)...);
|
||||
if (!T)
|
||||
return T.takeError();
|
||||
auto EI = EIF.get();
|
||||
if (!EI) {
|
||||
(*T)->disconnect();
|
||||
return EI.takeError();
|
||||
}
|
||||
if (auto Err = SREPC->setup(std::move(*T), std::move(*EI)))
|
||||
return joinErrors(std::move(Err), SREPC->disconnect());
|
||||
return std::move(SREPC);
|
||||
}
|
||||
|
||||
SimpleRemoteEPC(const SimpleRemoteEPC &) = delete;
|
||||
SimpleRemoteEPC &operator=(const SimpleRemoteEPC &) = delete;
|
||||
SimpleRemoteEPC(SimpleRemoteEPC &&) = delete;
|
||||
SimpleRemoteEPC &operator=(SimpleRemoteEPC &) = delete;
|
||||
~SimpleRemoteEPC();
|
||||
|
||||
/// Called at the end of the construction process to set up the instance.
|
||||
///
|
||||
/// Override to set up custom memory manager and/or memory access objects.
|
||||
/// This method must be called at the *end* of the subclass's
|
||||
/// implementation.
|
||||
virtual Error setup(std::unique_ptr<SimpleRemoteEPCTransport> T,
|
||||
const SimpleRemoteEPCExecutorInfo &EI);
|
||||
|
||||
Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
|
||||
|
||||
Expected<std::vector<tpctypes::LookupResult>>
|
||||
lookupSymbols(ArrayRef<LookupRequest> Request) override;
|
||||
|
||||
Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
|
||||
ArrayRef<std::string> Args) override;
|
||||
|
||||
void callWrapperAsync(SendResultFunction OnComplete,
|
||||
JITTargetAddress WrapperFnAddr,
|
||||
ArrayRef<char> ArgBuffer) override;
|
||||
|
||||
Error disconnect() override;
|
||||
|
||||
Expected<HandleMessageAction>
|
||||
handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
|
||||
ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) override;
|
||||
|
||||
void handleDisconnect(Error Err) override;
|
||||
|
||||
protected:
|
||||
void setMemoryManager(std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
|
||||
void setMemoryAccess(std::unique_ptr<MemoryAccess> MemAccess);
|
||||
|
||||
private:
|
||||
SimpleRemoteEPC(std::shared_ptr<SymbolStringPool> SSP)
|
||||
: ExecutorProcessControl(std::move(SSP)) {}
|
||||
|
||||
Error setupDefaultMemoryManager(const SimpleRemoteEPCExecutorInfo &EI);
|
||||
Error setupDefaultMemoryAccess(const SimpleRemoteEPCExecutorInfo &EI);
|
||||
|
||||
Error handleSetup(uint64_t SeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes);
|
||||
void prepareToReceiveSetupMessage(
|
||||
std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> &ExecInfoP);
|
||||
|
||||
Error handleResult(uint64_t SeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes);
|
||||
void handleCallWrapper(uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes);
|
||||
|
||||
uint64_t getNextSeqNo() { return NextSeqNo++; }
|
||||
void releaseSeqNo(uint64_t SeqNo) {}
|
||||
|
||||
using PendingCallWrapperResultsMap = DenseMap<uint64_t, SendResultFunction>;
|
||||
|
||||
std::atomic_bool Disconnected{false};
|
||||
std::mutex SimpleRemoteEPCMutex;
|
||||
std::unique_ptr<SimpleRemoteEPCTransport> T;
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
|
||||
std::unique_ptr<MemoryAccess> OwnedMemAccess;
|
||||
|
||||
ExecutorAddress LoadDylibAddr;
|
||||
ExecutorAddress LookupSymbolsAddr;
|
||||
ExecutorAddress RunAsMainAddr;
|
||||
|
||||
uint64_t NextSeqNo = 0;
|
||||
PendingCallWrapperResultsMap PendingCallWrapperResults;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEEPC_H
|
||||
@ -0,0 +1,149 @@
|
||||
//===---- SimpleRemoteEPCServer.h - EPC over abstract channel ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// EPC over simple abstract channel.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FunctionExtras.h"
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// A simple EPC server implementation.
|
||||
class SimpleRemoteEPCServer : public SimpleRemoteEPCTransportClient {
|
||||
public:
|
||||
using ReportErrorFunction = unique_function<void(Error)>;
|
||||
|
||||
class Dispatcher {
|
||||
public:
|
||||
virtual ~Dispatcher();
|
||||
virtual void dispatch(unique_function<void()> Work) = 0;
|
||||
virtual void shutdown() = 0;
|
||||
};
|
||||
|
||||
#if LLVM_ENABLE_THREADS
|
||||
class ThreadDispatcher : public Dispatcher {
|
||||
public:
|
||||
void dispatch(unique_function<void()> Work) override;
|
||||
void shutdown() override;
|
||||
|
||||
private:
|
||||
std::mutex DispatchMutex;
|
||||
bool Running = true;
|
||||
size_t Outstanding = 0;
|
||||
std::condition_variable OutstandingCV;
|
||||
};
|
||||
#endif
|
||||
|
||||
static StringMap<ExecutorAddress> defaultBootstrapSymbols();
|
||||
|
||||
template <typename TransportT, typename... TransportTCtorArgTs>
|
||||
static Expected<std::unique_ptr<SimpleRemoteEPCServer>>
|
||||
Create(std::unique_ptr<Dispatcher> D,
|
||||
StringMap<ExecutorAddress> BootstrapSymbols,
|
||||
TransportTCtorArgTs &&...TransportTCtorArgs) {
|
||||
auto SREPCServer = std::make_unique<SimpleRemoteEPCServer>();
|
||||
SREPCServer->D = std::move(D);
|
||||
SREPCServer->ReportError = [](Error Err) {
|
||||
logAllUnhandledErrors(std::move(Err), errs(), "SimpleRemoteEPCServer ");
|
||||
};
|
||||
auto T = TransportT::Create(
|
||||
*SREPCServer, std::forward<TransportTCtorArgTs>(TransportTCtorArgs)...);
|
||||
if (!T)
|
||||
return T.takeError();
|
||||
SREPCServer->T = std::move(*T);
|
||||
if (auto Err = SREPCServer->sendSetupMessage(std::move(BootstrapSymbols)))
|
||||
return std::move(Err);
|
||||
return std::move(SREPCServer);
|
||||
}
|
||||
|
||||
/// Set an error reporter for this server.
|
||||
void setErrorReporter(ReportErrorFunction ReportError) {
|
||||
this->ReportError = std::move(ReportError);
|
||||
}
|
||||
|
||||
/// Call to handle an incoming message.
|
||||
///
|
||||
/// Returns 'Disconnect' if the message is a 'detach' message from the remote
|
||||
/// otherwise returns 'Continue'. If the server has moved to an error state,
|
||||
/// returns an error, which should be reported and treated as a 'Disconnect'.
|
||||
Expected<HandleMessageAction>
|
||||
handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
|
||||
ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) override;
|
||||
|
||||
Error waitForDisconnect();
|
||||
|
||||
void handleDisconnect(Error Err) override;
|
||||
|
||||
private:
|
||||
Error sendSetupMessage(StringMap<ExecutorAddress> BootstrapSymbols);
|
||||
|
||||
Error handleResult(uint64_t SeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes);
|
||||
void handleCallWrapper(uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes);
|
||||
|
||||
static shared::detail::CWrapperFunctionResult
|
||||
loadDylibWrapper(const char *ArgData, size_t ArgSize);
|
||||
|
||||
static shared::detail::CWrapperFunctionResult
|
||||
lookupSymbolsWrapper(const char *ArgData, size_t ArgSize);
|
||||
|
||||
Expected<tpctypes::DylibHandle> loadDylib(const std::string &Path,
|
||||
uint64_t Mode);
|
||||
|
||||
Expected<std::vector<std::vector<ExecutorAddress>>>
|
||||
lookupSymbols(const std::vector<RemoteSymbolLookup> &L);
|
||||
|
||||
shared::WrapperFunctionResult
|
||||
doJITDispatch(const void *FnTag, const char *ArgData, size_t ArgSize);
|
||||
|
||||
static shared::detail::CWrapperFunctionResult
|
||||
jitDispatchEntry(void *DispatchCtx, const void *FnTag, const char *ArgData,
|
||||
size_t ArgSize);
|
||||
|
||||
uint64_t getNextSeqNo() { return NextSeqNo++; }
|
||||
void releaseSeqNo(uint64_t) {}
|
||||
|
||||
using PendingJITDispatchResultsMap =
|
||||
DenseMap<uint64_t, std::promise<shared::WrapperFunctionResult> *>;
|
||||
|
||||
std::mutex ServerStateMutex;
|
||||
std::condition_variable ShutdownCV;
|
||||
enum { ServerRunning, ServerShuttingDown, ServerShutDown } RunState;
|
||||
Error ShutdownErr = Error::success();
|
||||
std::unique_ptr<SimpleRemoteEPCTransport> T;
|
||||
std::unique_ptr<Dispatcher> D;
|
||||
ReportErrorFunction ReportError;
|
||||
|
||||
uint64_t NextSeqNo = 0;
|
||||
PendingJITDispatchResultsMap PendingJITDispatchResults;
|
||||
std::vector<sys::DynamicLibrary> Dylibs;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H
|
||||
@ -8,7 +8,6 @@ add_llvm_component_library(LLVMOrcJIT
|
||||
EPCDebugObjectRegistrar.cpp
|
||||
EPCEHFrameRegistrar.cpp
|
||||
EPCGenericJITLinkMemoryManager.cpp
|
||||
EPCGenericMemoryAccess.cpp
|
||||
EPCIndirectionUtils.cpp
|
||||
ExecutionUtils.cpp
|
||||
IndirectionUtils.cpp
|
||||
@ -27,6 +26,7 @@ add_llvm_component_library(LLVMOrcJIT
|
||||
OrcABISupport.cpp
|
||||
OrcV2CBindings.cpp
|
||||
RTDyldObjectLinkingLayer.cpp
|
||||
SimpleRemoteEPC.cpp
|
||||
Speculation.cpp
|
||||
SpeculateAnalyses.cpp
|
||||
ExecutorProcessControl.cpp
|
||||
|
||||
@ -86,32 +86,6 @@ private:
|
||||
SegInfoMap Segs;
|
||||
};
|
||||
|
||||
/// Create from a ExecutorProcessControl instance.
|
||||
Expected<std::unique_ptr<EPCGenericJITLinkMemoryManager>>
|
||||
EPCGenericJITLinkMemoryManager::CreateUsingOrcRTFuncs(
|
||||
ExecutorProcessControl &EPC) {
|
||||
|
||||
auto H = EPC.loadDylib("");
|
||||
if (!H)
|
||||
return H.takeError();
|
||||
|
||||
StringRef GlobalPrefix = "";
|
||||
if (EPC.getTargetTriple().isOSBinFormatMachO())
|
||||
GlobalPrefix = "_";
|
||||
|
||||
FuncAddrs FAs;
|
||||
if (auto Err = lookupAndRecordAddrs(
|
||||
EPC, *H,
|
||||
{{EPC.intern((GlobalPrefix + "__orc_rt_reserve").str()), &FAs.Reserve},
|
||||
{EPC.intern((GlobalPrefix + "__orc_rt_finalize").str()),
|
||||
&FAs.Finalize},
|
||||
{EPC.intern((GlobalPrefix + "__orc_rt_deallocate").str()),
|
||||
&FAs.Deallocate}}))
|
||||
return std::move(Err);
|
||||
|
||||
return std::make_unique<EPCGenericJITLinkMemoryManager>(EPC, std::move(FAs));
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>>
|
||||
EPCGenericJITLinkMemoryManager::allocate(const jitlink::JITLinkDylib *JD,
|
||||
const SegmentsRequestMap &Request) {
|
||||
|
||||
@ -1,46 +0,0 @@
|
||||
//===----- EPCGenericMemoryAccess.cpp - Generic EPC MemoryAccess impl -----===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
|
||||
#include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// Create from a ExecutorProcessControl instance.
|
||||
Expected<std::unique_ptr<EPCGenericMemoryAccess>>
|
||||
EPCGenericMemoryAccess::CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC) {
|
||||
|
||||
auto H = EPC.loadDylib("");
|
||||
if (!H)
|
||||
return H.takeError();
|
||||
|
||||
StringRef GlobalPrefix = "";
|
||||
if (EPC.getTargetTriple().isOSBinFormatMachO())
|
||||
GlobalPrefix = "_";
|
||||
|
||||
FuncAddrs FAs;
|
||||
if (auto Err = lookupAndRecordAddrs(
|
||||
EPC, *H,
|
||||
{{EPC.intern((GlobalPrefix + "__orc_rt_write_uint8s_wrapper").str()),
|
||||
&FAs.WriteUInt8s},
|
||||
{EPC.intern((GlobalPrefix + "__orc_rt_write_uint16s_wrapper").str()),
|
||||
&FAs.WriteUInt16s},
|
||||
{EPC.intern((GlobalPrefix + "__orc_rt_write_uint32s_wrapper").str()),
|
||||
&FAs.WriteUInt32s},
|
||||
{EPC.intern((GlobalPrefix + "__orc_rt_write_uint64s_wrapper").str()),
|
||||
&FAs.WriteUInt64s},
|
||||
{EPC.intern((GlobalPrefix + "__orc_rt_write_buffers_wrapper").str()),
|
||||
&FAs.WriteBuffers}}))
|
||||
return std::move(Err);
|
||||
|
||||
return std::make_unique<EPCGenericMemoryAccess>(EPC, std::move(FAs));
|
||||
}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
@ -1,6 +1,7 @@
|
||||
add_llvm_component_library(LLVMOrcShared
|
||||
OrcError.cpp
|
||||
RPCError.cpp
|
||||
SimpleRemoteEPCUtils.cpp
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
|
||||
|
||||
|
||||
252
llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp
Normal file
252
llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
//===------ SimpleRemoteEPCUtils.cpp - Utils for Simple Remote EPC --------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Message definitions and other utilities for SimpleRemoteEPC and
|
||||
// SimpleRemoteEPCServer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
struct FDMsgHeader {
|
||||
static constexpr unsigned MsgSizeOffset = 0;
|
||||
static constexpr unsigned OpCOffset = MsgSizeOffset + sizeof(uint64_t);
|
||||
static constexpr unsigned SeqNoOffset = OpCOffset + sizeof(uint64_t);
|
||||
static constexpr unsigned TagAddrOffset = SeqNoOffset + sizeof(uint64_t);
|
||||
static constexpr unsigned Size = TagAddrOffset + sizeof(uint64_t);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
|
||||
|
||||
const char *ExecutorSessionObjectName =
|
||||
"__llvm_orc_SimpleRemoteEPC_dispatch_ctx";
|
||||
const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn";
|
||||
|
||||
} // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
|
||||
|
||||
SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() {}
|
||||
SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() {}
|
||||
|
||||
Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
|
||||
FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD,
|
||||
int OutFD) {
|
||||
#if LLVM_ENABLE_THREADS
|
||||
if (InFD == -1)
|
||||
return make_error<StringError>("Invalid input file descriptor " +
|
||||
Twine(InFD),
|
||||
inconvertibleErrorCode());
|
||||
if (OutFD == -1)
|
||||
return make_error<StringError>("Invalid output file descriptor " +
|
||||
Twine(OutFD),
|
||||
inconvertibleErrorCode());
|
||||
std::unique_ptr<FDSimpleRemoteEPCTransport> FDT(
|
||||
new FDSimpleRemoteEPCTransport(C, InFD, OutFD));
|
||||
return FDT;
|
||||
#else
|
||||
return make_error<StringError>("FD-based SimpleRemoteEPC transport requires "
|
||||
"thread support, but llvm was built with "
|
||||
"LLVM_ENABLE_THREADS=Off",
|
||||
inconvertibleErrorCode());
|
||||
#endif
|
||||
}
|
||||
|
||||
FDSimpleRemoteEPCTransport::FDSimpleRemoteEPCTransport(
|
||||
SimpleRemoteEPCTransportClient &C, int InFD, int OutFD)
|
||||
: C(C), InFD(InFD), OutFD(OutFD) {
|
||||
#if LLVM_ENABLE_THREADS
|
||||
ListenerThread = std::thread([this]() { listenLoop(); });
|
||||
#endif
|
||||
}
|
||||
|
||||
FDSimpleRemoteEPCTransport::~FDSimpleRemoteEPCTransport() {
|
||||
#if LLVM_ENABLE_THREADS
|
||||
ListenerThread.join();
|
||||
#endif
|
||||
}
|
||||
|
||||
Error FDSimpleRemoteEPCTransport::sendMessage(SimpleRemoteEPCOpcode OpC,
|
||||
uint64_t SeqNo,
|
||||
ExecutorAddress TagAddr,
|
||||
ArrayRef<char> ArgBytes) {
|
||||
char HeaderBuffer[FDMsgHeader::Size];
|
||||
|
||||
*((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)) =
|
||||
FDMsgHeader::Size + ArgBytes.size();
|
||||
*((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)) =
|
||||
static_cast<uint64_t>(OpC);
|
||||
*((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)) = SeqNo;
|
||||
*((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)) =
|
||||
TagAddr.getValue();
|
||||
|
||||
std::lock_guard<std::mutex> Lock(M);
|
||||
if (OutFD == -1)
|
||||
return make_error<StringError>("FD-transport disconnected",
|
||||
inconvertibleErrorCode());
|
||||
if (int ErrNo = writeBytes(HeaderBuffer, FDMsgHeader::Size))
|
||||
return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
|
||||
if (int ErrNo = writeBytes(ArgBytes.data(), ArgBytes.size()))
|
||||
return errorCodeToError(std::error_code(ErrNo, std::generic_category()));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void FDSimpleRemoteEPCTransport::disconnect() {
|
||||
int CloseInFD = -1, CloseOutFD = -1;
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(M);
|
||||
std::swap(InFD, CloseInFD);
|
||||
std::swap(OutFD, CloseOutFD);
|
||||
}
|
||||
|
||||
// If CloseOutFD == CloseInFD then set CloseOutFD to -1 up-front so that we
|
||||
// don't double-close.
|
||||
if (CloseOutFD == CloseInFD)
|
||||
CloseOutFD = -1;
|
||||
|
||||
// Close InFD.
|
||||
if (CloseInFD != -1)
|
||||
while (close(CloseInFD) == -1) {
|
||||
if (errno == EBADF)
|
||||
break;
|
||||
}
|
||||
|
||||
// Close OutFD.
|
||||
if (CloseOutFD != -1) {
|
||||
while (close(CloseOutFD) == -1) {
|
||||
if (errno == EBADF)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Error makeUnexpectedEOFError() {
|
||||
return make_error<StringError>("Unexpected end-of-file",
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
Error FDSimpleRemoteEPCTransport::readBytes(char *Dst, size_t Size,
|
||||
bool *IsEOF) {
|
||||
assert(Dst && "Attempt to read into null.");
|
||||
ssize_t Completed = 0;
|
||||
while (Completed < static_cast<ssize_t>(Size)) {
|
||||
ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
|
||||
if (Read <= 0) {
|
||||
auto ErrNo = errno;
|
||||
if (Read == 0) {
|
||||
if (Completed == 0 && IsEOF) {
|
||||
*IsEOF = true;
|
||||
return Error::success();
|
||||
} else
|
||||
return makeUnexpectedEOFError();
|
||||
} else if (ErrNo == EAGAIN || ErrNo == EINTR)
|
||||
continue;
|
||||
else {
|
||||
std::lock_guard<std::mutex> Lock(M);
|
||||
if (InFD == -1 && IsEOF) { // Disconnected locally. Pretend this is EOF.
|
||||
*IsEOF = true;
|
||||
return Error::success();
|
||||
}
|
||||
return errorCodeToError(
|
||||
std::error_code(ErrNo, std::generic_category()));
|
||||
}
|
||||
}
|
||||
Completed += Read;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
int FDSimpleRemoteEPCTransport::writeBytes(const char *Src, size_t Size) {
|
||||
assert(Src && "Attempt to append from null.");
|
||||
ssize_t Completed = 0;
|
||||
while (Completed < static_cast<ssize_t>(Size)) {
|
||||
ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
|
||||
if (Written < 0) {
|
||||
auto ErrNo = errno;
|
||||
if (ErrNo == EAGAIN || ErrNo == EINTR)
|
||||
continue;
|
||||
else
|
||||
return ErrNo;
|
||||
}
|
||||
Completed += Written;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FDSimpleRemoteEPCTransport::listenLoop() {
|
||||
Error Err = Error::success();
|
||||
do {
|
||||
|
||||
char HeaderBuffer[FDMsgHeader::Size];
|
||||
// Read the header buffer.
|
||||
{
|
||||
bool IsEOF;
|
||||
if (auto Err2 = readBytes(HeaderBuffer, FDMsgHeader::Size, &IsEOF)) {
|
||||
Err = joinErrors(std::move(Err), std::move(Err2));
|
||||
break;
|
||||
}
|
||||
if (IsEOF)
|
||||
break;
|
||||
}
|
||||
|
||||
// Decode header buffer.
|
||||
uint64_t MsgSize;
|
||||
SimpleRemoteEPCOpcode OpC;
|
||||
uint64_t SeqNo;
|
||||
ExecutorAddress TagAddr;
|
||||
|
||||
MsgSize =
|
||||
*((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset));
|
||||
OpC = static_cast<SimpleRemoteEPCOpcode>(static_cast<uint64_t>(
|
||||
*((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset))));
|
||||
SeqNo =
|
||||
*((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset));
|
||||
TagAddr.setValue(
|
||||
*((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)));
|
||||
|
||||
if (MsgSize < FDMsgHeader::Size) {
|
||||
Err = joinErrors(std::move(Err),
|
||||
make_error<StringError>("Mesasge size too small",
|
||||
inconvertibleErrorCode()));
|
||||
break;
|
||||
}
|
||||
|
||||
// Read the argument bytes.
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes;
|
||||
ArgBytes.resize(MsgSize - FDMsgHeader::Size);
|
||||
if (auto Err2 = readBytes(ArgBytes.data(), ArgBytes.size())) {
|
||||
Err = joinErrors(std::move(Err), std::move(Err2));
|
||||
break;
|
||||
}
|
||||
|
||||
if (auto Action = C.handleMessage(OpC, SeqNo, TagAddr, ArgBytes)) {
|
||||
if (*Action == SimpleRemoteEPCTransportClient::EndSession)
|
||||
break;
|
||||
} else {
|
||||
Err = joinErrors(std::move(Err), Action.takeError());
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
C.handleDisconnect(std::move(Err));
|
||||
}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
324
llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
Normal file
324
llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
//===------- SimpleRemoteEPC.cpp -- Simple remote executor control --------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
|
||||
#include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
#define DEBUG_TYPE "orc"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace shared {
|
||||
|
||||
template <>
|
||||
class SPSSerializationTraits<SPSRemoteSymbolLookupSetElement,
|
||||
SymbolLookupSet::value_type> {
|
||||
public:
|
||||
static size_t size(const SymbolLookupSet::value_type &V) {
|
||||
return SPSArgList<SPSString, bool>::size(
|
||||
*V.first, V.second == SymbolLookupFlags::RequiredSymbol);
|
||||
}
|
||||
|
||||
static bool serialize(SPSOutputBuffer &OB,
|
||||
const SymbolLookupSet::value_type &V) {
|
||||
return SPSArgList<SPSString, bool>::serialize(
|
||||
OB, *V.first, V.second == SymbolLookupFlags::RequiredSymbol);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class TrivialSPSSequenceSerialization<SPSRemoteSymbolLookupSetElement,
|
||||
SymbolLookupSet> {
|
||||
public:
|
||||
static constexpr bool available = true;
|
||||
};
|
||||
|
||||
template <>
|
||||
class SPSSerializationTraits<SPSRemoteSymbolLookup,
|
||||
ExecutorProcessControl::LookupRequest> {
|
||||
using MemberSerialization =
|
||||
SPSArgList<SPSExecutorAddress, SPSRemoteSymbolLookupSet>;
|
||||
|
||||
public:
|
||||
static size_t size(const ExecutorProcessControl::LookupRequest &LR) {
|
||||
return MemberSerialization::size(ExecutorAddress(LR.Handle), LR.Symbols);
|
||||
}
|
||||
|
||||
static bool serialize(SPSOutputBuffer &OB,
|
||||
const ExecutorProcessControl::LookupRequest &LR) {
|
||||
return MemberSerialization::serialize(OB, ExecutorAddress(LR.Handle),
|
||||
LR.Symbols);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace shared
|
||||
|
||||
SimpleRemoteEPC::~SimpleRemoteEPC() {
|
||||
assert(Disconnected && "Destroyed without disconnection");
|
||||
}
|
||||
|
||||
Error SimpleRemoteEPC::setup(std::unique_ptr<SimpleRemoteEPCTransport> T,
|
||||
const SimpleRemoteEPCExecutorInfo &EI) {
|
||||
using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "SimpleRemoteEPC received setup message:\n"
|
||||
<< " Triple: " << EI.TargetTriple << "\n"
|
||||
<< " Page size: " << EI.PageSize << "\n"
|
||||
<< " Bootstrap symbols:\n";
|
||||
for (const auto &KV : EI.BootstrapSymbols)
|
||||
dbgs() << " " << KV.first() << ": "
|
||||
<< formatv("{0:x16}", KV.second.getValue()) << "\n";
|
||||
});
|
||||
this->T = std::move(T);
|
||||
TargetTriple = Triple(EI.TargetTriple);
|
||||
PageSize = EI.PageSize;
|
||||
|
||||
if (auto Err = EI.getBootstrapSymbols(
|
||||
{{JDI.JITDispatchContextAddress, ExecutorSessionObjectName},
|
||||
{JDI.JITDispatchFunctionAddress, DispatchFnName},
|
||||
{LoadDylibAddr, "__llvm_orc_load_dylib"},
|
||||
{LookupSymbolsAddr, "__llvm_orc_lookup_symbols"},
|
||||
{RunAsMainAddr, "__llvm_orc_run_as_main"}}))
|
||||
return Err;
|
||||
|
||||
if (!MemMgr)
|
||||
if (auto Err = setupDefaultMemoryManager(EI))
|
||||
return Err;
|
||||
if (!MemAccess)
|
||||
if (auto Err = setupDefaultMemoryAccess(EI))
|
||||
return Err;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<tpctypes::DylibHandle>
|
||||
SimpleRemoteEPC::loadDylib(const char *DylibPath) {
|
||||
Expected<tpctypes::DylibHandle> H((tpctypes::DylibHandle()));
|
||||
if (auto Err = callSPSWrapper<shared::SPSLoadDylibSignature>(
|
||||
LoadDylibAddr.getValue(), H, JDI.JITDispatchContextAddress,
|
||||
StringRef(DylibPath), (uint64_t)0))
|
||||
return std::move(Err);
|
||||
return H;
|
||||
}
|
||||
|
||||
Expected<std::vector<tpctypes::LookupResult>>
|
||||
SimpleRemoteEPC::lookupSymbols(ArrayRef<LookupRequest> Request) {
|
||||
Expected<std::vector<tpctypes::LookupResult>> R(
|
||||
(std::vector<tpctypes::LookupResult>()));
|
||||
|
||||
if (auto Err = callSPSWrapper<shared::SPSLookupSymbolsSignature>(
|
||||
LookupSymbolsAddr.getValue(), R, JDI.JITDispatchContextAddress,
|
||||
Request))
|
||||
return std::move(Err);
|
||||
return R;
|
||||
}
|
||||
|
||||
Expected<int32_t> SimpleRemoteEPC::runAsMain(JITTargetAddress MainFnAddr,
|
||||
ArrayRef<std::string> Args) {
|
||||
int64_t Result = 0;
|
||||
if (auto Err = callSPSWrapper<shared::SPSRunAsMainSignature>(
|
||||
RunAsMainAddr.getValue(), Result, ExecutorAddress(MainFnAddr), Args))
|
||||
return std::move(Err);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void SimpleRemoteEPC::callWrapperAsync(SendResultFunction OnComplete,
|
||||
JITTargetAddress WrapperFnAddr,
|
||||
ArrayRef<char> ArgBuffer) {
|
||||
uint64_t SeqNo;
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
|
||||
SeqNo = getNextSeqNo();
|
||||
assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
|
||||
PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
|
||||
}
|
||||
|
||||
if (auto Err = T->sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
|
||||
ExecutorAddress(WrapperFnAddr), ArgBuffer)) {
|
||||
getExecutionSession().reportError(std::move(Err));
|
||||
}
|
||||
}
|
||||
|
||||
Error SimpleRemoteEPC::disconnect() {
|
||||
Disconnected = true;
|
||||
T->disconnect();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
|
||||
SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
|
||||
ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) {
|
||||
using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
|
||||
if (static_cast<UT>(OpC) < static_cast<UT>(SimpleRemoteEPCOpcode::FirstOpC) ||
|
||||
static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
|
||||
return make_error<StringError>("Unexpected opcode",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
switch (OpC) {
|
||||
case SimpleRemoteEPCOpcode::Setup:
|
||||
if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
|
||||
return std::move(Err);
|
||||
break;
|
||||
case SimpleRemoteEPCOpcode::Hangup:
|
||||
// FIXME: Put EPC into 'detached' state.
|
||||
return SimpleRemoteEPCTransportClient::EndSession;
|
||||
case SimpleRemoteEPCOpcode::Result:
|
||||
if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
|
||||
return std::move(Err);
|
||||
break;
|
||||
case SimpleRemoteEPCOpcode::CallWrapper:
|
||||
handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
|
||||
break;
|
||||
}
|
||||
return ContinueSession;
|
||||
}
|
||||
|
||||
void SimpleRemoteEPC::handleDisconnect(Error Err) {
|
||||
PendingCallWrapperResultsMap TmpPending;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
|
||||
std::swap(TmpPending, PendingCallWrapperResults);
|
||||
}
|
||||
|
||||
for (auto &KV : TmpPending)
|
||||
KV.second(
|
||||
shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
|
||||
|
||||
if (Err) {
|
||||
// FIXME: Move ReportError to EPC.
|
||||
if (ES)
|
||||
ES->reportError(std::move(Err));
|
||||
else
|
||||
logAllUnhandledErrors(std::move(Err), errs(), "SimpleRemoteEPC: ");
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleRemoteEPC::setMemoryManager(
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
|
||||
OwnedMemMgr = std::move(MemMgr);
|
||||
this->MemMgr = OwnedMemMgr.get();
|
||||
}
|
||||
|
||||
void SimpleRemoteEPC::setMemoryAccess(std::unique_ptr<MemoryAccess> MemAccess) {
|
||||
OwnedMemAccess = std::move(MemAccess);
|
||||
this->MemAccess = OwnedMemAccess.get();
|
||||
}
|
||||
|
||||
Error SimpleRemoteEPC::setupDefaultMemoryManager(
|
||||
const SimpleRemoteEPCExecutorInfo &EI) {
|
||||
|
||||
EPCGenericJITLinkMemoryManager::FuncAddrs FAs;
|
||||
|
||||
if (auto Err = EI.getBootstrapSymbols(
|
||||
{{FAs.Reserve, "__llvm_orc_memory_reserve"},
|
||||
{FAs.Finalize, "__llvm_orc_memory_finalize"},
|
||||
{FAs.Deallocate, "__llvm_orc_memory_deallocate"}}))
|
||||
return Err;
|
||||
|
||||
setMemoryManager(
|
||||
std::make_unique<EPCGenericJITLinkMemoryManager>(*this, FAs));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error SimpleRemoteEPC::setupDefaultMemoryAccess(
|
||||
const SimpleRemoteEPCExecutorInfo &EI) {
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) {
|
||||
if (SeqNo != 0)
|
||||
return make_error<StringError>("Setup packet SeqNo not zero",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
if (TagAddr)
|
||||
return make_error<StringError>("Setup packet TagAddr not zero",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
|
||||
auto I = PendingCallWrapperResults.find(0);
|
||||
assert(PendingCallWrapperResults.size() == 1 &&
|
||||
I != PendingCallWrapperResults.end() &&
|
||||
"Setup message handler not connectly set up");
|
||||
auto SetupMsgHandler = std::move(I->second);
|
||||
PendingCallWrapperResults.erase(I);
|
||||
|
||||
auto WFR =
|
||||
shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
|
||||
SetupMsgHandler(std::move(WFR));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void SimpleRemoteEPC::prepareToReceiveSetupMessage(
|
||||
std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> &ExecInfoP) {
|
||||
PendingCallWrapperResults[0] =
|
||||
[&](shared::WrapperFunctionResult SetupMsgBytes) {
|
||||
if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
|
||||
ExecInfoP.set_value(
|
||||
make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
|
||||
return;
|
||||
}
|
||||
using SPSSerialize =
|
||||
shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
|
||||
shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
|
||||
SimpleRemoteEPCExecutorInfo EI;
|
||||
if (SPSSerialize::deserialize(IB, EI))
|
||||
ExecInfoP.set_value(EI);
|
||||
else
|
||||
ExecInfoP.set_value(make_error<StringError>(
|
||||
"Could not deserialize setup message", inconvertibleErrorCode()));
|
||||
};
|
||||
}
|
||||
|
||||
Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) {
|
||||
SendResultFunction SendResult;
|
||||
|
||||
if (TagAddr)
|
||||
return make_error<StringError>("Unexpected TagAddr in result message",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
|
||||
auto I = PendingCallWrapperResults.find(SeqNo);
|
||||
if (I == PendingCallWrapperResults.end())
|
||||
return make_error<StringError>("No call for sequence number " +
|
||||
Twine(SeqNo),
|
||||
inconvertibleErrorCode());
|
||||
SendResult = std::move(I->second);
|
||||
PendingCallWrapperResults.erase(I);
|
||||
releaseSeqNo(SeqNo);
|
||||
}
|
||||
|
||||
auto WFR =
|
||||
shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
|
||||
SendResult(std::move(WFR));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void SimpleRemoteEPC::handleCallWrapper(
|
||||
uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) {
|
||||
assert(ES && "No ExecutionSession attached");
|
||||
ES->runJITDispatchHandler(
|
||||
[this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {
|
||||
if (auto Err =
|
||||
T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
|
||||
ExecutorAddress(), {WFR.data(), WFR.size()}))
|
||||
getExecutionSession().reportError(std::move(Err));
|
||||
},
|
||||
TagAddr.getValue(), ArgBytes);
|
||||
}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
@ -1,6 +1,7 @@
|
||||
add_llvm_component_library(LLVMOrcTargetProcess
|
||||
JITLoaderGDB.cpp
|
||||
RegisterEHFrames.cpp
|
||||
SimpleRemoteEPCServer.cpp
|
||||
TargetExecutionUtils.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
|
||||
@ -0,0 +1,404 @@
|
||||
//===------- SimpleEPCServer.cpp - EPC over simple abstract channel -------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h"
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
|
||||
#define DEBUG_TYPE "orc"
|
||||
|
||||
using namespace llvm::orc::shared;
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
static llvm::orc::shared::detail::CWrapperFunctionResult
|
||||
reserveWrapper(const char *ArgData, size_t ArgSize) {
|
||||
return WrapperFunction<SPSOrcTargetProcessAllocate>::handle(
|
||||
ArgData, ArgSize,
|
||||
[](uint64_t Size) -> Expected<ExecutorAddress> {
|
||||
std::error_code EC;
|
||||
auto MB = sys::Memory::allocateMappedMemory(
|
||||
Size, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
|
||||
if (EC)
|
||||
return errorCodeToError(EC);
|
||||
return ExecutorAddress::fromPtr(MB.base());
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
static llvm::orc::shared::detail::CWrapperFunctionResult
|
||||
finalizeWrapper(const char *ArgData, size_t ArgSize) {
|
||||
return WrapperFunction<SPSOrcTargetProcessFinalize>::handle(
|
||||
ArgData, ArgSize,
|
||||
[](const tpctypes::FinalizeRequest &FR) -> Error {
|
||||
for (auto &Seg : FR) {
|
||||
char *Mem = Seg.Addr.toPtr<char *>();
|
||||
memcpy(Mem, Seg.Content.data(), Seg.Content.size());
|
||||
memset(Mem + Seg.Content.size(), 0,
|
||||
Seg.Size - Seg.Content.size());
|
||||
assert(Seg.Size <= std::numeric_limits<size_t>::max());
|
||||
if (auto EC = sys::Memory::protectMappedMemory(
|
||||
{Mem, static_cast<size_t>(Seg.Size)},
|
||||
tpctypes::fromWireProtectionFlags(Seg.Prot)))
|
||||
return errorCodeToError(EC);
|
||||
if (Seg.Prot & tpctypes::WPF_Exec)
|
||||
sys::Memory::InvalidateInstructionCache(Mem, Seg.Size);
|
||||
}
|
||||
return Error::success();
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
static llvm::orc::shared::detail::CWrapperFunctionResult
|
||||
deallocateWrapper(const char *ArgData, size_t ArgSize) {
|
||||
return WrapperFunction<SPSOrcTargetProcessDeallocate>::handle(
|
||||
ArgData, ArgSize,
|
||||
[](ExecutorAddress Base, uint64_t Size) -> Error {
|
||||
sys::MemoryBlock MB(Base.toPtr<void *>(), Size);
|
||||
if (auto EC = sys::Memory::releaseMappedMemory(MB))
|
||||
return errorCodeToError(EC);
|
||||
return Error::success();
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
template <typename WriteT, typename SPSWriteT>
|
||||
static llvm::orc::shared::detail::CWrapperFunctionResult
|
||||
writeUIntsWrapper(const char *ArgData, size_t ArgSize) {
|
||||
return WrapperFunction<void(SPSSequence<SPSWriteT>)>::handle(
|
||||
ArgData, ArgSize,
|
||||
[](std::vector<WriteT> Ws) {
|
||||
for (auto &W : Ws)
|
||||
*jitTargetAddressToPointer<decltype(W.Value) *>(W.Address) =
|
||||
W.Value;
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
static llvm::orc::shared::detail::CWrapperFunctionResult
|
||||
writeBuffersWrapper(const char *ArgData, size_t ArgSize) {
|
||||
return WrapperFunction<void(SPSSequence<SPSMemoryAccessBufferWrite>)>::handle(
|
||||
ArgData, ArgSize,
|
||||
[](std::vector<tpctypes::BufferWrite> Ws) {
|
||||
for (auto &W : Ws)
|
||||
memcpy(jitTargetAddressToPointer<char *>(W.Address),
|
||||
W.Buffer.data(), W.Buffer.size());
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
static llvm::orc::shared::detail::CWrapperFunctionResult
|
||||
runAsMainWrapper(const char *ArgData, size_t ArgSize) {
|
||||
return WrapperFunction<SPSRunAsMainSignature>::handle(
|
||||
ArgData, ArgSize,
|
||||
[](ExecutorAddress MainAddr,
|
||||
std::vector<std::string> Args) -> int64_t {
|
||||
return runAsMain(MainAddr.toPtr<int (*)(int, char *[])>(), Args);
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
SimpleRemoteEPCServer::Dispatcher::~Dispatcher() {}
|
||||
|
||||
#if LLVM_ENABLE_THREADS
|
||||
void SimpleRemoteEPCServer::ThreadDispatcher::dispatch(
|
||||
unique_function<void()> Work) {
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(DispatchMutex);
|
||||
if (!Running)
|
||||
return;
|
||||
++Outstanding;
|
||||
}
|
||||
|
||||
std::thread([this, Work = std::move(Work)]() mutable {
|
||||
Work();
|
||||
std::lock_guard<std::mutex> Lock(DispatchMutex);
|
||||
--Outstanding;
|
||||
OutstandingCV.notify_all();
|
||||
}).detach();
|
||||
}
|
||||
|
||||
void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() {
|
||||
std::unique_lock<std::mutex> Lock(DispatchMutex);
|
||||
Running = false;
|
||||
OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
|
||||
}
|
||||
#endif
|
||||
|
||||
StringMap<ExecutorAddress> SimpleRemoteEPCServer::defaultBootstrapSymbols() {
|
||||
StringMap<ExecutorAddress> DBS;
|
||||
|
||||
DBS["__llvm_orc_memory_reserve"] = ExecutorAddress::fromPtr(&reserveWrapper);
|
||||
DBS["__llvm_orc_memory_finalize"] =
|
||||
ExecutorAddress::fromPtr(&finalizeWrapper);
|
||||
DBS["__llvm_orc_memory_deallocate"] =
|
||||
ExecutorAddress::fromPtr(&deallocateWrapper);
|
||||
DBS["__llvm_orc_memory_write_uint8s"] = ExecutorAddress::fromPtr(
|
||||
&writeUIntsWrapper<tpctypes::UInt8Write,
|
||||
shared::SPSMemoryAccessUInt8Write>);
|
||||
DBS["__llvm_orc_memory_write_uint16s"] = ExecutorAddress::fromPtr(
|
||||
&writeUIntsWrapper<tpctypes::UInt16Write,
|
||||
shared::SPSMemoryAccessUInt16Write>);
|
||||
DBS["__llvm_orc_memory_write_uint32s"] = ExecutorAddress::fromPtr(
|
||||
&writeUIntsWrapper<tpctypes::UInt32Write,
|
||||
shared::SPSMemoryAccessUInt32Write>);
|
||||
DBS["__llvm_orc_memory_write_uint64s"] = ExecutorAddress::fromPtr(
|
||||
&writeUIntsWrapper<tpctypes::UInt64Write,
|
||||
shared::SPSMemoryAccessUInt64Write>);
|
||||
DBS["__llvm_orc_memory_write_buffers"] =
|
||||
ExecutorAddress::fromPtr(&writeBuffersWrapper);
|
||||
DBS["__llvm_orc_run_as_main"] = ExecutorAddress::fromPtr(&runAsMainWrapper);
|
||||
DBS["__llvm_orc_load_dylib"] = ExecutorAddress::fromPtr(&loadDylibWrapper);
|
||||
DBS["__llvm_orc_lookup_symbols"] =
|
||||
ExecutorAddress::fromPtr(&lookupSymbolsWrapper);
|
||||
return DBS;
|
||||
}
|
||||
|
||||
Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
|
||||
SimpleRemoteEPCServer::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
|
||||
ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) {
|
||||
using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
|
||||
if (static_cast<UT>(OpC) < static_cast<UT>(SimpleRemoteEPCOpcode::FirstOpC) ||
|
||||
static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
|
||||
return make_error<StringError>("Unexpected opcode",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
// TODO: Clean detach message?
|
||||
switch (OpC) {
|
||||
case SimpleRemoteEPCOpcode::Setup:
|
||||
return make_error<StringError>("Unexpected Setup opcode",
|
||||
inconvertibleErrorCode());
|
||||
case SimpleRemoteEPCOpcode::Hangup:
|
||||
return SimpleRemoteEPCTransportClient::EndSession;
|
||||
case SimpleRemoteEPCOpcode::Result:
|
||||
if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
|
||||
return std::move(Err);
|
||||
break;
|
||||
case SimpleRemoteEPCOpcode::CallWrapper:
|
||||
handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
|
||||
break;
|
||||
}
|
||||
return ContinueSession;
|
||||
}
|
||||
|
||||
Error SimpleRemoteEPCServer::waitForDisconnect() {
|
||||
std::unique_lock<std::mutex> Lock(ServerStateMutex);
|
||||
ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; });
|
||||
return std::move(ShutdownErr);
|
||||
}
|
||||
|
||||
void SimpleRemoteEPCServer::handleDisconnect(Error Err) {
|
||||
PendingJITDispatchResultsMap TmpPending;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(ServerStateMutex);
|
||||
std::swap(TmpPending, PendingJITDispatchResults);
|
||||
RunState = ServerShuttingDown;
|
||||
}
|
||||
|
||||
// Send out-of-band errors to any waiting threads.
|
||||
for (auto &KV : TmpPending)
|
||||
KV.second->set_value(
|
||||
shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
|
||||
|
||||
// TODO: Free attached resources.
|
||||
// 1. Close libraries in DylibHandles.
|
||||
|
||||
// Wait for dispatcher to clear.
|
||||
D->shutdown();
|
||||
|
||||
std::lock_guard<std::mutex> Lock(ServerStateMutex);
|
||||
ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err));
|
||||
RunState = ServerShutDown;
|
||||
ShutdownCV.notify_all();
|
||||
}
|
||||
|
||||
Error SimpleRemoteEPCServer::sendSetupMessage(
|
||||
StringMap<ExecutorAddress> BootstrapSymbols) {
|
||||
|
||||
using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
|
||||
|
||||
std::vector<char> SetupPacket;
|
||||
SimpleRemoteEPCExecutorInfo EI;
|
||||
EI.TargetTriple = sys::getProcessTriple();
|
||||
if (auto PageSize = sys::Process::getPageSize())
|
||||
EI.PageSize = *PageSize;
|
||||
else
|
||||
return PageSize.takeError();
|
||||
EI.BootstrapSymbols = std::move(BootstrapSymbols);
|
||||
|
||||
assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) &&
|
||||
"Dispatch context name should not be set");
|
||||
assert(!EI.BootstrapSymbols.count(DispatchFnName) &&
|
||||
"Dispatch function name should not be set");
|
||||
EI.BootstrapSymbols[ExecutorSessionObjectName] =
|
||||
ExecutorAddress::fromPtr(this);
|
||||
EI.BootstrapSymbols[DispatchFnName] =
|
||||
ExecutorAddress::fromPtr(jitDispatchEntry);
|
||||
|
||||
using SPSSerialize =
|
||||
shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
|
||||
auto SetupPacketBytes =
|
||||
shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI));
|
||||
shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size());
|
||||
if (!SPSSerialize::serialize(OB, EI))
|
||||
return make_error<StringError>("Could not send setup packet",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
return T->sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddress(),
|
||||
{SetupPacketBytes.data(), SetupPacketBytes.size()});
|
||||
}
|
||||
|
||||
Error SimpleRemoteEPCServer::handleResult(
|
||||
uint64_t SeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) {
|
||||
std::promise<shared::WrapperFunctionResult> *P = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(ServerStateMutex);
|
||||
auto I = PendingJITDispatchResults.find(SeqNo);
|
||||
if (I == PendingJITDispatchResults.end())
|
||||
return make_error<StringError>("No call for sequence number " +
|
||||
Twine(SeqNo),
|
||||
inconvertibleErrorCode());
|
||||
P = I->second;
|
||||
PendingJITDispatchResults.erase(I);
|
||||
releaseSeqNo(SeqNo);
|
||||
}
|
||||
auto R = shared::WrapperFunctionResult::allocate(ArgBytes.size());
|
||||
memcpy(R.data(), ArgBytes.data(), ArgBytes.size());
|
||||
P->set_value(std::move(R));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void SimpleRemoteEPCServer::handleCallWrapper(
|
||||
uint64_t RemoteSeqNo, ExecutorAddress TagAddr,
|
||||
SimpleRemoteEPCArgBytesVector ArgBytes) {
|
||||
D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
|
||||
using WrapperFnTy =
|
||||
shared::detail::CWrapperFunctionResult (*)(const char *, size_t);
|
||||
auto *Fn = TagAddr.toPtr<WrapperFnTy>();
|
||||
shared::WrapperFunctionResult ResultBytes(
|
||||
Fn(ArgBytes.data(), ArgBytes.size()));
|
||||
if (auto Err = T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
|
||||
ExecutorAddress(),
|
||||
{ResultBytes.data(), ResultBytes.size()}))
|
||||
ReportError(std::move(Err));
|
||||
});
|
||||
}
|
||||
|
||||
shared::detail::CWrapperFunctionResult
|
||||
SimpleRemoteEPCServer::loadDylibWrapper(const char *ArgData, size_t ArgSize) {
|
||||
return shared::WrapperFunction<shared::SPSLoadDylibSignature>::handle(
|
||||
ArgData, ArgSize,
|
||||
[](ExecutorAddress ExecutorSessionObj, std::string Path,
|
||||
uint64_t Flags) -> Expected<uint64_t> {
|
||||
return ExecutorSessionObj.toPtr<SimpleRemoteEPCServer *>()
|
||||
->loadDylib(Path, Flags);
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
shared::detail::CWrapperFunctionResult
|
||||
SimpleRemoteEPCServer::lookupSymbolsWrapper(const char *ArgData,
|
||||
size_t ArgSize) {
|
||||
return shared::WrapperFunction<shared::SPSLookupSymbolsSignature>::handle(
|
||||
ArgData, ArgSize,
|
||||
[](ExecutorAddress ExecutorSessionObj,
|
||||
std::vector<RemoteSymbolLookup> Lookup) {
|
||||
return ExecutorSessionObj.toPtr<SimpleRemoteEPCServer *>()
|
||||
->lookupSymbols(Lookup);
|
||||
})
|
||||
.release();
|
||||
}
|
||||
|
||||
Expected<tpctypes::DylibHandle>
|
||||
SimpleRemoteEPCServer::loadDylib(const std::string &Path, uint64_t Mode) {
|
||||
std::string ErrMsg;
|
||||
const char *P = Path.empty() ? nullptr : Path.c_str();
|
||||
auto DL = sys::DynamicLibrary::getPermanentLibrary(P, &ErrMsg);
|
||||
if (!DL.isValid())
|
||||
return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
|
||||
std::lock_guard<std::mutex> Lock(ServerStateMutex);
|
||||
uint64_t Id = Dylibs.size();
|
||||
Dylibs.push_back(std::move(DL));
|
||||
return Id;
|
||||
}
|
||||
|
||||
Expected<std::vector<std::vector<ExecutorAddress>>>
|
||||
SimpleRemoteEPCServer::lookupSymbols(const std::vector<RemoteSymbolLookup> &L) {
|
||||
std::vector<std::vector<ExecutorAddress>> Result;
|
||||
|
||||
for (const auto &E : L) {
|
||||
if (E.H >= Dylibs.size())
|
||||
return make_error<StringError>("Unrecognized handle",
|
||||
inconvertibleErrorCode());
|
||||
auto &DL = Dylibs[E.H];
|
||||
Result.push_back({});
|
||||
|
||||
for (const auto &Sym : E.Symbols) {
|
||||
|
||||
const char *DemangledSymName = Sym.Name.c_str();
|
||||
#ifdef __APPLE__
|
||||
if (*DemangledSymName == '_')
|
||||
++DemangledSymName;
|
||||
#endif
|
||||
|
||||
void *Addr = DL.getAddressOfSymbol(DemangledSymName);
|
||||
if (!Addr && Sym.Required)
|
||||
return make_error<StringError>(Twine("Missing definition for ") +
|
||||
DemangledSymName,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
Result.back().push_back(ExecutorAddress::fromPtr(Addr));
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(Result);
|
||||
}
|
||||
|
||||
shared::WrapperFunctionResult
|
||||
SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData,
|
||||
size_t ArgSize) {
|
||||
uint64_t SeqNo;
|
||||
std::promise<shared::WrapperFunctionResult> ResultP;
|
||||
auto ResultF = ResultP.get_future();
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(ServerStateMutex);
|
||||
if (RunState != ServerRunning)
|
||||
return shared::WrapperFunctionResult::createOutOfBandError(
|
||||
"jit_dispatch not available (EPC server shut down)");
|
||||
|
||||
SeqNo = getNextSeqNo();
|
||||
assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use");
|
||||
PendingJITDispatchResults[SeqNo] = &ResultP;
|
||||
}
|
||||
|
||||
if (auto Err =
|
||||
T->sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
|
||||
ExecutorAddress::fromPtr(FnTag), {ArgData, ArgSize}))
|
||||
ReportError(std::move(Err));
|
||||
|
||||
return ResultF.get();
|
||||
}
|
||||
|
||||
shared::detail::CWrapperFunctionResult
|
||||
SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag,
|
||||
const char *ArgData, size_t ArgSize) {
|
||||
return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx)
|
||||
->doJITDispatch(FnTag, ArgData, ArgSize)
|
||||
.release();
|
||||
}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
@ -13,8 +13,8 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
@ -90,8 +90,6 @@ int openListener(std::string Host, std::string PortStr) {
|
||||
static constexpr int ConnectionQueueLen = 1;
|
||||
listen(SockFD, ConnectionQueueLen);
|
||||
|
||||
outs() << "Listening at " << Host << ":" << PortStr << "\n";
|
||||
|
||||
#if defined(_AIX)
|
||||
assert(Hi_32(AI->ai_addrlen) == 0 && "Field is a size_t on 64-bit AIX");
|
||||
socklen_t AddrLen = Lo_32(AI->ai_addrlen);
|
||||
@ -104,6 +102,7 @@ int openListener(std::string Host, std::string PortStr) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#if LLVM_ENABLE_THREADS
|
||||
|
||||
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
|
||||
|
||||
@ -133,24 +132,22 @@ int main(int argc, char *argv[]) {
|
||||
"' is not a valid integer");
|
||||
|
||||
InFD = OutFD = openListener(Host.str(), PortStr.str());
|
||||
outs() << "Connection established. Running OrcRPCTPCServer...\n";
|
||||
} else
|
||||
printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
|
||||
}
|
||||
|
||||
ExitOnErr.setBanner(std::string(argv[0]) + ":");
|
||||
|
||||
using JITLinkExecutorEndpoint =
|
||||
shared::SingleThreadedRPCEndpoint<shared::FDRawByteChannel>;
|
||||
|
||||
shared::registerStringError<shared::FDRawByteChannel>();
|
||||
|
||||
shared::FDRawByteChannel C(InFD, OutFD);
|
||||
JITLinkExecutorEndpoint EP(C, true);
|
||||
OrcRPCTPCServer<JITLinkExecutorEndpoint> Server(EP);
|
||||
Server.setProgramName(std::string("llvm-jitlink-executor"));
|
||||
|
||||
ExitOnErr(Server.run());
|
||||
auto Server =
|
||||
ExitOnErr(SimpleRemoteEPCServer::Create<FDSimpleRemoteEPCTransport>(
|
||||
std::make_unique<SimpleRemoteEPCServer::ThreadDispatcher>(),
|
||||
SimpleRemoteEPCServer::defaultBootstrapSymbols(), InFD, OutFD));
|
||||
|
||||
ExitOnErr(Server->waitForDisconnect());
|
||||
return 0;
|
||||
|
||||
#else
|
||||
errs() << argv[0]
|
||||
<< " error: this tool requires threads, but LLVM was "
|
||||
"built with LLVM_ENABLE_THREADS=Off\n";
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -635,8 +635,7 @@ static Error loadDylibs(Session &S) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<ExecutorProcessControl>>
|
||||
LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor() {
|
||||
static Expected<std::unique_ptr<ExecutorProcessControl>> launchExecutor() {
|
||||
#ifndef LLVM_ON_UNIX
|
||||
// FIXME: Add support for Windows.
|
||||
return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr +
|
||||
@ -644,8 +643,6 @@ LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor() {
|
||||
inconvertibleErrorCode());
|
||||
#else
|
||||
|
||||
shared::registerStringError<LLVMJITLinkChannel>();
|
||||
|
||||
constexpr int ReadEnd = 0;
|
||||
constexpr int WriteEnd = 1;
|
||||
|
||||
@ -697,24 +694,8 @@ LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor() {
|
||||
close(ToExecutor[ReadEnd]);
|
||||
close(FromExecutor[WriteEnd]);
|
||||
|
||||
// Return an RPC channel connected to our end of the pipes.
|
||||
auto SSP = std::make_shared<SymbolStringPool>();
|
||||
auto Channel = std::make_unique<shared::FDRawByteChannel>(
|
||||
return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
|
||||
FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
|
||||
auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel, true);
|
||||
|
||||
auto ReportError = [](Error Err) {
|
||||
logAllUnhandledErrors(std::move(Err), errs(), "");
|
||||
};
|
||||
|
||||
Error Err = Error::success();
|
||||
std::unique_ptr<LLVMJITLinkRemoteExecutorProcessControl> REPC(
|
||||
new LLVMJITLinkRemoteExecutorProcessControl(
|
||||
std::move(SSP), std::move(Channel), std::move(Endpoint),
|
||||
std::move(ReportError), Err));
|
||||
if (Err)
|
||||
return std::move(Err);
|
||||
return std::move(REPC);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -764,8 +745,7 @@ static Expected<int> connectTCPSocket(std::string Host, std::string PortStr) {
|
||||
}
|
||||
#endif
|
||||
|
||||
Expected<std::unique_ptr<ExecutorProcessControl>>
|
||||
LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor() {
|
||||
static Expected<std::unique_ptr<ExecutorProcessControl>> connectToExecutor() {
|
||||
#ifndef LLVM_ON_UNIX
|
||||
// FIXME: Add TCP support for Windows.
|
||||
return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr +
|
||||
@ -773,8 +753,6 @@ LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor() {
|
||||
inconvertibleErrorCode());
|
||||
#else
|
||||
|
||||
shared::registerStringError<LLVMJITLinkChannel>();
|
||||
|
||||
StringRef Host, PortStr;
|
||||
std::tie(Host, PortStr) = StringRef(OutOfProcessExecutorConnect).split(':');
|
||||
if (Host.empty())
|
||||
@ -794,37 +772,10 @@ LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor() {
|
||||
if (!SockFD)
|
||||
return SockFD.takeError();
|
||||
|
||||
auto SSP = std::make_shared<SymbolStringPool>();
|
||||
auto Channel = std::make_unique<shared::FDRawByteChannel>(*SockFD, *SockFD);
|
||||
auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel, true);
|
||||
|
||||
auto ReportError = [](Error Err) {
|
||||
logAllUnhandledErrors(std::move(Err), errs(), "");
|
||||
};
|
||||
|
||||
Error Err = Error::success();
|
||||
std::unique_ptr<LLVMJITLinkRemoteExecutorProcessControl> REPC(
|
||||
new LLVMJITLinkRemoteExecutorProcessControl(
|
||||
std::move(SSP), std::move(Channel), std::move(Endpoint),
|
||||
std::move(ReportError), Err));
|
||||
if (Err)
|
||||
return std::move(Err);
|
||||
return std::move(REPC);
|
||||
return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(*SockFD, *SockFD);
|
||||
#endif
|
||||
}
|
||||
|
||||
Error LLVMJITLinkRemoteExecutorProcessControl::disconnect() {
|
||||
std::promise<MSVCPError> P;
|
||||
auto F = P.get_future();
|
||||
auto Err = closeConnection([&](Error Err) -> Error {
|
||||
P.set_value(std::move(Err));
|
||||
Finished = true;
|
||||
return Error::success();
|
||||
});
|
||||
ListenerThread.join();
|
||||
return joinErrors(std::move(Err), F.get());
|
||||
}
|
||||
|
||||
class PhonyExternalsGenerator : public DefinitionGenerator {
|
||||
public:
|
||||
Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
|
||||
@ -846,14 +797,13 @@ Expected<std::unique_ptr<Session>> Session::Create(Triple TT) {
|
||||
std::unique_ptr<ExecutorProcessControl> EPC;
|
||||
if (OutOfProcessExecutor.getNumOccurrences()) {
|
||||
/// If -oop-executor is passed then launch the executor.
|
||||
if (auto REPC = LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor())
|
||||
if (auto REPC = launchExecutor())
|
||||
EPC = std::move(*REPC);
|
||||
else
|
||||
return REPC.takeError();
|
||||
} else if (OutOfProcessExecutorConnect.getNumOccurrences()) {
|
||||
/// If -oop-executor-connect is passed then connect to the executor.
|
||||
if (auto REPC =
|
||||
LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor())
|
||||
if (auto REPC = connectToExecutor())
|
||||
EPC = std::move(*REPC);
|
||||
else
|
||||
return REPC.takeError();
|
||||
|
||||
@ -19,9 +19,9 @@
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
@ -48,66 +48,6 @@ private:
|
||||
Session &S;
|
||||
};
|
||||
|
||||
using LLVMJITLinkChannel = orc::shared::FDRawByteChannel;
|
||||
using LLVMJITLinkRPCEndpoint =
|
||||
orc::shared::MultiThreadedRPCEndpoint<LLVMJITLinkChannel>;
|
||||
using LLVMJITLinkRemoteMemoryAccess =
|
||||
orc::OrcRPCEPCMemoryAccess<LLVMJITLinkRPCEndpoint>;
|
||||
|
||||
class LLVMJITLinkRemoteExecutorProcessControl
|
||||
: public orc::OrcRPCExecutorProcessControlBase<LLVMJITLinkRPCEndpoint> {
|
||||
public:
|
||||
using BaseT = orc::OrcRPCExecutorProcessControlBase<LLVMJITLinkRPCEndpoint>;
|
||||
static Expected<std::unique_ptr<ExecutorProcessControl>> LaunchExecutor();
|
||||
|
||||
static Expected<std::unique_ptr<ExecutorProcessControl>> ConnectToExecutor();
|
||||
|
||||
Error disconnect() override;
|
||||
|
||||
private:
|
||||
using LLVMJITLinkRemoteMemoryAccess =
|
||||
orc::OrcRPCEPCMemoryAccess<LLVMJITLinkRemoteExecutorProcessControl>;
|
||||
|
||||
using LLVMJITLinkRemoteMemoryManager = orc::OrcRPCEPCJITLinkMemoryManager<
|
||||
LLVMJITLinkRemoteExecutorProcessControl>;
|
||||
|
||||
LLVMJITLinkRemoteExecutorProcessControl(
|
||||
std::shared_ptr<orc::SymbolStringPool> SSP,
|
||||
std::unique_ptr<LLVMJITLinkChannel> Channel,
|
||||
std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint,
|
||||
ErrorReporter ReportError, Error &Err)
|
||||
: BaseT(std::move(SSP), *Endpoint, std::move(ReportError)),
|
||||
Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) {
|
||||
ErrorAsOutParameter _(&Err);
|
||||
|
||||
ListenerThread = std::thread([&]() {
|
||||
while (!Finished) {
|
||||
if (auto Err = this->Endpoint->handleOne()) {
|
||||
reportError(std::move(Err));
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (auto Err2 = initializeORCRPCEPCBase()) {
|
||||
Err = joinErrors(std::move(Err2), disconnect());
|
||||
return;
|
||||
}
|
||||
|
||||
OwnedMemAccess = std::make_unique<LLVMJITLinkRemoteMemoryAccess>(*this);
|
||||
MemAccess = OwnedMemAccess.get();
|
||||
OwnedMemMgr = std::make_unique<LLVMJITLinkRemoteMemoryManager>(*this);
|
||||
MemMgr = OwnedMemMgr.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<LLVMJITLinkChannel> Channel;
|
||||
std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint;
|
||||
std::unique_ptr<ExecutorProcessControl::MemoryAccess> OwnedMemAccess;
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
|
||||
std::atomic<bool> Finished{false};
|
||||
std::thread ListenerThread;
|
||||
};
|
||||
|
||||
struct Session {
|
||||
orc::ExecutionSession ES;
|
||||
orc::JITDylib *MainJD = nullptr;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user