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