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
.getValue());
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
, ExecutorAddr(MainFnAddr
), Args
))
53 return std::move(Err
);
57 void SimpleRemoteEPC::callWrapperAsync(ExecutorAddr WrapperFnAddr
,
58 IncomingWFRHandler OnComplete
,
59 ArrayRef
<char> ArgBuffer
) {
62 std::lock_guard
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
63 SeqNo
= getNextSeqNo();
64 assert(!PendingCallWrapperResults
.count(SeqNo
) && "SeqNo already in use");
65 PendingCallWrapperResults
[SeqNo
] = std::move(OnComplete
);
68 if (auto Err
= sendMessage(SimpleRemoteEPCOpcode::CallWrapper
, SeqNo
,
69 WrapperFnAddr
, ArgBuffer
)) {
72 // We just registered OnComplete, but there may be a race between this
73 // thread returning from sendMessage and handleDisconnect being called from
74 // the transport's listener thread. If handleDisconnect gets there first
75 // then it will have failed 'H' for us. If we get there first (or if
76 // handleDisconnect already ran) then we need to take care of it.
78 std::lock_guard
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
79 auto I
= PendingCallWrapperResults
.find(SeqNo
);
80 if (I
!= PendingCallWrapperResults
.end()) {
81 H
= std::move(I
->second
);
82 PendingCallWrapperResults
.erase(I
);
87 H(shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
89 getExecutionSession().reportError(std::move(Err
));
93 Error
SimpleRemoteEPC::disconnect() {
96 std::unique_lock
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
97 DisconnectCV
.wait(Lock
, [this] { return Disconnected
; });
98 return std::move(DisconnectErr
);
101 Expected
<SimpleRemoteEPCTransportClient::HandleMessageAction
>
102 SimpleRemoteEPC::handleMessage(SimpleRemoteEPCOpcode OpC
, uint64_t SeqNo
,
103 ExecutorAddr TagAddr
,
104 SimpleRemoteEPCArgBytesVector ArgBytes
) {
107 dbgs() << "SimpleRemoteEPC::handleMessage: opc = ";
109 case SimpleRemoteEPCOpcode::Setup
:
111 assert(SeqNo
== 0 && "Non-zero SeqNo for Setup?");
112 assert(TagAddr
.getValue() == 0 && "Non-zero TagAddr for Setup?");
114 case SimpleRemoteEPCOpcode::Hangup
:
116 assert(SeqNo
== 0 && "Non-zero SeqNo for Hangup?");
117 assert(TagAddr
.getValue() == 0 && "Non-zero TagAddr for Hangup?");
119 case SimpleRemoteEPCOpcode::Result
:
121 assert(TagAddr
.getValue() == 0 && "Non-zero TagAddr for Result?");
123 case SimpleRemoteEPCOpcode::CallWrapper
:
124 dbgs() << "CallWrapper";
127 dbgs() << ", seqno = " << SeqNo
128 << ", tag-addr = " << formatv("{0:x}", TagAddr
.getValue())
129 << ", arg-buffer = " << formatv("{0:x}", ArgBytes
.size())
133 using UT
= std::underlying_type_t
<SimpleRemoteEPCOpcode
>;
134 if (static_cast<UT
>(OpC
) > static_cast<UT
>(SimpleRemoteEPCOpcode::LastOpC
))
135 return make_error
<StringError
>("Unexpected opcode",
136 inconvertibleErrorCode());
139 case SimpleRemoteEPCOpcode::Setup
:
140 if (auto Err
= handleSetup(SeqNo
, TagAddr
, std::move(ArgBytes
)))
141 return std::move(Err
);
143 case SimpleRemoteEPCOpcode::Hangup
:
145 if (auto Err
= handleHangup(std::move(ArgBytes
)))
146 return std::move(Err
);
148 case SimpleRemoteEPCOpcode::Result
:
149 if (auto Err
= handleResult(SeqNo
, TagAddr
, std::move(ArgBytes
)))
150 return std::move(Err
);
152 case SimpleRemoteEPCOpcode::CallWrapper
:
153 handleCallWrapper(SeqNo
, TagAddr
, std::move(ArgBytes
));
156 return ContinueSession
;
159 void SimpleRemoteEPC::handleDisconnect(Error Err
) {
161 dbgs() << "SimpleRemoteEPC::handleDisconnect: "
162 << (Err
? "failure" : "success") << "\n";
165 PendingCallWrapperResultsMap TmpPending
;
168 std::lock_guard
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
169 std::swap(TmpPending
, PendingCallWrapperResults
);
172 for (auto &KV
: TmpPending
)
174 shared::WrapperFunctionResult::createOutOfBandError("disconnecting"));
176 std::lock_guard
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
177 DisconnectErr
= joinErrors(std::move(DisconnectErr
), std::move(Err
));
179 DisconnectCV
.notify_all();
182 Expected
<std::unique_ptr
<jitlink::JITLinkMemoryManager
>>
183 SimpleRemoteEPC::createDefaultMemoryManager(SimpleRemoteEPC
&SREPC
) {
184 EPCGenericJITLinkMemoryManager::SymbolAddrs SAs
;
185 if (auto Err
= SREPC
.getBootstrapSymbols(
186 {{SAs
.Allocator
, rt::SimpleExecutorMemoryManagerInstanceName
},
187 {SAs
.Reserve
, rt::SimpleExecutorMemoryManagerReserveWrapperName
},
188 {SAs
.Finalize
, rt::SimpleExecutorMemoryManagerFinalizeWrapperName
},
190 rt::SimpleExecutorMemoryManagerDeallocateWrapperName
}}))
191 return std::move(Err
);
193 return std::make_unique
<EPCGenericJITLinkMemoryManager
>(SREPC
, SAs
);
196 Expected
<std::unique_ptr
<ExecutorProcessControl::MemoryAccess
>>
197 SimpleRemoteEPC::createDefaultMemoryAccess(SimpleRemoteEPC
&SREPC
) {
201 Error
SimpleRemoteEPC::sendMessage(SimpleRemoteEPCOpcode OpC
, uint64_t SeqNo
,
202 ExecutorAddr TagAddr
,
203 ArrayRef
<char> ArgBytes
) {
204 assert(OpC
!= SimpleRemoteEPCOpcode::Setup
&&
205 "SimpleRemoteEPC sending Setup message? That's the wrong direction.");
208 dbgs() << "SimpleRemoteEPC::sendMessage: opc = ";
210 case SimpleRemoteEPCOpcode::Hangup
:
212 assert(SeqNo
== 0 && "Non-zero SeqNo for Hangup?");
213 assert(TagAddr
.getValue() == 0 && "Non-zero TagAddr for Hangup?");
215 case SimpleRemoteEPCOpcode::Result
:
217 assert(TagAddr
.getValue() == 0 && "Non-zero TagAddr for Result?");
219 case SimpleRemoteEPCOpcode::CallWrapper
:
220 dbgs() << "CallWrapper";
223 llvm_unreachable("Invalid opcode");
225 dbgs() << ", seqno = " << SeqNo
226 << ", tag-addr = " << formatv("{0:x}", TagAddr
.getValue())
227 << ", arg-buffer = " << formatv("{0:x}", ArgBytes
.size())
230 auto Err
= T
->sendMessage(OpC
, SeqNo
, TagAddr
, ArgBytes
);
233 dbgs() << " \\--> SimpleRemoteEPC::sendMessage failed\n";
238 Error
SimpleRemoteEPC::handleSetup(uint64_t SeqNo
, ExecutorAddr TagAddr
,
239 SimpleRemoteEPCArgBytesVector ArgBytes
) {
241 return make_error
<StringError
>("Setup packet SeqNo not zero",
242 inconvertibleErrorCode());
245 return make_error
<StringError
>("Setup packet TagAddr not zero",
246 inconvertibleErrorCode());
248 std::lock_guard
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
249 auto I
= PendingCallWrapperResults
.find(0);
250 assert(PendingCallWrapperResults
.size() == 1 &&
251 I
!= PendingCallWrapperResults
.end() &&
252 "Setup message handler not connectly set up");
253 auto SetupMsgHandler
= std::move(I
->second
);
254 PendingCallWrapperResults
.erase(I
);
257 shared::WrapperFunctionResult::copyFrom(ArgBytes
.data(), ArgBytes
.size());
258 SetupMsgHandler(std::move(WFR
));
259 return Error::success();
262 Error
SimpleRemoteEPC::setup(Setup S
) {
263 using namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
;
265 std::promise
<MSVCPExpected
<SimpleRemoteEPCExecutorInfo
>> EIP
;
266 auto EIF
= EIP
.get_future();
268 // Prepare a handler for the setup packet.
269 PendingCallWrapperResults
[0] =
271 [&](shared::WrapperFunctionResult SetupMsgBytes
) {
272 if (const char *ErrMsg
= SetupMsgBytes
.getOutOfBandError()) {
274 make_error
<StringError
>(ErrMsg
, inconvertibleErrorCode()));
278 shared::SPSArgList
<shared::SPSSimpleRemoteEPCExecutorInfo
>;
279 shared::SPSInputBuffer
IB(SetupMsgBytes
.data(), SetupMsgBytes
.size());
280 SimpleRemoteEPCExecutorInfo EI
;
281 if (SPSSerialize::deserialize(IB
, EI
))
284 EIP
.set_value(make_error
<StringError
>(
285 "Could not deserialize setup message", inconvertibleErrorCode()));
288 // Start the transport.
289 if (auto Err
= T
->start())
292 // Wait for setup packet to arrive.
296 return EI
.takeError();
300 dbgs() << "SimpleRemoteEPC received setup message:\n"
301 << " Triple: " << EI
->TargetTriple
<< "\n"
302 << " Page size: " << EI
->PageSize
<< "\n"
303 << " Bootstrap symbols:\n";
304 for (const auto &KV
: EI
->BootstrapSymbols
)
305 dbgs() << " " << KV
.first() << ": "
306 << formatv("{0:x16}", KV
.second
.getValue()) << "\n";
308 TargetTriple
= Triple(EI
->TargetTriple
);
309 PageSize
= EI
->PageSize
;
310 BootstrapSymbols
= std::move(EI
->BootstrapSymbols
);
312 if (auto Err
= getBootstrapSymbols(
313 {{JDI
.JITDispatchContext
, ExecutorSessionObjectName
},
314 {JDI
.JITDispatchFunction
, DispatchFnName
},
315 {RunAsMainAddr
, rt::RunAsMainWrapperName
}}))
319 EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(*this))
320 DylibMgr
= std::make_unique
<EPCGenericDylibManager
>(std::move(*DM
));
322 return DM
.takeError();
324 // Set a default CreateMemoryManager if none is specified.
325 if (!S
.CreateMemoryManager
)
326 S
.CreateMemoryManager
= createDefaultMemoryManager
;
328 if (auto MemMgr
= S
.CreateMemoryManager(*this)) {
329 OwnedMemMgr
= std::move(*MemMgr
);
330 this->MemMgr
= OwnedMemMgr
.get();
332 return MemMgr
.takeError();
334 // Set a default CreateMemoryAccess if none is specified.
335 if (!S
.CreateMemoryAccess
)
336 S
.CreateMemoryAccess
= createDefaultMemoryAccess
;
338 if (auto MemAccess
= S
.CreateMemoryAccess(*this)) {
339 OwnedMemAccess
= std::move(*MemAccess
);
340 this->MemAccess
= OwnedMemAccess
.get();
342 return MemAccess
.takeError();
344 return Error::success();
347 Error
SimpleRemoteEPC::handleResult(uint64_t SeqNo
, ExecutorAddr TagAddr
,
348 SimpleRemoteEPCArgBytesVector ArgBytes
) {
349 IncomingWFRHandler SendResult
;
352 return make_error
<StringError
>("Unexpected TagAddr in result message",
353 inconvertibleErrorCode());
356 std::lock_guard
<std::mutex
> Lock(SimpleRemoteEPCMutex
);
357 auto I
= PendingCallWrapperResults
.find(SeqNo
);
358 if (I
== PendingCallWrapperResults
.end())
359 return make_error
<StringError
>("No call for sequence number " +
361 inconvertibleErrorCode());
362 SendResult
= std::move(I
->second
);
363 PendingCallWrapperResults
.erase(I
);
368 shared::WrapperFunctionResult::copyFrom(ArgBytes
.data(), ArgBytes
.size());
369 SendResult(std::move(WFR
));
370 return Error::success();
373 void SimpleRemoteEPC::handleCallWrapper(
374 uint64_t RemoteSeqNo
, ExecutorAddr TagAddr
,
375 SimpleRemoteEPCArgBytesVector ArgBytes
) {
376 assert(ES
&& "No ExecutionSession attached");
377 D
->dispatch(makeGenericNamedTask(
378 [this, RemoteSeqNo
, TagAddr
, ArgBytes
= std::move(ArgBytes
)]() {
379 ES
->runJITDispatchHandler(
380 [this, RemoteSeqNo
](shared::WrapperFunctionResult WFR
) {
382 sendMessage(SimpleRemoteEPCOpcode::Result
, RemoteSeqNo
,
383 ExecutorAddr(), {WFR
.data(), WFR
.size()}))
384 getExecutionSession().reportError(std::move(Err
));
386 TagAddr
.getValue(), ArgBytes
);
388 "callWrapper task"));
391 Error
SimpleRemoteEPC::handleHangup(SimpleRemoteEPCArgBytesVector ArgBytes
) {
392 using namespace llvm::orc::shared
;
393 auto WFR
= WrapperFunctionResult::copyFrom(ArgBytes
.data(), ArgBytes
.size());
394 if (const char *ErrMsg
= WFR
.getOutOfBandError())
395 return make_error
<StringError
>(ErrMsg
, inconvertibleErrorCode());
397 detail::SPSSerializableError Info
;
398 SPSInputBuffer
IB(WFR
.data(), WFR
.size());
399 if (!SPSArgList
<SPSError
>::deserialize(IB
, Info
))
400 return make_error
<StringError
>("Could not deserialize hangup info",
401 inconvertibleErrorCode());
402 return fromSPSSerializable(std::move(Info
));
405 } // end namespace orc
406 } // end namespace llvm