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
25*3a3cb929SKazu Hirata ExecutorBootstrapService::~ExecutorBootstrapService() = default;
2678b083dbSLang Hames
27*3a3cb929SKazu Hirata SimpleRemoteEPCServer::Dispatcher::~Dispatcher() = default;
288fe3d9dfSLang Hames
298fe3d9dfSLang Hames #if LLVM_ENABLE_THREADS
dispatch(unique_function<void ()> Work)308fe3d9dfSLang Hames void SimpleRemoteEPCServer::ThreadDispatcher::dispatch(
318fe3d9dfSLang Hames unique_function<void()> Work) {
328fe3d9dfSLang Hames {
338fe3d9dfSLang Hames std::lock_guard<std::mutex> Lock(DispatchMutex);
348fe3d9dfSLang Hames if (!Running)
358fe3d9dfSLang Hames return;
368fe3d9dfSLang Hames ++Outstanding;
378fe3d9dfSLang Hames }
388fe3d9dfSLang Hames
398fe3d9dfSLang Hames std::thread([this, Work = std::move(Work)]() mutable {
408fe3d9dfSLang Hames Work();
418fe3d9dfSLang Hames std::lock_guard<std::mutex> Lock(DispatchMutex);
428fe3d9dfSLang Hames --Outstanding;
438fe3d9dfSLang Hames OutstandingCV.notify_all();
448fe3d9dfSLang Hames }).detach();
458fe3d9dfSLang Hames }
468fe3d9dfSLang Hames
shutdown()478fe3d9dfSLang Hames void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() {
488fe3d9dfSLang Hames std::unique_lock<std::mutex> Lock(DispatchMutex);
498fe3d9dfSLang Hames Running = false;
508fe3d9dfSLang Hames OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
518fe3d9dfSLang Hames }
528fe3d9dfSLang Hames #endif
538fe3d9dfSLang Hames
defaultBootstrapSymbols()54ef391df2SLang Hames StringMap<ExecutorAddr> SimpleRemoteEPCServer::defaultBootstrapSymbols() {
55ef391df2SLang Hames StringMap<ExecutorAddr> DBS;
562c8e7849SLang Hames rt_bootstrap::addTo(DBS);
57bb72f073SLang Hames return DBS;
58bb72f073SLang Hames }
59bb72f073SLang Hames
60bb72f073SLang Hames Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
handleMessage(SimpleRemoteEPCOpcode OpC,uint64_t SeqNo,ExecutorAddr TagAddr,SimpleRemoteEPCArgBytesVector ArgBytes)61bb72f073SLang Hames SimpleRemoteEPCServer::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
62ef391df2SLang Hames ExecutorAddr TagAddr,
63bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes) {
64175c1a39SLang Hames
65175c1a39SLang Hames LLVM_DEBUG({
66175c1a39SLang Hames dbgs() << "SimpleRemoteEPCServer::handleMessage: opc = ";
67175c1a39SLang Hames switch (OpC) {
68175c1a39SLang Hames case SimpleRemoteEPCOpcode::Setup:
69175c1a39SLang Hames dbgs() << "Setup";
70175c1a39SLang Hames assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
71175c1a39SLang Hames assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Setup?");
72175c1a39SLang Hames break;
73175c1a39SLang Hames case SimpleRemoteEPCOpcode::Hangup:
74175c1a39SLang Hames dbgs() << "Hangup";
75175c1a39SLang Hames assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
76175c1a39SLang Hames assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Hangup?");
77175c1a39SLang Hames break;
78175c1a39SLang Hames case SimpleRemoteEPCOpcode::Result:
79175c1a39SLang Hames dbgs() << "Result";
80175c1a39SLang Hames assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Result?");
81175c1a39SLang Hames break;
82175c1a39SLang Hames case SimpleRemoteEPCOpcode::CallWrapper:
83175c1a39SLang Hames dbgs() << "CallWrapper";
84175c1a39SLang Hames break;
85175c1a39SLang Hames }
86175c1a39SLang Hames dbgs() << ", seqno = " << SeqNo
87175c1a39SLang Hames << ", tag-addr = " << formatv("{0:x}", TagAddr.getValue())
88175c1a39SLang Hames << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
89175c1a39SLang Hames << " bytes\n";
90175c1a39SLang Hames });
91175c1a39SLang Hames
92bb72f073SLang Hames using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
93d11a0c5dSLang Hames if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
94bb72f073SLang Hames return make_error<StringError>("Unexpected opcode",
95bb72f073SLang Hames inconvertibleErrorCode());
96bb72f073SLang Hames
97bb72f073SLang Hames // TODO: Clean detach message?
98bb72f073SLang Hames switch (OpC) {
99bb72f073SLang Hames case SimpleRemoteEPCOpcode::Setup:
100bb72f073SLang Hames return make_error<StringError>("Unexpected Setup opcode",
101bb72f073SLang Hames inconvertibleErrorCode());
102bb72f073SLang Hames case SimpleRemoteEPCOpcode::Hangup:
103bb72f073SLang Hames return SimpleRemoteEPCTransportClient::EndSession;
104bb72f073SLang Hames case SimpleRemoteEPCOpcode::Result:
105bb72f073SLang Hames if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
106bb72f073SLang Hames return std::move(Err);
107bb72f073SLang Hames break;
108bb72f073SLang Hames case SimpleRemoteEPCOpcode::CallWrapper:
109bb72f073SLang Hames handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
110bb72f073SLang Hames break;
111bb72f073SLang Hames }
112bb72f073SLang Hames return ContinueSession;
113bb72f073SLang Hames }
114bb72f073SLang Hames
waitForDisconnect()115bb72f073SLang Hames Error SimpleRemoteEPCServer::waitForDisconnect() {
116bb72f073SLang Hames std::unique_lock<std::mutex> Lock(ServerStateMutex);
117bb72f073SLang Hames ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; });
118bb72f073SLang Hames return std::move(ShutdownErr);
119bb72f073SLang Hames }
120bb72f073SLang Hames
handleDisconnect(Error Err)121bb72f073SLang Hames void SimpleRemoteEPCServer::handleDisconnect(Error Err) {
122bb72f073SLang Hames PendingJITDispatchResultsMap TmpPending;
123bb72f073SLang Hames
124bb72f073SLang Hames {
125bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex);
126bb72f073SLang Hames std::swap(TmpPending, PendingJITDispatchResults);
127bb72f073SLang Hames RunState = ServerShuttingDown;
128bb72f073SLang Hames }
129bb72f073SLang Hames
130bb72f073SLang Hames // Send out-of-band errors to any waiting threads.
131bb72f073SLang Hames for (auto &KV : TmpPending)
132bb72f073SLang Hames KV.second->set_value(
133bb72f073SLang Hames shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
134bb72f073SLang Hames
135bb72f073SLang Hames // Wait for dispatcher to clear.
136bb72f073SLang Hames D->shutdown();
137bb72f073SLang Hames
138c965fde7SLang Hames // Shut down services.
139c965fde7SLang Hames while (!Services.empty()) {
140c965fde7SLang Hames ShutdownErr =
141c965fde7SLang Hames joinErrors(std::move(ShutdownErr), Services.back()->shutdown());
142c965fde7SLang Hames Services.pop_back();
143c965fde7SLang Hames }
144c965fde7SLang Hames
145bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex);
146bb72f073SLang Hames ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(Err));
147bb72f073SLang Hames RunState = ServerShutDown;
148bb72f073SLang Hames ShutdownCV.notify_all();
149bb72f073SLang Hames }
150bb72f073SLang Hames
sendMessage(SimpleRemoteEPCOpcode OpC,uint64_t SeqNo,ExecutorAddr TagAddr,ArrayRef<char> ArgBytes)151175c1a39SLang Hames Error SimpleRemoteEPCServer::sendMessage(SimpleRemoteEPCOpcode OpC,
152175c1a39SLang Hames uint64_t SeqNo, ExecutorAddr TagAddr,
153175c1a39SLang Hames ArrayRef<char> ArgBytes) {
154175c1a39SLang Hames
155175c1a39SLang Hames LLVM_DEBUG({
156175c1a39SLang Hames dbgs() << "SimpleRemoteEPCServer::sendMessage: opc = ";
157175c1a39SLang Hames switch (OpC) {
158175c1a39SLang Hames case SimpleRemoteEPCOpcode::Setup:
159175c1a39SLang Hames dbgs() << "Setup";
160175c1a39SLang Hames assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
161175c1a39SLang Hames assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Setup?");
162175c1a39SLang Hames break;
163175c1a39SLang Hames case SimpleRemoteEPCOpcode::Hangup:
164175c1a39SLang Hames dbgs() << "Hangup";
165175c1a39SLang Hames assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
166175c1a39SLang Hames assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Hangup?");
167175c1a39SLang Hames break;
168175c1a39SLang Hames case SimpleRemoteEPCOpcode::Result:
169175c1a39SLang Hames dbgs() << "Result";
170175c1a39SLang Hames assert(TagAddr.getValue() == 0 && "Non-zero TagAddr for Result?");
171175c1a39SLang Hames break;
172175c1a39SLang Hames case SimpleRemoteEPCOpcode::CallWrapper:
173175c1a39SLang Hames dbgs() << "CallWrapper";
174175c1a39SLang Hames break;
175175c1a39SLang Hames }
176175c1a39SLang Hames dbgs() << ", seqno = " << SeqNo
177175c1a39SLang Hames << ", tag-addr = " << formatv("{0:x}", TagAddr.getValue())
178175c1a39SLang Hames << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
179175c1a39SLang Hames << " bytes\n";
180175c1a39SLang Hames });
181175c1a39SLang Hames auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
182175c1a39SLang Hames LLVM_DEBUG({
183175c1a39SLang Hames if (Err)
184175c1a39SLang Hames dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
185175c1a39SLang Hames });
186175c1a39SLang Hames return Err;
187175c1a39SLang Hames }
188175c1a39SLang Hames
sendSetupMessage(StringMap<ExecutorAddr> BootstrapSymbols)189bb72f073SLang Hames Error SimpleRemoteEPCServer::sendSetupMessage(
190ef391df2SLang Hames StringMap<ExecutorAddr> BootstrapSymbols) {
191bb72f073SLang Hames
192bb72f073SLang Hames using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
193bb72f073SLang Hames
194bb72f073SLang Hames std::vector<char> SetupPacket;
195bb72f073SLang Hames SimpleRemoteEPCExecutorInfo EI;
196bb72f073SLang Hames EI.TargetTriple = sys::getProcessTriple();
197bb72f073SLang Hames if (auto PageSize = sys::Process::getPageSize())
198bb72f073SLang Hames EI.PageSize = *PageSize;
199bb72f073SLang Hames else
200bb72f073SLang Hames return PageSize.takeError();
201bb72f073SLang Hames EI.BootstrapSymbols = std::move(BootstrapSymbols);
202bb72f073SLang Hames
203bb72f073SLang Hames assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) &&
204bb72f073SLang Hames "Dispatch context name should not be set");
205bb72f073SLang Hames assert(!EI.BootstrapSymbols.count(DispatchFnName) &&
206bb72f073SLang Hames "Dispatch function name should not be set");
207ef391df2SLang Hames EI.BootstrapSymbols[ExecutorSessionObjectName] = ExecutorAddr::fromPtr(this);
208ef391df2SLang Hames EI.BootstrapSymbols[DispatchFnName] = ExecutorAddr::fromPtr(jitDispatchEntry);
209bb72f073SLang Hames
210bb72f073SLang Hames using SPSSerialize =
211bb72f073SLang Hames shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
212bb72f073SLang Hames auto SetupPacketBytes =
213bb72f073SLang Hames shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI));
214bb72f073SLang Hames shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size());
215bb72f073SLang Hames if (!SPSSerialize::serialize(OB, EI))
216bb72f073SLang Hames return make_error<StringError>("Could not send setup packet",
217bb72f073SLang Hames inconvertibleErrorCode());
218bb72f073SLang Hames
219175c1a39SLang Hames return sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddr(),
220bb72f073SLang Hames {SetupPacketBytes.data(), SetupPacketBytes.size()});
221bb72f073SLang Hames }
222bb72f073SLang Hames
handleResult(uint64_t SeqNo,ExecutorAddr TagAddr,SimpleRemoteEPCArgBytesVector ArgBytes)223bb72f073SLang Hames Error SimpleRemoteEPCServer::handleResult(
224ef391df2SLang Hames uint64_t SeqNo, ExecutorAddr TagAddr,
225bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes) {
226bb72f073SLang Hames std::promise<shared::WrapperFunctionResult> *P = nullptr;
227bb72f073SLang Hames {
228bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex);
229bb72f073SLang Hames auto I = PendingJITDispatchResults.find(SeqNo);
230bb72f073SLang Hames if (I == PendingJITDispatchResults.end())
231bb72f073SLang Hames return make_error<StringError>("No call for sequence number " +
232bb72f073SLang Hames Twine(SeqNo),
233bb72f073SLang Hames inconvertibleErrorCode());
234bb72f073SLang Hames P = I->second;
235bb72f073SLang Hames PendingJITDispatchResults.erase(I);
236bb72f073SLang Hames releaseSeqNo(SeqNo);
237bb72f073SLang Hames }
238bb72f073SLang Hames auto R = shared::WrapperFunctionResult::allocate(ArgBytes.size());
239bb72f073SLang Hames memcpy(R.data(), ArgBytes.data(), ArgBytes.size());
240bb72f073SLang Hames P->set_value(std::move(R));
241bb72f073SLang Hames return Error::success();
242bb72f073SLang Hames }
243bb72f073SLang Hames
handleCallWrapper(uint64_t RemoteSeqNo,ExecutorAddr TagAddr,SimpleRemoteEPCArgBytesVector ArgBytes)244bb72f073SLang Hames void SimpleRemoteEPCServer::handleCallWrapper(
245ef391df2SLang Hames uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
246bb72f073SLang Hames SimpleRemoteEPCArgBytesVector ArgBytes) {
247bb72f073SLang Hames D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
248bb72f073SLang Hames using WrapperFnTy =
249213666f8SLang Hames shared::CWrapperFunctionResult (*)(const char *, size_t);
250bb72f073SLang Hames auto *Fn = TagAddr.toPtr<WrapperFnTy>();
251bb72f073SLang Hames shared::WrapperFunctionResult ResultBytes(
252bb72f073SLang Hames Fn(ArgBytes.data(), ArgBytes.size()));
253175c1a39SLang Hames if (auto Err = sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
254ef391df2SLang Hames ExecutorAddr(),
255bb72f073SLang Hames {ResultBytes.data(), ResultBytes.size()}))
256bb72f073SLang Hames ReportError(std::move(Err));
257bb72f073SLang Hames });
258bb72f073SLang Hames }
259bb72f073SLang Hames
260bb72f073SLang Hames shared::WrapperFunctionResult
doJITDispatch(const void * FnTag,const char * ArgData,size_t ArgSize)261bb72f073SLang Hames SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData,
262bb72f073SLang Hames size_t ArgSize) {
263bb72f073SLang Hames uint64_t SeqNo;
264bb72f073SLang Hames std::promise<shared::WrapperFunctionResult> ResultP;
265bb72f073SLang Hames auto ResultF = ResultP.get_future();
266bb72f073SLang Hames {
267bb72f073SLang Hames std::lock_guard<std::mutex> Lock(ServerStateMutex);
268bb72f073SLang Hames if (RunState != ServerRunning)
269bb72f073SLang Hames return shared::WrapperFunctionResult::createOutOfBandError(
270bb72f073SLang Hames "jit_dispatch not available (EPC server shut down)");
271bb72f073SLang Hames
272bb72f073SLang Hames SeqNo = getNextSeqNo();
273bb72f073SLang Hames assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use");
274bb72f073SLang Hames PendingJITDispatchResults[SeqNo] = &ResultP;
275bb72f073SLang Hames }
276bb72f073SLang Hames
277175c1a39SLang Hames if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
278ef391df2SLang Hames ExecutorAddr::fromPtr(FnTag), {ArgData, ArgSize}))
279bb72f073SLang Hames ReportError(std::move(Err));
280bb72f073SLang Hames
281bb72f073SLang Hames return ResultF.get();
282bb72f073SLang Hames }
283bb72f073SLang Hames
284213666f8SLang Hames shared::CWrapperFunctionResult
jitDispatchEntry(void * DispatchCtx,const void * FnTag,const char * ArgData,size_t ArgSize)285bb72f073SLang Hames SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag,
286bb72f073SLang Hames const char *ArgData, size_t ArgSize) {
287bb72f073SLang Hames return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx)
288bb72f073SLang Hames ->doJITDispatch(FnTag, ArgData, ArgSize)
289bb72f073SLang Hames .release();
290bb72f073SLang Hames }
291bb72f073SLang Hames
292bb72f073SLang Hames } // end namespace orc
293bb72f073SLang Hames } // end namespace llvm
294