LLVM 24.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
16
17#define DEBUG_TYPE "orc"
18
19using namespace llvm::orc::shared;
20
21namespace llvm {
22namespace orc {
23
25
27
28#if LLVM_ENABLE_THREADS
29void SimpleRemoteEPCServer::ThreadDispatcher::dispatch(
30 unique_function<void()> Work) {
31 {
32 std::lock_guard<std::mutex> Lock(DispatchMutex);
33 if (!Running)
34 return;
35 ++Outstanding;
36 }
37
38 std::thread([this, Work = std::move(Work)]() mutable {
39 Work();
40 std::lock_guard<std::mutex> Lock(DispatchMutex);
41 --Outstanding;
42 OutstandingCV.notify_all();
43 }).detach();
44}
45
46void SimpleRemoteEPCServer::ThreadDispatcher::shutdown() {
47 std::unique_lock<std::mutex> Lock(DispatchMutex);
48 Running = false;
49 OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
50}
51#endif
52
58
61 ExecutorAddr TagAddr,
63
65 dbgs() << "SimpleRemoteEPCServer::handleMessage: opc = ";
66 switch (OpC) {
68 dbgs() << "Setup";
69 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
70 assert(!TagAddr && "Non-zero TagAddr for Setup?");
71 break;
73 dbgs() << "Hangup";
74 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
75 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
76 break;
78 dbgs() << "Result";
79 assert(!TagAddr && "Non-zero TagAddr for Result?");
80 break;
82 dbgs() << "CallWrapper";
83 break;
84 }
85 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
86 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
87 << " bytes\n";
88 });
89
90 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
91 if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
92 return make_error<StringError>("Unexpected opcode",
94
95 // TODO: Clean detach message?
96 switch (OpC) {
98 return make_error<StringError>("Unexpected Setup opcode",
101 {
102 std::lock_guard<std::mutex> Lock(ServerStateMutex);
103 RemoteHangup = true;
104 }
105 if (auto Err = decodeHangupPayload(std::move(ArgBytes)))
106 return std::move(Err);
108 }
110 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
111 return std::move(Err);
112 break;
114 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
115 break;
116 }
117 return ContinueSession;
118}
119
121 std::unique_lock<std::mutex> Lock(ServerStateMutex);
122 ShutdownCV.wait(Lock, [this]() { return RunState == ServerShutDown; });
123 return std::move(ShutdownErr);
124}
125
127 PendingJITDispatchResultsMap TmpPending;
128
129 {
130 std::lock_guard<std::mutex> Lock(ServerStateMutex);
131 std::swap(TmpPending, PendingJITDispatchResults);
132 RunState = ServerShuttingDown;
133 }
134
135 // Send out-of-band errors to any waiting threads.
136 for (auto &KV : TmpPending)
137 KV.second->set_value(
139
140 // Wait for dispatcher to clear.
141 D->shutdown();
142
143 // Shut down services.
144 while (!Services.empty()) {
145 ShutdownErr =
146 joinErrors(std::move(ShutdownErr), Services.back()->shutdown());
147 Services.pop_back();
148 }
149
150 std::lock_guard<std::mutex> Lock(ServerStateMutex);
151
152 // The server never initiates a disconnection, so if the transport reported no
153 // error and no hangup arrived then the controller went away without telling
154 // us. The cause is not knowable from here -- it may have crashed, been
155 // killed, or become unreachable -- so report what was observed rather than a
156 // cause.
157 //
158 // A missing hangup is evidence, not proof: a hangup can also be lost in
159 // transit, since closing a TCP socket with unread data queued sends an RST,
160 // which can discard bytes the peer had already delivered. We accept that
161 // rather than draining the read side before closing -- the cost is a
162 // misleading diagnostic on a session that is ending regardless, whereas a
163 // drain risks stalling teardown on a peer that never closes.
164 Error DisconnectReason =
165 (!Err && !RemoteHangup)
166 ? make_error<StringError>("Connection closed without hangup",
168 : std::move(Err);
169
170 ShutdownErr = joinErrors(std::move(ShutdownErr), std::move(DisconnectReason));
171 RunState = ServerShutDown;
172 ShutdownCV.notify_all();
173}
174
175Error SimpleRemoteEPCServer::sendMessage(SimpleRemoteEPCOpcode OpC,
176 uint64_t SeqNo, ExecutorAddr TagAddr,
177 ArrayRef<char> ArgBytes) {
178
179 LLVM_DEBUG({
180 dbgs() << "SimpleRemoteEPCServer::sendMessage: opc = ";
181 switch (OpC) {
183 dbgs() << "Setup";
184 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
185 assert(!TagAddr && "Non-zero TagAddr for Setup?");
186 break;
188 dbgs() << "Hangup";
189 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
190 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
191 break;
193 dbgs() << "Result";
194 assert(!TagAddr && "Non-zero TagAddr for Result?");
195 break;
197 dbgs() << "CallWrapper";
198 break;
199 }
200 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
201 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
202 << " bytes\n";
203 });
204 auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
205 LLVM_DEBUG({
206 if (Err)
207 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
208 });
209 return Err;
210}
211
212Error SimpleRemoteEPCServer::sendSetupMessage(
213 StringMap<std::vector<char>> BootstrapMap,
214 StringMap<ExecutorAddr> BootstrapSymbols) {
215
216 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
217
218 SimpleRemoteEPCExecutorInfo EI;
221 EI.PageSize = *PageSize;
222 else
223 return PageSize.takeError();
224 EI.BootstrapMap = std::move(BootstrapMap);
225 EI.BootstrapSymbols = std::move(BootstrapSymbols);
226
227 assert(!EI.BootstrapSymbols.count(ExecutorSessionObjectName) &&
228 "Dispatch context name should not be set");
229 assert(!EI.BootstrapSymbols.count(DispatchFnName) &&
230 "Dispatch function name should not be set");
234
235 using SPSSerialize =
236 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
237 auto SetupPacketBytes =
238 shared::WrapperFunctionBuffer::allocate(SPSSerialize::size(EI));
239 shared::SPSOutputBuffer OB(SetupPacketBytes.data(), SetupPacketBytes.size());
240 if (!SPSSerialize::serialize(OB, EI))
241 return make_error<StringError>("Could not send setup packet",
243
244 return sendMessage(SimpleRemoteEPCOpcode::Setup, 0, ExecutorAddr(),
245 {SetupPacketBytes.data(), SetupPacketBytes.size()});
246}
247
248Error SimpleRemoteEPCServer::handleResult(
249 uint64_t SeqNo, ExecutorAddr TagAddr,
251 std::promise<shared::WrapperFunctionBuffer> *P = nullptr;
252 {
253 std::lock_guard<std::mutex> Lock(ServerStateMutex);
254 auto I = PendingJITDispatchResults.find(SeqNo);
255 if (I == PendingJITDispatchResults.end())
256 return make_error<StringError>("No call for sequence number " +
257 Twine(SeqNo),
259 P = I->second;
260 PendingJITDispatchResults.erase(I);
261 releaseSeqNo(SeqNo);
262 }
264 memcpy(R.data(), ArgBytes.data(), ArgBytes.size());
265 P->set_value(std::move(R));
266 return Error::success();
267}
268
269void SimpleRemoteEPCServer::handleCallWrapper(
270 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
272 D->dispatch([this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
273 using WrapperFnTy =
274 shared::CWrapperFunctionBuffer (*)(const char *, size_t);
275 auto *Fn = TagAddr.toPtr<WrapperFnTy>();
276 shared::WrapperFunctionBuffer ResultBytes(
277 Fn(ArgBytes.data(), ArgBytes.size()));
278 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
279 ExecutorAddr(),
280 {ResultBytes.data(), ResultBytes.size()}))
281 ReportError(std::move(Err));
282 });
283}
284
286SimpleRemoteEPCServer::doJITDispatch(const void *FnTag, const char *ArgData,
287 size_t ArgSize) {
288 uint64_t SeqNo;
289 std::promise<shared::WrapperFunctionBuffer> ResultP;
290 auto ResultF = ResultP.get_future();
291 {
292 std::lock_guard<std::mutex> Lock(ServerStateMutex);
293 if (RunState != ServerRunning)
295 "jit_dispatch not available (EPC server shut down)");
296
297 SeqNo = getNextSeqNo();
298 assert(!PendingJITDispatchResults.count(SeqNo) && "SeqNo already in use");
299 PendingJITDispatchResults[SeqNo] = &ResultP;
300 }
301
302 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
303 ExecutorAddr::fromPtr(FnTag), {ArgData, ArgSize}))
304 ReportError(std::move(Err));
305
306 return ResultF.get();
307}
308
310SimpleRemoteEPCServer::jitDispatchEntry(void *DispatchCtx, const void *FnTag,
311 const char *ArgData, size_t ArgSize) {
312 return reinterpret_cast<SimpleRemoteEPCServer *>(DispatchCtx)
313 ->doJITDispatch(FnTag, ArgData, ArgSize)
314 .release();
315}
316
317} // end namespace orc
318} // end namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
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:119
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
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
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:129
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()
void handleDisconnect(Error Err) override
Handle a disconnection from the underlying transport.
Expected< HandleMessageAction > handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, shared::WrapperFunctionBuffer ArgBytes) override
Call to handle an incoming message.
C++ wrapper function buffer: Same as CWrapperFunctionBuffer but auto-releases memory.
size_t size() const
Returns the size of the data contained in this instance.
static WrapperFunctionBuffer createOutOfBandError(const char *Msg)
Create an out-of-band error by copying the given string.
char * data()
Get a pointer to the data contained in this instance.
static WrapperFunctionBuffer allocate(size_t Size)
Create a WrapperFunctionBuffer with the given size and return a pointer to the underlying memory.
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)
Adds all default target-process bootstrap wrappers.
LLVM_ABI void addDefaultBootstrapValuesForHostProcess(StringMap< std::vector< char > > &BootstrapMap, StringMap< ExecutorAddr > &BootstrapSymbols)
LLVM_ABI Error decodeHangupPayload(shared::WrapperFunctionBuffer Payload)
Decode a Hangup payload produced by encodeHangupPayload.
LLVM_ABI std::string getProcessTriple()
getProcessTriple() - Return an appropriate target triple for generating code to be loaded into the cu...
Definition Host.cpp:2653
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:94
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:209
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:880
StringMap< std::vector< char > > BootstrapMap