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)
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>>
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 
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 
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 
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 
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 
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
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
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
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
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