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