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
dispatch(unique_function<void ()> Work)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
shutdown()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
defaultBootstrapSymbols()56 StringMap<ExecutorAddr> SimpleRemoteEPCServer::defaultBootstrapSymbols() {
57 StringMap<ExecutorAddr> DBS;
58 rt_bootstrap::addTo(DBS);
59 return DBS;
60 }
61
62 Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
handleMessage(SimpleRemoteEPCOpcode OpC,uint64_t SeqNo,ExecutorAddr TagAddr,SimpleRemoteEPCArgBytesVector ArgBytes)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
waitForDisconnect()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
handleDisconnect(Error Err)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
sendMessage(SimpleRemoteEPCOpcode OpC,uint64_t SeqNo,ExecutorAddr TagAddr,ArrayRef<char> ArgBytes)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
sendSetupMessage(StringMap<std::vector<char>> BootstrapMap,StringMap<ExecutorAddr> BootstrapSymbols)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
handleResult(uint64_t SeqNo,ExecutorAddr TagAddr,SimpleRemoteEPCArgBytesVector ArgBytes)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
handleCallWrapper(uint64_t RemoteSeqNo,ExecutorAddr TagAddr,SimpleRemoteEPCArgBytesVector ArgBytes)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
doJITDispatch(const void * FnTag,const char * ArgData,size_t ArgSize)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
jitDispatchEntry(void * DispatchCtx,const void * FnTag,const char * ArgData,size_t ArgSize)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