LLVM 17.0.0git
ExecutorSharedMemoryMapperService.cpp
Go to the documentation of this file.
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
10
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
24namespace llvm {
25namespace orc {
26namespace rt_bootstrap {
27
28#if defined(_WIN32)
29static 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;
40 return PAGE_EXECUTE_READWRITE;
41 if (MP == MemProt::Exec)
42 return PAGE_EXECUTE;
43
44 return PAGE_NOACCESS;
45}
46#endif
47
48Expected<std::pair<ExecutorAddr, std::string>>
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",
118#endif
119}
120
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.RAG.Prot & MemProt::Read) == MemProt::Read)
136 NativeProt |= PROT_READ;
137 if ((Segment.RAG.Prot & MemProt::Write) == MemProt::Write)
138 NativeProt |= PROT_WRITE;
139 if ((Segment.RAG.Prot & 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 = getWindowsProtectionFlags(Segment.RAG.Prot);
148
149 if (!VirtualProtect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt,
150 &NativeProt))
151 return errorCodeToError(mapWindowsError(GetLastError()));
152
153#endif
154
155 if ((Segment.RAG.Prot & MemProt::Exec) == MemProt::Exec)
156 sys::Memory::InvalidateInstructionCache(Segment.Addr.toPtr<void *>(),
157 Segment.Size);
158 }
159
160 // Run finalization actions and get deinitlization action list.
161 auto DeinitializeActions = shared::runFinalizeActions(FR.Actions);
162 if (!DeinitializeActions) {
163 return DeinitializeActions.takeError();
164 }
165
166 {
167 std::lock_guard<std::mutex> Lock(Mutex);
168 Allocations[MinAddr].DeinitializationActions =
169 std::move(*DeinitializeActions);
170 Reservations[Reservation.toPtr<void *>()].Allocations.push_back(MinAddr);
171 }
172
173 return MinAddr;
174
175#else
176 return make_error<StringError>(
177 "SharedMemoryMapper is not supported on this platform yet",
179#endif
180}
181
183 const std::vector<ExecutorAddr> &Bases) {
184 Error AllErr = Error::success();
185
186 {
187 std::lock_guard<std::mutex> Lock(Mutex);
188
189 for (auto Base : llvm::reverse(Bases)) {
191 Allocations[Base].DeinitializationActions)) {
192 AllErr = joinErrors(std::move(AllErr), std::move(Err));
193 }
194
195 // Remove the allocation from the allocation list of its reservation
196 for (auto &Reservation : Reservations) {
197 auto AllocationIt =
198 std::find(Reservation.second.Allocations.begin(),
199 Reservation.second.Allocations.end(), Base);
200 if (AllocationIt != Reservation.second.Allocations.end()) {
201 Reservation.second.Allocations.erase(AllocationIt);
202 break;
203 }
204 }
205
206 Allocations.erase(Base);
207 }
208 }
209
210 return AllErr;
211}
212
214 const std::vector<ExecutorAddr> &Bases) {
215#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
216 Error Err = Error::success();
217
218 for (auto Base : Bases) {
219 std::vector<ExecutorAddr> AllocAddrs;
220 size_t Size;
221
222#if defined(_WIN32)
223 HANDLE SharedMemoryFile;
224#endif
225
226 {
227 std::lock_guard<std::mutex> Lock(Mutex);
228 auto &R = Reservations[Base.toPtr<void *>()];
229 Size = R.Size;
230
231#if defined(_WIN32)
232 SharedMemoryFile = R.SharedMemoryFile;
233#endif
234
235 AllocAddrs.swap(R.Allocations);
236 }
237
238 // deinitialize sub allocations
239 if (Error E = deinitialize(AllocAddrs))
240 Err = joinErrors(std::move(Err), std::move(E));
241
242#if defined(LLVM_ON_UNIX)
243
244 if (munmap(Base.toPtr<void *>(), Size) != 0)
245 Err = joinErrors(std::move(Err), errorCodeToError(std::error_code(
246 errno, std::generic_category())));
247
248#elif defined(_WIN32)
249 (void)Size;
250
251 if (!UnmapViewOfFile(Base.toPtr<void *>()))
252 Err = joinErrors(std::move(Err),
253 errorCodeToError(mapWindowsError(GetLastError())));
254
255 CloseHandle(SharedMemoryFile);
256
257#endif
258
259 std::lock_guard<std::mutex> Lock(Mutex);
260 Reservations.erase(Base.toPtr<void *>());
261 }
262
263 return Err;
264#else
265 return make_error<StringError>(
266 "SharedMemoryMapper is not supported on this platform yet",
268#endif
269}
270
272 if (Reservations.empty())
273 return Error::success();
274
275 std::vector<ExecutorAddr> ReservationAddrs;
276 ReservationAddrs.reserve(Reservations.size());
277 for (const auto &R : Reservations)
278 ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
279
280 return release(std::move(ReservationAddrs));
281}
282
288 ExecutorAddr::fromPtr(&reserveWrapper);
290 ExecutorAddr::fromPtr(&initializeWrapper);
292 ExecutorAddr::fromPtr(&deinitializeWrapper);
294 ExecutorAddr::fromPtr(&releaseWrapper);
295}
296
298ExecutorSharedMemoryMapperService::reserveWrapper(const char *ArgData,
299 size_t ArgSize) {
302 handle(ArgData, ArgSize,
305 .release();
306}
307
309ExecutorSharedMemoryMapperService::initializeWrapper(const char *ArgData,
310 size_t ArgSize) {
313 handle(ArgData, ArgSize,
316 .release();
317}
318
320ExecutorSharedMemoryMapperService::deinitializeWrapper(const char *ArgData,
321 size_t ArgSize) {
322 return shared::WrapperFunction<
324 handle(ArgData, ArgSize,
327 .release();
328}
329
331ExecutorSharedMemoryMapperService::releaseWrapper(const char *ArgData,
332 size_t ArgSize) {
333 return shared::WrapperFunction<
335 handle(ArgData, ArgSize,
338 .release();
339}
340
341} // namespace rt_bootstrap
342} // end namespace orc
343} // end namespace llvm
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
uint64_t Addr
uint64_t Size
Provides a library for accessing information about this process and other processes on the operating ...
bool erase(const KeyT &Val)
Definition: DenseMap.h:329
unsigned size() const
Definition: DenseMap.h:99
bool empty() const
Definition: DenseMap.h:98
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Tagged union holding either a T or a Error.
Definition: Error.h:470
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:111
Represents an address in the executor process.
static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap=UnwrapFn())
Create an ExecutorAddr from the given pointer.
std::enable_if_t< std::is_pointer< T >::value, T > toPtr(WrapFn &&Wrap=WrapFn()) const
Cast this ExecutorAddr to a pointer of the given type.
Expected< std::pair< ExecutorAddr, std::string > > reserve(uint64_t Size)
Expected< ExecutorAddr > initialize(ExecutorAddr Reservation, tpctypes::SharedMemoryFinalizeRequest &FR)
static void InvalidateInstructionCache(const void *Addr, size_t Len)
InvalidateInstructionCache - Before the JIT can run a block of code that has been emitted it must inv...
static Pid getProcessId()
Get the process's identifier.
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, shared::SPSExecutorAddr, shared::SPSSharedMemoryFinalizeRequest) SPSExecutorSharedMemoryMapperServiceInitializeSignature
Definition: OrcRTBridge.h:78
const char * ExecutorSharedMemoryMapperServiceInstanceName
Definition: OrcRTBridge.cpp:31
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSExecutorSharedMemoryMapperServiceReleaseSignature
Definition: OrcRTBridge.h:83
const char * ExecutorSharedMemoryMapperServiceReserveWrapperName
Definition: OrcRTBridge.cpp:33
shared::SPSExpected< shared::SPSTuple< shared::SPSExecutorAddr, shared::SPSString > >(shared::SPSExecutorAddr, uint64_t) SPSExecutorSharedMemoryMapperServiceReserveSignature
Definition: OrcRTBridge.h:74
const char * ExecutorSharedMemoryMapperServiceDeinitializeWrapperName
Definition: OrcRTBridge.cpp:37
const char * ExecutorSharedMemoryMapperServiceReleaseWrapperName
Definition: OrcRTBridge.cpp:39
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSExecutorSharedMemoryMapperServiceDeinitializeSignature
Definition: OrcRTBridge.h:81
const char * ExecutorSharedMemoryMapperServiceInitializeWrapperName
Definition: OrcRTBridge.cpp:35
MethodWrapperHandler< RetT, ClassT, ArgTs... > makeMethodWrapperHandler(RetT(ClassT::*Method)(ArgTs...))
Create a MethodWrapperHandler object from the given method pointer.
Error runDeallocActions(ArrayRef< WrapperFunctionCall > DAs)
Run deallocation actions.
Expected< std::vector< WrapperFunctionCall > > runFinalizeActions(AllocActions &AAs)
Run finalize actions.
MemProt
Describes Read/Write/Exec permissions for memory.
Definition: MemoryFlags.h:27
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:79
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:511
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:427
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:92
std::error_code mapWindowsError(unsigned EV)
std::vector< SharedMemorySegFinalizeRequest > Segments