LLVM 17.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
28SimpleRemoteEPC::loadDylib(const char *DylibPath) {
29 return DylibMgr->open(DylibPath, 0);
30}
31
34 std::vector<tpctypes::LookupResult> Result;
35
36 for (auto &Element : Request) {
37 if (auto R = DylibMgr->lookup(Element.Handle, Element.Symbols)) {
38 Result.push_back({});
39 Result.back().reserve(R->size());
40 for (auto Addr : *R)
41 Result.back().push_back(Addr);
42 } else
43 return R.takeError();
44 }
45 return std::move(Result);
46}
47
50 int64_t Result = 0;
51 if (auto Err = callSPSWrapper<rt::SPSRunAsMainSignature>(
52 RunAsMainAddr, Result, MainFnAddr, Args))
53 return std::move(Err);
54 return Result;
55}
56
58 int32_t Result = 0;
59 if (auto Err = callSPSWrapper<rt::SPSRunAsVoidFunctionSignature>(
60 RunAsVoidFunctionAddr, Result, VoidFnAddr))
61 return std::move(Err);
62 return Result;
63}
64
66 int Arg) {
67 int32_t Result = 0;
68 if (auto Err = callSPSWrapper<rt::SPSRunAsIntFunctionSignature>(
69 RunAsIntFunctionAddr, Result, IntFnAddr, Arg))
70 return std::move(Err);
71 return Result;
72}
73
75 IncomingWFRHandler OnComplete,
76 ArrayRef<char> ArgBuffer) {
77 uint64_t SeqNo;
78 {
79 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
80 SeqNo = getNextSeqNo();
81 assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
82 PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
83 }
84
85 if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
86 WrapperFnAddr, ArgBuffer)) {
88
89 // We just registered OnComplete, but there may be a race between this
90 // thread returning from sendMessage and handleDisconnect being called from
91 // the transport's listener thread. If handleDisconnect gets there first
92 // then it will have failed 'H' for us. If we get there first (or if
93 // handleDisconnect already ran) then we need to take care of it.
94 {
95 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
96 auto I = PendingCallWrapperResults.find(SeqNo);
97 if (I != PendingCallWrapperResults.end()) {
98 H = std::move(I->second);
99 PendingCallWrapperResults.erase(I);
100 }
101 }
102
103 if (H)
105
106 getExecutionSession().reportError(std::move(Err));
107 }
108}
109
111 T->disconnect();
112 D->shutdown();
113 std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
114 DisconnectCV.wait(Lock, [this] { return Disconnected; });
115 return std::move(DisconnectErr);
116}
117
120 ExecutorAddr TagAddr,
122
123 LLVM_DEBUG({
124 dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";
125 switch (OpC) {
127 dbgs() << "Setup";
128 assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
129 assert(!TagAddr && "Non-zero TagAddr for Setup?");
130 break;
132 dbgs() << "Hangup";
133 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
134 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
135 break;
137 dbgs() << "Result";
138 assert(!TagAddr && "Non-zero TagAddr for Result?");
139 break;
141 dbgs() << "CallWrapper";
142 break;
143 }
144 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
145 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
146 << " bytes\n";
147 });
148
149 using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
150 if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
151 return make_error<StringError>("Unexpected opcode",
153
154 switch (OpC) {
156 if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
157 return std::move(Err);
158 break;
160 T->disconnect();
161 if (auto Err = handleHangup(std::move(ArgBytes)))
162 return std::move(Err);
163 return EndSession;
165 if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
166 return std::move(Err);
167 break;
169 handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
170 break;
171 }
172 return ContinueSession;
173}
174
176 LLVM_DEBUG({
177 dbgs() << "SimpleRemoteEPC::handleDisconnect: "
178 << (Err ? "failure" : "success") << "\n";
179 });
180
182
183 {
184 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
185 std::swap(TmpPending, PendingCallWrapperResults);
186 }
187
188 for (auto &KV : TmpPending)
189 KV.second(
191
192 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
193 DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));
194 Disconnected = true;
195 DisconnectCV.notify_all();
196}
197
199SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC &SREPC) {
201 if (auto Err = SREPC.getBootstrapSymbols(
202 {{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
203 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
204 {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
205 {SAs.Deallocate,
206 rt::SimpleExecutorMemoryManagerDeallocateWrapperName}}))
207 return std::move(Err);
208
209 return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
210}
211
212Expected<std::unique_ptr<ExecutorProcessControl::MemoryAccess>>
213SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC &SREPC) {
214 return nullptr;
215}
216
217Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
218 ExecutorAddr TagAddr,
219 ArrayRef<char> ArgBytes) {
220 assert(OpC != SimpleRemoteEPCOpcode::Setup &&
221 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
222
223 LLVM_DEBUG({
224 dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";
225 switch (OpC) {
226 case SimpleRemoteEPCOpcode::Hangup:
227 dbgs() << "Hangup";
228 assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
229 assert(!TagAddr && "Non-zero TagAddr for Hangup?");
230 break;
231 case SimpleRemoteEPCOpcode::Result:
232 dbgs() << "Result";
233 assert(!TagAddr && "Non-zero TagAddr for Result?");
234 break;
235 case SimpleRemoteEPCOpcode::CallWrapper:
236 dbgs() << "CallWrapper";
237 break;
238 default:
239 llvm_unreachable("Invalid opcode");
240 }
241 dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
242 << ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
243 << " bytes\n";
244 });
245 auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
246 LLVM_DEBUG({
247 if (Err)
248 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
249 });
250 return Err;
251}
252
253Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
254 SimpleRemoteEPCArgBytesVector ArgBytes) {
255 if (SeqNo != 0)
256 return make_error<StringError>("Setup packet SeqNo not zero",
258
259 if (TagAddr)
260 return make_error<StringError>("Setup packet TagAddr not zero",
262
263 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
264 auto I = PendingCallWrapperResults.find(0);
265 assert(PendingCallWrapperResults.size() == 1 &&
266 I != PendingCallWrapperResults.end() &&
267 "Setup message handler not connectly set up");
268 auto SetupMsgHandler = std::move(I->second);
269 PendingCallWrapperResults.erase(I);
270
271 auto WFR =
272 shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
273 SetupMsgHandler(std::move(WFR));
274 return Error::success();
275}
276
277Error SimpleRemoteEPC::setup(Setup S) {
278 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
279
280 std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
281 auto EIF = EIP.get_future();
282
283 // Prepare a handler for the setup packet.
284 PendingCallWrapperResults[0] =
285 RunInPlace()(
286 [&](shared::WrapperFunctionResult SetupMsgBytes) {
287 if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
288 EIP.set_value(
289 make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
290 return;
291 }
292 using SPSSerialize =
293 shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
294 shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
295 SimpleRemoteEPCExecutorInfo EI;
296 if (SPSSerialize::deserialize(IB, EI))
297 EIP.set_value(EI);
298 else
299 EIP.set_value(make_error<StringError>(
300 "Could not deserialize setup message", inconvertibleErrorCode()));
301 });
302
303 // Start the transport.
304 if (auto Err = T->start())
305 return Err;
306
307 // Wait for setup packet to arrive.
308 auto EI = EIF.get();
309 if (!EI) {
310 T->disconnect();
311 return EI.takeError();
312 }
313
314 LLVM_DEBUG({
315 dbgs() << "SimpleRemoteEPC received setup message:\n"
316 << " Triple: " << EI->TargetTriple << "\n"
317 << " Page size: " << EI->PageSize << "\n"
318 << " Bootstrap map" << (EI->BootstrapMap.empty() ? " empty" : ":")
319 << "\n";
320 for (const auto &KV : EI->BootstrapMap)
321 dbgs() << " " << KV.first() << ": " << KV.second.size()
322 << "-byte SPS encoded buffer\n";
323 dbgs() << " Bootstrap symbols"
324 << (EI->BootstrapSymbols.empty() ? " empty" : ":") << "\n";
325 for (const auto &KV : EI->BootstrapSymbols)
326 dbgs() << " " << KV.first() << ": " << KV.second << "\n";
327 });
328 TargetTriple = Triple(EI->TargetTriple);
329 PageSize = EI->PageSize;
330 BootstrapMap = std::move(EI->BootstrapMap);
331 BootstrapSymbols = std::move(EI->BootstrapSymbols);
332
333 if (auto Err = getBootstrapSymbols(
334 {{JDI.JITDispatchContext, ExecutorSessionObjectName},
335 {JDI.JITDispatchFunction, DispatchFnName},
336 {RunAsMainAddr, rt::RunAsMainWrapperName},
337 {RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},
338 {RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))
339 return Err;
340
341 if (auto DM =
342 EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(*this))
343 DylibMgr = std::make_unique<EPCGenericDylibManager>(std::move(*DM));
344 else
345 return DM.takeError();
346
347 // Set a default CreateMemoryManager if none is specified.
348 if (!S.CreateMemoryManager)
349 S.CreateMemoryManager = createDefaultMemoryManager;
350
351 if (auto MemMgr = S.CreateMemoryManager(*this)) {
352 OwnedMemMgr = std::move(*MemMgr);
353 this->MemMgr = OwnedMemMgr.get();
354 } else
355 return MemMgr.takeError();
356
357 // Set a default CreateMemoryAccess if none is specified.
358 if (!S.CreateMemoryAccess)
359 S.CreateMemoryAccess = createDefaultMemoryAccess;
360
361 if (auto MemAccess = S.CreateMemoryAccess(*this)) {
362 OwnedMemAccess = std::move(*MemAccess);
363 this->MemAccess = OwnedMemAccess.get();
364 } else
365 return MemAccess.takeError();
366
367 return Error::success();
368}
369
370Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
371 SimpleRemoteEPCArgBytesVector ArgBytes) {
372 IncomingWFRHandler SendResult;
373
374 if (TagAddr)
375 return make_error<StringError>("Unexpected TagAddr in result message",
377
378 {
379 std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
380 auto I = PendingCallWrapperResults.find(SeqNo);
381 if (I == PendingCallWrapperResults.end())
382 return make_error<StringError>("No call for sequence number " +
383 Twine(SeqNo),
385 SendResult = std::move(I->second);
386 PendingCallWrapperResults.erase(I);
387 releaseSeqNo(SeqNo);
388 }
389
390 auto WFR =
391 shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
392 SendResult(std::move(WFR));
393 return Error::success();
394}
395
396void SimpleRemoteEPC::handleCallWrapper(
397 uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
398 SimpleRemoteEPCArgBytesVector ArgBytes) {
399 assert(ES && "No ExecutionSession attached");
400 D->dispatch(makeGenericNamedTask(
401 [this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
402 ES->runJITDispatchHandler(
403 [this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {
404 if (auto Err =
405 sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
406 ExecutorAddr(), {WFR.data(), WFR.size()}))
407 getExecutionSession().reportError(std::move(Err));
408 },
409 TagAddr, ArgBytes);
410 },
411 "callWrapper task"));
412}
413
414Error SimpleRemoteEPC::handleHangup(SimpleRemoteEPCArgBytesVector ArgBytes) {
415 using namespace llvm::orc::shared;
416 auto WFR = WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
417 if (const char *ErrMsg = WFR.getOutOfBandError())
418 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
419
421 SPSInputBuffer IB(WFR.data(), WFR.size());
423 return make_error<StringError>("Could not deserialize hangup info",
425 return fromSPSSerializable(std::move(Info));
426}
427
428} // end namespace orc
429} // end namespace llvm
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
static Error reportError(StringRef Message)
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
#define LLVM_DEBUG(X)
Definition: Debug.h:101
static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")
uint64_t Addr
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:58
#define H(x, y, z)
Definition: MD5.cpp:57
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:155
bool erase(const KeyT &Val)
Definition: DenseMap.h:329
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition: DenseMap.h:151
iterator end()
Definition: DenseMap.h:84
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Tagged union holding either a T or a Error.
Definition: Error.h:470
size_t size() const
Definition: SmallVector.h:91
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
void reportError(Error Err)
Report a error for this execution session.
Definition: Core.h:1487
Represents an address in the executor process.
A handler or incoming WrapperFunctionResults – either return values from callWrapper* calls,...
std::unique_ptr< TaskDispatcher > D
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< 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, SimpleRemoteEPCArgBytesVector ArgBytes) override
Handle receipt of a message.
Error disconnect() override
Disconnect from the target process.
Expected< tpctypes::DylibHandle > loadDylib(const char *DylibPath) override
Load the dynamic library at the given path and return a handle to it.
Expected< std::vector< tpctypes::LookupResult > > lookupSymbols(ArrayRef< LookupRequest > Request) override
Search for symbols in 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.
A utility class for serializing to a blob from a variadic list.
Input char buffer with underflow check.
static WrapperFunctionResult 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.
Error fromSPSSerializable(SPSSerializableError BSE)
std::unique_ptr< GenericNamedTask > makeGenericNamedTask(FnT &&Fn, std::string Desc)
Create a generic named task from a std::string description.
Definition: TaskDispatch.h:78
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:79
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:427
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860