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 
11bb72f073SLang Hames #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
12bb72f073SLang Hames #include "llvm/Support/FormatVariadic.h"
13bb72f073SLang Hames #include "llvm/Support/Host.h"
14bb72f073SLang Hames #include "llvm/Support/Process.h"
15bb72f073SLang Hames 
162c8e7849SLang Hames #include "OrcRTBootstrap.h"
172c8e7849SLang Hames 
18bb72f073SLang Hames #define DEBUG_TYPE "orc"
19bb72f073SLang Hames 
20bb72f073SLang Hames using namespace llvm::orc::shared;
21bb72f073SLang Hames 
22bb72f073SLang Hames namespace llvm {
23bb72f073SLang Hames namespace orc {
24bb72f073SLang Hames 
2578b083dbSLang Hames ExecutorBootstrapService::~ExecutorBootstrapService() {}
2678b083dbSLang Hames 
27bb72f073SLang Hames SimpleRemoteEPCServer::Dispatcher::~Dispatcher() {}
28bb72f073SLang Hames 
29bb72f073SLang Hames #if LLVM_ENABLE_THREADS
30bb72f073SLang Hames void SimpleRemoteEPCServer::ThreadDispatcher::dispatch(
31bb72f073SLang Hames     unique_function<void()> Work) {
32bb72f073SLang Hames   {
33bb72f073SLang Hames     std::lock_guard<std::mutex> Lock(DispatchMutex);
34bb72f073SLang Hames     if (!Running)
35bb72f073SLang Hames       return;
36bb72f073SLang Hames     ++Outstanding;
37bb72f073SLang Hames   }
38bb72f073SLang Hames 
39bb72f073SLang Hames   std::thread([this, Work = std::move(Work)]() mutable {
40bb72f073SLang Hames     Work();
41bb72f073SLang Hames     std::lock_guard<std::mutex> Lock(DispatchMutex);
42bb72f073SLang Hames     --Outstanding;
43bb72f073SLang Hames     OutstandingCV.notify_all();
44bb72f073SLang Hames   }).detach();
45bb72f073SLang Hames }
46bb72f073SLang Hames 
47bb72f073SLang Hames void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() {
48bb72f073SLang Hames   std::unique_lock<std::mutex> Lock(DispatchMutex);
49bb72f073SLang Hames   Running = false;
50bb72f073SLang Hames   OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
51bb72f073SLang Hames }
52bb72f073SLang Hames #endif
53bb72f073SLang Hames 
54*ef391df2SLang Hames StringMap<ExecutorAddr> SimpleRemoteEPCServer::defaultBootstrapSymbols() {
55*ef391df2SLang Hames   StringMap<ExecutorAddr> DBS;
562c8e7849SLang Hames   rt_bootstrap::addTo(DBS);
57bb72f073SLang Hames   return DBS;
58bb72f073SLang Hames }
59bb72f073SLang Hames 
60bb72f073SLang Hames Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
61bb72f073SLang Hames SimpleRemoteEPCServer::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
62*ef391df2SLang Hames                                      ExecutorAddr TagAddr,
63bb72f073SLang Hames                                      SimpleRemoteEPCArgBytesVector ArgBytes) {
64bb72f073SLang Hames   using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
65d11a0c5dSLang Hames   if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
66bb72f073SLang Hames     return make_error<StringError>("Unexpected opcode",
67bb72f073SLang Hames                                    inconvertibleErrorCode());
68bb72f073SLang Hames 
69bb72f073SLang Hames   // TODO: Clean detach message?
70bb72f073SLang Hames   switch (OpC) {
71bb72f073SLang Hames   case SimpleRemoteEPCOpcode::Setup:
72bb72f073SLang Hames     return make_error<StringError>("Unexpected Setup opcode",
73bb72f073SLang Hames                                    inconvertibleErrorCode());
74bb72f073SLang Hames   case SimpleRemoteEPCOpcode::Hangup:
75bb72f073SLang Hames     return SimpleRemoteEPCTransportClient::EndSession;
76bb72f073SLang Hames   case SimpleRemoteEPCOpcode::Result:
77bb72f073SLang Hames     if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
78bb72f073SLang Hames       return std::move(Err);
79bb72f073SLang Hames     break;
80bb72f073SLang Hames   case SimpleRemoteEPCOpcode::CallWrapper:
81bb72f073SLang Hames     handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
82bb72f073SLang Hames     break;
83bb72f073SLang Hames   }
84bb72f073SLang Hames   return ContinueSession;
85bb72f073SLang Hames }
86bb72f073SLang Hames 
87bb72f073SLang Hames Error SimpleRemoteEPCServer::waitForDisconnect() {
88bb72f073SLang Hames   std::unique_lock<std::mutex> Lock(ServerStateMutex);
89bb72f073SLang Hames   ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; });
90bb72f073SLang Hames   return std::move(ShutdownErr);
91bb72f073SLang Hames }
92bb72f073SLang Hames 
93bb72f073SLang Hames void SimpleRemoteEPCServer::handleDisconnect(Error Err) {
94bb72f073SLang Hames   PendingJITDispatchResultsMap TmpPending;
95bb72f073SLang Hames 
96bb72f073SLang Hames   {
97bb72f073SLang Hames     std::lock_guard<std::mutex> Lock(ServerStateMutex);
98bb72f073SLang Hames     std::swap(TmpPending, PendingJITDispatchResults);
99bb72f073SLang Hames     RunState = ServerShuttingDown;
100bb72f073SLang Hames   }
101bb72f073SLang Hames 
102bb72f073SLang Hames   // Send out-of-band errors to any waiting threads.
103bb72f073SLang Hames   for (auto &KV : TmpPending)
104bb72f073SLang Hames     KV.second->set_value(
105bb72f073SLang Hames         shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
106bb72f073SLang Hames 
107bb72f073SLang Hames   // TODO: Free attached resources.
108bb72f073SLang Hames   // 1. Close libraries in DylibHandles.
109bb72f073SLang Hames 
110bb72f073SLang Hames   // Wait for dispatcher to clear.
111bb72f073SLang Hames   D->shutdown();
112bb72f073SLang Hames 
113c965fde7SLang Hames   // Shut down services.
114c965fde7SLang Hames   while (!Services.empty()) {
115c965fde7SLang Hames     ShutdownErr =
116c965fde7SLang Hames       joinErrors(std::move(ShutdownErr), Services.back()->shutdown());
117c965fde7SLang Hames     Services.pop_back();
118c965fde7SLang Hames   }
119c965fde7SLang Hames 
120bb72f073SLang Hames   std::lock_guard<std::mutex> Lock(ServerStateMutex);
121bb72f073SLang Hames   ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err));
122bb72f073SLang Hames   RunState = ServerShutDown;
123bb72f073SLang Hames   ShutdownCV.notify_all();
124bb72f073SLang Hames }
125bb72f073SLang Hames 
126bb72f073SLang Hames Error SimpleRemoteEPCServer::sendSetupMessage(
127*ef391df2SLang Hames     StringMap<ExecutorAddr> BootstrapSymbols) {
128bb72f073SLang Hames 
129bb72f073SLang Hames   using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
130bb72f073SLang Hames 
131bb72f073SLang Hames   std::vector<char> SetupPacket;
132bb72f073SLang Hames   SimpleRemoteEPCExecutorInfo EI;
133bb72f073SLang Hames   EI.TargetTriple = sys::getProcessTriple();
134bb72f073SLang Hames   if (auto PageSize = sys::Process::getPageSize())
135bb72f073SLang Hames     EI.PageSize = *PageSize;
136bb72f073SLang Hames   else
137bb72f073SLang Hames     return PageSize.takeError();
138bb72f073SLang Hames   EI.BootstrapSymbols = std::move(BootstrapSymbols);
139bb72f073SLang Hames 
140bb72f073SLang Hames   assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) &&
141bb72f073SLang Hames          "Dispatch context name should not be set");
142bb72f073SLang Hames   assert(!EI.BootstrapSymbols.count(DispatchFnName) &&
143bb72f073SLang Hames          "Dispatch function name should not be set");
144*ef391df2SLang Hames   EI.BootstrapSymbols[ExecutorSessionObjectName] = ExecutorAddr::fromPtr(this);
145*ef391df2SLang Hames   EI.BootstrapSymbols[DispatchFnName] = ExecutorAddr::fromPtr(jitDispatchEntry);
146bb72f073SLang Hames 
147bb72f073SLang Hames   using SPSSerialize =
148bb72f073SLang Hames       shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
149bb72f073SLang Hames   auto SetupPacketBytes =
150bb72f073SLang Hames       shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI));
151bb72f073SLang Hames   shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size());
152bb72f073SLang Hames   if (!SPSSerialize::serialize(OB, EI))
153bb72f073SLang Hames     return make_error<StringError>("Could not send setup packet",
154bb72f073SLang Hames                                    inconvertibleErrorCode());
155bb72f073SLang Hames 
156*ef391df2SLang Hames   return T->sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddr(),
157bb72f073SLang Hames                         {SetupPacketBytes.data(), SetupPacketBytes.size()});
158bb72f073SLang Hames }
159bb72f073SLang Hames 
160bb72f073SLang Hames Error SimpleRemoteEPCServer::handleResult(
161*ef391df2SLang Hames     uint64_t SeqNo, ExecutorAddr TagAddr,
162bb72f073SLang Hames     SimpleRemoteEPCArgBytesVector ArgBytes) {
163bb72f073SLang Hames   std::promise<shared::WrapperFunctionResult> *P = nullptr;
164bb72f073SLang Hames   {
165bb72f073SLang Hames     std::lock_guard<std::mutex> Lock(ServerStateMutex);
166bb72f073SLang Hames     auto I = PendingJITDispatchResults.find(SeqNo);
167bb72f073SLang Hames     if (I == PendingJITDispatchResults.end())
168bb72f073SLang Hames       return make_error<StringError>("No call for sequence number " +
169bb72f073SLang Hames                                          Twine(SeqNo),
170bb72f073SLang Hames                                      inconvertibleErrorCode());
171bb72f073SLang Hames     P = I->second;
172bb72f073SLang Hames     PendingJITDispatchResults.erase(I);
173bb72f073SLang Hames     releaseSeqNo(SeqNo);
174bb72f073SLang Hames   }
175bb72f073SLang Hames   auto R = shared::WrapperFunctionResult::allocate(ArgBytes.size());
176bb72f073SLang Hames   memcpy(R.data(), ArgBytes.data(), ArgBytes.size());
177bb72f073SLang Hames   P->set_value(std::move(R));
178bb72f073SLang Hames   return Error::success();
179bb72f073SLang Hames }
180bb72f073SLang Hames 
181bb72f073SLang Hames void SimpleRemoteEPCServer::handleCallWrapper(
182*ef391df2SLang Hames     uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
183bb72f073SLang Hames     SimpleRemoteEPCArgBytesVector ArgBytes) {
184bb72f073SLang Hames   D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
185bb72f073SLang Hames     using WrapperFnTy =
186bb72f073SLang Hames         shared::detail::CWrapperFunctionResult (*)(const char *, size_t);
187bb72f073SLang Hames     auto *Fn = TagAddr.toPtr<WrapperFnTy>();
188bb72f073SLang Hames     shared::WrapperFunctionResult ResultBytes(
189bb72f073SLang Hames         Fn(ArgBytes.data(), ArgBytes.size()));
190bb72f073SLang Hames     if (auto Err = T->sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
191*ef391df2SLang Hames                                   ExecutorAddr(),
192bb72f073SLang Hames                                   {ResultBytes.data(), ResultBytes.size()}))
193bb72f073SLang Hames       ReportError(std::move(Err));
194bb72f073SLang Hames   });
195bb72f073SLang Hames }
196bb72f073SLang Hames 
197bb72f073SLang Hames shared::WrapperFunctionResult
198bb72f073SLang Hames SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData,
199bb72f073SLang Hames                                      size_t ArgSize) {
200bb72f073SLang Hames   uint64_t SeqNo;
201bb72f073SLang Hames   std::promise<shared::WrapperFunctionResult> ResultP;
202bb72f073SLang Hames   auto ResultF = ResultP.get_future();
203bb72f073SLang Hames   {
204bb72f073SLang Hames     std::lock_guard<std::mutex> Lock(ServerStateMutex);
205bb72f073SLang Hames     if (RunState != ServerRunning)
206bb72f073SLang Hames       return shared::WrapperFunctionResult::createOutOfBandError(
207bb72f073SLang Hames           "jit_dispatch not available (EPC server shut down)");
208bb72f073SLang Hames 
209bb72f073SLang Hames     SeqNo = getNextSeqNo();
210bb72f073SLang Hames     assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use");
211bb72f073SLang Hames     PendingJITDispatchResults[SeqNo] = &ResultP;
212bb72f073SLang Hames   }
213bb72f073SLang Hames 
214bb72f073SLang Hames   if (auto Err =
215bb72f073SLang Hames           T->sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
216*ef391df2SLang Hames                          ExecutorAddr::fromPtr(FnTag), {ArgData, ArgSize}))
217bb72f073SLang Hames     ReportError(std::move(Err));
218bb72f073SLang Hames 
219bb72f073SLang Hames   return ResultF.get();
220bb72f073SLang Hames }
221bb72f073SLang Hames 
222bb72f073SLang Hames shared::detail::CWrapperFunctionResult
223bb72f073SLang Hames SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag,
224bb72f073SLang Hames                                         const char *ArgData, size_t ArgSize) {
225bb72f073SLang Hames   return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx)
226bb72f073SLang Hames       ->doJITDispatch(FnTag, ArgData, ArgSize)
227bb72f073SLang Hames       .release();
228bb72f073SLang Hames }
229bb72f073SLang Hames 
230bb72f073SLang Hames } // end namespace orc
231bb72f073SLang Hames } // end namespace llvm
232