LLVM 24.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
16
17#define DEBUG_TYPE "orc"
18
19namespace llvm {
20namespace orc {
21
23#ifndef NDEBUG
24 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
25 assert(Disconnected && "Destroyed without disconnection");
26#endif // NDEBUG
27}
28
31 int64_t Result = 0;
33 RunAsMainAddr, Result, MainFnAddr, Args))
34 return std::move(Err);
35 return Result;
36}
37
39 IncomingWFRHandler OnComplete,
40 ArrayRef<char> ArgBuffer) {
41 uint64_t SeqNo;
42 {
43 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
44 SeqNo = getNextSeqNo();
45 assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
46 PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
47 }
48
49 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
50 WrapperFnAddr, ArgBuffer)) {
52
53 // We just registered OnComplete, but there may be a race between this
54 // thread returning from sendMessage and handleDisconnect being called from
55 // the transport's listener thread. If handleDisconnect gets there first
56 // then it will have failed 'H' for us. If we get there first (or if
57 // handleDisconnect already ran) then we need to take care of it.
58 {
59 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
60 auto I = PendingCallWrapperResults.find(SeqNo);
61 if (I != PendingCallWrapperResults.end()) {
62 H = std::move(I->second);
63 PendingCallWrapperResults.erase(I);
64 }
65 }
66
67 if (H)
69
70 getExecutionSession().reportError(std::move(Err));
71 }
72}
73
78
82 if (!DM)
83 return DM.takeError();
84 return std::make_unique<EPCGenericDylibManager>(std::move(*DM));
85}
86
107
109 T->disconnect();
110 D->shutdown();
111 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
112 DisconnectCV.wait(Lock, [this] { return Disconnected; });
113 return std::move(DisconnectErr);
114}
115
118 ExecutorAddr TagAddr,
120
121 LLVM_DEBUG({
122 dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";
123 switch (OpC) {
125 dbgs() << "Setup";
126 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
127 assert(!TagAddr && "Non-zero TagAddr for Setup?");
128 break;
130 dbgs() << "Hangup";
131 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
132 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
133 break;
135 dbgs() << "Result";
136 assert(!TagAddr && "Non-zero TagAddr for Result?");
137 break;
139 dbgs() << "CallWrapper";
140 break;
141 }
142 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
143 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
144 << " bytes\n";
145 });
146
147 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
148 if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
149 return make_error<StringError>("Unexpected opcode",
151
152 switch (OpC) {
154 if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
155 return std::move(Err);
156 break;
158 T->disconnect();
159 if (auto Err = handleHangup(std::move(ArgBytes)))
160 return std::move(Err);
161 return EndSession;
163 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
164 return std::move(Err);
165 break;
167 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
168 break;
169 }
170 return ContinueSession;
171}
172
174 LLVM_DEBUG({
175 dbgs() << "SimpleRemoteEPC::handleDisconnect: "
176 << (Err ? "failure" : "success") << "\n";
177 });
178
179 PendingCallWrapperResultsMap TmpPending;
180
181 {
182 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
183 std::swap(TmpPending, PendingCallWrapperResults);
184 }
185
186 for (auto &KV : TmpPending)
187 KV.second(
189
190 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
191 DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));
192 Disconnected = true;
193 DisconnectCV.notify_all();
194}
195
199 if (auto Err = SREPC.getBootstrapSymbols(
200 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
201 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
202 {SAs.Initialize,
203 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
204 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
205 return std::move(Err);
206
207 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
208}
209
210Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
211 ExecutorAddr TagAddr,
212 ArrayRef<char> ArgBytes) {
213 assert(OpC != SimpleRemoteEPCOpcode::Setup &&
214 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
215
216 LLVM_DEBUG({
217 dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";
218 switch (OpC) {
219 case SimpleRemoteEPCOpcode::Hangup:
220 dbgs() << "Hangup";
221 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
222 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
223 break;
224 case SimpleRemoteEPCOpcode::Result:
225 dbgs() << "Result";
226 assert(!TagAddr && "Non-zero TagAddr for Result?");
227 break;
228 case SimpleRemoteEPCOpcode::CallWrapper:
229 dbgs() << "CallWrapper";
230 break;
231 default:
232 llvm_unreachable("Invalid opcode");
233 }
234 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
235 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
236 << " bytes\n";
237 });
238 auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
239 LLVM_DEBUG({
240 if (Err)
241 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
242 });
243 return Err;
244}
245
246Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
247 shared::WrapperFunctionBuffer ArgBytes) {
248 if (SeqNo != 0)
249 return make_error<StringError>("Setup packet SeqNo not zero",
251
252 if (TagAddr)
253 return make_error<StringError>("Setup packet TagAddr not zero",
255
256 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
257 auto I = PendingCallWrapperResults.find(0);
258 assert(PendingCallWrapperResults.size() == 1 &&
259 I != PendingCallWrapperResults.end() &&
260 "Setup message handler not connectly set up");
261 auto SetupMsgHandler = std::move(I->second);
262 PendingCallWrapperResults.erase(I);
263
264 auto WFR =
265 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
266 SetupMsgHandler(std::move(WFR));
267 return Error::success();
268}
269
270Error SimpleRemoteEPC::setup() {
271 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
272
273 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
274 auto EIF = EIP.get_future();
275
276 // Prepare a handler for the setup packet.
277 PendingCallWrapperResults[0] =
278 RunInPlace()(
279 [&](shared::WrapperFunctionBuffer SetupMsgBytes) {
280 if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
281 EIP.set_value(
283 return;
284 }
285 using SPSSerialize =
286 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
287 shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
288 SimpleRemoteEPCExecutorInfo EI;
289 if (SPSSerialize::deserialize(IB, EI))
290 EIP.set_value(EI);
291 else
292 EIP.set_value(make_error<StringError>(
293 "Could not deserialize setup message", inconvertibleErrorCode()));
294 });
295
296 // Start the transport.
297 if (auto Err = T->start())
298 return Err;
299
300 // Wait for setup packet to arrive.
301 auto EI = EIF.get();
302 if (!EI) {
303 T->disconnect();
304 return EI.takeError();
305 }
306
307 LLVM_DEBUG({
308 dbgs() << "SimpleRemoteEPC received setup message:\n"
309 << " Triple: " << EI->TargetTriple << "\n"
310 << " Page size: " << EI->PageSize << "\n"
311 << " Bootstrap map" << (EI->BootstrapMap.empty() ? " empty" : ":")
312 << "\n";
313 for (const auto &KV : EI->BootstrapMap)
314 dbgs() << " " << KV.first() << ": " << KV.second.size()
315 << "-byte SPS encoded buffer\n";
316 dbgs() << " Bootstrap symbols"
317 << (EI->BootstrapSymbols.empty() ? " empty" : ":") << "\n";
318 for (const auto &KV : EI->BootstrapSymbols)
319 dbgs() << " " << KV.first() << ": " << KV.second << "\n";
320 });
321 TargetTriple = Triple(EI->TargetTriple);
322 PageSize = EI->PageSize;
323 BootstrapMap = std::move(EI->BootstrapMap);
324 BootstrapSymbols = std::move(EI->BootstrapSymbols);
325
326 BootstrapSymbols[rt::DispatchName] = BootstrapSymbols[DispatchFnName];
327 BootstrapSymbols[rt::DispatchCtxName] =
328 BootstrapSymbols[ExecutorSessionObjectName];
329
330 if (auto Err =
331 getBootstrapSymbols({{RunAsMainAddr, rt::sps::CallMainCIName}}))
332 return Err;
333
334 return Error::success();
335}
336
337Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
338 shared::WrapperFunctionBuffer ArgBytes) {
339 IncomingWFRHandler SendResult;
340
341 if (TagAddr)
342 return make_error<StringError>("Unexpected TagAddr in result message",
344
345 {
346 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
347 auto I = PendingCallWrapperResults.find(SeqNo);
348 if (I == PendingCallWrapperResults.end())
349 return make_error<StringError>("No call for sequence number " +
350 Twine(SeqNo),
352 SendResult = std::move(I->second);
353 PendingCallWrapperResults.erase(I);
354 releaseSeqNo(SeqNo);
355 }
356
357 auto WFR =
358 shared::WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
359 SendResult(std::move(WFR));
360 return Error::success();
361}
362
363void SimpleRemoteEPC::handleCallWrapper(
364 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
365 shared::WrapperFunctionBuffer ArgBytes) {
366 assert(ES && "No ExecutionSession attached");
367 D->dispatch(makeGenericNamedTask(
368 [this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() mutable {
369 ES->runJITDispatchHandler(
370 [this, RemoteSeqNo](shared::WrapperFunctionBuffer WFR) {
371 if (auto Err =
372 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
373 ExecutorAddr(), {WFR.data(), WFR.size()}))
374 getExecutionSession().reportError(std::move(Err));
375 },
376 TagAddr, std::move(ArgBytes));
377 },
378 "callWrapper task"));
379}
380
381Error SimpleRemoteEPC::handleHangup(shared::WrapperFunctionBuffer ArgBytes) {
382 using namespace llvm::orc::shared;
383 auto WFR = WrapperFunctionBuffer::copyFrom(ArgBytes.data(), ArgBytes.size());
384 if (const char *ErrMsg = WFR.getOutOfBandError())
386
388 SPSInputBuffer IB(WFR.data(), WFR.size());
389 if (!SPSArgList<SPSError>::deserialize(IB, Info))
390 return make_error<StringError>("Could not deserialize hangup info",
392 return fromSPSSerializable(std::move(Info));
393}
394
395} // end namespace orc
396} // 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:119
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:48
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static Expected< EPCGenericDylibManager > CreateWithDefaultBootstrapSymbols(ExecutorProcessControl &EPC)
Create an EPCGenericDylibManager instance by looking up the LLVM-style SimpleExecutorDylibManager sym...
static Expected< std::unique_ptr< EPCGenericJITLinkMemoryManager > > Create(JITDylib &JD, rt::SimpleExecutorMemoryManagerSymbolNames SNs=rt::orc_rt_SimpleNativeMemoryMapSPSSymbols)
Create an EPCGenericJITLinkMemoryManager using the given implementation symbol names.
void reportError(Error Err)
Report a error for this execution session.
Definition Core.h:1262
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< std::unique_ptr< jitlink::JITLinkMemoryManager > > createDefaultMemoryManager() override
Create a default JITLinkMemoryManager for the target process.
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.
void callWrapperAsync(ExecutorAddr WrapperFnAddr, IncomingWFRHandler OnComplete, ArrayRef< char > ArgBuffer) override
Run a wrapper function in the executor.
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: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
Symbol addresses for memory management implementation.
Function addresses for memory access.