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