461 lines · cpp
1//===------- SimpleRemoteEPC.cpp -- Simple remote executor control --------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"10#include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"11#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"12#include "llvm/Support/FormatVariadic.h"13 14#define DEBUG_TYPE "orc"15 16namespace llvm {17namespace orc {18 19SimpleRemoteEPC::~SimpleRemoteEPC() {20#ifndef NDEBUG21 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);22 assert(Disconnected && "Destroyed without disconnection");23#endif // NDEBUG24}25 26Expected<tpctypes::DylibHandle>27SimpleRemoteEPC::loadDylib(const char *DylibPath) {28 return EPCDylibMgr->open(DylibPath, 0);29}30 31/// Async helper to chain together calls to DylibMgr::lookupAsync to fulfill all32/// all the requests.33/// FIXME: The dylib manager should support multiple LookupRequests natively.34static void35lookupSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr,36 ArrayRef<DylibManager::LookupRequest> Request,37 std::vector<tpctypes::LookupResult> Result,38 DylibManager::SymbolLookupCompleteFn Complete) {39 if (Request.empty())40 return Complete(std::move(Result));41 42 auto &Element = Request.front();43 DylibMgr.lookupAsync(Element.Handle, Element.Symbols,44 [&DylibMgr, Request, Complete = std::move(Complete),45 Result = std::move(Result)](auto R) mutable {46 if (!R)47 return Complete(R.takeError());48 Result.push_back({});49 Result.back().reserve(R->size());50 llvm::append_range(Result.back(), *R);51 52 lookupSymbolsAsyncHelper(53 DylibMgr, Request.drop_front(), std::move(Result),54 std::move(Complete));55 });56}57 58void SimpleRemoteEPC::lookupSymbolsAsync(ArrayRef<LookupRequest> Request,59 SymbolLookupCompleteFn Complete) {60 lookupSymbolsAsyncHelper(*EPCDylibMgr, Request, {}, std::move(Complete));61}62 63Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr,64 ArrayRef<std::string> Args) {65 int64_t Result = 0;66 if (auto Err = callSPSWrapper<rt::SPSRunAsMainSignature>(67 RunAsMainAddr, Result, MainFnAddr, Args))68 return std::move(Err);69 return Result;70}71 72Expected<int32_t> SimpleRemoteEPC::runAsVoidFunction(ExecutorAddr VoidFnAddr) {73 int32_t Result = 0;74 if (auto Err = callSPSWrapper<rt::SPSRunAsVoidFunctionSignature>(75 RunAsVoidFunctionAddr, Result, VoidFnAddr))76 return std::move(Err);77 return Result;78}79 80Expected<int32_t> SimpleRemoteEPC::runAsIntFunction(ExecutorAddr IntFnAddr,81 int Arg) {82 int32_t Result = 0;83 if (auto Err = callSPSWrapper<rt::SPSRunAsIntFunctionSignature>(84 RunAsIntFunctionAddr, Result, IntFnAddr, Arg))85 return std::move(Err);86 return Result;87}88 89void SimpleRemoteEPC::callWrapperAsync(ExecutorAddr WrapperFnAddr,90 IncomingWFRHandler OnComplete,91 ArrayRef<char> ArgBuffer) {92 uint64_t SeqNo;93 {94 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);95 SeqNo = getNextSeqNo();96 assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");97 PendingCallWrapperResults[SeqNo] = std::move(OnComplete);98 }99 100 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,101 WrapperFnAddr, ArgBuffer)) {102 IncomingWFRHandler H;103 104 // We just registered OnComplete, but there may be a race between this105 // thread returning from sendMessage and handleDisconnect being called from106 // the transport's listener thread. If handleDisconnect gets there first107 // then it will have failed 'H' for us. If we get there first (or if108 // handleDisconnect already ran) then we need to take care of it.109 {110 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);111 auto I = PendingCallWrapperResults.find(SeqNo);112 if (I != PendingCallWrapperResults.end()) {113 H = std::move(I->second);114 PendingCallWrapperResults.erase(I);115 }116 }117 118 if (H)119 H(shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));120 121 getExecutionSession().reportError(std::move(Err));122 }123}124 125Error SimpleRemoteEPC::disconnect() {126 T->disconnect();127 D->shutdown();128 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);129 DisconnectCV.wait(Lock, [this] { return Disconnected; });130 return std::move(DisconnectErr);131}132 133Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>134SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,135 ExecutorAddr TagAddr,136 SimpleRemoteEPCArgBytesVector ArgBytes) {137 138 LLVM_DEBUG({139 dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";140 switch (OpC) {141 case SimpleRemoteEPCOpcode::Setup:142 dbgs() << "Setup";143 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");144 assert(!TagAddr && "Non-zero TagAddr for Setup?");145 break;146 case SimpleRemoteEPCOpcode::Hangup:147 dbgs() << "Hangup";148 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");149 assert(!TagAddr && "Non-zero TagAddr for Hangup?");150 break;151 case SimpleRemoteEPCOpcode::Result:152 dbgs() << "Result";153 assert(!TagAddr && "Non-zero TagAddr for Result?");154 break;155 case SimpleRemoteEPCOpcode::CallWrapper:156 dbgs() << "CallWrapper";157 break;158 }159 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr160 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())161 << " bytes\n";162 });163 164 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;165 if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))166 return make_error<StringError>("Unexpected opcode",167 inconvertibleErrorCode());168 169 switch (OpC) {170 case SimpleRemoteEPCOpcode::Setup:171 if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))172 return std::move(Err);173 break;174 case SimpleRemoteEPCOpcode::Hangup:175 T->disconnect();176 if (auto Err = handleHangup(std::move(ArgBytes)))177 return std::move(Err);178 return EndSession;179 case SimpleRemoteEPCOpcode::Result:180 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))181 return std::move(Err);182 break;183 case SimpleRemoteEPCOpcode::CallWrapper:184 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));185 break;186 }187 return ContinueSession;188}189 190void SimpleRemoteEPC::handleDisconnect(Error Err) {191 LLVM_DEBUG({192 dbgs() << "SimpleRemoteEPC::handleDisconnect: "193 << (Err ? "failure" : "success") << "\n";194 });195 196 PendingCallWrapperResultsMap TmpPending;197 198 {199 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);200 std::swap(TmpPending, PendingCallWrapperResults);201 }202 203 for (auto &KV : TmpPending)204 KV.second(205 shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));206 207 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);208 DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));209 Disconnected = true;210 DisconnectCV.notify_all();211}212 213Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>214SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC &SREPC) {215 EPCGenericJITLinkMemoryManager::SymbolAddrs SAs;216 if (auto Err = SREPC.getBootstrapSymbols(217 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},218 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},219 {SAs.Initialize,220 rt::SimpleExecutorMemoryManagerInitializeWrapperName},221 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))222 return std::move(Err);223 224 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);225}226 227Expected<std::unique_ptr<MemoryAccess>>228SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC &SREPC) {229 EPCGenericMemoryAccess::FuncAddrs FAs;230 if (auto Err = SREPC.getBootstrapSymbols(231 {{FAs.WriteUInt8s, rt::MemoryWriteUInt8sWrapperName},232 {FAs.WriteUInt16s, rt::MemoryWriteUInt16sWrapperName},233 {FAs.WriteUInt32s, rt::MemoryWriteUInt32sWrapperName},234 {FAs.WriteUInt64s, rt::MemoryWriteUInt64sWrapperName},235 {FAs.WriteBuffers, rt::MemoryWriteBuffersWrapperName},236 {FAs.WritePointers, rt::MemoryWritePointersWrapperName},237 {FAs.ReadUInt8s, rt::MemoryReadUInt8sWrapperName},238 {FAs.ReadUInt16s, rt::MemoryReadUInt16sWrapperName},239 {FAs.ReadUInt32s, rt::MemoryReadUInt32sWrapperName},240 {FAs.ReadUInt64s, rt::MemoryReadUInt64sWrapperName},241 {FAs.ReadBuffers, rt::MemoryReadBuffersWrapperName},242 {FAs.ReadStrings, rt::MemoryReadStringsWrapperName}}))243 return std::move(Err);244 245 return std::make_unique<EPCGenericMemoryAccess>(SREPC, FAs);246}247 248Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,249 ExecutorAddr TagAddr,250 ArrayRef<char> ArgBytes) {251 assert(OpC != SimpleRemoteEPCOpcode::Setup &&252 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");253 254 LLVM_DEBUG({255 dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";256 switch (OpC) {257 case SimpleRemoteEPCOpcode::Hangup:258 dbgs() << "Hangup";259 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");260 assert(!TagAddr && "Non-zero TagAddr for Hangup?");261 break;262 case SimpleRemoteEPCOpcode::Result:263 dbgs() << "Result";264 assert(!TagAddr && "Non-zero TagAddr for Result?");265 break;266 case SimpleRemoteEPCOpcode::CallWrapper:267 dbgs() << "CallWrapper";268 break;269 default:270 llvm_unreachable("Invalid opcode");271 }272 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr273 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())274 << " bytes\n";275 });276 auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);277 LLVM_DEBUG({278 if (Err)279 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";280 });281 return Err;282}283 284Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,285 SimpleRemoteEPCArgBytesVector ArgBytes) {286 if (SeqNo != 0)287 return make_error<StringError>("Setup packet SeqNo not zero",288 inconvertibleErrorCode());289 290 if (TagAddr)291 return make_error<StringError>("Setup packet TagAddr not zero",292 inconvertibleErrorCode());293 294 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);295 auto I = PendingCallWrapperResults.find(0);296 assert(PendingCallWrapperResults.size() == 1 &&297 I != PendingCallWrapperResults.end() &&298 "Setup message handler not connectly set up");299 auto SetupMsgHandler = std::move(I->second);300 PendingCallWrapperResults.erase(I);301 302 auto WFR =303 shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());304 SetupMsgHandler(std::move(WFR));305 return Error::success();306}307 308Error SimpleRemoteEPC::setup(Setup S) {309 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;310 311 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;312 auto EIF = EIP.get_future();313 314 // Prepare a handler for the setup packet.315 PendingCallWrapperResults[0] =316 RunInPlace()(317 [&](shared::WrapperFunctionResult SetupMsgBytes) {318 if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {319 EIP.set_value(320 make_error<StringError>(ErrMsg, inconvertibleErrorCode()));321 return;322 }323 using SPSSerialize =324 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;325 shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());326 SimpleRemoteEPCExecutorInfo EI;327 if (SPSSerialize::deserialize(IB, EI))328 EIP.set_value(EI);329 else330 EIP.set_value(make_error<StringError>(331 "Could not deserialize setup message", inconvertibleErrorCode()));332 });333 334 // Start the transport.335 if (auto Err = T->start())336 return Err;337 338 // Wait for setup packet to arrive.339 auto EI = EIF.get();340 if (!EI) {341 T->disconnect();342 return EI.takeError();343 }344 345 LLVM_DEBUG({346 dbgs() << "SimpleRemoteEPC received setup message:\n"347 << " Triple: " << EI->TargetTriple << "\n"348 << " Page size: " << EI->PageSize << "\n"349 << " Bootstrap map" << (EI->BootstrapMap.empty() ? " empty" : ":")350 << "\n";351 for (const auto &KV : EI->BootstrapMap)352 dbgs() << " " << KV.first() << ": " << KV.second.size()353 << "-byte SPS encoded buffer\n";354 dbgs() << " Bootstrap symbols"355 << (EI->BootstrapSymbols.empty() ? " empty" : ":") << "\n";356 for (const auto &KV : EI->BootstrapSymbols)357 dbgs() << " " << KV.first() << ": " << KV.second << "\n";358 });359 TargetTriple = Triple(EI->TargetTriple);360 PageSize = EI->PageSize;361 BootstrapMap = std::move(EI->BootstrapMap);362 BootstrapSymbols = std::move(EI->BootstrapSymbols);363 364 if (auto Err = getBootstrapSymbols(365 {{JDI.JITDispatchContext, ExecutorSessionObjectName},366 {JDI.JITDispatchFunction, DispatchFnName},367 {RunAsMainAddr, rt::RunAsMainWrapperName},368 {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},369 {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))370 return Err;371 372 if (auto DM =373 EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(*this))374 EPCDylibMgr = std::make_unique<EPCGenericDylibManager>(std::move(*DM));375 else376 return DM.takeError();377 378 // Set a default CreateMemoryManager if none is specified.379 if (!S.CreateMemoryManager)380 S.CreateMemoryManager = createDefaultMemoryManager;381 382 if (auto MemMgr = S.CreateMemoryManager(*this)) {383 OwnedMemMgr = std::move(*MemMgr);384 this->MemMgr = OwnedMemMgr.get();385 } else386 return MemMgr.takeError();387 388 // Set a default CreateMemoryAccess if none is specified.389 if (!S.CreateMemoryAccess)390 S.CreateMemoryAccess = createDefaultMemoryAccess;391 392 if (auto MemAccess = S.CreateMemoryAccess(*this)) {393 OwnedMemAccess = std::move(*MemAccess);394 this->MemAccess = OwnedMemAccess.get();395 } else396 return MemAccess.takeError();397 398 return Error::success();399}400 401Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,402 SimpleRemoteEPCArgBytesVector ArgBytes) {403 IncomingWFRHandler SendResult;404 405 if (TagAddr)406 return make_error<StringError>("Unexpected TagAddr in result message",407 inconvertibleErrorCode());408 409 {410 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);411 auto I = PendingCallWrapperResults.find(SeqNo);412 if (I == PendingCallWrapperResults.end())413 return make_error<StringError>("No call for sequence number " +414 Twine(SeqNo),415 inconvertibleErrorCode());416 SendResult = std::move(I->second);417 PendingCallWrapperResults.erase(I);418 releaseSeqNo(SeqNo);419 }420 421 auto WFR =422 shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());423 SendResult(std::move(WFR));424 return Error::success();425}426 427void SimpleRemoteEPC::handleCallWrapper(428 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,429 SimpleRemoteEPCArgBytesVector ArgBytes) {430 assert(ES && "No ExecutionSession attached");431 D->dispatch(makeGenericNamedTask(432 [this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {433 ES->runJITDispatchHandler(434 [this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {435 if (auto Err =436 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,437 ExecutorAddr(), {WFR.data(), WFR.size()}))438 getExecutionSession().reportError(std::move(Err));439 },440 TagAddr, ArgBytes);441 },442 "callWrapper task"));443}444 445Error SimpleRemoteEPC::handleHangup(SimpleRemoteEPCArgBytesVector ArgBytes) {446 using namespace llvm::orc::shared;447 auto WFR = WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());448 if (const char *ErrMsg = WFR.getOutOfBandError())449 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());450 451 orc::shared::detail::SPSSerializableError Info;452 SPSInputBuffer IB(WFR.data(), WFR.size());453 if (!SPSArgList<SPSError>::deserialize(IB, Info))454 return make_error<StringError>("Could not deserialize hangup info",455 inconvertibleErrorCode());456 return fromSPSSerializable(std::move(Info));457}458 459} // end namespace orc460} // end namespace llvm461