1 //===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===//
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 "RemoteJITUtils.h"
11 #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
12 #include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
13 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
14 #include "llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h"
15 #include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
16 #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
17 #include "llvm/Support/FileSystem.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/ToolOutputFile.h"
23 #include <netinet/in.h>
24 #include <sys/socket.h>
26 #endif // LLVM_ON_UNIX
29 using namespace llvm::orc
;
34 class RemoteExecutorProcessControl
35 : public OrcRPCExecutorProcessControlBase
<
36 shared::MultiThreadedRPCEndpoint
<JITLinkExecutor::RPCChannel
>> {
38 using RPCChannel
= JITLinkExecutor::RPCChannel
;
39 using RPCEndpoint
= shared::MultiThreadedRPCEndpoint
<RPCChannel
>;
42 using ThisT
= RemoteExecutorProcessControl
;
43 using BaseT
= OrcRPCExecutorProcessControlBase
<RPCEndpoint
>;
44 using MemoryAccess
= OrcRPCEPCMemoryAccess
<ThisT
>;
45 using MemoryManager
= OrcRPCEPCJITLinkMemoryManager
<ThisT
>;
48 using BaseT::initializeORCRPCEPCBase
;
50 RemoteExecutorProcessControl(std::unique_ptr
<RPCChannel
> Channel
,
51 std::unique_ptr
<RPCEndpoint
> Endpoint
,
52 BaseT::ErrorReporter ReportError
);
54 void initializeMemoryManagement();
55 Error
disconnect() override
;
58 std::unique_ptr
<RPCChannel
> Channel
;
59 std::unique_ptr
<RPCEndpoint
> Endpoint
;
60 std::unique_ptr
<MemoryAccess
> OwnedMemAccess
;
61 std::unique_ptr
<MemoryManager
> OwnedMemMgr
;
62 std::atomic
<bool> Finished
{false};
63 std::thread ListenerThread
;
66 RemoteExecutorProcessControl::RemoteExecutorProcessControl(
67 std::unique_ptr
<RPCChannel
> Channel
, std::unique_ptr
<RPCEndpoint
> Endpoint
,
68 BaseT::ErrorReporter ReportError
)
69 : BaseT(std::make_shared
<SymbolStringPool
>(), *Endpoint
,
70 std::move(ReportError
)),
71 Channel(std::move(Channel
)), Endpoint(std::move(Endpoint
)) {
73 ListenerThread
= std::thread([&]() {
75 if (auto Err
= this->Endpoint
->handleOne()) {
76 reportError(std::move(Err
));
83 void RemoteExecutorProcessControl::initializeMemoryManagement() {
84 OwnedMemAccess
= std::make_unique
<MemoryAccess
>(*this);
85 OwnedMemMgr
= std::make_unique
<MemoryManager
>(*this);
87 // Base class needs non-owning access.
88 MemAccess
= OwnedMemAccess
.get();
89 MemMgr
= OwnedMemMgr
.get();
92 Error
RemoteExecutorProcessControl::disconnect() {
93 std::promise
<MSVCPError
> P
;
94 auto F
= P
.get_future();
95 auto Err
= closeConnection([&](Error Err
) -> Error
{
96 P
.set_value(std::move(Err
));
98 return Error::success();
100 ListenerThread
.join();
101 return joinErrors(std::move(Err
), F
.get());
107 JITLinkExecutor::JITLinkExecutor() = default;
108 JITLinkExecutor::~JITLinkExecutor() = default;
110 Expected
<std::unique_ptr
<ObjectLayer
>>
111 JITLinkExecutor::operator()(ExecutionSession
&ES
, const Triple
&TT
) {
112 assert(EPC
&& "RemoteExecutorProcessControl must be initialized");
113 return std::make_unique
<ObjectLinkingLayer
>(ES
, EPC
->getMemMgr());
116 std::unique_ptr
<ExecutionSession
> JITLinkExecutor::startSession() {
117 assert(OwnedEPC
&& "RemoteExecutorProcessControl must be initialized");
118 return std::make_unique
<ExecutionSession
>(std::move(OwnedEPC
));
121 Error
JITLinkExecutor::addDebugSupport(ObjectLayer
&ObjLayer
) {
122 auto Registrar
= createJITLoaderGDBRegistrar(EPC
->getExecutionSession());
124 return Registrar
.takeError();
126 cast
<ObjectLinkingLayer
>(&ObjLayer
)->addPlugin(
127 std::make_unique
<DebugObjectManagerPlugin
>(ObjLayer
.getExecutionSession(),
128 std::move(*Registrar
)));
130 return Error::success();
133 Expected
<std::unique_ptr
<DefinitionGenerator
>>
134 JITLinkExecutor::loadDylib(StringRef RemotePath
) {
135 if (auto Handle
= EPC
->loadDylib(RemotePath
.data()))
136 return std::make_unique
<EPCDynamicLibrarySearchGenerator
>(
137 EPC
->getExecutionSession(), *Handle
);
139 return Handle
.takeError();
142 Expected
<int> JITLinkExecutor::runAsMain(JITEvaluatedSymbol MainSym
,
143 ArrayRef
<std::string
> Args
) {
144 return EPC
->runAsMain(MainSym
.getAddress(), Args
);
147 Error
JITLinkExecutor::disconnect() { return EPC
->disconnect(); }
149 static std::string
defaultPath(const char *HostArgv0
, StringRef ExecutorName
) {
150 // This just needs to be some symbol in the binary; C++ doesn't
151 // allow taking the address of ::main however.
152 void *P
= (void *)(intptr_t)defaultPath
;
153 SmallString
<256> FullName(sys::fs::getMainExecutable(HostArgv0
, P
));
154 sys::path::remove_filename(FullName
);
155 sys::path::append(FullName
, ExecutorName
);
156 return FullName
.str().str();
159 Expected
<std::unique_ptr
<ChildProcessJITLinkExecutor
>>
160 JITLinkExecutor::FindLocal(const char *HostArgv
) {
161 std::string BestGuess
= defaultPath(HostArgv
, "llvm-jitlink-executor");
162 auto Executor
= CreateLocal(BestGuess
);
164 consumeError(Executor
.takeError());
165 return make_error
<StringError
>(
166 formatv("Unable to find usable executor: {0}", BestGuess
),
167 inconvertibleErrorCode());
172 Expected
<std::unique_ptr
<ChildProcessJITLinkExecutor
>>
173 JITLinkExecutor::CreateLocal(std::string ExecutablePath
) {
174 if (!sys::fs::can_execute(ExecutablePath
))
175 return make_error
<StringError
>(
176 formatv("Specified executor invalid: {0}", ExecutablePath
),
177 inconvertibleErrorCode());
178 return std::unique_ptr
<ChildProcessJITLinkExecutor
>(
179 new ChildProcessJITLinkExecutor(std::move(ExecutablePath
)));
182 TCPSocketJITLinkExecutor::TCPSocketJITLinkExecutor(
183 std::unique_ptr
<RemoteExecutorProcessControl
> EPC
) {
184 this->OwnedEPC
= std::move(EPC
);
185 this->EPC
= this->OwnedEPC
.get();
190 // FIXME: Add support for Windows.
191 Error
ChildProcessJITLinkExecutor::launch(ExecutionSession
&ES
) {
192 return make_error
<StringError
>(
193 "Remote JITing not yet supported on non-unix platforms",
194 inconvertibleErrorCode());
197 // FIXME: Add support for Windows.
198 Expected
<std::unique_ptr
<TCPSocketJITLinkExecutor
>>
199 JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress
,
200 ExecutionSession
&ES
) {
201 return make_error
<StringError
>(
202 "Remote JITing not yet supported on non-unix platforms",
203 inconvertibleErrorCode());
208 Error
ChildProcessJITLinkExecutor::launch(
209 unique_function
<void(Error
)> ErrorReporter
) {
210 constexpr int ReadEnd
= 0;
211 constexpr int WriteEnd
= 1;
217 // Create pipes to/from the executor..
218 if (pipe(ToExecutor
) != 0 || pipe(FromExecutor
) != 0)
219 return make_error
<StringError
>("Unable to create pipe for executor",
220 inconvertibleErrorCode());
223 if (ProcessID
== 0) {
226 // Close the parent ends of the pipes
227 close(ToExecutor
[WriteEnd
]);
228 close(FromExecutor
[ReadEnd
]);
230 // Execute the child process.
231 std::unique_ptr
<char[]> ExecPath
, FDSpecifier
;
233 ExecPath
= std::make_unique
<char[]>(ExecutablePath
.size() + 1);
234 strcpy(ExecPath
.get(), ExecutablePath
.data());
236 std::string
FDSpecifierStr("filedescs=");
237 FDSpecifierStr
+= utostr(ToExecutor
[ReadEnd
]);
238 FDSpecifierStr
+= ',';
239 FDSpecifierStr
+= utostr(FromExecutor
[WriteEnd
]);
240 FDSpecifier
= std::make_unique
<char[]>(FDSpecifierStr
.size() + 1);
241 strcpy(FDSpecifier
.get(), FDSpecifierStr
.c_str());
244 char *const Args
[] = {ExecPath
.get(), FDSpecifier
.get(), nullptr};
245 int RC
= execvp(ExecPath
.get(), Args
);
247 return make_error
<StringError
>(
248 "Unable to launch out-of-process executor '" + ExecutablePath
+ "'\n",
249 inconvertibleErrorCode());
251 llvm_unreachable("Fork won't return in success case");
253 // else we're the parent...
255 // Close the child ends of the pipes
256 close(ToExecutor
[ReadEnd
]);
257 close(FromExecutor
[WriteEnd
]);
260 std::make_unique
<RPCChannel
>(FromExecutor
[ReadEnd
], ToExecutor
[WriteEnd
]);
261 auto Endpoint
= std::make_unique
<RemoteExecutorProcessControl::RPCEndpoint
>(
264 OwnedEPC
= std::make_unique
<RemoteExecutorProcessControl
>(
265 std::move(Channel
), std::move(Endpoint
), std::move(ErrorReporter
));
267 if (auto Err
= OwnedEPC
->initializeORCRPCEPCBase())
268 return joinErrors(std::move(Err
), OwnedEPC
->disconnect());
270 OwnedEPC
->initializeMemoryManagement();
271 EPC
= OwnedEPC
.get();
273 shared::registerStringError
<RPCChannel
>();
274 return Error::success();
277 static Expected
<int> connectTCPSocketImpl(std::string Host
,
278 std::string PortStr
) {
281 Hints
.ai_family
= AF_INET
;
282 Hints
.ai_socktype
= SOCK_STREAM
;
283 Hints
.ai_flags
= AI_NUMERICSERV
;
285 if (int EC
= getaddrinfo(Host
.c_str(), PortStr
.c_str(), &Hints
, &AI
))
286 return make_error
<StringError
>(
287 formatv("address resolution failed ({0})", gai_strerror(EC
)),
288 inconvertibleErrorCode());
290 // Cycle through the returned addrinfo structures and connect to the first
291 // reachable endpoint.
294 for (Server
= AI
; Server
!= nullptr; Server
= Server
->ai_next
) {
295 // If socket fails, maybe it's because the address family is not supported.
296 // Skip to the next addrinfo structure.
297 if ((SockFD
= socket(AI
->ai_family
, AI
->ai_socktype
, AI
->ai_protocol
)) < 0)
300 // If connect works, we exit the loop with a working socket.
301 if (connect(SockFD
, Server
->ai_addr
, Server
->ai_addrlen
) == 0)
308 // Did we reach the end of the loop without connecting to a valid endpoint?
309 if (Server
== nullptr)
310 return make_error
<StringError
>("invalid hostname",
311 inconvertibleErrorCode());
316 Expected
<std::unique_ptr
<TCPSocketJITLinkExecutor
>>
317 JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress
,
318 unique_function
<void(Error
)> ErrorReporter
) {
319 auto CreateErr
= [NetworkAddress
](StringRef Details
) {
320 return make_error
<StringError
>(
321 formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress
,
323 inconvertibleErrorCode());
326 StringRef Host
, PortStr
;
327 std::tie(Host
, PortStr
) = NetworkAddress
.split(':');
329 return CreateErr("host name cannot be empty");
331 return CreateErr("port cannot be empty");
333 if (PortStr
.getAsInteger(10, Port
))
334 return CreateErr("port number is not a valid integer");
336 Expected
<int> SockFD
= connectTCPSocketImpl(Host
.str(), PortStr
.str());
338 return CreateErr(toString(SockFD
.takeError()));
340 auto Channel
= std::make_unique
<RPCChannel
>(*SockFD
, *SockFD
);
341 auto Endpoint
= std::make_unique
<RemoteExecutorProcessControl::RPCEndpoint
>(
344 auto EPC
= std::make_unique
<RemoteExecutorProcessControl
>(
345 std::move(Channel
), std::move(Endpoint
), std::move(ErrorReporter
));
347 if (auto Err
= EPC
->initializeORCRPCEPCBase())
348 return joinErrors(std::move(Err
), EPC
->disconnect());
350 EPC
->initializeMemoryManagement();
351 shared::registerStringError
<RPCChannel
>();
353 return std::unique_ptr
<TCPSocketJITLinkExecutor
>(
354 new TCPSocketJITLinkExecutor(std::move(EPC
)));