Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
35266 views
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
9
#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
10
#include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
11
#include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
12
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
13
#include "llvm/Support/FormatVariadic.h"
14
15
#define DEBUG_TYPE "orc"
16
17
namespace llvm {
18
namespace orc {
19
20
SimpleRemoteEPC::~SimpleRemoteEPC() {
21
#ifndef NDEBUG
22
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
23
assert(Disconnected && "Destroyed without disconnection");
24
#endif // NDEBUG
25
}
26
27
Expected<tpctypes::DylibHandle>
28
SimpleRemoteEPC::loadDylib(const char *DylibPath) {
29
return DylibMgr->open(DylibPath, 0);
30
}
31
32
/// Async helper to chain together calls to DylibMgr::lookupAsync to fulfill all
33
/// all the requests.
34
/// FIXME: The dylib manager should support multiple LookupRequests natively.
35
static void
36
lookupSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr,
37
ArrayRef<SimpleRemoteEPC::LookupRequest> Request,
38
std::vector<tpctypes::LookupResult> Result,
39
SimpleRemoteEPC::SymbolLookupCompleteFn Complete) {
40
if (Request.empty())
41
return Complete(std::move(Result));
42
43
auto &Element = Request.front();
44
DylibMgr.lookupAsync(Element.Handle, Element.Symbols,
45
[&DylibMgr, Request, Complete = std::move(Complete),
46
Result = std::move(Result)](auto R) mutable {
47
if (!R)
48
return Complete(R.takeError());
49
Result.push_back({});
50
Result.back().reserve(R->size());
51
for (auto Addr : *R)
52
Result.back().push_back(Addr);
53
54
lookupSymbolsAsyncHelper(
55
DylibMgr, Request.drop_front(), std::move(Result),
56
std::move(Complete));
57
});
58
}
59
60
void SimpleRemoteEPC::lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
61
SymbolLookupCompleteFn Complete) {
62
lookupSymbolsAsyncHelper(*DylibMgr, Request, {}, std::move(Complete));
63
}
64
65
Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr,
66
ArrayRef<std::string> Args) {
67
int64_t Result = 0;
68
if (auto Err = callSPSWrapper<rt::SPSRunAsMainSignature>(
69
RunAsMainAddr, Result, MainFnAddr, Args))
70
return std::move(Err);
71
return Result;
72
}
73
74
Expected<int32_t> SimpleRemoteEPC::runAsVoidFunction(ExecutorAddr VoidFnAddr) {
75
int32_t Result = 0;
76
if (auto Err = callSPSWrapper<rt::SPSRunAsVoidFunctionSignature>(
77
RunAsVoidFunctionAddr, Result, VoidFnAddr))
78
return std::move(Err);
79
return Result;
80
}
81
82
Expected<int32_t> SimpleRemoteEPC::runAsIntFunction(ExecutorAddr IntFnAddr,
83
int Arg) {
84
int32_t Result = 0;
85
if (auto Err = callSPSWrapper<rt::SPSRunAsIntFunctionSignature>(
86
RunAsIntFunctionAddr, Result, IntFnAddr, Arg))
87
return std::move(Err);
88
return Result;
89
}
90
91
void SimpleRemoteEPC::callWrapperAsync(ExecutorAddr WrapperFnAddr,
92
IncomingWFRHandler OnComplete,
93
ArrayRef<char> ArgBuffer) {
94
uint64_t SeqNo;
95
{
96
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
97
SeqNo = getNextSeqNo();
98
assert(!PendingCallWrapperResults.count(SeqNo) && "SeqNo already in use");
99
PendingCallWrapperResults[SeqNo] = std::move(OnComplete);
100
}
101
102
if (auto Err = sendMessage(SimpleRemoteEPCOpcode::CallWrapper, SeqNo,
103
WrapperFnAddr, ArgBuffer)) {
104
IncomingWFRHandler H;
105
106
// We just registered OnComplete, but there may be a race between this
107
// thread returning from sendMessage and handleDisconnect being called from
108
// the transport's listener thread. If handleDisconnect gets there first
109
// then it will have failed 'H' for us. If we get there first (or if
110
// handleDisconnect already ran) then we need to take care of it.
111
{
112
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
113
auto I = PendingCallWrapperResults.find(SeqNo);
114
if (I != PendingCallWrapperResults.end()) {
115
H = std::move(I->second);
116
PendingCallWrapperResults.erase(I);
117
}
118
}
119
120
if (H)
121
H(shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
122
123
getExecutionSession().reportError(std::move(Err));
124
}
125
}
126
127
Error SimpleRemoteEPC::disconnect() {
128
T->disconnect();
129
D->shutdown();
130
std::unique_lock<std::mutex> Lock(SimpleRemoteEPCMutex);
131
DisconnectCV.wait(Lock, [this] { return Disconnected; });
132
return std::move(DisconnectErr);
133
}
134
135
Expected<SimpleRemoteEPCTransportClient::HandleMessageAction>
136
SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
137
ExecutorAddr TagAddr,
138
SimpleRemoteEPCArgBytesVector ArgBytes) {
139
140
LLVM_DEBUG({
141
dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";
142
switch (OpC) {
143
case SimpleRemoteEPCOpcode::Setup:
144
dbgs() << "Setup";
145
assert(SeqNo == 0 && "Non-zero SeqNo for Setup?");
146
assert(!TagAddr && "Non-zero TagAddr for Setup?");
147
break;
148
case SimpleRemoteEPCOpcode::Hangup:
149
dbgs() << "Hangup";
150
assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
151
assert(!TagAddr && "Non-zero TagAddr for Hangup?");
152
break;
153
case SimpleRemoteEPCOpcode::Result:
154
dbgs() << "Result";
155
assert(!TagAddr && "Non-zero TagAddr for Result?");
156
break;
157
case SimpleRemoteEPCOpcode::CallWrapper:
158
dbgs() << "CallWrapper";
159
break;
160
}
161
dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
162
<< ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
163
<< " bytes\n";
164
});
165
166
using UT = std::underlying_type_t<SimpleRemoteEPCOpcode>;
167
if (static_cast<UT>(OpC) > static_cast<UT>(SimpleRemoteEPCOpcode::LastOpC))
168
return make_error<StringError>("Unexpected opcode",
169
inconvertibleErrorCode());
170
171
switch (OpC) {
172
case SimpleRemoteEPCOpcode::Setup:
173
if (auto Err = handleSetup(SeqNo, TagAddr, std::move(ArgBytes)))
174
return std::move(Err);
175
break;
176
case SimpleRemoteEPCOpcode::Hangup:
177
T->disconnect();
178
if (auto Err = handleHangup(std::move(ArgBytes)))
179
return std::move(Err);
180
return EndSession;
181
case SimpleRemoteEPCOpcode::Result:
182
if (auto Err = handleResult(SeqNo, TagAddr, std::move(ArgBytes)))
183
return std::move(Err);
184
break;
185
case SimpleRemoteEPCOpcode::CallWrapper:
186
handleCallWrapper(SeqNo, TagAddr, std::move(ArgBytes));
187
break;
188
}
189
return ContinueSession;
190
}
191
192
void SimpleRemoteEPC::handleDisconnect(Error Err) {
193
LLVM_DEBUG({
194
dbgs() << "SimpleRemoteEPC::handleDisconnect: "
195
<< (Err ? "failure" : "success") << "\n";
196
});
197
198
PendingCallWrapperResultsMap TmpPending;
199
200
{
201
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
202
std::swap(TmpPending, PendingCallWrapperResults);
203
}
204
205
for (auto &KV : TmpPending)
206
KV.second(
207
shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
208
209
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
210
DisconnectErr = joinErrors(std::move(DisconnectErr), std::move(Err));
211
Disconnected = true;
212
DisconnectCV.notify_all();
213
}
214
215
Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
216
SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC &SREPC) {
217
EPCGenericJITLinkMemoryManager::SymbolAddrs SAs;
218
if (auto Err = SREPC.getBootstrapSymbols(
219
{{SAs.Allocator, rt::SimpleExecutorMemoryManagerInstanceName},
220
{SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
221
{SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
222
{SAs.Deallocate,
223
rt::SimpleExecutorMemoryManagerDeallocateWrapperName}}))
224
return std::move(Err);
225
226
return std::make_unique<EPCGenericJITLinkMemoryManager>(SREPC, SAs);
227
}
228
229
Expected<std::unique_ptr<ExecutorProcessControl::MemoryAccess>>
230
SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC &SREPC) {
231
return nullptr;
232
}
233
234
Error SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
235
ExecutorAddr TagAddr,
236
ArrayRef<char> ArgBytes) {
237
assert(OpC != SimpleRemoteEPCOpcode::Setup &&
238
"SimpleRemoteEPC sending Setup message? That's the wrong direction.");
239
240
LLVM_DEBUG({
241
dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";
242
switch (OpC) {
243
case SimpleRemoteEPCOpcode::Hangup:
244
dbgs() << "Hangup";
245
assert(SeqNo == 0 && "Non-zero SeqNo for Hangup?");
246
assert(!TagAddr && "Non-zero TagAddr for Hangup?");
247
break;
248
case SimpleRemoteEPCOpcode::Result:
249
dbgs() << "Result";
250
assert(!TagAddr && "Non-zero TagAddr for Result?");
251
break;
252
case SimpleRemoteEPCOpcode::CallWrapper:
253
dbgs() << "CallWrapper";
254
break;
255
default:
256
llvm_unreachable("Invalid opcode");
257
}
258
dbgs() << ", seqno = " << SeqNo << ", tag-addr = " << TagAddr
259
<< ", arg-buffer = " << formatv("{0:x}", ArgBytes.size())
260
<< " bytes\n";
261
});
262
auto Err = T->sendMessage(OpC, SeqNo, TagAddr, ArgBytes);
263
LLVM_DEBUG({
264
if (Err)
265
dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
266
});
267
return Err;
268
}
269
270
Error SimpleRemoteEPC::handleSetup(uint64_t SeqNo, ExecutorAddr TagAddr,
271
SimpleRemoteEPCArgBytesVector ArgBytes) {
272
if (SeqNo != 0)
273
return make_error<StringError>("Setup packet SeqNo not zero",
274
inconvertibleErrorCode());
275
276
if (TagAddr)
277
return make_error<StringError>("Setup packet TagAddr not zero",
278
inconvertibleErrorCode());
279
280
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
281
auto I = PendingCallWrapperResults.find(0);
282
assert(PendingCallWrapperResults.size() == 1 &&
283
I != PendingCallWrapperResults.end() &&
284
"Setup message handler not connectly set up");
285
auto SetupMsgHandler = std::move(I->second);
286
PendingCallWrapperResults.erase(I);
287
288
auto WFR =
289
shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
290
SetupMsgHandler(std::move(WFR));
291
return Error::success();
292
}
293
294
Error SimpleRemoteEPC::setup(Setup S) {
295
using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames;
296
297
std::promise<MSVCPExpected<SimpleRemoteEPCExecutorInfo>> EIP;
298
auto EIF = EIP.get_future();
299
300
// Prepare a handler for the setup packet.
301
PendingCallWrapperResults[0] =
302
RunInPlace()(
303
[&](shared::WrapperFunctionResult SetupMsgBytes) {
304
if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
305
EIP.set_value(
306
make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
307
return;
308
}
309
using SPSSerialize =
310
shared::SPSArgList<shared::SPSSimpleRemoteEPCExecutorInfo>;
311
shared::SPSInputBuffer IB(SetupMsgBytes.data(), SetupMsgBytes.size());
312
SimpleRemoteEPCExecutorInfo EI;
313
if (SPSSerialize::deserialize(IB, EI))
314
EIP.set_value(EI);
315
else
316
EIP.set_value(make_error<StringError>(
317
"Could not deserialize setup message", inconvertibleErrorCode()));
318
});
319
320
// Start the transport.
321
if (auto Err = T->start())
322
return Err;
323
324
// Wait for setup packet to arrive.
325
auto EI = EIF.get();
326
if (!EI) {
327
T->disconnect();
328
return EI.takeError();
329
}
330
331
LLVM_DEBUG({
332
dbgs() << "SimpleRemoteEPC received setup message:\n"
333
<< " Triple: " << EI->TargetTriple << "\n"
334
<< " Page size: " << EI->PageSize << "\n"
335
<< " Bootstrap map" << (EI->BootstrapMap.empty() ? " empty" : ":")
336
<< "\n";
337
for (const auto &KV : EI->BootstrapMap)
338
dbgs() << " " << KV.first() << ": " << KV.second.size()
339
<< "-byte SPS encoded buffer\n";
340
dbgs() << " Bootstrap symbols"
341
<< (EI->BootstrapSymbols.empty() ? " empty" : ":") << "\n";
342
for (const auto &KV : EI->BootstrapSymbols)
343
dbgs() << " " << KV.first() << ": " << KV.second << "\n";
344
});
345
TargetTriple = Triple(EI->TargetTriple);
346
PageSize = EI->PageSize;
347
BootstrapMap = std::move(EI->BootstrapMap);
348
BootstrapSymbols = std::move(EI->BootstrapSymbols);
349
350
if (auto Err = getBootstrapSymbols(
351
{{JDI.JITDispatchContext, ExecutorSessionObjectName},
352
{JDI.JITDispatchFunction, DispatchFnName},
353
{RunAsMainAddr, rt::RunAsMainWrapperName},
354
{RunAsVoidFunctionAddr, rt::RunAsVoidFunctionWrapperName},
355
{RunAsIntFunctionAddr, rt::RunAsIntFunctionWrapperName}}))
356
return Err;
357
358
if (auto DM =
359
EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(*this))
360
DylibMgr = std::make_unique<EPCGenericDylibManager>(std::move(*DM));
361
else
362
return DM.takeError();
363
364
// Set a default CreateMemoryManager if none is specified.
365
if (!S.CreateMemoryManager)
366
S.CreateMemoryManager = createDefaultMemoryManager;
367
368
if (auto MemMgr = S.CreateMemoryManager(*this)) {
369
OwnedMemMgr = std::move(*MemMgr);
370
this->MemMgr = OwnedMemMgr.get();
371
} else
372
return MemMgr.takeError();
373
374
// Set a default CreateMemoryAccess if none is specified.
375
if (!S.CreateMemoryAccess)
376
S.CreateMemoryAccess = createDefaultMemoryAccess;
377
378
if (auto MemAccess = S.CreateMemoryAccess(*this)) {
379
OwnedMemAccess = std::move(*MemAccess);
380
this->MemAccess = OwnedMemAccess.get();
381
} else
382
return MemAccess.takeError();
383
384
return Error::success();
385
}
386
387
Error SimpleRemoteEPC::handleResult(uint64_t SeqNo, ExecutorAddr TagAddr,
388
SimpleRemoteEPCArgBytesVector ArgBytes) {
389
IncomingWFRHandler SendResult;
390
391
if (TagAddr)
392
return make_error<StringError>("Unexpected TagAddr in result message",
393
inconvertibleErrorCode());
394
395
{
396
std::lock_guard<std::mutex> Lock(SimpleRemoteEPCMutex);
397
auto I = PendingCallWrapperResults.find(SeqNo);
398
if (I == PendingCallWrapperResults.end())
399
return make_error<StringError>("No call for sequence number " +
400
Twine(SeqNo),
401
inconvertibleErrorCode());
402
SendResult = std::move(I->second);
403
PendingCallWrapperResults.erase(I);
404
releaseSeqNo(SeqNo);
405
}
406
407
auto WFR =
408
shared::WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
409
SendResult(std::move(WFR));
410
return Error::success();
411
}
412
413
void SimpleRemoteEPC::handleCallWrapper(
414
uint64_t RemoteSeqNo, ExecutorAddr TagAddr,
415
SimpleRemoteEPCArgBytesVector ArgBytes) {
416
assert(ES && "No ExecutionSession attached");
417
D->dispatch(makeGenericNamedTask(
418
[this, RemoteSeqNo, TagAddr, ArgBytes = std::move(ArgBytes)]() {
419
ES->runJITDispatchHandler(
420
[this, RemoteSeqNo](shared::WrapperFunctionResult WFR) {
421
if (auto Err =
422
sendMessage(SimpleRemoteEPCOpcode::Result, RemoteSeqNo,
423
ExecutorAddr(), {WFR.data(), WFR.size()}))
424
getExecutionSession().reportError(std::move(Err));
425
},
426
TagAddr, ArgBytes);
427
},
428
"callWrapper task"));
429
}
430
431
Error SimpleRemoteEPC::handleHangup(SimpleRemoteEPCArgBytesVector ArgBytes) {
432
using namespace llvm::orc::shared;
433
auto WFR = WrapperFunctionResult::copyFrom(ArgBytes.data(), ArgBytes.size());
434
if (const char *ErrMsg = WFR.getOutOfBandError())
435
return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
436
437
detail::SPSSerializableError Info;
438
SPSInputBuffer IB(WFR.data(), WFR.size());
439
if (!SPSArgList<SPSError>::deserialize(IB, Info))
440
return make_error<StringError>("Could not deserialize hangup info",
441
inconvertibleErrorCode());
442
return fromSPSSerializable(std::move(Info));
443
}
444
445
} // end namespace orc
446
} // end namespace llvm
447
448