1 //===------- SimpleEPCServer.cpp - EPC over simple abstract channel -------===// 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/TargetProcess/SimpleRemoteEPCServer.h" 10 11 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 12 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h" 13 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" 14 #include "llvm/Support/FormatVariadic.h" 15 #include "llvm/Support/Process.h" 16 #include "llvm/TargetParser/Host.h" 17 18 #include "OrcRTBootstrap.h" 19 20 #define DEBUG_TYPE "orc" 21 22 using namespace llvm::orc::shared; 23 24 namespace llvm { 25 namespace orc { 26 27 ExecutorBootstrapService::~ExecutorBootstrapService() = default; 28 29 SimpleRemoteEPCServer::Dispatcher::~Dispatcher() = default; 30 31 #if LLVM_ENABLE_THREADS 32 void SimpleRemoteEPCServer::ThreadDispatcher::dispatch( 33 unique_function<void()> Work) { 34 { 35 std::lock_guard<std::mutex> Lock(DispatchMutex); 36 if (!Running) 37 return; 38 ++Outstanding; 39 } 40 41 std::thread([this, Work = std::move(Work)]() mutable { 42 Work(); 43 std::lock_guard<std::mutex> Lock(DispatchMutex); 44 --Outstanding; 45 OutstandingCV.notify_all(); 46 }).detach(); 47 } 48 49 void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() { 50 std::unique_lock<std::mutex> Lock(DispatchMutex); 51 Running = false; 52 OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; }); 53 } 54 #endif 55 56 StringMap<ExecutorAddr> SimpleRemoteEPCServer::defaultBootstrapSymbols() { 57 StringMap<ExecutorAddr> DBS; 58 rt_bootstrap::addTo(DBS); 59 return DBS; 60 } 61 62 Expected<SimpleRemoteEPCTransportClient::HandleMessageAction> 63 SimpleRemoteEPCServer::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, 64 ExecutorAddr TagAddr, 65 SimpleRemoteEPCArgBytesVector ArgBytes) { 66 67 LLVM_DEBUG({ 68 dbgs() << "SimpleRemoteEPCServer::handleMessage: opc = "; 69 switch (OpC) { 70 case SimpleRemoteEPCOpcode::Setup: 71 dbgs() << "Setup"; 72 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?"); 73 assert(!TagAddr && "Non-zero TagAddr for Setup?"); 74 break; 75 case SimpleRemoteEPCOpcode::Hangup: 76 dbgs() << "Hangup"; 77 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?"); 78 assert(!TagAddr && "Non-zero TagAddr for Hangup?"); 79 break; 80 case SimpleRemoteEPCOpcode::Result: 81 dbgs() << "Result"; 82 assert(!TagAddr && "Non-zero TagAddr for Result?"); 83 break; 84 case SimpleRemoteEPCOpcode::CallWrapper: 85 dbgs() << "CallWrapper"; 86 break; 87 } 88 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr 89 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size()) 90 << " bytes\n"; 91 }); 92 93 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>; 94 if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC)) 95 return make_error<StringError>("Unexpected opcode", 96 inconvertibleErrorCode()); 97 98 // TODO: Clean detach message? 99 switch (OpC) { 100 case SimpleRemoteEPCOpcode::Setup: 101 return make_error<StringError>("Unexpected Setup opcode", 102 inconvertibleErrorCode()); 103 case SimpleRemoteEPCOpcode::Hangup: 104 return SimpleRemoteEPCTransportClient::EndSession; 105 case SimpleRemoteEPCOpcode::Result: 106 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes))) 107 return std::move(Err); 108 break; 109 case SimpleRemoteEPCOpcode::CallWrapper: 110 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes)); 111 break; 112 } 113 return ContinueSession; 114 } 115 116 Error SimpleRemoteEPCServer::waitForDisconnect() { 117 std::unique_lock<std::mutex> Lock(ServerStateMutex); 118 ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; }); 119 return std::move(ShutdownErr); 120 } 121 122 void SimpleRemoteEPCServer::handleDisconnect(Error Err) { 123 PendingJITDispatchResultsMap TmpPending; 124 125 { 126 std::lock_guard<std::mutex> Lock(ServerStateMutex); 127 std::swap(TmpPending, PendingJITDispatchResults); 128 RunState = ServerShuttingDown; 129 } 130 131 // Send out-of-band errors to any waiting threads. 132 for (auto &KV : TmpPending) 133 KV.second->set_value( 134 shared::WrapperFunctionResult::createOutOfBandError("disconnecting")); 135 136 // Wait for dispatcher to clear. 137 D->shutdown(); 138 139 // Shut down services. 140 while (!Services.empty()) { 141 ShutdownErr = 142 joinErrors(std::move(ShutdownErr), Services.back()->shutdown()); 143 Services.pop_back(); 144 } 145 146 std::lock_guard<std::mutex> Lock(ServerStateMutex); 147 ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err)); 148 RunState = ServerShutDown; 149 ShutdownCV.notify_all(); 150 } 151 152 Error SimpleRemoteEPCServer::sendMessage(SimpleRemoteEPCOpcode OpC, 153 uint64_t SeqNo, ExecutorAddr TagAddr, 154 ArrayRef<char> ArgBytes) { 155 156 LLVM_DEBUG({ 157 dbgs() << "SimpleRemoteEPCServer::sendMessage: opc = "; 158 switch (OpC) { 159 case SimpleRemoteEPCOpcode::Setup: 160 dbgs() << "Setup"; 161 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?"); 162 assert(!TagAddr && "Non-zero TagAddr for Setup?"); 163 break; 164 case SimpleRemoteEPCOpcode::Hangup: 165 dbgs() << "Hangup"; 166 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?"); 167 assert(!TagAddr && "Non-zero TagAddr for Hangup?"); 168 break; 169 case SimpleRemoteEPCOpcode::Result: 170 dbgs() << "Result"; 171 assert(!TagAddr && "Non-zero TagAddr for Result?"); 172 break; 173 case SimpleRemoteEPCOpcode::CallWrapper: 174 dbgs() << "CallWrapper"; 175 break; 176 } 177 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr 178 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size()) 179 << " bytes\n"; 180 }); 181 auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes); 182 LLVM_DEBUG({ 183 if (Err) 184 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n"; 185 }); 186 return Err; 187 } 188 189 Error SimpleRemoteEPCServer::sendSetupMessage( 190 StringMap<std::vector<char>> BootstrapMap, 191 StringMap<ExecutorAddr> BootstrapSymbols) { 192 193 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames; 194 195 std::vector<char> SetupPacket; 196 SimpleRemoteEPCExecutorInfo EI; 197 EI.TargetTriple = sys::getProcessTriple(); 198 if (auto PageSize = sys::Process::getPageSize()) 199 EI.PageSize = *PageSize; 200 else 201 return PageSize.takeError(); 202 EI.BootstrapMap = std::move(BootstrapMap); 203 EI.BootstrapSymbols = std::move(BootstrapSymbols); 204 205 assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) && 206 "Dispatch context name should not be set"); 207 assert(!EI.BootstrapSymbols.count(DispatchFnName) && 208 "Dispatch function name should not be set"); 209 EI.BootstrapSymbols[ExecutorSessionObjectName] = ExecutorAddr::fromPtr(this); 210 EI.BootstrapSymbols[DispatchFnName] = ExecutorAddr::fromPtr(jitDispatchEntry); 211 EI.BootstrapSymbols[rt::RegisterEHFrameSectionWrapperName] = 212 ExecutorAddr::fromPtr(&llvm_orc_registerEHFrameSectionWrapper); 213 EI.BootstrapSymbols[rt::DeregisterEHFrameSectionWrapperName] = 214 ExecutorAddr::fromPtr(&llvm_orc_deregisterEHFrameSectionWrapper); 215 216 using SPSSerialize = 217 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>; 218 auto SetupPacketBytes = 219 shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI)); 220 shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size()); 221 if (!SPSSerialize::serialize(OB, EI)) 222 return make_error<StringError>("Could not send setup packet", 223 inconvertibleErrorCode()); 224 225 return sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddr(), 226 {SetupPacketBytes.data(), SetupPacketBytes.size()}); 227 } 228 229 Error SimpleRemoteEPCServer::handleResult( 230 uint64_t SeqNo, ExecutorAddr TagAddr, 231 SimpleRemoteEPCArgBytesVector ArgBytes) { 232 std::promise<shared::WrapperFunctionResult> *P = nullptr; 233 { 234 std::lock_guard<std::mutex> Lock(ServerStateMutex); 235 auto I = PendingJITDispatchResults.find(SeqNo); 236 if (I == PendingJITDispatchResults.end()) 237 return make_error<StringError>("No call for sequence number " + 238 Twine(SeqNo), 239 inconvertibleErrorCode()); 240 P = I->second; 241 PendingJITDispatchResults.erase(I); 242 releaseSeqNo(SeqNo); 243 } 244 auto R = shared::WrapperFunctionResult::allocate(ArgBytes.size()); 245 memcpy(R.data(), ArgBytes.data(), ArgBytes.size()); 246 P->set_value(std::move(R)); 247 return Error::success(); 248 } 249 250 void SimpleRemoteEPCServer::handleCallWrapper( 251 uint64_t RemoteSeqNo, ExecutorAddr TagAddr, 252 SimpleRemoteEPCArgBytesVector ArgBytes) { 253 D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() { 254 using WrapperFnTy = 255 shared::CWrapperFunctionResult (*)(const char *, size_t); 256 auto *Fn = TagAddr.toPtr<WrapperFnTy>(); 257 shared::WrapperFunctionResult ResultBytes( 258 Fn(ArgBytes.data(), ArgBytes.size())); 259 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo, 260 ExecutorAddr(), 261 {ResultBytes.data(), ResultBytes.size()})) 262 ReportError(std::move(Err)); 263 }); 264 } 265 266 shared::WrapperFunctionResult 267 SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData, 268 size_t ArgSize) { 269 uint64_t SeqNo; 270 std::promise<shared::WrapperFunctionResult> ResultP; 271 auto ResultF = ResultP.get_future(); 272 { 273 std::lock_guard<std::mutex> Lock(ServerStateMutex); 274 if (RunState != ServerRunning) 275 return shared::WrapperFunctionResult::createOutOfBandError( 276 "jit_dispatch not available (EPC server shut down)"); 277 278 SeqNo = getNextSeqNo(); 279 assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use"); 280 PendingJITDispatchResults[SeqNo] = &ResultP; 281 } 282 283 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo, 284 ExecutorAddr::fromPtr(FnTag), {ArgData, ArgSize})) 285 ReportError(std::move(Err)); 286 287 return ResultF.get(); 288 } 289 290 shared::CWrapperFunctionResult 291 SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag, 292 const char *ArgData, size_t ArgSize) { 293 return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx) 294 ->doJITDispatch(FnTag, ArgData, ArgSize) 295 .release(); 296 } 297 298 } // end namespace orc 299 } // end namespace llvm 300