summaryrefslogtreecommitdiff
path: root/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp
diff options
context:
space:
mode:
authorLang Hames <lhames@gmail.com>2021-09-11 19:07:16 +1000
committerLang Hames <lhames@gmail.com>2021-09-12 14:23:22 +1000
commitbb72f073808a42e35ddc52cb0810470ffeb3cce3 (patch)
tree80bab82798f21b53379e0b4e8e5ff48b724d27e5 /llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp
parent15e9575fb5988a66aa6e57a55818b54b575dd795 (diff)
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.
Diffstat (limited to 'llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp')
-rw-r--r--llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp404
1 files changed, 404 insertions, 0 deletions
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp
new file mode 100644
index 000000000000..d3180ccf1ae3
--- /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<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