1 //===---------- ExecutorSharedMemoryMapperService.cpp -----------*- 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 #include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.h"
10
11 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
12 #include "llvm/Support/Process.h"
13 #include "llvm/Support/WindowsError.h"
14
15 #include <sstream>
16
17 #if defined(LLVM_ON_UNIX)
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <sys/mman.h>
21 #include <unistd.h>
22 #endif
23
24 namespace llvm {
25 namespace orc {
26 namespace rt_bootstrap {
27
28 #if defined(_WIN32)
getWindowsProtectionFlags(MemProt MP)29 static DWORD getWindowsProtectionFlags(MemProt MP) {
30 if (MP == MemProt::Read)
31 return PAGE_READONLY;
32 if (MP == MemProt::Write ||
33 MP == (MemProt::Write | MemProt::Read)) {
34 // Note: PAGE_WRITE is not supported by VirtualProtect
35 return PAGE_READWRITE;
36 }
37 if (MP == (MemProt::Read | MemProt::Exec))
38 return PAGE_EXECUTE_READ;
39 if (MP == (MemProt::Read | MemProt::Write | MemProt::Exec))
40 return PAGE_EXECUTE_READWRITE;
41 if (MP == MemProt::Exec)
42 return PAGE_EXECUTE;
43
44 return PAGE_NOACCESS;
45 }
46 #endif
47
48 Expected<std::pair<ExecutorAddr, std::string>>
reserve(uint64_t Size)49 ExecutorSharedMemoryMapperService::reserve(uint64_t Size) {
50 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
51
52 #if defined(LLVM_ON_UNIX)
53
54 std::string SharedMemoryName;
55 {
56 std::stringstream SharedMemoryNameStream;
57 SharedMemoryNameStream << "/jitlink_" << sys::Process::getProcessId() << '_'
58 << (++SharedMemoryCount);
59 SharedMemoryName = SharedMemoryNameStream.str();
60 }
61
62 int SharedMemoryFile =
63 shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT | O_EXCL, 0700);
64 if (SharedMemoryFile < 0)
65 return errorCodeToError(std::error_code(errno, std::generic_category()));
66
67 // by default size is 0
68 if (ftruncate(SharedMemoryFile, Size) < 0)
69 return errorCodeToError(std::error_code(errno, std::generic_category()));
70
71 void *Addr = mmap(nullptr, Size, PROT_NONE, MAP_SHARED, SharedMemoryFile, 0);
72 if (Addr == MAP_FAILED)
73 return errorCodeToError(std::error_code(errno, std::generic_category()));
74
75 close(SharedMemoryFile);
76
77 #elif defined(_WIN32)
78
79 std::string SharedMemoryName;
80 {
81 std::stringstream SharedMemoryNameStream;
82 SharedMemoryNameStream << "jitlink_" << sys::Process::getProcessId() << '_'
83 << (++SharedMemoryCount);
84 SharedMemoryName = SharedMemoryNameStream.str();
85 }
86
87 std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
88 SharedMemoryName.end());
89 HANDLE SharedMemoryFile = CreateFileMappingW(
90 INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, Size >> 32,
91 Size & 0xffffffff, WideSharedMemoryName.c_str());
92 if (!SharedMemoryFile)
93 return errorCodeToError(mapWindowsError(GetLastError()));
94
95 void *Addr = MapViewOfFile(SharedMemoryFile,
96 FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);
97 if (!Addr) {
98 CloseHandle(SharedMemoryFile);
99 return errorCodeToError(mapWindowsError(GetLastError()));
100 }
101
102 #endif
103
104 {
105 std::lock_guard<std::mutex> Lock(Mutex);
106 Reservations[Addr].Size = Size;
107 #if defined(_WIN32)
108 Reservations[Addr].SharedMemoryFile = SharedMemoryFile;
109 #endif
110 }
111
112 return std::make_pair(ExecutorAddr::fromPtr(Addr),
113 std::move(SharedMemoryName));
114 #else
115 return make_error<StringError>(
116 "SharedMemoryMapper is not supported on this platform yet",
117 inconvertibleErrorCode());
118 #endif
119 }
120
initialize(ExecutorAddr Reservation,tpctypes::SharedMemoryFinalizeRequest & FR)121 Expected<ExecutorAddr> ExecutorSharedMemoryMapperService::initialize(
122 ExecutorAddr Reservation, tpctypes::SharedMemoryFinalizeRequest &FR) {
123 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
124
125 ExecutorAddr MinAddr(~0ULL);
126
127 // Contents are already in place
128 for (auto &Segment : FR.Segments) {
129 if (Segment.Addr < MinAddr)
130 MinAddr = Segment.Addr;
131
132 #if defined(LLVM_ON_UNIX)
133
134 int NativeProt = 0;
135 if ((Segment.AG.getMemProt() & MemProt::Read) == MemProt::Read)
136 NativeProt |= PROT_READ;
137 if ((Segment.AG.getMemProt() & MemProt::Write) == MemProt::Write)
138 NativeProt |= PROT_WRITE;
139 if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec)
140 NativeProt |= PROT_EXEC;
141
142 if (mprotect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt))
143 return errorCodeToError(std::error_code(errno, std::generic_category()));
144
145 #elif defined(_WIN32)
146
147 DWORD NativeProt =
148 getWindowsProtectionFlags(Segment.AG.getMemProt());
149
150 if (!VirtualProtect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt,
151 &NativeProt))
152 return errorCodeToError(mapWindowsError(GetLastError()));
153
154 #endif
155
156 if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::Exec)
157 sys::Memory::InvalidateInstructionCache(Segment.Addr.toPtr<void *>(),
158 Segment.Size);
159 }
160
161 // Run finalization actions and get deinitlization action list.
162 auto DeinitializeActions = shared::runFinalizeActions(FR.Actions);
163 if (!DeinitializeActions) {
164 return DeinitializeActions.takeError();
165 }
166
167 {
168 std::lock_guard<std::mutex> Lock(Mutex);
169 Allocations[MinAddr].DeinitializationActions =
170 std::move(*DeinitializeActions);
171 Reservations[Reservation.toPtr<void *>()].Allocations.push_back(MinAddr);
172 }
173
174 return MinAddr;
175
176 #else
177 return make_error<StringError>(
178 "SharedMemoryMapper is not supported on this platform yet",
179 inconvertibleErrorCode());
180 #endif
181 }
182
deinitialize(const std::vector<ExecutorAddr> & Bases)183 Error ExecutorSharedMemoryMapperService::deinitialize(
184 const std::vector<ExecutorAddr> &Bases) {
185 Error AllErr = Error::success();
186
187 {
188 std::lock_guard<std::mutex> Lock(Mutex);
189
190 for (auto Base : llvm::reverse(Bases)) {
191 if (Error Err = shared::runDeallocActions(
192 Allocations[Base].DeinitializationActions)) {
193 AllErr = joinErrors(std::move(AllErr), std::move(Err));
194 }
195
196 // Remove the allocation from the allocation list of its reservation
197 for (auto &Reservation : Reservations) {
198 auto AllocationIt =
199 std::find(Reservation.second.Allocations.begin(),
200 Reservation.second.Allocations.end(), Base);
201 if (AllocationIt != Reservation.second.Allocations.end()) {
202 Reservation.second.Allocations.erase(AllocationIt);
203 break;
204 }
205 }
206
207 Allocations.erase(Base);
208 }
209 }
210
211 return AllErr;
212 }
213
release(const std::vector<ExecutorAddr> & Bases)214 Error ExecutorSharedMemoryMapperService::release(
215 const std::vector<ExecutorAddr> &Bases) {
216 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
217 Error Err = Error::success();
218
219 for (auto Base : Bases) {
220 std::vector<ExecutorAddr> AllocAddrs;
221 size_t Size;
222
223 #if defined(_WIN32)
224 HANDLE SharedMemoryFile;
225 #endif
226
227 {
228 std::lock_guard<std::mutex> Lock(Mutex);
229 auto &R = Reservations[Base.toPtr<void *>()];
230 Size = R.Size;
231
232 #if defined(_WIN32)
233 SharedMemoryFile = R.SharedMemoryFile;
234 #endif
235
236 AllocAddrs.swap(R.Allocations);
237 }
238
239 // deinitialize sub allocations
240 if (Error E = deinitialize(AllocAddrs))
241 Err = joinErrors(std::move(Err), std::move(E));
242
243 #if defined(LLVM_ON_UNIX)
244
245 if (munmap(Base.toPtr<void *>(), Size) != 0)
246 Err = joinErrors(std::move(Err), errorCodeToError(std::error_code(
247 errno, std::generic_category())));
248
249 #elif defined(_WIN32)
250 (void)Size;
251
252 if (!UnmapViewOfFile(Base.toPtr<void *>()))
253 Err = joinErrors(std::move(Err),
254 errorCodeToError(mapWindowsError(GetLastError())));
255
256 CloseHandle(SharedMemoryFile);
257
258 #endif
259
260 std::lock_guard<std::mutex> Lock(Mutex);
261 Reservations.erase(Base.toPtr<void *>());
262 }
263
264 return Err;
265 #else
266 return make_error<StringError>(
267 "SharedMemoryMapper is not supported on this platform yet",
268 inconvertibleErrorCode());
269 #endif
270 }
271
shutdown()272 Error ExecutorSharedMemoryMapperService::shutdown() {
273 if (Reservations.empty())
274 return Error::success();
275
276 std::vector<ExecutorAddr> ReservationAddrs;
277 ReservationAddrs.reserve(Reservations.size());
278 for (const auto &R : Reservations)
279 ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
280
281 return release(std::move(ReservationAddrs));
282 }
283
addBootstrapSymbols(StringMap<ExecutorAddr> & M)284 void ExecutorSharedMemoryMapperService::addBootstrapSymbols(
285 StringMap<ExecutorAddr> &M) {
286 M[rt::ExecutorSharedMemoryMapperServiceInstanceName] =
287 ExecutorAddr::fromPtr(this);
288 M[rt::ExecutorSharedMemoryMapperServiceReserveWrapperName] =
289 ExecutorAddr::fromPtr(&reserveWrapper);
290 M[rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName] =
291 ExecutorAddr::fromPtr(&initializeWrapper);
292 M[rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName] =
293 ExecutorAddr::fromPtr(&deinitializeWrapper);
294 M[rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName] =
295 ExecutorAddr::fromPtr(&releaseWrapper);
296 }
297
298 llvm::orc::shared::CWrapperFunctionResult
reserveWrapper(const char * ArgData,size_t ArgSize)299 ExecutorSharedMemoryMapperService::reserveWrapper(const char *ArgData,
300 size_t ArgSize) {
301 return shared::WrapperFunction<
302 rt::SPSExecutorSharedMemoryMapperServiceReserveSignature>::
303 handle(ArgData, ArgSize,
304 shared::makeMethodWrapperHandler(
305 &ExecutorSharedMemoryMapperService::reserve))
306 .release();
307 }
308
309 llvm::orc::shared::CWrapperFunctionResult
initializeWrapper(const char * ArgData,size_t ArgSize)310 ExecutorSharedMemoryMapperService::initializeWrapper(const char *ArgData,
311 size_t ArgSize) {
312 return shared::WrapperFunction<
313 rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature>::
314 handle(ArgData, ArgSize,
315 shared::makeMethodWrapperHandler(
316 &ExecutorSharedMemoryMapperService::initialize))
317 .release();
318 }
319
320 llvm::orc::shared::CWrapperFunctionResult
deinitializeWrapper(const char * ArgData,size_t ArgSize)321 ExecutorSharedMemoryMapperService::deinitializeWrapper(const char *ArgData,
322 size_t ArgSize) {
323 return shared::WrapperFunction<
324 rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature>::
325 handle(ArgData, ArgSize,
326 shared::makeMethodWrapperHandler(
327 &ExecutorSharedMemoryMapperService::deinitialize))
328 .release();
329 }
330
331 llvm::orc::shared::CWrapperFunctionResult
releaseWrapper(const char * ArgData,size_t ArgSize)332 ExecutorSharedMemoryMapperService::releaseWrapper(const char *ArgData,
333 size_t ArgSize) {
334 return shared::WrapperFunction<
335 rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature>::
336 handle(ArgData, ArgSize,
337 shared::makeMethodWrapperHandler(
338 &ExecutorSharedMemoryMapperService::release))
339 .release();
340 }
341
342 } // namespace rt_bootstrap
343 } // end namespace orc
344 } // end namespace llvm
345