xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp (revision 1f4d91ecb8529678a3d3919d7523743bd21942ca)
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