[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / examples / OrcV2Examples / LLJITWithRemoteDebugging / RemoteJITUtils.cpp
blob2616dd225d021caa656ff18d061609f9942249b9
1 //===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
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"
21 #ifdef LLVM_ON_UNIX
22 #include <netdb.h>
23 #include <netinet/in.h>
24 #include <sys/socket.h>
25 #include <unistd.h>
26 #endif // LLVM_ON_UNIX
28 using namespace llvm;
29 using namespace llvm::orc;
31 namespace llvm {
32 namespace orc {
34 class RemoteExecutorProcessControl
35 : public OrcRPCExecutorProcessControlBase<
36 shared::MultiThreadedRPCEndpoint<JITLinkExecutor::RPCChannel>> {
37 public:
38 using RPCChannel = JITLinkExecutor::RPCChannel;
39 using RPCEndpoint = shared::MultiThreadedRPCEndpoint<RPCChannel>;
41 private:
42 using ThisT = RemoteExecutorProcessControl;
43 using BaseT = OrcRPCExecutorProcessControlBase<RPCEndpoint>;
44 using MemoryAccess = OrcRPCEPCMemoryAccess<ThisT>;
45 using MemoryManager = OrcRPCEPCJITLinkMemoryManager<ThisT>;
47 public:
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;
57 private:
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([&]() {
74 while (!Finished) {
75 if (auto Err = this->Endpoint->handleOne()) {
76 reportError(std::move(Err));
77 return;
80 });
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));
97 Finished = true;
98 return Error::success();
99 });
100 ListenerThread.join();
101 return joinErrors(std::move(Err), F.get());
104 } // namespace orc
105 } // namespace llvm
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());
123 if (!Registrar)
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);
138 else
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);
163 if (!Executor) {
164 consumeError(Executor.takeError());
165 return make_error<StringError>(
166 formatv("Unable to find usable executor: {0}", BestGuess),
167 inconvertibleErrorCode());
169 return Executor;
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();
188 #ifndef LLVM_ON_UNIX
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());
206 #else
208 Error ChildProcessJITLinkExecutor::launch(
209 unique_function<void(Error)> ErrorReporter) {
210 constexpr int ReadEnd = 0;
211 constexpr int WriteEnd = 1;
213 // Pipe FDs.
214 int ToExecutor[2];
215 int FromExecutor[2];
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());
222 ProcessID = fork();
223 if (ProcessID == 0) {
224 // In the child...
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);
246 if (RC != 0)
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]);
259 auto Channel =
260 std::make_unique<RPCChannel>(FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
261 auto Endpoint = std::make_unique<RemoteExecutorProcessControl::RPCEndpoint>(
262 *Channel, true);
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) {
279 addrinfo *AI;
280 addrinfo Hints{};
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.
292 int SockFD;
293 addrinfo *Server;
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)
298 continue;
300 // If connect works, we exit the loop with a working socket.
301 if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
302 break;
304 close(SockFD);
306 freeaddrinfo(AI);
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());
313 return SockFD;
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,
322 Details),
323 inconvertibleErrorCode());
326 StringRef Host, PortStr;
327 std::tie(Host, PortStr) = NetworkAddress.split(':');
328 if (Host.empty())
329 return CreateErr("host name cannot be empty");
330 if (PortStr.empty())
331 return CreateErr("port cannot be empty");
332 int Port = 0;
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());
337 if (!SockFD)
338 return CreateErr(toString(SockFD.takeError()));
340 auto Channel = std::make_unique<RPCChannel>(*SockFD, *SockFD);
341 auto Endpoint = std::make_unique<RemoteExecutorProcessControl::RPCEndpoint>(
342 *Channel, true);
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)));
357 #endif