xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.cpp (revision d3d9f7caf96680dad4ef0fd108e64ca044a0a113)
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)
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>>
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 
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.AG.getMemProt() & MemProt::Read) == MemProt::Read)
141       NativeProt |= PROT_READ;
142     if ((Segment.AG.getMemProt() & MemProt::Write) == MemProt::Write)
143       NativeProt |= PROT_WRITE;
144     if ((Segment.AG.getMemProt() & MemProt::Exec) == MemProt::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.AG.getMemProt() & MemProt::Exec) == MemProt::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 
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 : llvm::reverse(Bases)) {
196       if (Error Err = shared::runDeallocActions(
197               Allocations[Base].DeinitializationActions)) {
198         AllErr = joinErrors(std::move(AllErr), std::move(Err));
199       }
200 
201       // Remove the allocation from the allocation list of its reservation
202       for (auto &Reservation : Reservations) {
203         auto AllocationIt =
204             std::find(Reservation.second.Allocations.begin(),
205                       Reservation.second.Allocations.end(), Base);
206         if (AllocationIt != Reservation.second.Allocations.end()) {
207           Reservation.second.Allocations.erase(AllocationIt);
208           break;
209         }
210       }
211 
212       Allocations.erase(Base);
213     }
214   }
215 
216   return AllErr;
217 }
218 
219 Error ExecutorSharedMemoryMapperService::release(
220     const std::vector<ExecutorAddr> &Bases) {
221 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
222   Error Err = Error::success();
223 
224   for (auto Base : Bases) {
225     std::vector<ExecutorAddr> AllocAddrs;
226     size_t Size;
227 
228 #if defined(_WIN32)
229     HANDLE SharedMemoryFile;
230 #endif
231 
232     {
233       std::lock_guard<std::mutex> Lock(Mutex);
234       auto &R = Reservations[Base.toPtr<void *>()];
235       Size = R.Size;
236 
237 #if defined(_WIN32)
238       SharedMemoryFile = R.SharedMemoryFile;
239 #endif
240 
241       AllocAddrs.swap(R.Allocations);
242     }
243 
244     // deinitialize sub allocations
245     if (Error E = deinitialize(AllocAddrs))
246       Err = joinErrors(std::move(Err), std::move(E));
247 
248 #if defined(LLVM_ON_UNIX)
249 
250     if (munmap(Base.toPtr<void *>(), Size) != 0)
251       Err = joinErrors(std::move(Err), errorCodeToError(std::error_code(
252                                            errno, std::generic_category())));
253 
254 #elif defined(_WIN32)
255     (void)Size;
256 
257     if (!UnmapViewOfFile(Base.toPtr<void *>()))
258       Err = joinErrors(std::move(Err),
259                        errorCodeToError(mapWindowsError(GetLastError())));
260 
261     CloseHandle(SharedMemoryFile);
262 
263 #endif
264 
265     std::lock_guard<std::mutex> Lock(Mutex);
266     Reservations.erase(Base.toPtr<void *>());
267   }
268 
269   return Err;
270 #else
271   return make_error<StringError>(
272       "SharedMemoryMapper is not supported on this platform yet",
273       inconvertibleErrorCode());
274 #endif
275 }
276 
277 Error ExecutorSharedMemoryMapperService::shutdown() {
278   if (Reservations.empty())
279     return Error::success();
280 
281   std::vector<ExecutorAddr> ReservationAddrs;
282   ReservationAddrs.reserve(Reservations.size());
283   for (const auto &R : Reservations)
284     ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
285 
286   return release(std::move(ReservationAddrs));
287 }
288 
289 void ExecutorSharedMemoryMapperService::addBootstrapSymbols(
290     StringMap<ExecutorAddr> &M) {
291   M[rt::ExecutorSharedMemoryMapperServiceInstanceName] =
292       ExecutorAddr::fromPtr(this);
293   M[rt::ExecutorSharedMemoryMapperServiceReserveWrapperName] =
294       ExecutorAddr::fromPtr(&reserveWrapper);
295   M[rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName] =
296       ExecutorAddr::fromPtr(&initializeWrapper);
297   M[rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName] =
298       ExecutorAddr::fromPtr(&deinitializeWrapper);
299   M[rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName] =
300       ExecutorAddr::fromPtr(&releaseWrapper);
301 }
302 
303 llvm::orc::shared::CWrapperFunctionResult
304 ExecutorSharedMemoryMapperService::reserveWrapper(const char *ArgData,
305                                                   size_t ArgSize) {
306   return shared::WrapperFunction<
307              rt::SPSExecutorSharedMemoryMapperServiceReserveSignature>::
308       handle(ArgData, ArgSize,
309              shared::makeMethodWrapperHandler(
310                  &ExecutorSharedMemoryMapperService::reserve))
311           .release();
312 }
313 
314 llvm::orc::shared::CWrapperFunctionResult
315 ExecutorSharedMemoryMapperService::initializeWrapper(const char *ArgData,
316                                                      size_t ArgSize) {
317   return shared::WrapperFunction<
318              rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature>::
319       handle(ArgData, ArgSize,
320              shared::makeMethodWrapperHandler(
321                  &ExecutorSharedMemoryMapperService::initialize))
322           .release();
323 }
324 
325 llvm::orc::shared::CWrapperFunctionResult
326 ExecutorSharedMemoryMapperService::deinitializeWrapper(const char *ArgData,
327                                                        size_t ArgSize) {
328   return shared::WrapperFunction<
329              rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature>::
330       handle(ArgData, ArgSize,
331              shared::makeMethodWrapperHandler(
332                  &ExecutorSharedMemoryMapperService::deinitialize))
333           .release();
334 }
335 
336 llvm::orc::shared::CWrapperFunctionResult
337 ExecutorSharedMemoryMapperService::releaseWrapper(const char *ArgData,
338                                                   size_t ArgSize) {
339   return shared::WrapperFunction<
340              rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature>::
341       handle(ArgData, ArgSize,
342              shared::makeMethodWrapperHandler(
343                  &ExecutorSharedMemoryMapperService::release))
344           .release();
345 }
346 
347 } // namespace rt_bootstrap
348 } // end namespace orc
349 } // end namespace llvm
350