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