1bb72f073SLang Hames //===------- SimpleEPCServer.cpp - EPC over simple abstract channel -------===// 2bb72f073SLang Hames // 3bb72f073SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bb72f073SLang Hames // See https://llvm.org/LICENSE.txt for license information. 5bb72f073SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bb72f073SLang Hames // 7bb72f073SLang Hames //===----------------------------------------------------------------------===// 8bb72f073SLang Hames 9bb72f073SLang Hames #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.h" 10bb72f073SLang Hames 11bb72f073SLang Hames #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h" 12bb72f073SLang Hames #include "llvm/Support/FormatVariadic.h" 13bb72f073SLang Hames #include "llvm/Support/Host.h" 14bb72f073SLang Hames #include "llvm/Support/Process.h" 15bb72f073SLang Hames 162c8e7849SLang Hames #include "OrcRTBootstrap.h" 172c8e7849SLang Hames 18bb72f073SLang Hames #define DEBUG_TYPE "orc" 19bb72f073SLang Hames 20bb72f073SLang Hames using namespace llvm::orc::shared; 21bb72f073SLang Hames 22bb72f073SLang Hames namespace llvm { 23bb72f073SLang Hames namespace orc { 24bb72f073SLang Hames 2578b083dbSLang Hames ExecutorBootstrapService::~ExecutorBootstrapService() {} 2678b083dbSLang Hames 27bb72f073SLang Hames SimpleRemoteEPCServer::Dispatcher::~Dispatcher() {} 28bb72f073SLang Hames 29bb72f073SLang Hames #if LLVM_ENABLE_THREADS 30bb72f073SLang Hames void SimpleRemoteEPCServer::ThreadDispatcher::dispatch( 31bb72f073SLang Hames unique_function<void()> Work) { 32bb72f073SLang Hames { 33bb72f073SLang Hames std::lock_guard<std::mutex> Lock(DispatchMutex); 34bb72f073SLang Hames if (!Running) 35bb72f073SLang Hames return; 36bb72f073SLang Hames ++Outstanding; 37bb72f073SLang Hames } 38bb72f073SLang Hames 39bb72f073SLang Hames std::thread([this, Work = std::move(Work)]() mutable { 40bb72f073SLang Hames Work(); 41bb72f073SLang Hames std::lock_guard<std::mutex> Lock(DispatchMutex); 42bb72f073SLang Hames --Outstanding; 43bb72f073SLang Hames OutstandingCV.notify_all(); 44bb72f073SLang Hames }).detach(); 45bb72f073SLang Hames } 46bb72f073SLang Hames 47bb72f073SLang Hames void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() { 48bb72f073SLang Hames std::unique_lock<std::mutex> Lock(DispatchMutex); 49bb72f073SLang Hames Running = false; 50bb72f073SLang Hames OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; }); 51bb72f073SLang Hames } 52bb72f073SLang Hames #endif 53bb72f073SLang Hames 54*ef391df2SLang Hames StringMap<ExecutorAddr> SimpleRemoteEPCServer::defaultBootstrapSymbols() { 55*ef391df2SLang Hames StringMap<ExecutorAddr> DBS; 562c8e7849SLang Hames rt_bootstrap::addTo(DBS); 57bb72f073SLang Hames return DBS; 58bb72f073SLang Hames } 59bb72f073SLang Hames 60bb72f073SLang Hames Expected<SimpleRemoteEPCTransportClient::HandleMessageAction> 61bb72f073SLang Hames SimpleRemoteEPCServer::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, 62*ef391df2SLang Hames ExecutorAddr TagAddr, 63bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes) { 64bb72f073SLang Hames using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>; 65d11a0c5dSLang Hames if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC)) 66bb72f073SLang Hames return make_error<StringError>("Unexpected opcode", 67bb72f073SLang Hames inconvertibleErrorCode()); 68bb72f073SLang Hames 69bb72f073SLang Hames // TODO: Clean detach message? 70bb72f073SLang Hames switch (OpC) { 71bb72f073SLang Hames case SimpleRemoteEPCOpcode::Setup: 72bb72f073SLang Hames return make_error<StringError>("Unexpected Setup opcode", 73bb72f073SLang Hames inconvertibleErrorCode()); 74bb72f073SLang Hames case SimpleRemoteEPCOpcode::Hangup: 75bb72f073SLang Hames return SimpleRemoteEPCTransportClient::EndSession; 76bb72f073SLang Hames case SimpleRemoteEPCOpcode::Result: 77bb72f073SLang Hames if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes))) 78bb72f073SLang Hames return std::move(Err); 79bb72f073SLang Hames break; 80bb72f073SLang Hames case SimpleRemoteEPCOpcode::CallWrapper: 81bb72f073SLang Hames handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes)); 82bb72f073SLang Hames break; 83bb72f073SLang Hames } 84bb72f073SLang Hames return ContinueSession; 85bb72f073SLang Hames } 86bb72f073SLang Hames 87bb72f073SLang Hames Error SimpleRemoteEPCServer::waitForDisconnect() { 88bb72f073SLang Hames std::unique_lock<std::mutex> Lock(ServerStateMutex); 89bb72f073SLang Hames ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; }); 90bb72f073SLang Hames return std::move(ShutdownErr); 91bb72f073SLang Hames } 92bb72f073SLang Hames 93bb72f073SLang Hames void SimpleRemoteEPCServer::handleDisconnect(Error Err) { 94bb72f073SLang Hames PendingJITDispatchResultsMap TmpPending; 95bb72f073SLang Hames 96bb72f073SLang Hames { 97bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex); 98bb72f073SLang Hames std::swap(TmpPending, PendingJITDispatchResults); 99bb72f073SLang Hames RunState = ServerShuttingDown; 100bb72f073SLang Hames } 101bb72f073SLang Hames 102bb72f073SLang Hames // Send out-of-band errors to any waiting threads. 103bb72f073SLang Hames for (auto &KV : TmpPending) 104bb72f073SLang Hames KV.second->set_value( 105bb72f073SLang Hames shared::WrapperFunctionResult::createOutOfBandError("disconnecting")); 106bb72f073SLang Hames 107bb72f073SLang Hames // TODO: Free attached resources. 108bb72f073SLang Hames // 1. Close libraries in DylibHandles. 109bb72f073SLang Hames 110bb72f073SLang Hames // Wait for dispatcher to clear. 111bb72f073SLang Hames D->shutdown(); 112bb72f073SLang Hames 113c965fde7SLang Hames // Shut down services. 114c965fde7SLang Hames while (!Services.empty()) { 115c965fde7SLang Hames ShutdownErr = 116c965fde7SLang Hames joinErrors(std::move(ShutdownErr), Services.back()->shutdown()); 117c965fde7SLang Hames Services.pop_back(); 118c965fde7SLang Hames } 119c965fde7SLang Hames 120bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex); 121bb72f073SLang Hames ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err)); 122bb72f073SLang Hames RunState = ServerShutDown; 123bb72f073SLang Hames ShutdownCV.notify_all(); 124bb72f073SLang Hames } 125bb72f073SLang Hames 126bb72f073SLang Hames Error SimpleRemoteEPCServer::sendSetupMessage( 127*ef391df2SLang Hames StringMap<ExecutorAddr> BootstrapSymbols) { 128bb72f073SLang Hames 129bb72f073SLang Hames using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames; 130bb72f073SLang Hames 131bb72f073SLang Hames std::vector<char> SetupPacket; 132bb72f073SLang Hames SimpleRemoteEPCExecutorInfo EI; 133bb72f073SLang Hames EI.TargetTriple = sys::getProcessTriple(); 134bb72f073SLang Hames if (auto PageSize = sys::Process::getPageSize()) 135bb72f073SLang Hames EI.PageSize = *PageSize; 136bb72f073SLang Hames else 137bb72f073SLang Hames return PageSize.takeError(); 138bb72f073SLang Hames EI.BootstrapSymbols = std::move(BootstrapSymbols); 139bb72f073SLang Hames 140bb72f073SLang Hames assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) && 141bb72f073SLang Hames "Dispatch context name should not be set"); 142bb72f073SLang Hames assert(!EI.BootstrapSymbols.count(DispatchFnName) && 143bb72f073SLang Hames "Dispatch function name should not be set"); 144*ef391df2SLang Hames EI.BootstrapSymbols[ExecutorSessionObjectName] = ExecutorAddr::fromPtr(this); 145*ef391df2SLang Hames EI.BootstrapSymbols[DispatchFnName] = ExecutorAddr::fromPtr(jitDispatchEntry); 146bb72f073SLang Hames 147bb72f073SLang Hames using SPSSerialize = 148bb72f073SLang Hames shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>; 149bb72f073SLang Hames auto SetupPacketBytes = 150bb72f073SLang Hames shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI)); 151bb72f073SLang Hames shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size()); 152bb72f073SLang Hames if (!SPSSerialize::serialize(OB, EI)) 153bb72f073SLang Hames return make_error<StringError>("Could not send setup packet", 154bb72f073SLang Hames inconvertibleErrorCode()); 155bb72f073SLang Hames 156*ef391df2SLang Hames return T->sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddr(), 157bb72f073SLang Hames {SetupPacketBytes.data(), SetupPacketBytes.size()}); 158bb72f073SLang Hames } 159bb72f073SLang Hames 160bb72f073SLang Hames Error SimpleRemoteEPCServer::handleResult( 161*ef391df2SLang Hames uint64_t SeqNo, ExecutorAddr TagAddr, 162bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes) { 163bb72f073SLang Hames std::promise<shared::WrapperFunctionResult> *P = nullptr; 164bb72f073SLang Hames { 165bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex); 166bb72f073SLang Hames auto I = PendingJITDispatchResults.find(SeqNo); 167bb72f073SLang Hames if (I == PendingJITDispatchResults.end()) 168bb72f073SLang Hames return make_error<StringError>("No call for sequence number " + 169bb72f073SLang Hames Twine(SeqNo), 170bb72f073SLang Hames inconvertibleErrorCode()); 171bb72f073SLang Hames P = I->second; 172bb72f073SLang Hames PendingJITDispatchResults.erase(I); 173bb72f073SLang Hames releaseSeqNo(SeqNo); 174bb72f073SLang Hames } 175bb72f073SLang Hames auto R = shared::WrapperFunctionResult::allocate(ArgBytes.size()); 176bb72f073SLang Hames memcpy(R.data(), ArgBytes.data(), ArgBytes.size()); 177bb72f073SLang Hames P->set_value(std::move(R)); 178bb72f073SLang Hames return Error::success(); 179bb72f073SLang Hames } 180bb72f073SLang Hames 181bb72f073SLang Hames void SimpleRemoteEPCServer::handleCallWrapper( 182*ef391df2SLang Hames uint64_t RemoteSeqNo, ExecutorAddr TagAddr, 183bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes) { 184bb72f073SLang Hames D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() { 185bb72f073SLang Hames using WrapperFnTy = 186bb72f073SLang Hames shared::detail::CWrapperFunctionResult (*)(const char *, size_t); 187bb72f073SLang Hames auto *Fn = TagAddr.toPtr<WrapperFnTy>(); 188bb72f073SLang Hames shared::WrapperFunctionResult ResultBytes( 189bb72f073SLang Hames Fn(ArgBytes.data(), ArgBytes.size())); 190bb72f073SLang Hames if (auto Err = T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo, 191*ef391df2SLang Hames ExecutorAddr(), 192bb72f073SLang Hames {ResultBytes.data(), ResultBytes.size()})) 193bb72f073SLang Hames ReportError(std::move(Err)); 194bb72f073SLang Hames }); 195bb72f073SLang Hames } 196bb72f073SLang Hames 197bb72f073SLang Hames shared::WrapperFunctionResult 198bb72f073SLang Hames SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData, 199bb72f073SLang Hames size_t ArgSize) { 200bb72f073SLang Hames uint64_t SeqNo; 201bb72f073SLang Hames std::promise<shared::WrapperFunctionResult> ResultP; 202bb72f073SLang Hames auto ResultF = ResultP.get_future(); 203bb72f073SLang Hames { 204bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex); 205bb72f073SLang Hames if (RunState != ServerRunning) 206bb72f073SLang Hames return shared::WrapperFunctionResult::createOutOfBandError( 207bb72f073SLang Hames "jit_dispatch not available (EPC server shut down)"); 208bb72f073SLang Hames 209bb72f073SLang Hames SeqNo = getNextSeqNo(); 210bb72f073SLang Hames assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use"); 211bb72f073SLang Hames PendingJITDispatchResults[SeqNo] = &ResultP; 212bb72f073SLang Hames } 213bb72f073SLang Hames 214bb72f073SLang Hames if (auto Err = 215bb72f073SLang Hames T->sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo, 216*ef391df2SLang Hames ExecutorAddr::fromPtr(FnTag), {ArgData, ArgSize})) 217bb72f073SLang Hames ReportError(std::move(Err)); 218bb72f073SLang Hames 219bb72f073SLang Hames return ResultF.get(); 220bb72f073SLang Hames } 221bb72f073SLang Hames 222bb72f073SLang Hames shared::detail::CWrapperFunctionResult 223bb72f073SLang Hames SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag, 224bb72f073SLang Hames const char *ArgData, size_t ArgSize) { 225bb72f073SLang Hames return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx) 226bb72f073SLang Hames ->doJITDispatch(FnTag, ArgData, ArgSize) 227bb72f073SLang Hames .release(); 228bb72f073SLang Hames } 229bb72f073SLang Hames 230bb72f073SLang Hames } // end namespace orc 231bb72f073SLang Hames } // end namespace llvm 232