LLVM 22.0.0git
SimpleRemoteEPCServer.cpp
Go to the documentation of this file.
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
10
17
18#include "OrcRTBootstrap.h"
19
20#define DEBUG_TYPE "orc"
21
22using namespace llvm::orc::shared;
23
24namespace llvm {
25namespace orc {
26
28
30
31#if LLVM_ENABLE_THREADS
32void 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
49void 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
61
64 ExecutorAddr TagAddr,
66
68 dbgs() << "SimpleRemoteEPCServer::handleMessage: opc = ";
69 switch (OpC) {
71 dbgs() << "Setup";
72 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
73 assert(!TagAddr && "Non-zero TagAddr for Setup?");
74 break;
76 dbgs() << "Hangup";
77 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
78 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
79 break;
81 dbgs() << "Result";
82 assert(!TagAddr && "Non-zero TagAddr for Result?");
83 break;
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",
97
98 // TODO: Clean detach message?
99 switch (OpC) {
101 return make_error<StringError>("Unexpected Setup opcode",
106 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
107 return std::move(Err);
108 break;
110 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
111 break;
112 }
113 return ContinueSession;
114}
115
117 std::unique_lock<std::mutex> Lock(ServerStateMutex);
118 ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; });
119 return std::move(ShutdownErr);
120}
121
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(
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
152Error 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) {
160 dbgs() << "Setup";
161 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
162 assert(!TagAddr && "Non-zero TagAddr for Setup?");
163 break;
165 dbgs() << "Hangup";
166 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
167 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
168 break;
170 dbgs() << "Result";
171 assert(!TagAddr && "Non-zero TagAddr for Result?");
172 break;
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
189Error SimpleRemoteEPCServer::sendSetupMessage(
190 StringMap<std::vector<char>> BootstrapMap,
191 StringMap<ExecutorAddr> BootstrapSymbols) {
192
193 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
194
195 SimpleRemoteEPCExecutorInfo EI;
198 EI.PageSize = *PageSize;
199 else
200 return PageSize.takeError();
201 EI.BootstrapMap = std::move(BootstrapMap);
202 EI.BootstrapSymbols = std::move(BootstrapSymbols);
203
204 assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) &&
205 "Dispatch context name should not be set");
206 assert(!EI.BootstrapSymbols.count(DispatchFnName) &&
207 "Dispatch function name should not be set");
211
212 using SPSSerialize =
213 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
214 auto SetupPacketBytes =
215 shared::WrapperFunctionResult::allocate(SPSSerialize::size(EI));
216 shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size());
217 if (!SPSSerialize::serialize(OB, EI))
218 return make_error<StringError>("Could not send setup packet",
220
221 return sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddr(),
222 {SetupPacketBytes.data(), SetupPacketBytes.size()});
223}
224
225Error SimpleRemoteEPCServer::handleResult(
226 uint64_t SeqNo, ExecutorAddr TagAddr,
228 std::promise<shared::WrapperFunctionResult> *P = nullptr;
229 {
230 std::lock_guard<std::mutex> Lock(ServerStateMutex);
231 auto I = PendingJITDispatchResults.find(SeqNo);
232 if (I == PendingJITDispatchResults.end())
233 return make_error<StringError>("No call for sequence number " +
234 Twine(SeqNo),
236 P = I->second;
237 PendingJITDispatchResults.erase(I);
238 releaseSeqNo(SeqNo);
239 }
241 memcpy(R.data(), ArgBytes.data(), ArgBytes.size());
242 P->set_value(std::move(R));
243 return Error::success();
244}
245
246void SimpleRemoteEPCServer::handleCallWrapper(
247 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
249 D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
250 using WrapperFnTy =
251 shared::CWrapperFunctionResult (*)(const char *, size_t);
252 auto *Fn = TagAddr.toPtr<WrapperFnTy>();
253 shared::WrapperFunctionResult ResultBytes(
254 Fn(ArgBytes.data(), ArgBytes.size()));
255 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
256 ExecutorAddr(),
257 {ResultBytes.data(), ResultBytes.size()}))
258 ReportError(std::move(Err));
259 });
260}
261
263SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData,
264 size_t ArgSize) {
265 uint64_t SeqNo;
266 std::promise<shared::WrapperFunctionResult> ResultP;
267 auto ResultF = ResultP.get_future();
268 {
269 std::lock_guard<std::mutex> Lock(ServerStateMutex);
270 if (RunState != ServerRunning)
272 "jit_dispatch not available (EPC server shut down)");
273
274 SeqNo = getNextSeqNo();
275 assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use");
276 PendingJITDispatchResults[SeqNo] = &ResultP;
277 }
278
279 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
280 ExecutorAddr::fromPtr(FnTag), {ArgData, ArgSize}))
281 ReportError(std::move(Err));
282
283 return ResultF.get();
284}
285
287SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag,
288 const char *ArgData, size_t ArgSize) {
289 return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx)
290 ->doJITDispatch(FnTag, ArgData, ArgSize)
291 .release();
292}
293
294} // end namespace orc
295} // end namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
#define I(x, y, z)
Definition MD5.cpp:57
#define T
#define P(N)
Provides a library for accessing information about this process and other processes on the operating ...
#define LLVM_DEBUG(...)
Definition Debug.h:114
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
size - Get the array size.
Definition ArrayRef.h:142
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
pointer data()
Return a pointer to the vector's buffer, even if empty().
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:133
Represents an address in the executor process.
static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap=UnwrapFn())
Create an ExecutorAddr from the given pointer.
std::enable_if_t< std::is_pointer< T >::value, T > toPtr(WrapFn &&Wrap=WrapFn()) const
Cast this ExecutorAddr to a pointer of the given type.
static StringMap< ExecutorAddr > defaultBootstrapSymbols()
Expected< HandleMessageAction > handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, SimpleRemoteEPCArgBytesVector ArgBytes) override
Call to handle an incoming message.
void handleDisconnect(Error Err) override
Handle a disconnection from the underlying transport.
C++ wrapper function result: Same as CWrapperFunctionResult but auto-releases memory.
static WrapperFunctionResult allocate(size_t Size)
Create a WrapperFunctionResult with the given size and return a pointer to the underlying memory.
static WrapperFunctionResult createOutOfBandError(const char *Msg)
Create an out-of-band error by copying the given string.
static LLVM_ABI Expected< unsigned > getPageSize()
Get the process's page size.
unique_function is a type-erasing functor similar to std::function.
@ OB
OB - OneByte - Set if this instruction has a one byte opcode.
void addTo(StringMap< ExecutorAddr > &M)
LLVM_ABI void addDefaultBootstrapValuesForHostProcess(StringMap< std::vector< char > > &BootstrapMap, StringMap< ExecutorAddr > &BootstrapSymbols)
SmallVector< char, 128 > SimpleRemoteEPCArgBytesVector
LLVM_ABI std::string getProcessTriple()
getProcessTriple() - Return an appropriate target triple for generating code to be loaded into the cu...
Definition Host.cpp:2451
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:98
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition Error.h:442
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:869
StringMap< std::vector< char > > BootstrapMap