LLVM 23.0.0git
SimpleRemoteEPC.cpp
Go to the documentation of this file.
1//===------- SimpleRemoteEPC.cpp -- Simple remote executor control --------===//
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
14
15#define DEBUG_TYPE "orc"
16
17namespace llvm {
18namespace orc {
19
21#ifndef NDEBUG
22 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
23 assert(Disconnected && "Destroyed without disconnection");
24#endif // NDEBUG
25}
26
29 int64_t Result = 0;
31 RunAsMainAddr, Result, MainFnAddr, Args))
32 return std::move(Err);
33 return Result;
34}
35
37 int32_t Result = 0;
39 RunAsVoidFunctionAddr, Result, VoidFnAddr))
40 return std::move(Err);
41 return Result;
42}
43
45 int Arg) {
46 int32_t Result = 0;
48 RunAsIntFunctionAddr, Result, IntFnAddr, Arg))
49 return std::move(Err);
50 return Result;
51}
52
54 IncomingWFRHandler OnComplete,
55 ArrayRef<char> ArgBuffer) {
56 uint64_t SeqNo;
57 {
58 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
59 SeqNo = getNextSeqNo();
60 assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
61 PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
62 }
63
64 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
65 WrapperFnAddr, ArgBuffer)) {
67
68 // We just registered OnComplete, but there may be a race between this
69 // thread returning from sendMessage and handleDisconnect being called from
70 // the transport's listener thread. If handleDisconnect gets there first
71 // then it will have failed 'H' for us. If we get there first (or if
72 // handleDisconnect already ran) then we need to take care of it.
73 {
74 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
75 auto I = PendingCallWrapperResults.find(SeqNo);
76 if (I != PendingCallWrapperResults.end()) {
77 H = std::move(I->second);
78 PendingCallWrapperResults.erase(I);
79 }
80 }
81
82 if (H)
84
85 getExecutionSession().reportError(std::move(Err));
86 }
87}
88
92 if (!DM)
93 return DM.takeError();
94 return std::make_unique<EPCGenericDylibManager>(std::move(*DM));
95}
96
117
119 T->disconnect();
120 D->shutdown();
121 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
122 DisconnectCV.wait(Lock, [this] { return Disconnected; });
123 return std::move(DisconnectErr);
124}
125
128 ExecutorAddr TagAddr,
130
131 LLVM_DEBUG({
132 dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";
133 switch (OpC) {
135 dbgs() << "Setup";
136 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
137 assert(!TagAddr && "Non-zero TagAddr for Setup?");
138 break;
140 dbgs() << "Hangup";
141 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
142 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
143 break;
145 dbgs() << "Result";
146 assert(!TagAddr && "Non-zero TagAddr for Result?");
147 break;
149 dbgs() << "CallWrapper";
150 break;
151 }
152 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
153 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
154 << " bytes\n";
155 });
156
157 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
158 if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
159 return make_error<StringError>("Unexpected opcode",
161
162 switch (OpC) {
164 if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
165 return std::move(Err);
166 break;
168 T->disconnect();
169 if (auto Err = handleHangup(std::move(ArgBytes)))
170 return std::move(Err);
171 return EndSession;
173 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
174 return std::move(Err);
175 break;
177 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
178 break;
179 }
180 return ContinueSession;
181}
182
184 LLVM_DEBUG({
185 dbgs() << "SimpleRemoteEPC::handleDisconnect: "
186 << (Err ? "failure" : "success") << "\n";
187 });
188
189 PendingCallWrapperResultsMap TmpPending;
190
191 {
192 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
193 std::swap(TmpPending, PendingCallWrapperResults);
194 }
195
196 for (auto &KV : TmpPending)
197 KV.second(
199
200 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
201 DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));
202 Disconnected = true;
203 DisconnectCV.notify_all();
204}
205
207SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC &SREPC) {
209 if (auto Err = SREPC.getBootstrapSymbols(
210 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
211 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
212 {SAs.Initialize,
213 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
214 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
215 return std::move(Err);
216
217 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
218}
219
220Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
221 ExecutorAddr TagAddr,
222 ArrayRef<char> ArgBytes) {
223 assert(OpC != SimpleRemoteEPCOpcode::Setup &&
224 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
225
226 LLVM_DEBUG({
227 dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";
228 switch (OpC) {
229 case SimpleRemoteEPCOpcode::Hangup:
230 dbgs() << "Hangup";
231 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
232 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
233 break;
234 case SimpleRemoteEPCOpcode::Result:
235 dbgs() << "Result";
236 assert(!TagAddr && "Non-zero TagAddr for Result?");
237 break;
238 case SimpleRemoteEPCOpcode::CallWrapper:
239 dbgs() << "CallWrapper";
240 break;
241 default:
242 llvm_unreachable("Invalid opcode");
243 }
244 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
245 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
246 << " bytes\n";
247 });
248 auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
249 LLVM_DEBUG({
250 if (Err)
251 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
252 });
253 return Err;
254}
255
256Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
257 shared::WrapperFunctionBuffer ArgBytes) {
258 if (SeqNo != 0)
259 return make_error<StringError>("Setup packet SeqNo not zero",
261
262 if (TagAddr)
263 return make_error<StringError>("Setup packet TagAddr not zero",
265
266 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
267 auto I = PendingCallWrapperResults.find(0);
268 assert(PendingCallWrapperResults.size() == 1 &&
269 I != PendingCallWrapperResults.end() &&
270 "Setup message handler not connectly set up");
271 auto SetupMsgHandler = std::move(I->second);
272 PendingCallWrapperResults.erase(I);
273
274 auto WFR =
275 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
276 SetupMsgHandler(std::move(WFR));
277 return Error::success();
278}
279
280Error SimpleRemoteEPC::setup(Setup S) {
281 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
282
283 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
284 auto EIF = EIP.get_future();
285
286 // Prepare a handler for the setup packet.
287 PendingCallWrapperResults[0] =
288 RunInPlace()(
289 [&](shared::WrapperFunctionBuffer SetupMsgBytes) {
290 if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
291 EIP.set_value(
293 return;
294 }
295 using SPSSerialize =
296 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
297 shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
298 SimpleRemoteEPCExecutorInfo EI;
299 if (SPSSerialize::deserialize(IB, EI))
300 EIP.set_value(EI);
301 else
302 EIP.set_value(make_error<StringError>(
303 "Could not deserialize setup message", inconvertibleErrorCode()));
304 });
305
306 // Start the transport.
307 if (auto Err = T->start())
308 return Err;
309
310 // Wait for setup packet to arrive.
311 auto EI = EIF.get();
312 if (!EI) {
313 T->disconnect();
314 return EI.takeError();
315 }
316
317 LLVM_DEBUG({
318 dbgs() << "SimpleRemoteEPC received setup message:\n"
319 << " Triple: " << EI->TargetTriple << "\n"
320 << " Page size: " << EI->PageSize << "\n"
321 << " Bootstrap map" << (EI->BootstrapMap.empty() ? " empty" : ":")
322 << "\n";
323 for (const auto &KV : EI->BootstrapMap)
324 dbgs() << " " << KV.first() << ": " << KV.second.size()
325 << "-byte SPS encoded buffer\n";
326 dbgs() << " Bootstrap symbols"
327 << (EI->BootstrapSymbols.empty() ? " empty" : ":") << "\n";
328 for (const auto &KV : EI->BootstrapSymbols)
329 dbgs() << " " << KV.first() << ": " << KV.second << "\n";
330 });
331 TargetTriple = Triple(EI->TargetTriple);
332 PageSize = EI->PageSize;
333 BootstrapMap = std::move(EI->BootstrapMap);
334 BootstrapSymbols = std::move(EI->BootstrapSymbols);
335
336 if (auto Err = getBootstrapSymbols(
337 {{JDI.JITDispatchContext, ExecutorSessionObjectName},
338 {JDI.JITDispatchFunction, DispatchFnName},
339 {RunAsMainAddr, rt::RunAsMainWrapperName},
340 {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},
341 {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))
342 return Err;
343
344 // Set a default CreateMemoryManager if none is specified.
345 if (!S.CreateMemoryManager)
346 S.CreateMemoryManager = createDefaultMemoryManager;
347
348 if (auto MemMgr = S.CreateMemoryManager(*this)) {
349 OwnedMemMgr = std::move(*MemMgr);
350 this->MemMgr = OwnedMemMgr.get();
351 } else
352 return MemMgr.takeError();
353
354 return Error::success();
355}
356
357Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
358 shared::WrapperFunctionBuffer ArgBytes) {
359 IncomingWFRHandler SendResult;
360
361 if (TagAddr)
362 return make_error<StringError>("Unexpected TagAddr in result message",
364
365 {
366 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
367 auto I = PendingCallWrapperResults.find(SeqNo);
368 if (I == PendingCallWrapperResults.end())
369 return make_error<StringError>("No call for sequence number " +
370 Twine(SeqNo),
372 SendResult = std::move(I->second);
373 PendingCallWrapperResults.erase(I);
374 releaseSeqNo(SeqNo);
375 }
376
377 auto WFR =
378 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
379 SendResult(std::move(WFR));
380 return Error::success();
381}
382
383void SimpleRemoteEPC::handleCallWrapper(
384 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
385 shared::WrapperFunctionBuffer ArgBytes) {
386 assert(ES && "No ExecutionSession attached");
387 D->dispatch(makeGenericNamedTask(
388 [this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() mutable {
389 ES->runJITDispatchHandler(
390 [this, RemoteSeqNo](shared::WrapperFunctionBuffer WFR) {
391 if (auto Err =
392 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
393 ExecutorAddr(), {WFR.data(), WFR.size()}))
394 getExecutionSession().reportError(std::move(Err));
395 },
396 TagAddr, std::move(ArgBytes));
397 },
398 "callWrapper task"));
399}
400
401Error SimpleRemoteEPC::handleHangup(shared::WrapperFunctionBuffer ArgBytes) {
402 using namespace llvm::orc::shared;
403 auto WFR = WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
404 if (const char *ErrMsg = WFR.getOutOfBandError())
406
408 SPSInputBuffer IB(WFR.data(), WFR.size());
409 if (!SPSArgList<SPSError>::deserialize(IB, Info))
410 return make_error<StringError>("Could not deserialize hangup info",
412 return fromSPSSerializable(std::move(Info));
413}
414
415} // end namespace orc
416} // end namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")
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 H(x, y, z)
Definition MD5.cpp:56
#define T
#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
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
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static LLVM_ABI Expected< EPCGenericDylibManager > CreateWithDefaultBootstrapSymbols(ExecutorProcessControl &EPC)
Create an EPCGenericMemoryAccess instance from a given set of function addrs.
void reportError(Error Err)
Report a error for this execution session.
Definition Core.h:1506
Represents an address in the executor process.
A handler or incoming WrapperFunctionBuffers – either return values from callWrapper* calls,...
std::unique_ptr< TaskDispatcher > D
Error callSPSWrapper(ExecutorAddr WrapperFnAddr, WrapperCallArgTs &&...WrapperCallArgs)
Run a wrapper function using SPS to serialize the arguments and deserialize the results.
Error getBootstrapSymbols(ArrayRef< std::pair< ExecutorAddr &, StringRef > > Pairs) const
For each (ExecutorAddr&, StringRef) pair, looks up the string in the bootstrap symbols map and writes...
ExecutionSession & getExecutionSession()
Return the ExecutionSession associated with this instance.
void handleDisconnect(Error Err) override
Handle a disconnection from the underlying transport.
Expected< std::unique_ptr< MemoryAccess > > createDefaultMemoryAccess() override
Create a default MemoryAccess for the target process.
Expected< int32_t > runAsMain(ExecutorAddr MainFnAddr, ArrayRef< std::string > Args) override
Run function with a main-like signature.
Expected< HandleMessageAction > handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo, ExecutorAddr TagAddr, shared::WrapperFunctionBuffer ArgBytes) override
Handle receipt of a message.
Expected< std::unique_ptr< DylibManager > > createDefaultDylibMgr() override
Create a default DylibManager for the target process.
Error disconnect() override
Disconnect from the target process.
Expected< int32_t > runAsVoidFunction(ExecutorAddr VoidFnAddr) override
Run function with a int (*)(void) signature.
void callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef< char > ArgBuffer) override
Run a wrapper function in the executor.
Expected< int32_t > runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) override
Run function with a int (*)(int) signature.
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.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI const char * MemoryReadUInt64sWrapperName
LLVM_ABI const char * MemoryWriteUInt16sWrapperName
LLVM_ABI const char * MemoryReadStringsWrapperName
LLVM_ABI const char * MemoryReadUInt16sWrapperName
LLVM_ABI const char * MemoryReadUInt32sWrapperName
LLVM_ABI const char * MemoryWriteUInt64sWrapperName
LLVM_ABI const char * MemoryWriteUInt8sWrapperName
LLVM_ABI const char * MemoryWritePointersWrapperName
LLVM_ABI const char * MemoryWriteUInt32sWrapperName
LLVM_ABI const char * MemoryWriteBuffersWrapperName
LLVM_ABI const char * MemoryReadBuffersWrapperName
LLVM_ABI const char * MemoryReadUInt8sWrapperName
Error fromSPSSerializable(SPSSerializableError BSE)
std::unique_ptr< GenericNamedTask > makeGenericNamedTask(FnT &&Fn, std::string Desc)
Create a generic named task from a std::string description.
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: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:872
Symbol addresses for memory management implementation.
Function addresses for memory access.