Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Interpreter/RemoteJITUtils.cpp
213766 views
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
//===----------------------------------------------------------------------===//
8
//
9
// FIXME: Unify this code with similar functionality in llvm-jitlink.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/Interpreter/RemoteJITUtils.h"
14
15
#include "llvm/ADT/StringExtras.h"
16
#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
17
#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
18
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
19
#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
20
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
21
#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
22
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
23
#include "llvm/Support/FileSystem.h"
24
#include "llvm/Support/Path.h"
25
26
#ifdef LLVM_ON_UNIX
27
#include <netdb.h>
28
#include <netinet/in.h>
29
#include <sys/socket.h>
30
#include <unistd.h>
31
#endif // LLVM_ON_UNIX
32
33
using namespace llvm;
34
using namespace llvm::orc;
35
36
Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
37
SizeString = SizeString.trim();
38
39
uint64_t Units = 1024;
40
41
if (SizeString.ends_with_insensitive("kb"))
42
SizeString = SizeString.drop_back(2).rtrim();
43
else if (SizeString.ends_with_insensitive("mb")) {
44
Units = 1024 * 1024;
45
SizeString = SizeString.drop_back(2).rtrim();
46
} else if (SizeString.ends_with_insensitive("gb")) {
47
Units = 1024 * 1024 * 1024;
48
SizeString = SizeString.drop_back(2).rtrim();
49
}
50
51
uint64_t SlabSize = 0;
52
if (SizeString.getAsInteger(10, SlabSize))
53
return make_error<StringError>("Invalid numeric format for slab size",
54
inconvertibleErrorCode());
55
56
return SlabSize * Units;
57
}
58
59
Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
60
createSharedMemoryManager(SimpleRemoteEPC &SREPC,
61
StringRef SlabAllocateSizeString) {
62
SharedMemoryMapper::SymbolAddrs SAs;
63
if (auto Err = SREPC.getBootstrapSymbols(
64
{{SAs.Instance, rt::ExecutorSharedMemoryMapperServiceInstanceName},
65
{SAs.Reserve,
66
rt::ExecutorSharedMemoryMapperServiceReserveWrapperName},
67
{SAs.Initialize,
68
rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName},
69
{SAs.Deinitialize,
70
rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName},
71
{SAs.Release,
72
rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName}}))
73
return std::move(Err);
74
75
#ifdef _WIN32
76
size_t SlabSize = 1024 * 1024;
77
#else
78
size_t SlabSize = 1024 * 1024 * 1024;
79
#endif
80
81
if (!SlabAllocateSizeString.empty()) {
82
if (Expected<uint64_t> S = getSlabAllocSize(SlabAllocateSizeString))
83
SlabSize = *S;
84
else
85
return S.takeError();
86
}
87
88
return MapperJITLinkMemoryManager::CreateWithMapper<SharedMemoryMapper>(
89
SlabSize, SREPC, SAs);
90
}
91
92
Expected<std::unique_ptr<SimpleRemoteEPC>>
93
launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,
94
llvm::StringRef SlabAllocateSizeString) {
95
#ifndef LLVM_ON_UNIX
96
// FIXME: Add support for Windows.
97
return make_error<StringError>("-" + ExecutablePath +
98
" not supported on non-unix platforms",
99
inconvertibleErrorCode());
100
#elif !LLVM_ENABLE_THREADS
101
// Out of process mode using SimpleRemoteEPC depends on threads.
102
return make_error<StringError>(
103
"-" + ExecutablePath +
104
" requires threads, but LLVM was built with "
105
"LLVM_ENABLE_THREADS=Off",
106
inconvertibleErrorCode());
107
#else
108
109
if (!sys::fs::can_execute(ExecutablePath))
110
return make_error<StringError>(
111
formatv("Specified executor invalid: {0}", ExecutablePath),
112
inconvertibleErrorCode());
113
114
constexpr int ReadEnd = 0;
115
constexpr int WriteEnd = 1;
116
117
// Pipe FDs.
118
int ToExecutor[2];
119
int FromExecutor[2];
120
121
pid_t ChildPID;
122
123
// Create pipes to/from the executor..
124
if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
125
return make_error<StringError>("Unable to create pipe for executor",
126
inconvertibleErrorCode());
127
128
ChildPID = fork();
129
130
if (ChildPID == 0) {
131
// In the child...
132
133
// Close the parent ends of the pipes
134
close(ToExecutor[WriteEnd]);
135
close(FromExecutor[ReadEnd]);
136
137
// Execute the child process.
138
std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
139
{
140
ExecutorPath = std::make_unique<char[]>(ExecutablePath.size() + 1);
141
strcpy(ExecutorPath.get(), ExecutablePath.data());
142
143
std::string FDSpecifierStr("filedescs=");
144
FDSpecifierStr += utostr(ToExecutor[ReadEnd]);
145
FDSpecifierStr += ',';
146
FDSpecifierStr += utostr(FromExecutor[WriteEnd]);
147
FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
148
strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
149
}
150
151
char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};
152
int RC = execvp(ExecutorPath.get(), Args);
153
if (RC != 0) {
154
errs() << "unable to launch out-of-process executor \""
155
<< ExecutorPath.get() << "\"\n";
156
exit(1);
157
}
158
}
159
// else we're the parent...
160
161
// Close the child ends of the pipes
162
close(ToExecutor[ReadEnd]);
163
close(FromExecutor[WriteEnd]);
164
165
SimpleRemoteEPC::Setup S = SimpleRemoteEPC::Setup();
166
if (UseSharedMemory)
167
S.CreateMemoryManager = [SlabAllocateSizeString](SimpleRemoteEPC &EPC) {
168
return createSharedMemoryManager(EPC, SlabAllocateSizeString);
169
};
170
171
return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
172
std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
173
std::move(S), FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
174
#endif
175
}
176
177
#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
178
179
static Expected<int> connectTCPSocketImpl(std::string Host,
180
std::string PortStr) {
181
addrinfo *AI;
182
addrinfo Hints{};
183
Hints.ai_family = AF_INET;
184
Hints.ai_socktype = SOCK_STREAM;
185
Hints.ai_flags = AI_NUMERICSERV;
186
187
if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))
188
return make_error<StringError>(
189
formatv("address resolution failed ({0})", gai_strerror(EC)),
190
inconvertibleErrorCode());
191
// Cycle through the returned addrinfo structures and connect to the first
192
// reachable endpoint.
193
int SockFD;
194
addrinfo *Server;
195
for (Server = AI; Server != nullptr; Server = Server->ai_next) {
196
// socket might fail, e.g. if the address family is not supported. Skip to
197
// the next addrinfo structure in such a case.
198
if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
199
continue;
200
201
// If connect returns null, we exit the loop with a working socket.
202
if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
203
break;
204
205
close(SockFD);
206
}
207
freeaddrinfo(AI);
208
209
// If we reached the end of the loop without connecting to a valid endpoint,
210
// dump the last error that was logged in socket() or connect().
211
if (Server == nullptr)
212
return make_error<StringError>("invalid hostname",
213
inconvertibleErrorCode());
214
215
return SockFD;
216
}
217
#endif
218
219
Expected<std::unique_ptr<SimpleRemoteEPC>>
220
connectTCPSocket(StringRef NetworkAddress, bool UseSharedMemory,
221
llvm::StringRef SlabAllocateSizeString) {
222
#ifndef LLVM_ON_UNIX
223
// FIXME: Add TCP support for Windows.
224
return make_error<StringError>("-" + NetworkAddress +
225
" not supported on non-unix platforms",
226
inconvertibleErrorCode());
227
#elif !LLVM_ENABLE_THREADS
228
// Out of process mode using SimpleRemoteEPC depends on threads.
229
return make_error<StringError>(
230
"-" + NetworkAddress +
231
" requires threads, but LLVM was built with "
232
"LLVM_ENABLE_THREADS=Off",
233
inconvertibleErrorCode());
234
#else
235
236
auto CreateErr = [NetworkAddress](Twine Details) {
237
return make_error<StringError>(
238
formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,
239
Details),
240
inconvertibleErrorCode());
241
};
242
243
StringRef Host, PortStr;
244
std::tie(Host, PortStr) = NetworkAddress.split(':');
245
if (Host.empty())
246
return CreateErr("Host name for -" + NetworkAddress + " can not be empty");
247
if (PortStr.empty())
248
return CreateErr("Port number in -" + NetworkAddress + " can not be empty");
249
int Port = 0;
250
if (PortStr.getAsInteger(10, Port))
251
return CreateErr("Port number '" + PortStr + "' is not a valid integer");
252
253
Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());
254
if (!SockFD)
255
return SockFD.takeError();
256
257
SimpleRemoteEPC::Setup S = SimpleRemoteEPC::Setup();
258
if (UseSharedMemory)
259
S.CreateMemoryManager = [SlabAllocateSizeString](SimpleRemoteEPC &EPC) {
260
return createSharedMemoryManager(EPC, SlabAllocateSizeString);
261
};
262
263
return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
264
std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),
265
std::move(S), *SockFD, *SockFD);
266
#endif
267
}
268
269