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