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 11*122ebe3bSLang Hames #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 12*122ebe3bSLang Hames #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" 13bb72f073SLang Hames #include "llvm/Support/FormatVariadic.h" 14bb72f073SLang Hames #include "llvm/Support/Process.h" 15d768bf99SArchibald Elliott #include "llvm/TargetParser/Host.h" 16bb72f073SLang Hames 172c8e7849SLang Hames #include "OrcRTBootstrap.h" 182c8e7849SLang Hames 19bb72f073SLang Hames #define DEBUG_TYPE "orc" 20bb72f073SLang Hames 21bb72f073SLang Hames using namespace llvm::orc::shared; 22bb72f073SLang Hames 23bb72f073SLang Hames namespace llvm { 24bb72f073SLang Hames namespace orc { 25bb72f073SLang Hames 263a3cb929SKazu Hirata ExecutorBootstrapService::~ExecutorBootstrapService() = default; 2778b083dbSLang Hames 283a3cb929SKazu Hirata SimpleRemoteEPCServer::Dispatcher::~Dispatcher() = default; 298fe3d9dfSLang Hames 308fe3d9dfSLang Hames #if LLVM_ENABLE_THREADS 318fe3d9dfSLang Hames void SimpleRemoteEPCServer::ThreadDispatcher::dispatch( 328fe3d9dfSLang Hames unique_function<void()> Work) { 338fe3d9dfSLang Hames { 348fe3d9dfSLang Hames std::lock_guard<std::mutex> Lock(DispatchMutex); 358fe3d9dfSLang Hames if (!Running) 368fe3d9dfSLang Hames return; 378fe3d9dfSLang Hames ++Outstanding; 388fe3d9dfSLang Hames } 398fe3d9dfSLang Hames 408fe3d9dfSLang Hames std::thread([this, Work = std::move(Work)]() mutable { 418fe3d9dfSLang Hames Work(); 428fe3d9dfSLang Hames std::lock_guard<std::mutex> Lock(DispatchMutex); 438fe3d9dfSLang Hames --Outstanding; 448fe3d9dfSLang Hames OutstandingCV.notify_all(); 458fe3d9dfSLang Hames }).detach(); 468fe3d9dfSLang Hames } 478fe3d9dfSLang Hames 488fe3d9dfSLang Hames void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() { 498fe3d9dfSLang Hames std::unique_lock<std::mutex> Lock(DispatchMutex); 508fe3d9dfSLang Hames Running = false; 518fe3d9dfSLang Hames OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; }); 528fe3d9dfSLang Hames } 538fe3d9dfSLang Hames #endif 548fe3d9dfSLang Hames 55ef391df2SLang Hames StringMap<ExecutorAddr> SimpleRemoteEPCServer::defaultBootstrapSymbols() { 56ef391df2SLang Hames StringMap<ExecutorAddr> DBS; 572c8e7849SLang Hames rt_bootstrap::addTo(DBS); 58bb72f073SLang Hames return DBS; 59bb72f073SLang Hames } 60bb72f073SLang Hames 61bb72f073SLang Hames Expected<SimpleRemoteEPCTransportClient::HandleMessageAction> 62bb72f073SLang Hames SimpleRemoteEPCServer::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, 63ef391df2SLang Hames ExecutorAddr TagAddr, 64bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes) { 65175c1a39SLang Hames 66175c1a39SLang Hames LLVM_DEBUG({ 67175c1a39SLang Hames dbgs() << "SimpleRemoteEPCServer::handleMessage: opc = "; 68175c1a39SLang Hames switch (OpC) { 69175c1a39SLang Hames case SimpleRemoteEPCOpcode::Setup: 70175c1a39SLang Hames dbgs() << "Setup"; 71175c1a39SLang Hames assert(SeqNo == 0 && "Non-zero SeqNo for Setup?"); 72fdd9df19SLang Hames assert(!TagAddr && "Non-zero TagAddr for Setup?"); 73175c1a39SLang Hames break; 74175c1a39SLang Hames case SimpleRemoteEPCOpcode::Hangup: 75175c1a39SLang Hames dbgs() << "Hangup"; 76175c1a39SLang Hames assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?"); 77fdd9df19SLang Hames assert(!TagAddr && "Non-zero TagAddr for Hangup?"); 78175c1a39SLang Hames break; 79175c1a39SLang Hames case SimpleRemoteEPCOpcode::Result: 80175c1a39SLang Hames dbgs() << "Result"; 81fdd9df19SLang Hames assert(!TagAddr && "Non-zero TagAddr for Result?"); 82175c1a39SLang Hames break; 83175c1a39SLang Hames case SimpleRemoteEPCOpcode::CallWrapper: 84175c1a39SLang Hames dbgs() << "CallWrapper"; 85175c1a39SLang Hames break; 86175c1a39SLang Hames } 87fdd9df19SLang Hames dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr 88175c1a39SLang Hames << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size()) 89175c1a39SLang Hames << " bytes\n"; 90175c1a39SLang Hames }); 91175c1a39SLang Hames 92bb72f073SLang Hames using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>; 93d11a0c5dSLang Hames if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC)) 94bb72f073SLang Hames return make_error<StringError>("Unexpected opcode", 95bb72f073SLang Hames inconvertibleErrorCode()); 96bb72f073SLang Hames 97bb72f073SLang Hames // TODO: Clean detach message? 98bb72f073SLang Hames switch (OpC) { 99bb72f073SLang Hames case SimpleRemoteEPCOpcode::Setup: 100bb72f073SLang Hames return make_error<StringError>("Unexpected Setup opcode", 101bb72f073SLang Hames inconvertibleErrorCode()); 102bb72f073SLang Hames case SimpleRemoteEPCOpcode::Hangup: 103bb72f073SLang Hames return SimpleRemoteEPCTransportClient::EndSession; 104bb72f073SLang Hames case SimpleRemoteEPCOpcode::Result: 105bb72f073SLang Hames if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes))) 106bb72f073SLang Hames return std::move(Err); 107bb72f073SLang Hames break; 108bb72f073SLang Hames case SimpleRemoteEPCOpcode::CallWrapper: 109bb72f073SLang Hames handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes)); 110bb72f073SLang Hames break; 111bb72f073SLang Hames } 112bb72f073SLang Hames return ContinueSession; 113bb72f073SLang Hames } 114bb72f073SLang Hames 115bb72f073SLang Hames Error SimpleRemoteEPCServer::waitForDisconnect() { 116bb72f073SLang Hames std::unique_lock<std::mutex> Lock(ServerStateMutex); 117bb72f073SLang Hames ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; }); 118bb72f073SLang Hames return std::move(ShutdownErr); 119bb72f073SLang Hames } 120bb72f073SLang Hames 121bb72f073SLang Hames void SimpleRemoteEPCServer::handleDisconnect(Error Err) { 122bb72f073SLang Hames PendingJITDispatchResultsMap TmpPending; 123bb72f073SLang Hames 124bb72f073SLang Hames { 125bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex); 126bb72f073SLang Hames std::swap(TmpPending, PendingJITDispatchResults); 127bb72f073SLang Hames RunState = ServerShuttingDown; 128bb72f073SLang Hames } 129bb72f073SLang Hames 130bb72f073SLang Hames // Send out-of-band errors to any waiting threads. 131bb72f073SLang Hames for (auto &KV : TmpPending) 132bb72f073SLang Hames KV.second->set_value( 133bb72f073SLang Hames shared::WrapperFunctionResult::createOutOfBandError("disconnecting")); 134bb72f073SLang Hames 135bb72f073SLang Hames // Wait for dispatcher to clear. 136bb72f073SLang Hames D->shutdown(); 137bb72f073SLang Hames 138c965fde7SLang Hames // Shut down services. 139c965fde7SLang Hames while (!Services.empty()) { 140c965fde7SLang Hames ShutdownErr = 141c965fde7SLang Hames joinErrors(std::move(ShutdownErr), Services.back()->shutdown()); 142c965fde7SLang Hames Services.pop_back(); 143c965fde7SLang Hames } 144c965fde7SLang Hames 145bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex); 146bb72f073SLang Hames ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err)); 147bb72f073SLang Hames RunState = ServerShutDown; 148bb72f073SLang Hames ShutdownCV.notify_all(); 149bb72f073SLang Hames } 150bb72f073SLang Hames 151175c1a39SLang Hames Error SimpleRemoteEPCServer::sendMessage(SimpleRemoteEPCOpcode OpC, 152175c1a39SLang Hames uint64_t SeqNo, ExecutorAddr TagAddr, 153175c1a39SLang Hames ArrayRef<char> ArgBytes) { 154175c1a39SLang Hames 155175c1a39SLang Hames LLVM_DEBUG({ 156175c1a39SLang Hames dbgs() << "SimpleRemoteEPCServer::sendMessage: opc = "; 157175c1a39SLang Hames switch (OpC) { 158175c1a39SLang Hames case SimpleRemoteEPCOpcode::Setup: 159175c1a39SLang Hames dbgs() << "Setup"; 160175c1a39SLang Hames assert(SeqNo == 0 && "Non-zero SeqNo for Setup?"); 161fdd9df19SLang Hames assert(!TagAddr && "Non-zero TagAddr for Setup?"); 162175c1a39SLang Hames break; 163175c1a39SLang Hames case SimpleRemoteEPCOpcode::Hangup: 164175c1a39SLang Hames dbgs() << "Hangup"; 165175c1a39SLang Hames assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?"); 166fdd9df19SLang Hames assert(!TagAddr && "Non-zero TagAddr for Hangup?"); 167175c1a39SLang Hames break; 168175c1a39SLang Hames case SimpleRemoteEPCOpcode::Result: 169175c1a39SLang Hames dbgs() << "Result"; 170fdd9df19SLang Hames assert(!TagAddr && "Non-zero TagAddr for Result?"); 171175c1a39SLang Hames break; 172175c1a39SLang Hames case SimpleRemoteEPCOpcode::CallWrapper: 173175c1a39SLang Hames dbgs() << "CallWrapper"; 174175c1a39SLang Hames break; 175175c1a39SLang Hames } 176fdd9df19SLang Hames dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr 177175c1a39SLang Hames << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size()) 178175c1a39SLang Hames << " bytes\n"; 179175c1a39SLang Hames }); 180175c1a39SLang Hames auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes); 181175c1a39SLang Hames LLVM_DEBUG({ 182175c1a39SLang Hames if (Err) 183175c1a39SLang Hames dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n"; 184175c1a39SLang Hames }); 185175c1a39SLang Hames return Err; 186175c1a39SLang Hames } 187175c1a39SLang Hames 188bb72f073SLang Hames Error SimpleRemoteEPCServer::sendSetupMessage( 189060319a2SLang Hames StringMap<std::vector<char>> BootstrapMap, 190ef391df2SLang Hames StringMap<ExecutorAddr> BootstrapSymbols) { 191bb72f073SLang Hames 192bb72f073SLang Hames using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames; 193bb72f073SLang Hames 194bb72f073SLang Hames std::vector<char> SetupPacket; 195bb72f073SLang Hames SimpleRemoteEPCExecutorInfo EI; 196bb72f073SLang Hames EI.TargetTriple = sys::getProcessTriple(); 197bb72f073SLang Hames if (auto PageSize = sys::Process::getPageSize()) 198bb72f073SLang Hames EI.PageSize = *PageSize; 199bb72f073SLang Hames else 200bb72f073SLang Hames return PageSize.takeError(); 201060319a2SLang Hames EI.BootstrapMap = std::move(BootstrapMap); 202bb72f073SLang Hames EI.BootstrapSymbols = std::move(BootstrapSymbols); 203bb72f073SLang Hames 204bb72f073SLang Hames assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) && 205bb72f073SLang Hames "Dispatch context name should not be set"); 206bb72f073SLang Hames assert(!EI.BootstrapSymbols.count(DispatchFnName) && 207bb72f073SLang Hames "Dispatch function name should not be set"); 208ef391df2SLang Hames EI.BootstrapSymbols[ExecutorSessionObjectName] = ExecutorAddr::fromPtr(this); 209ef391df2SLang Hames EI.BootstrapSymbols[DispatchFnName] = ExecutorAddr::fromPtr(jitDispatchEntry); 210*122ebe3bSLang Hames EI.BootstrapSymbols[rt::RegisterEHFrameSectionWrapperName] = 211*122ebe3bSLang Hames ExecutorAddr::fromPtr(&llvm_orc_registerEHFrameSectionWrapper); 212*122ebe3bSLang Hames EI.BootstrapSymbols[rt::DeregisterEHFrameSectionWrapperName] = 213*122ebe3bSLang Hames ExecutorAddr::fromPtr(&llvm_orc_deregisterEHFrameSectionWrapper); 214bb72f073SLang Hames 215bb72f073SLang Hames using SPSSerialize = 216bb72f073SLang Hames shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>; 217bb72f073SLang Hames auto SetupPacketBytes = 218bb72f073SLang Hames shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI)); 219bb72f073SLang Hames shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size()); 220bb72f073SLang Hames if (!SPSSerialize::serialize(OB, EI)) 221bb72f073SLang Hames return make_error<StringError>("Could not send setup packet", 222bb72f073SLang Hames inconvertibleErrorCode()); 223bb72f073SLang Hames 224175c1a39SLang Hames return sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddr(), 225bb72f073SLang Hames {SetupPacketBytes.data(), SetupPacketBytes.size()}); 226bb72f073SLang Hames } 227bb72f073SLang Hames 228bb72f073SLang Hames Error SimpleRemoteEPCServer::handleResult( 229ef391df2SLang Hames uint64_t SeqNo, ExecutorAddr TagAddr, 230bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes) { 231bb72f073SLang Hames std::promise<shared::WrapperFunctionResult> *P = nullptr; 232bb72f073SLang Hames { 233bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex); 234bb72f073SLang Hames auto I = PendingJITDispatchResults.find(SeqNo); 235bb72f073SLang Hames if (I == PendingJITDispatchResults.end()) 236bb72f073SLang Hames return make_error<StringError>("No call for sequence number " + 237bb72f073SLang Hames Twine(SeqNo), 238bb72f073SLang Hames inconvertibleErrorCode()); 239bb72f073SLang Hames P = I->second; 240bb72f073SLang Hames PendingJITDispatchResults.erase(I); 241bb72f073SLang Hames releaseSeqNo(SeqNo); 242bb72f073SLang Hames } 243bb72f073SLang Hames auto R = shared::WrapperFunctionResult::allocate(ArgBytes.size()); 244bb72f073SLang Hames memcpy(R.data(), ArgBytes.data(), ArgBytes.size()); 245bb72f073SLang Hames P->set_value(std::move(R)); 246bb72f073SLang Hames return Error::success(); 247bb72f073SLang Hames } 248bb72f073SLang Hames 249bb72f073SLang Hames void SimpleRemoteEPCServer::handleCallWrapper( 250ef391df2SLang Hames uint64_t RemoteSeqNo, ExecutorAddr TagAddr, 251bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes) { 252bb72f073SLang Hames D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() { 253bb72f073SLang Hames using WrapperFnTy = 254213666f8SLang Hames shared::CWrapperFunctionResult (*)(const char *, size_t); 255bb72f073SLang Hames auto *Fn = TagAddr.toPtr<WrapperFnTy>(); 256bb72f073SLang Hames shared::WrapperFunctionResult ResultBytes( 257bb72f073SLang Hames Fn(ArgBytes.data(), ArgBytes.size())); 258175c1a39SLang Hames if (auto Err = sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo, 259ef391df2SLang Hames ExecutorAddr(), 260bb72f073SLang Hames {ResultBytes.data(), ResultBytes.size()})) 261bb72f073SLang Hames ReportError(std::move(Err)); 262bb72f073SLang Hames }); 263bb72f073SLang Hames } 264bb72f073SLang Hames 265bb72f073SLang Hames shared::WrapperFunctionResult 266bb72f073SLang Hames SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData, 267bb72f073SLang Hames size_t ArgSize) { 268bb72f073SLang Hames uint64_t SeqNo; 269bb72f073SLang Hames std::promise<shared::WrapperFunctionResult> ResultP; 270bb72f073SLang Hames auto ResultF = ResultP.get_future(); 271bb72f073SLang Hames { 272bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex); 273bb72f073SLang Hames if (RunState != ServerRunning) 274bb72f073SLang Hames return shared::WrapperFunctionResult::createOutOfBandError( 275bb72f073SLang Hames "jit_dispatch not available (EPC server shut down)"); 276bb72f073SLang Hames 277bb72f073SLang Hames SeqNo = getNextSeqNo(); 278bb72f073SLang Hames assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use"); 279bb72f073SLang Hames PendingJITDispatchResults[SeqNo] = &ResultP; 280bb72f073SLang Hames } 281bb72f073SLang Hames 282175c1a39SLang Hames if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo, 283ef391df2SLang Hames ExecutorAddr::fromPtr(FnTag), {ArgData, ArgSize})) 284bb72f073SLang Hames ReportError(std::move(Err)); 285bb72f073SLang Hames 286bb72f073SLang Hames return ResultF.get(); 287bb72f073SLang Hames } 288bb72f073SLang Hames 289213666f8SLang Hames shared::CWrapperFunctionResult 290bb72f073SLang Hames SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag, 291bb72f073SLang Hames const char *ArgData, size_t ArgSize) { 292bb72f073SLang Hames return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx) 293bb72f073SLang Hames ->doJITDispatch(FnTag, ArgData, ArgSize) 294bb72f073SLang Hames .release(); 295bb72f073SLang Hames } 296bb72f073SLang Hames 297bb72f073SLang Hames } // end namespace orc 298bb72f073SLang Hames } // end namespace llvm 299