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
15
16#define DEBUG_TYPE "orc"
17
18namespace llvm {
19namespace orc {
20
22#ifndef NDEBUG
23 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
24 assert(Disconnected && "Destroyed without disconnection");
25#endif // NDEBUG
26}
27
30 int64_t Result = 0;
32 RunAsMainAddr, Result, MainFnAddr, Args))
33 return std::move(Err);
34 return Result;
35}
36
38 int32_t Result = 0;
40 RunAsVoidFunctionAddr, Result, VoidFnAddr))
41 return std::move(Err);
42 return Result;
43}
44
46 int Arg) {
47 int32_t Result = 0;
49 RunAsIntFunctionAddr, Result, IntFnAddr, Arg))
50 return std::move(Err);
51 return Result;
52}
53
55 IncomingWFRHandler OnComplete,
56 ArrayRef<char> ArgBuffer) {
57 uint64_t SeqNo;
58 {
59 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
60 SeqNo = getNextSeqNo();
61 assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
62 PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
63 }
64
65 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
66 WrapperFnAddr, ArgBuffer)) {
68
69 // We just registered OnComplete, but there may be a race between this
70 // thread returning from sendMessage and handleDisconnect being called from
71 // the transport's listener thread. If handleDisconnect gets there first
72 // then it will have failed 'H' for us. If we get there first (or if
73 // handleDisconnect already ran) then we need to take care of it.
74 {
75 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
76 auto I = PendingCallWrapperResults.find(SeqNo);
77 if (I != PendingCallWrapperResults.end()) {
78 H = std::move(I->second);
79 PendingCallWrapperResults.erase(I);
80 }
81 }
82
83 if (H)
85
86 getExecutionSession().reportError(std::move(Err));
87 }
88}
89
93 if (!DM)
94 return DM.takeError();
95 return std::make_unique<EPCGenericDylibManager>(std::move(*DM));
96}
97
118
120 T->disconnect();
121 D->shutdown();
122 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
123 DisconnectCV.wait(Lock, [this] { return Disconnected; });
124 return std::move(DisconnectErr);
125}
126
129 ExecutorAddr TagAddr,
131
132 LLVM_DEBUG({
133 dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";
134 switch (OpC) {
136 dbgs() << "Setup";
137 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
138 assert(!TagAddr && "Non-zero TagAddr for Setup?");
139 break;
141 dbgs() << "Hangup";
142 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
143 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
144 break;
146 dbgs() << "Result";
147 assert(!TagAddr && "Non-zero TagAddr for Result?");
148 break;
150 dbgs() << "CallWrapper";
151 break;
152 }
153 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
154 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
155 << " bytes\n";
156 });
157
158 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
159 if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
160 return make_error<StringError>("Unexpected opcode",
162
163 switch (OpC) {
165 if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
166 return std::move(Err);
167 break;
169 T->disconnect();
170 if (auto Err = handleHangup(std::move(ArgBytes)))
171 return std::move(Err);
172 return EndSession;
174 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
175 return std::move(Err);
176 break;
178 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
179 break;
180 }
181 return ContinueSession;
182}
183
185 LLVM_DEBUG({
186 dbgs() << "SimpleRemoteEPC::handleDisconnect: "
187 << (Err ? "failure" : "success") << "\n";
188 });
189
190 PendingCallWrapperResultsMap TmpPending;
191
192 {
193 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
194 std::swap(TmpPending, PendingCallWrapperResults);
195 }
196
197 for (auto &KV : TmpPending)
198 KV.second(
200
201 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
202 DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));
203 Disconnected = true;
204 DisconnectCV.notify_all();
205}
206
208SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC &SREPC) {
210 if (auto Err = SREPC.getBootstrapSymbols(
211 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
212 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
213 {SAs.Initialize,
214 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
215 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
216 return std::move(Err);
217
218 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
219}
220
221Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
222 ExecutorAddr TagAddr,
223 ArrayRef<char> ArgBytes) {
224 assert(OpC != SimpleRemoteEPCOpcode::Setup &&
225 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
226
227 LLVM_DEBUG({
228 dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";
229 switch (OpC) {
230 case SimpleRemoteEPCOpcode::Hangup:
231 dbgs() << "Hangup";
232 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
233 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
234 break;
235 case SimpleRemoteEPCOpcode::Result:
236 dbgs() << "Result";
237 assert(!TagAddr && "Non-zero TagAddr for Result?");
238 break;
239 case SimpleRemoteEPCOpcode::CallWrapper:
240 dbgs() << "CallWrapper";
241 break;
242 default:
243 llvm_unreachable("Invalid opcode");
244 }
245 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
246 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
247 << " bytes\n";
248 });
249 auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
250 LLVM_DEBUG({
251 if (Err)
252 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
253 });
254 return Err;
255}
256
257Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
258 shared::WrapperFunctionBuffer ArgBytes) {
259 if (SeqNo != 0)
260 return make_error<StringError>("Setup packet SeqNo not zero",
262
263 if (TagAddr)
264 return make_error<StringError>("Setup packet TagAddr not zero",
266
267 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
268 auto I = PendingCallWrapperResults.find(0);
269 assert(PendingCallWrapperResults.size() == 1 &&
270 I != PendingCallWrapperResults.end() &&
271 "Setup message handler not connectly set up");
272 auto SetupMsgHandler = std::move(I->second);
273 PendingCallWrapperResults.erase(I);
274
275 auto WFR =
276 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
277 SetupMsgHandler(std::move(WFR));
278 return Error::success();
279}
280
281Error SimpleRemoteEPC::setup(Setup S) {
282 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
283
284 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
285 auto EIF = EIP.get_future();
286
287 // Prepare a handler for the setup packet.
288 PendingCallWrapperResults[0] =
289 RunInPlace()(
290 [&](shared::WrapperFunctionBuffer SetupMsgBytes) {
291 if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
292 EIP.set_value(
294 return;
295 }
296 using SPSSerialize =
297 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
298 shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
299 SimpleRemoteEPCExecutorInfo EI;
300 if (SPSSerialize::deserialize(IB, EI))
301 EIP.set_value(EI);
302 else
303 EIP.set_value(make_error<StringError>(
304 "Could not deserialize setup message", inconvertibleErrorCode()));
305 });
306
307 // Start the transport.
308 if (auto Err = T->start())
309 return Err;
310
311 // Wait for setup packet to arrive.
312 auto EI = EIF.get();
313 if (!EI) {
314 T->disconnect();
315 return EI.takeError();
316 }
317
318 LLVM_DEBUG({
319 dbgs() << "SimpleRemoteEPC received setup message:\n"
320 << " Triple: " << EI->TargetTriple << "\n"
321 << " Page size: " << EI->PageSize << "\n"
322 << " Bootstrap map" << (EI->BootstrapMap.empty() ? " empty" : ":")
323 << "\n";
324 for (const auto &KV : EI->BootstrapMap)
325 dbgs() << " " << KV.first() << ": " << KV.second.size()
326 << "-byte SPS encoded buffer\n";
327 dbgs() << " Bootstrap symbols"
328 << (EI->BootstrapSymbols.empty() ? " empty" : ":") << "\n";
329 for (const auto &KV : EI->BootstrapSymbols)
330 dbgs() << " " << KV.first() << ": " << KV.second << "\n";
331 });
332 TargetTriple = Triple(EI->TargetTriple);
333 PageSize = EI->PageSize;
334 BootstrapMap = std::move(EI->BootstrapMap);
335 BootstrapSymbols = std::move(EI->BootstrapSymbols);
336
337 if (auto Err = getBootstrapSymbols(
338 {{JDI.JITDispatchContext, ExecutorSessionObjectName},
339 {JDI.JITDispatchFunction, DispatchFnName},
340 {RunAsMainAddr, rt::RunAsMainWrapperName},
341 {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},
342 {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))
343 return Err;
344
345 // Set a default CreateMemoryManager if none is specified.
346 if (!S.CreateMemoryManager)
347 S.CreateMemoryManager = createDefaultMemoryManager;
348
349 if (auto MemMgr = S.CreateMemoryManager(*this)) {
350 OwnedMemMgr = std::move(*MemMgr);
351 this->MemMgr = OwnedMemMgr.get();
352 } else
353 return MemMgr.takeError();
354
355 return Error::success();
356}
357
358Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
359 shared::WrapperFunctionBuffer ArgBytes) {
360 IncomingWFRHandler SendResult;
361
362 if (TagAddr)
363 return make_error<StringError>("Unexpected TagAddr in result message",
365
366 {
367 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
368 auto I = PendingCallWrapperResults.find(SeqNo);
369 if (I == PendingCallWrapperResults.end())
370 return make_error<StringError>("No call for sequence number " +
371 Twine(SeqNo),
373 SendResult = std::move(I->second);
374 PendingCallWrapperResults.erase(I);
375 releaseSeqNo(SeqNo);
376 }
377
378 auto WFR =
379 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
380 SendResult(std::move(WFR));
381 return Error::success();
382}
383
384void SimpleRemoteEPC::handleCallWrapper(
385 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
386 shared::WrapperFunctionBuffer ArgBytes) {
387 assert(ES && "No ExecutionSession attached");
388 D->dispatch(makeGenericNamedTask(
389 [this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() mutable {
390 ES->runJITDispatchHandler(
391 [this, RemoteSeqNo](shared::WrapperFunctionBuffer WFR) {
392 if (auto Err =
393 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
394 ExecutorAddr(), {WFR.data(), WFR.size()}))
395 getExecutionSession().reportError(std::move(Err));
396 },
397 TagAddr, std::move(ArgBytes));
398 },
399 "callWrapper task"));
400}
401
402Error SimpleRemoteEPC::handleHangup(shared::WrapperFunctionBuffer ArgBytes) {
403 using namespace llvm::orc::shared;
404 auto WFR = WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
405 if (const char *ErrMsg = WFR.getOutOfBandError())
407
409 SPSInputBuffer IB(WFR.data(), WFR.size());
410 if (!SPSArgList<SPSError>::deserialize(IB, Info))
411 return make_error<StringError>("Could not deserialize hangup info",
413 return fromSPSSerializable(std::move(Info));
414}
415
416} // end namespace orc
417} // 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.