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