From bb72f073808a42e35ddc52cb0810470ffeb3cce3 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Sat, 11 Sep 2021 19:07:16 +1000 Subject: [PATCH] Re-apply bb27e456435 and 5629afea910 with fixes. This reapplies bb27e4564355243e479cab40885d6e0f7f640572 (SimpleRemoteEPC support) and 2269a941a450a0d395161cfb792be58870b2875b (#include fix) with further fixes to support building with LLVM_ENABLE_THREADS=Off. --- llvm/include/llvm/ExecutionEngine/Orc/Core.h | 3 +- .../Orc/EPCGenericJITLinkMemoryManager.h | 5 - .../ExecutionEngine/Orc/EPCGenericMemoryAccess.h | 5 - .../Orc/Shared/SimpleRemoteEPCUtils.h | 250 +++++++++++++ .../llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h | 136 +++++++ .../Orc/TargetProcess/SimpleRemoteEPCServer.h | 149 ++++++++ llvm/lib/ExecutionEngine/Orc/CMakeLists.txt | 2 +- .../Orc/EPCGenericJITLinkMemoryManager.cpp | 26 -- .../ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp | 46 --- llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt | 1 + .../Orc/Shared/SimpleRemoteEPCUtils.cpp | 252 +++++++++++++ llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp | 324 +++++++++++++++++ .../Orc/TargetProcess/CMakeLists.txt | 1 + .../Orc/TargetProcess/SimpleRemoteEPCServer.cpp | 404 +++++++++++++++++++++ .../llvm-jitlink-executor.cpp | 31 +- llvm/tools/llvm-jitlink/llvm-jitlink.cpp | 62 +--- llvm/tools/llvm-jitlink/llvm-jitlink.h | 62 +--- 17 files changed, 1541 insertions(+), 218 deletions(-) create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h delete mode 100644 llvm/lib/ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp create mode 100644 llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp create mode 100644 llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp create mode 100644 llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h index 331a921..062b1f3 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h @@ -1302,7 +1302,8 @@ public: /// object. ExecutionSession(std::unique_ptr 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 diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h index 0dd1e6a..4800712 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h @@ -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> - CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC); - Expected> allocate(const jitlink::JITLinkDylib *JD, const SegmentsRequestMap &Request) override; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h index fe9d1c1..80a84ce 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h @@ -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> - CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC); - void writeUInt8sAsync(ArrayRef Ws, WriteResultFn OnWriteComplete) override { using namespace shared; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h new file mode 100644 index 0000000..7d1df16 --- /dev/null +++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h @@ -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 +#include +#include + +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 BootstrapSymbols; + + Expected getBootstrapSymbol(StringRef Name) const { + auto I = BootstrapSymbols.find(Name); + if (I == BootstrapSymbols.end()) + return make_error("Symbol \"" + Name + + "\" not found in " + "bootstrap symbols map", + inconvertibleErrorCode()); + return I->second; + } + + Error getBootstrapSymbols( + ArrayRef> 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; + +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 + 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 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> + Create(SimpleRemoteEPCTransportClient &C, int InFD, int OutFD); + + /// Create a FDSimpleRemoteEPCTransport using the given FD for both + /// reading and writing. + static Expected> + Create(SimpleRemoteEPCTransportClient &C, int FD) { + return Create(C, FD, FD); + } + + ~FDSimpleRemoteEPCTransport() override; + + Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, + ExecutorAddress TagAddr, ArrayRef 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; + +struct RemoteSymbolLookup { + uint64_t H; + RemoteSymbolLookupSet Symbols; +}; + +namespace shared { + +using SPSRemoteSymbolLookupSetElement = SPSTuple; + +using SPSRemoteSymbolLookupSet = SPSSequence; + +using SPSRemoteSymbolLookup = SPSTuple; + +/// Tuple containing target triple, page size, and bootstrap symbols. +using SPSSimpleRemoteEPCExecutorInfo = + SPSTuple>>; + +template <> +class SPSSerializationTraits { +public: + static size_t size(const RemoteSymbolLookupSetElement &V) { + return SPSArgList::size(V.Name, V.Required); + } + + static size_t serialize(SPSOutputBuffer &OB, + const RemoteSymbolLookupSetElement &V) { + return SPSArgList::serialize(OB, V.Name, V.Required); + } + + static size_t deserialize(SPSInputBuffer &IB, + RemoteSymbolLookupSetElement &V) { + return SPSArgList::deserialize(IB, V.Name, V.Required); + } +}; + +template <> +class SPSSerializationTraits { +public: + static size_t size(const RemoteSymbolLookup &V) { + return SPSArgList::size(V.H, V.Symbols); + } + + static size_t serialize(SPSOutputBuffer &OB, const RemoteSymbolLookup &V) { + return SPSArgList::serialize(OB, V.H, + V.Symbols); + } + + static size_t deserialize(SPSInputBuffer &IB, RemoteSymbolLookup &V) { + return SPSArgList::deserialize( + IB, V.H, V.Symbols); + } +}; + +template <> +class SPSSerializationTraits { +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); + +using SPSLoadDylibSignature = + SPSExpected(SPSExecutorAddress, SPSString, uint64_t); + +using SPSLookupSymbolsSignature = + SPSExpected>>( + SPSExecutorAddress, SPSSequence); + +} // end namespace shared +} // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h b/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h new file mode 100644 index 0000000..252474a --- /dev/null +++ b/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h @@ -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 + +namespace llvm { +namespace orc { + +class SimpleRemoteEPC : public ExecutorProcessControl, + public SimpleRemoteEPCTransportClient { +public: + /// Create a SimpleRemoteEPC using the given transport type and args. + template + static Expected> + Create(TransportTCtorArgTs &&...TransportTCtorArgs) { + std::unique_ptr SREPC( + new SimpleRemoteEPC(std::make_shared())); + + // Prepare for setup packet. + std::promise> EIP; + auto EIF = EIP.get_future(); + SREPC->prepareToReceiveSetupMessage(EIP); + auto T = TransportT::Create( + *SREPC, std::forward(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 T, + const SimpleRemoteEPCExecutorInfo &EI); + + Expected loadDylib(const char *DylibPath) override; + + Expected> + lookupSymbols(ArrayRef Request) override; + + Expected runAsMain(JITTargetAddress MainFnAddr, + ArrayRef Args) override; + + void callWrapperAsync(SendResultFunction OnComplete, + JITTargetAddress WrapperFnAddr, + ArrayRef ArgBuffer) override; + + Error disconnect() override; + + Expected + handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, + ExecutorAddress TagAddr, + SimpleRemoteEPCArgBytesVector ArgBytes) override; + + void handleDisconnect(Error Err) override; + +protected: + void setMemoryManager(std::unique_ptr MemMgr); + void setMemoryAccess(std::unique_ptr MemAccess); + +private: + SimpleRemoteEPC(std::shared_ptr 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> &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; + + std::atomic_bool Disconnected{false}; + std::mutex SimpleRemoteEPCMutex; + std::unique_ptr T; + std::unique_ptr OwnedMemMgr; + std::unique_ptr 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 diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h new file mode 100644 index 0000000..121d8d4 --- /dev/null +++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.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 +#include +#include +#include + +namespace llvm { +namespace orc { + +/// A simple EPC server implementation. +class SimpleRemoteEPCServer : public SimpleRemoteEPCTransportClient { +public: + using ReportErrorFunction = unique_function; + + class Dispatcher { + public: + virtual ~Dispatcher(); + virtual void dispatch(unique_function Work) = 0; + virtual void shutdown() = 0; + }; + +#if LLVM_ENABLE_THREADS + class ThreadDispatcher : public Dispatcher { + public: + void dispatch(unique_function Work) override; + void shutdown() override; + + private: + std::mutex DispatchMutex; + bool Running = true; + size_t Outstanding = 0; + std::condition_variable OutstandingCV; + }; +#endif + + static StringMap defaultBootstrapSymbols(); + + template + static Expected> + Create(std::unique_ptr D, + StringMap BootstrapSymbols, + TransportTCtorArgTs &&...TransportTCtorArgs) { + auto SREPCServer = std::make_unique(); + SREPCServer->D = std::move(D); + SREPCServer->ReportError = [](Error Err) { + logAllUnhandledErrors(std::move(Err), errs(), "SimpleRemoteEPCServer "); + }; + auto T = TransportT::Create( + *SREPCServer, std::forward(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 + handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, + ExecutorAddress TagAddr, + SimpleRemoteEPCArgBytesVector ArgBytes) override; + + Error waitForDisconnect(); + + void handleDisconnect(Error Err) override; + +private: + Error sendSetupMessage(StringMap 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 loadDylib(const std::string &Path, + uint64_t Mode); + + Expected>> + lookupSymbols(const std::vector &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 *>; + + std::mutex ServerStateMutex; + std::condition_variable ShutdownCV; + enum { ServerRunning, ServerShuttingDown, ServerShutDown } RunState; + Error ShutdownErr = Error::success(); + std::unique_ptr T; + std::unique_ptr D; + ReportErrorFunction ReportError; + + uint64_t NextSeqNo = 0; + PendingJITDispatchResultsMap PendingJITDispatchResults; + std::vector Dylibs; +}; + +} // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEREMOTEEPCSERVER_H diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt index 982a93c..8e8e0d3 100644 --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -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 diff --git a/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp b/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp index ac6de22..5303b7c 100644 --- a/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp +++ b/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp @@ -86,32 +86,6 @@ private: SegInfoMap Segs; }; -/// Create from a ExecutorProcessControl instance. -Expected> -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(EPC, std::move(FAs)); -} - Expected> EPCGenericJITLinkMemoryManager::allocate(const jitlink::JITLinkDylib *JD, const SegmentsRequestMap &Request) { diff --git a/llvm/lib/ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp b/llvm/lib/ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp deleted file mode 100644 index e4ecd47..0000000 --- a/llvm/lib/ExecutionEngine/Orc/EPCGenericMemoryAccess.cpp +++ /dev/null @@ -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> -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(EPC, std::move(FAs)); -} - -} // end namespace orc -} // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt index dddfda1..7480572 100644 --- a/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt @@ -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 diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp new file mode 100644 index 0000000..a99bfd2e --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp @@ -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 +#else +#include +#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> +FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD, + int OutFD) { +#if LLVM_ENABLE_THREADS + if (InFD == -1) + return make_error("Invalid input file descriptor " + + Twine(InFD), + inconvertibleErrorCode()); + if (OutFD == -1) + return make_error("Invalid output file descriptor " + + Twine(OutFD), + inconvertibleErrorCode()); + std::unique_ptr FDT( + new FDSimpleRemoteEPCTransport(C, InFD, OutFD)); + return FDT; +#else + return make_error("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 ArgBytes) { + char HeaderBuffer[FDMsgHeader::Size]; + + *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::MsgSizeOffset)) = + FDMsgHeader::Size + ArgBytes.size(); + *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::OpCOffset)) = + static_cast(OpC); + *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::SeqNoOffset)) = SeqNo; + *((support::ulittle64_t *)(HeaderBuffer + FDMsgHeader::TagAddrOffset)) = + TagAddr.getValue(); + + std::lock_guard Lock(M); + if (OutFD == -1) + return make_error("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 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("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(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 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(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(static_cast( + *((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("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 diff --git a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp new file mode 100644 index 0000000..d60a6a2 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp @@ -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 { +public: + static size_t size(const SymbolLookupSet::value_type &V) { + return SPSArgList::size( + *V.first, V.second == SymbolLookupFlags::RequiredSymbol); + } + + static bool serialize(SPSOutputBuffer &OB, + const SymbolLookupSet::value_type &V) { + return SPSArgList::serialize( + OB, *V.first, V.second == SymbolLookupFlags::RequiredSymbol); + } +}; + +template <> +class TrivialSPSSequenceSerialization { +public: + static constexpr bool available = true; +}; + +template <> +class SPSSerializationTraits { + using MemberSerialization = + SPSArgList; + +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 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 +SimpleRemoteEPC::loadDylib(const char *DylibPath) { + Expected H((tpctypes::DylibHandle())); + if (auto Err = callSPSWrapper( + LoadDylibAddr.getValue(), H, JDI.JITDispatchContextAddress, + StringRef(DylibPath), (uint64_t)0)) + return std::move(Err); + return H; +} + +Expected> +SimpleRemoteEPC::lookupSymbols(ArrayRef Request) { + Expected> R( + (std::vector())); + + if (auto Err = callSPSWrapper( + LookupSymbolsAddr.getValue(), R, JDI.JITDispatchContextAddress, + Request)) + return std::move(Err); + return R; +} + +Expected SimpleRemoteEPC::runAsMain(JITTargetAddress MainFnAddr, + ArrayRef Args) { + int64_t Result = 0; + if (auto Err = callSPSWrapper( + RunAsMainAddr.getValue(), Result, ExecutorAddress(MainFnAddr), Args)) + return std::move(Err); + return Result; +} + +void SimpleRemoteEPC::callWrapperAsync(SendResultFunction OnComplete, + JITTargetAddress WrapperFnAddr, + ArrayRef ArgBuffer) { + uint64_t SeqNo; + { + std::lock_guard 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 +SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, + ExecutorAddress TagAddr, + SimpleRemoteEPCArgBytesVector ArgBytes) { + using UT = std::underlying_type_t; + if (static_cast(OpC) < static_cast(SimpleRemoteEPCOpcode::FirstOpC) || + static_cast(OpC) > static_cast(SimpleRemoteEPCOpcode::LastOpC)) + return make_error("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 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 MemMgr) { + OwnedMemMgr = std::move(MemMgr); + this->MemMgr = OwnedMemMgr.get(); +} + +void SimpleRemoteEPC::setMemoryAccess(std::unique_ptr 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(*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("Setup packet SeqNo not zero", + inconvertibleErrorCode()); + + if (TagAddr) + return make_error("Setup packet TagAddr not zero", + inconvertibleErrorCode()); + + std::lock_guard 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> &ExecInfoP) { + PendingCallWrapperResults[0] = + [&](shared::WrapperFunctionResult SetupMsgBytes) { + if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) { + ExecInfoP.set_value( + make_error(ErrMsg, inconvertibleErrorCode())); + return; + } + using SPSSerialize = + shared::SPSArgList; + shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size()); + SimpleRemoteEPCExecutorInfo EI; + if (SPSSerialize::deserialize(IB, EI)) + ExecInfoP.set_value(EI); + else + ExecInfoP.set_value(make_error( + "Could not deserialize setup message", inconvertibleErrorCode())); + }; +} + +Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddress TagAddr, + SimpleRemoteEPCArgBytesVector ArgBytes) { + SendResultFunction SendResult; + + if (TagAddr) + return make_error("Unexpected TagAddr in result message", + inconvertibleErrorCode()); + + { + std::lock_guard Lock(SimpleRemoteEPCMutex); + auto I = PendingCallWrapperResults.find(SeqNo); + if (I == PendingCallWrapperResults.end()) + return make_error("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 diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt index b04c09c5..548bf94 100644 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_component_library(LLVMOrcTargetProcess JITLoaderGDB.cpp RegisterEHFrames.cpp + SimpleRemoteEPCServer.cpp TargetExecutionUtils.cpp ADDITIONAL_HEADER_DIRS diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp new file mode 100644 index 0000000..d3180cc --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp @@ -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::handle( + ArgData, ArgSize, + [](uint64_t Size) -> Expected { + 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::handle( + ArgData, ArgSize, + [](const tpctypes::FinalizeRequest &FR) -> Error { + for (auto &Seg : FR) { + char *Mem = Seg.Addr.toPtr(); + 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::max()); + if (auto EC = sys::Memory::protectMappedMemory( + {Mem, static_cast(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::handle( + ArgData, ArgSize, + [](ExecutorAddress Base, uint64_t Size) -> Error { + sys::MemoryBlock MB(Base.toPtr(), Size); + if (auto EC = sys::Memory::releaseMappedMemory(MB)) + return errorCodeToError(EC); + return Error::success(); + }) + .release(); +} + +template +static llvm::orc::shared::detail::CWrapperFunctionResult +writeUIntsWrapper(const char *ArgData, size_t ArgSize) { + return WrapperFunction)>::handle( + ArgData, ArgSize, + [](std::vector Ws) { + for (auto &W : Ws) + *jitTargetAddressToPointer(W.Address) = + W.Value; + }) + .release(); +} + +static llvm::orc::shared::detail::CWrapperFunctionResult +writeBuffersWrapper(const char *ArgData, size_t ArgSize) { + return WrapperFunction)>::handle( + ArgData, ArgSize, + [](std::vector Ws) { + for (auto &W : Ws) + memcpy(jitTargetAddressToPointer(W.Address), + W.Buffer.data(), W.Buffer.size()); + }) + .release(); +} + +static llvm::orc::shared::detail::CWrapperFunctionResult +runAsMainWrapper(const char *ArgData, size_t ArgSize) { + return WrapperFunction::handle( + ArgData, ArgSize, + [](ExecutorAddress MainAddr, + std::vector Args) -> int64_t { + return runAsMain(MainAddr.toPtr(), Args); + }) + .release(); +} + +SimpleRemoteEPCServer::Dispatcher::~Dispatcher() {} + +#if LLVM_ENABLE_THREADS +void SimpleRemoteEPCServer::ThreadDispatcher::dispatch( + unique_function Work) { + { + std::lock_guard Lock(DispatchMutex); + if (!Running) + return; + ++Outstanding; + } + + std::thread([this, Work = std::move(Work)]() mutable { + Work(); + std::lock_guard Lock(DispatchMutex); + --Outstanding; + OutstandingCV.notify_all(); + }).detach(); +} + +void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() { + std::unique_lock Lock(DispatchMutex); + Running = false; + OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; }); +} +#endif + +StringMap SimpleRemoteEPCServer::defaultBootstrapSymbols() { + StringMap 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); + DBS["__llvm_orc_memory_write_uint16s"] = ExecutorAddress::fromPtr( + &writeUIntsWrapper); + DBS["__llvm_orc_memory_write_uint32s"] = ExecutorAddress::fromPtr( + &writeUIntsWrapper); + DBS["__llvm_orc_memory_write_uint64s"] = ExecutorAddress::fromPtr( + &writeUIntsWrapper); + 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 +SimpleRemoteEPCServer::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, + ExecutorAddress TagAddr, + SimpleRemoteEPCArgBytesVector ArgBytes) { + using UT = std::underlying_type_t; + if (static_cast(OpC) < static_cast(SimpleRemoteEPCOpcode::FirstOpC) || + static_cast(OpC) > static_cast(SimpleRemoteEPCOpcode::LastOpC)) + return make_error("Unexpected opcode", + inconvertibleErrorCode()); + + // TODO: Clean detach message? + switch (OpC) { + case SimpleRemoteEPCOpcode::Setup: + return make_error("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 Lock(ServerStateMutex); + ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; }); + return std::move(ShutdownErr); +} + +void SimpleRemoteEPCServer::handleDisconnect(Error Err) { + PendingJITDispatchResultsMap TmpPending; + + { + std::lock_guard 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 Lock(ServerStateMutex); + ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err)); + RunState = ServerShutDown; + ShutdownCV.notify_all(); +} + +Error SimpleRemoteEPCServer::sendSetupMessage( + StringMap BootstrapSymbols) { + + using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames; + + std::vector 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; + auto SetupPacketBytes = + shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI)); + shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size()); + if (!SPSSerialize::serialize(OB, EI)) + return make_error("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 *P = nullptr; + { + std::lock_guard Lock(ServerStateMutex); + auto I = PendingJITDispatchResults.find(SeqNo); + if (I == PendingJITDispatchResults.end()) + return make_error("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(); + 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::handle( + ArgData, ArgSize, + [](ExecutorAddress ExecutorSessionObj, std::string Path, + uint64_t Flags) -> Expected { + return ExecutorSessionObj.toPtr() + ->loadDylib(Path, Flags); + }) + .release(); +} + +shared::detail::CWrapperFunctionResult +SimpleRemoteEPCServer::lookupSymbolsWrapper(const char *ArgData, + size_t ArgSize) { + return shared::WrapperFunction::handle( + ArgData, ArgSize, + [](ExecutorAddress ExecutorSessionObj, + std::vector Lookup) { + return ExecutorSessionObj.toPtr() + ->lookupSymbols(Lookup); + }) + .release(); +} + +Expected +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(std::move(ErrMsg), inconvertibleErrorCode()); + std::lock_guard Lock(ServerStateMutex); + uint64_t Id = Dylibs.size(); + Dylibs.push_back(std::move(DL)); + return Id; +} + +Expected>> +SimpleRemoteEPCServer::lookupSymbols(const std::vector &L) { + std::vector> Result; + + for (const auto &E : L) { + if (E.H >= Dylibs.size()) + return make_error("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(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 ResultP; + auto ResultF = ResultP.get_future(); + { + std::lock_guard 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(DispatchCtx) + ->doJITDispatch(FnTag, ArgData, ArgSize) + .release(); +} + +} // end namespace orc +} // end namespace llvm diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp index 7f197a5..2fb4cb3 100644 --- a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp +++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp @@ -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::registerStringError(); - - shared::FDRawByteChannel C(InFD, OutFD); - JITLinkExecutorEndpoint EP(C, true); - OrcRPCTPCServer Server(EP); - Server.setProgramName(std::string("llvm-jitlink-executor")); - - ExitOnErr(Server.run()); + auto Server = + ExitOnErr(SimpleRemoteEPCServer::Create( + std::make_unique(), + 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 } diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp index dd97baf..2e4b9cf 100644 --- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp @@ -635,8 +635,7 @@ static Error loadDylibs(Session &S) { return Error::success(); } -Expected> -LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor() { +static Expected> launchExecutor() { #ifndef LLVM_ON_UNIX // FIXME: Add support for Windows. return make_error("-" + OutOfProcessExecutor.ArgStr + @@ -644,8 +643,6 @@ LLVMJITLinkRemoteExecutorProcessControl::LaunchExecutor() { inconvertibleErrorCode()); #else - shared::registerStringError(); - 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(); - auto Channel = std::make_unique( + return SimpleRemoteEPC::Create( FromExecutor[ReadEnd], ToExecutor[WriteEnd]); - auto Endpoint = std::make_unique(*Channel, true); - - auto ReportError = [](Error Err) { - logAllUnhandledErrors(std::move(Err), errs(), ""); - }; - - Error Err = Error::success(); - std::unique_ptr 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 connectTCPSocket(std::string Host, std::string PortStr) { } #endif -Expected> -LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor() { +static Expected> connectToExecutor() { #ifndef LLVM_ON_UNIX // FIXME: Add TCP support for Windows. return make_error("-" + OutOfProcessExecutorConnect.ArgStr + @@ -773,8 +753,6 @@ LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor() { inconvertibleErrorCode()); #else - shared::registerStringError(); - 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(); - auto Channel = std::make_unique(*SockFD, *SockFD); - auto Endpoint = std::make_unique(*Channel, true); - - auto ReportError = [](Error Err) { - logAllUnhandledErrors(std::move(Err), errs(), ""); - }; - - Error Err = Error::success(); - std::unique_ptr 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(*SockFD, *SockFD); #endif } -Error LLVMJITLinkRemoteExecutorProcessControl::disconnect() { - std::promise 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> Session::Create(Triple TT) { std::unique_ptr 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(); diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.h b/llvm/tools/llvm-jitlink/llvm-jitlink.h index acb64a9..0a4654a 100644 --- a/llvm/tools/llvm-jitlink/llvm-jitlink.h +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.h @@ -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; -using LLVMJITLinkRemoteMemoryAccess = - orc::OrcRPCEPCMemoryAccess; - -class LLVMJITLinkRemoteExecutorProcessControl - : public orc::OrcRPCExecutorProcessControlBase { -public: - using BaseT = orc::OrcRPCExecutorProcessControlBase; - static Expected> LaunchExecutor(); - - static Expected> ConnectToExecutor(); - - Error disconnect() override; - -private: - using LLVMJITLinkRemoteMemoryAccess = - orc::OrcRPCEPCMemoryAccess; - - using LLVMJITLinkRemoteMemoryManager = orc::OrcRPCEPCJITLinkMemoryManager< - LLVMJITLinkRemoteExecutorProcessControl>; - - LLVMJITLinkRemoteExecutorProcessControl( - std::shared_ptr SSP, - std::unique_ptr Channel, - std::unique_ptr 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(*this); - MemAccess = OwnedMemAccess.get(); - OwnedMemMgr = std::make_unique(*this); - MemMgr = OwnedMemMgr.get(); - } - - std::unique_ptr Channel; - std::unique_ptr Endpoint; - std::unique_ptr OwnedMemAccess; - std::unique_ptr OwnedMemMgr; - std::atomic Finished{false}; - std::thread ListenerThread; -}; - struct Session { orc::ExecutionSession ES; orc::JITDylib *MainJD = nullptr; -- 2.7.4