1 //===------- SimpleRemoteEPC.cpp -- Simple remote executor control --------===//
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
7 //===----------------------------------------------------------------------===//
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"
15 #define DEBUG_TYPE "orc"
20 SimpleRemoteEPC::~SimpleRemoteEPC() {
22 std::lock_guard
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
23 assert(Disconnected
&& "Destroyed without disconnection");
27 Expected
<tpctypes::DylibHandle
>
28 SimpleRemoteEPC::loadDylib(const char *DylibPath
) {
29 return DylibMgr
->open(DylibPath
, 0);
32 Expected
<std::vector
<tpctypes::LookupResult
>>
33 SimpleRemoteEPC::lookupSymbols(ArrayRef
<LookupRequest
> Request
) {
34 std::vector
<tpctypes::LookupResult
> Result
;
36 for (auto &Element
: Request
) {
37 if (auto R
= DylibMgr
->lookup(Element
.Handle
, Element
.Symbols
)) {
39 Result
.back().reserve(R
->size());
41 Result
.back().push_back(Addr
);
45 return std::move(Result
);
48 Expected
<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr
,
49 ArrayRef
<std::string
> Args
) {
51 if (auto Err
= callSPSWrapper
<rt::SPSRunAsMainSignature
>(
52 RunAsMainAddr
, Result
, MainFnAddr
, Args
))
53 return std::move(Err
);
57 Expected
<int32_t> SimpleRemoteEPC::runAsVoidFunction(ExecutorAddr VoidFnAddr
) {
59 if (auto Err
= callSPSWrapper
<rt::SPSRunAsVoidFunctionSignature
>(
60 RunAsVoidFunctionAddr
, Result
, VoidFnAddr
))
61 return std::move(Err
);
65 Expected
<int32_t> SimpleRemoteEPC::runAsIntFunction(ExecutorAddr IntFnAddr
,
68 if (auto Err
= callSPSWrapper
<rt::SPSRunAsIntFunctionSignature
>(
69 RunAsIntFunctionAddr
, Result
, IntFnAddr
, Arg
))
70 return std::move(Err
);
74 void SimpleRemoteEPC::callWrapperAsync(ExecutorAddr WrapperFnAddr
,
75 IncomingWFRHandler OnComplete
,
76 ArrayRef
<char> ArgBuffer
) {
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
);
85 if (auto Err
= sendMessage(SimpleRemoteEPCOpcode::CallWrapper
, SeqNo
,
86 WrapperFnAddr
, ArgBuffer
)) {
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.
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
);
104 H(shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
106 getExecutionSession().reportError(std::move(Err
));
110 Error
SimpleRemoteEPC::disconnect() {
113 std::unique_lock
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
114 DisconnectCV
.wait(Lock
, [this] { return Disconnected
; });
115 return std::move(DisconnectErr
);
118 Expected
<SimpleRemoteEPCTransportClient::HandleMessageAction
>
119 SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC
, uint64_t SeqNo
,
120 ExecutorAddr TagAddr
,
121 SimpleRemoteEPCArgBytesVector ArgBytes
) {
124 dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";
126 case SimpleRemoteEPCOpcode::Setup
:
128 assert(SeqNo
== 0 && "Non-zero SeqNo for Setup?");
129 assert(!TagAddr
&& "Non-zero TagAddr for Setup?");
131 case SimpleRemoteEPCOpcode::Hangup
:
133 assert(SeqNo
== 0 && "Non-zero SeqNo for Hangup?");
134 assert(!TagAddr
&& "Non-zero TagAddr for Hangup?");
136 case SimpleRemoteEPCOpcode::Result
:
138 assert(!TagAddr
&& "Non-zero TagAddr for Result?");
140 case SimpleRemoteEPCOpcode::CallWrapper
:
141 dbgs() << "CallWrapper";
144 dbgs() << ", seqno = " << SeqNo
<< ", tag-addr = " << TagAddr
145 << ", arg-buffer = " << formatv("{0:x}", ArgBytes
.size())
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",
152 inconvertibleErrorCode());
155 case SimpleRemoteEPCOpcode::Setup
:
156 if (auto Err
= handleSetup(SeqNo
, TagAddr
, std::move(ArgBytes
)))
157 return std::move(Err
);
159 case SimpleRemoteEPCOpcode::Hangup
:
161 if (auto Err
= handleHangup(std::move(ArgBytes
)))
162 return std::move(Err
);
164 case SimpleRemoteEPCOpcode::Result
:
165 if (auto Err
= handleResult(SeqNo
, TagAddr
, std::move(ArgBytes
)))
166 return std::move(Err
);
168 case SimpleRemoteEPCOpcode::CallWrapper
:
169 handleCallWrapper(SeqNo
, TagAddr
, std::move(ArgBytes
));
172 return ContinueSession
;
175 void SimpleRemoteEPC::handleDisconnect(Error Err
) {
177 dbgs() << "SimpleRemoteEPC::handleDisconnect: "
178 << (Err
? "failure" : "success") << "\n";
181 PendingCallWrapperResultsMap TmpPending
;
184 std::lock_guard
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
185 std::swap(TmpPending
, PendingCallWrapperResults
);
188 for (auto &KV
: TmpPending
)
190 shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
192 std::lock_guard
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
193 DisconnectErr
= joinErrors(std::move(DisconnectErr
), std::move(Err
));
195 DisconnectCV
.notify_all();
198 Expected
<std::unique_ptr
<jitlink::JITLinkMemoryManager
>>
199 SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC
&SREPC
) {
200 EPCGenericJITLinkMemoryManager::SymbolAddrs SAs
;
201 if (auto Err
= SREPC
.getBootstrapSymbols(
202 {{SAs
.Allocator
, rt::SimpleExecutorMemoryManagerInstanceName
},
203 {SAs
.Reserve
, rt::SimpleExecutorMemoryManagerReserveWrapperName
},
204 {SAs
.Finalize
, rt::SimpleExecutorMemoryManagerFinalizeWrapperName
},
206 rt::SimpleExecutorMemoryManagerDeallocateWrapperName
}}))
207 return std::move(Err
);
209 return std::make_unique
<EPCGenericJITLinkMemoryManager
>(SREPC
, SAs
);
212 Expected
<std::unique_ptr
<ExecutorProcessControl::MemoryAccess
>>
213 SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC
&SREPC
) {
217 Error
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.");
224 dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";
226 case SimpleRemoteEPCOpcode::Hangup
:
228 assert(SeqNo
== 0 && "Non-zero SeqNo for Hangup?");
229 assert(!TagAddr
&& "Non-zero TagAddr for Hangup?");
231 case SimpleRemoteEPCOpcode::Result
:
233 assert(!TagAddr
&& "Non-zero TagAddr for Result?");
235 case SimpleRemoteEPCOpcode::CallWrapper
:
236 dbgs() << "CallWrapper";
239 llvm_unreachable("Invalid opcode");
241 dbgs() << ", seqno = " << SeqNo
<< ", tag-addr = " << TagAddr
242 << ", arg-buffer = " << formatv("{0:x}", ArgBytes
.size())
245 auto Err
= T
->sendMessage(OpC
, SeqNo
, TagAddr
, ArgBytes
);
248 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
253 Error
SimpleRemoteEPC::handleSetup(uint64_t SeqNo
, ExecutorAddr TagAddr
,
254 SimpleRemoteEPCArgBytesVector ArgBytes
) {
256 return make_error
<StringError
>("Setup packet SeqNo not zero",
257 inconvertibleErrorCode());
260 return make_error
<StringError
>("Setup packet TagAddr not zero",
261 inconvertibleErrorCode());
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
);
272 shared::WrapperFunctionResult::copyFrom(ArgBytes
.data(), ArgBytes
.size());
273 SetupMsgHandler(std::move(WFR
));
274 return Error::success();
277 Error
SimpleRemoteEPC::setup(Setup S
) {
278 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
;
280 std::promise
<MSVCPExpected
<SimpleRemoteEPCExecutorInfo
>> EIP
;
281 auto EIF
= EIP
.get_future();
283 // Prepare a handler for the setup packet.
284 PendingCallWrapperResults
[0] =
286 [&](shared::WrapperFunctionResult SetupMsgBytes
) {
287 if (const char *ErrMsg
= SetupMsgBytes
.getOutOfBandError()) {
289 make_error
<StringError
>(ErrMsg
, inconvertibleErrorCode()));
293 shared::SPSArgList
<shared::SPSSimpleRemoteEPCExecutorInfo
>;
294 shared::SPSInputBuffer
IB(SetupMsgBytes
.data(), SetupMsgBytes
.size());
295 SimpleRemoteEPCExecutorInfo EI
;
296 if (SPSSerialize::deserialize(IB
, EI
))
299 EIP
.set_value(make_error
<StringError
>(
300 "Could not deserialize setup message", inconvertibleErrorCode()));
303 // Start the transport.
304 if (auto Err
= T
->start())
307 // Wait for setup packet to arrive.
311 return EI
.takeError();
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" : ":")
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";
328 TargetTriple
= Triple(EI
->TargetTriple
);
329 PageSize
= EI
->PageSize
;
330 BootstrapMap
= std::move(EI
->BootstrapMap
);
331 BootstrapSymbols
= std::move(EI
->BootstrapSymbols
);
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
}}))
342 EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(*this))
343 DylibMgr
= std::make_unique
<EPCGenericDylibManager
>(std::move(*DM
));
345 return DM
.takeError();
347 // Set a default CreateMemoryManager if none is specified.
348 if (!S
.CreateMemoryManager
)
349 S
.CreateMemoryManager
= createDefaultMemoryManager
;
351 if (auto MemMgr
= S
.CreateMemoryManager(*this)) {
352 OwnedMemMgr
= std::move(*MemMgr
);
353 this->MemMgr
= OwnedMemMgr
.get();
355 return MemMgr
.takeError();
357 // Set a default CreateMemoryAccess if none is specified.
358 if (!S
.CreateMemoryAccess
)
359 S
.CreateMemoryAccess
= createDefaultMemoryAccess
;
361 if (auto MemAccess
= S
.CreateMemoryAccess(*this)) {
362 OwnedMemAccess
= std::move(*MemAccess
);
363 this->MemAccess
= OwnedMemAccess
.get();
365 return MemAccess
.takeError();
367 return Error::success();
370 Error
SimpleRemoteEPC::handleResult(uint64_t SeqNo
, ExecutorAddr TagAddr
,
371 SimpleRemoteEPCArgBytesVector ArgBytes
) {
372 IncomingWFRHandler SendResult
;
375 return make_error
<StringError
>("Unexpected TagAddr in result message",
376 inconvertibleErrorCode());
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 " +
384 inconvertibleErrorCode());
385 SendResult
= std::move(I
->second
);
386 PendingCallWrapperResults
.erase(I
);
391 shared::WrapperFunctionResult::copyFrom(ArgBytes
.data(), ArgBytes
.size());
392 SendResult(std::move(WFR
));
393 return Error::success();
396 void 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
) {
405 sendMessage(SimpleRemoteEPCOpcode::Result
, RemoteSeqNo
,
406 ExecutorAddr(), {WFR
.data(), WFR
.size()}))
407 getExecutionSession().reportError(std::move(Err
));
411 "callWrapper task"));
414 Error
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());
420 detail::SPSSerializableError Info
;
421 SPSInputBuffer
IB(WFR
.data(), WFR
.size());
422 if (!SPSArgList
<SPSError
>::deserialize(IB
, Info
))
423 return make_error
<StringError
>("Could not deserialize hangup info",
424 inconvertibleErrorCode());
425 return fromSPSSerializable(std::move(Info
));
428 } // end namespace orc
429 } // end namespace llvm