LLVM 22.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#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
15#include <future>
16#include <sstream>
17
18#if defined(LLVM_ON_UNIX)
19#include <errno.h>
20#include <fcntl.h>
21#include <sys/mman.h>
22#if defined(__MVS__)
23#include "llvm/Support/BLAKE3.h"
24#include <sys/shm.h>
25#endif
26#include <unistd.h>
27#endif
28
29namespace llvm {
30namespace orc {
31namespace rt_bootstrap {
32
33#if defined(_WIN32)
34static DWORD getWindowsProtectionFlags(MemProt MP) {
35 if (MP == MemProt::Read)
36 return PAGE_READONLY;
37 if (MP == MemProt::Write ||
38 MP == (MemProt::Write | MemProt::Read)) {
39 // Note: PAGE_WRITE is not supported by VirtualProtect
40 return PAGE_READWRITE;
41 }
42 if (MP == (MemProt::Read | MemProt::Exec))
43 return PAGE_EXECUTE_READ;
45 return PAGE_EXECUTE_READWRITE;
46 if (MP == MemProt::Exec)
47 return PAGE_EXECUTE;
48
49 return PAGE_NOACCESS;
50}
51#endif
52
53Expected<std::pair<ExecutorAddr, std::string>>
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#if defined(__MVS__)
69 reinterpret_cast<const uint8_t *>(SharedMemoryName.c_str()),
70 SharedMemoryName.size());
71 auto HashedName = BLAKE3::hash<sizeof(key_t)>(Data);
72 key_t Key = *reinterpret_cast<key_t *>(HashedName.data());
73 int SharedMemoryId =
74 shmget(Key, Size, IPC_CREAT | IPC_EXCL | __IPC_SHAREAS | 0700);
75 if (SharedMemoryId < 0)
77
78 void *Addr = shmat(SharedMemoryId, nullptr, 0);
79 if (Addr == reinterpret_cast<void *>(-1))
81#else
82 int SharedMemoryFile =
83 shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT | O_EXCL, 0700);
84 if (SharedMemoryFile < 0)
86
87 // by default size is 0
88 if (ftruncate(SharedMemoryFile, Size) < 0)
90
91 void *Addr = mmap(nullptr, Size, PROT_NONE, MAP_SHARED, SharedMemoryFile, 0);
92 if (Addr == MAP_FAILED)
94
95 close(SharedMemoryFile);
96#endif
97
98#elif defined(_WIN32)
99
100 std::string SharedMemoryName;
101 {
102 std::stringstream SharedMemoryNameStream;
103 SharedMemoryNameStream << "jitlink_" << sys::Process::getProcessId() << '_'
104 << (++SharedMemoryCount);
105 SharedMemoryName = SharedMemoryNameStream.str();
106 }
107
108 std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
109 SharedMemoryName.end());
110 HANDLE SharedMemoryFile = CreateFileMappingW(
111 INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, Size >> 32,
112 Size & 0xffffffff, WideSharedMemoryName.c_str());
113 if (!SharedMemoryFile)
114 return errorCodeToError(mapWindowsError(GetLastError()));
115
116 void *Addr = MapViewOfFile(SharedMemoryFile,
117 FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);
118 if (!Addr) {
119 CloseHandle(SharedMemoryFile);
120 return errorCodeToError(mapWindowsError(GetLastError()));
121 }
122
123#endif
124
125 {
126 std::lock_guard<std::mutex> Lock(Mutex);
127 Reservations[Addr].Size = Size;
128#if defined(_WIN32)
129 Reservations[Addr].SharedMemoryFile = SharedMemoryFile;
130#endif
131 }
132
133 return std::make_pair(ExecutorAddr::fromPtr(Addr),
134 std::move(SharedMemoryName));
135#else
136 return make_error<StringError>(
137 "SharedMemoryMapper is not supported on this platform yet",
139#endif
140}
141
144#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
145
146 ExecutorAddr MinAddr(~0ULL);
147
148 // Contents are already in place
149 for (auto &Segment : FR.Segments) {
150 if (Segment.Addr < MinAddr)
151 MinAddr = Segment.Addr;
152
153#if defined(LLVM_ON_UNIX)
154
155#if defined(__MVS__)
156 // TODO Is it possible to change the protection level?
157#else
158 int NativeProt = 0;
159 if ((Segment.RAG.Prot & MemProt::Read) == MemProt::Read)
160 NativeProt |= PROT_READ;
161 if ((Segment.RAG.Prot & MemProt::Write) == MemProt::Write)
162 NativeProt |= PROT_WRITE;
163 if ((Segment.RAG.Prot & MemProt::Exec) == MemProt::Exec)
164 NativeProt |= PROT_EXEC;
165
166 if (mprotect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt))
168#endif
169
170#elif defined(_WIN32)
171
172 DWORD NativeProt = getWindowsProtectionFlags(Segment.RAG.Prot);
173
174 if (!VirtualProtect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt,
175 &NativeProt))
176 return errorCodeToError(mapWindowsError(GetLastError()));
177
178#endif
179
180 if ((Segment.RAG.Prot & MemProt::Exec) == MemProt::Exec)
181 sys::Memory::InvalidateInstructionCache(Segment.Addr.toPtr<void *>(),
182 Segment.Size);
183 }
184
185 // Run finalization actions and get deinitlization action list.
186 std::vector<shared::WrapperFunctionCall> DeinitializeActions;
187 {
188 std::promise<MSVCPExpected<std::vector<shared::WrapperFunctionCall>>> P;
189 auto F = P.get_future();
191 FR.Actions, [&](Expected<std::vector<shared::WrapperFunctionCall>> R) {
192 P.set_value(std::move(R));
193 });
194 if (auto DeinitializeActionsOrErr = F.get())
195 DeinitializeActions = std::move(*DeinitializeActionsOrErr);
196 else
197 return DeinitializeActionsOrErr.takeError();
198 }
199
200 {
201 std::lock_guard<std::mutex> Lock(Mutex);
202 Allocations[MinAddr].DeinitializationActions =
203 std::move(DeinitializeActions);
204 Reservations[Reservation.toPtr<void *>()].Allocations.push_back(MinAddr);
205 }
206
207 return MinAddr;
208
209#else
210 return make_error<StringError>(
211 "SharedMemoryMapper is not supported on this platform yet",
213#endif
214}
215
217 const std::vector<ExecutorAddr> &Bases) {
218 Error AllErr = Error::success();
219
220 {
221 std::lock_guard<std::mutex> Lock(Mutex);
222
223 for (auto Base : llvm::reverse(Bases)) {
225 Allocations[Base].DeinitializationActions, [&](Error Err) {
226 if (Err)
227 AllErr = joinErrors(std::move(AllErr), std::move(Err));
228 });
229
230 // Remove the allocation from the allocation list of its reservation
231 for (auto &Reservation : Reservations) {
232 auto AllocationIt = llvm::find(Reservation.second.Allocations, Base);
233 if (AllocationIt != Reservation.second.Allocations.end()) {
234 Reservation.second.Allocations.erase(AllocationIt);
235 break;
236 }
237 }
238
239 Allocations.erase(Base);
240 }
241 }
242
243 return AllErr;
244}
245
247 const std::vector<ExecutorAddr> &Bases) {
248#if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
249 Error Err = Error::success();
250
251 for (auto Base : Bases) {
252 std::vector<ExecutorAddr> AllocAddrs;
253 size_t Size;
254
255#if defined(_WIN32)
256 HANDLE SharedMemoryFile;
257#endif
258
259 {
260 std::lock_guard<std::mutex> Lock(Mutex);
261 auto &R = Reservations[Base.toPtr<void *>()];
262 Size = R.Size;
263
264#if defined(_WIN32)
265 SharedMemoryFile = R.SharedMemoryFile;
266#endif
267
268 AllocAddrs.swap(R.Allocations);
269 }
270
271 // deinitialize sub allocations
272 if (Error E = deinitialize(AllocAddrs))
273 Err = joinErrors(std::move(Err), std::move(E));
274
275#if defined(LLVM_ON_UNIX)
276
277#if defined(__MVS__)
278 (void)Size;
279
280 if (shmdt(Base.toPtr<void *>()) < 0)
281 Err = joinErrors(std::move(Err), errorCodeToError(errnoAsErrorCode()));
282#else
283 if (munmap(Base.toPtr<void *>(), Size) != 0)
284 Err = joinErrors(std::move(Err), errorCodeToError(errnoAsErrorCode()));
285#endif
286
287#elif defined(_WIN32)
288 (void)Size;
289
290 if (!UnmapViewOfFile(Base.toPtr<void *>()))
291 Err = joinErrors(std::move(Err),
292 errorCodeToError(mapWindowsError(GetLastError())));
293
294 CloseHandle(SharedMemoryFile);
295
296#endif
297
298 std::lock_guard<std::mutex> Lock(Mutex);
299 Reservations.erase(Base.toPtr<void *>());
300 }
301
302 return Err;
303#else
304 return make_error<StringError>(
305 "SharedMemoryMapper is not supported on this platform yet",
307#endif
308}
309
311 if (Reservations.empty())
312 return Error::success();
313
314 std::vector<ExecutorAddr> ReservationAddrs;
315 ReservationAddrs.reserve(Reservations.size());
316 for (const auto &R : Reservations)
317 ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
318
319 return release(std::move(ReservationAddrs));
320}
321
327 ExecutorAddr::fromPtr(&reserveWrapper);
329 ExecutorAddr::fromPtr(&initializeWrapper);
331 ExecutorAddr::fromPtr(&deinitializeWrapper);
333 ExecutorAddr::fromPtr(&releaseWrapper);
334}
335
337ExecutorSharedMemoryMapperService::reserveWrapper(const char *ArgData,
338 size_t ArgSize) {
341 handle(ArgData, ArgSize,
344 .release();
345}
346
348ExecutorSharedMemoryMapperService::initializeWrapper(const char *ArgData,
349 size_t ArgSize) {
352 handle(ArgData, ArgSize,
355 .release();
356}
357
359ExecutorSharedMemoryMapperService::deinitializeWrapper(const char *ArgData,
360 size_t ArgSize) {
361 return shared::WrapperFunction<
363 handle(ArgData, ArgSize,
366 .release();
367}
368
370ExecutorSharedMemoryMapperService::releaseWrapper(const char *ArgData,
371 size_t ArgSize) {
372 return shared::WrapperFunction<
374 handle(ArgData, ArgSize,
377 .release();
378}
379
380} // namespace rt_bootstrap
381} // end namespace orc
382} // end namespace llvm
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
uint64_t Addr
uint64_t Size
#define F(x, y, z)
Definition: MD5.cpp:55
#define P(N)
Provides a library for accessing information about this process and other processes on the operating ...
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
bool erase(const KeyT &Val)
Definition: DenseMap.h:303
unsigned size() const
Definition: DenseMap.h:108
bool empty() const
Definition: DenseMap.h:107
Lightweight error class with error context and mandatory checking.
Definition: Error.h:159
static ErrorSuccess success()
Create a success value.
Definition: Error.h:336
Tagged union holding either a T or a Error.
Definition: Error.h:485
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:133
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 LLVM_ABI 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 LLVM_ABI Pid getProcessId()
Get the process's identifier.
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, shared::SPSExecutorAddr, shared::SPSSharedMemoryFinalizeRequest) SPSExecutorSharedMemoryMapperServiceInitializeSignature
Definition: OrcRTBridge.h:90
LLVM_ABI const char * ExecutorSharedMemoryMapperServiceInstanceName
Definition: OrcRTBridge.cpp:31
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSExecutorSharedMemoryMapperServiceReleaseSignature
Definition: OrcRTBridge.h:95
LLVM_ABI const char * ExecutorSharedMemoryMapperServiceReserveWrapperName
Definition: OrcRTBridge.cpp:33
shared::SPSExpected< shared::SPSTuple< shared::SPSExecutorAddr, shared::SPSString > >(shared::SPSExecutorAddr, uint64_t) SPSExecutorSharedMemoryMapperServiceReserveSignature
Definition: OrcRTBridge.h:86
LLVM_ABI const char * ExecutorSharedMemoryMapperServiceDeinitializeWrapperName
Definition: OrcRTBridge.cpp:37
LLVM_ABI const char * ExecutorSharedMemoryMapperServiceReleaseWrapperName
Definition: OrcRTBridge.cpp:39
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSExecutorSharedMemoryMapperServiceDeinitializeSignature
Definition: OrcRTBridge.h:93
LLVM_ABI 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.
LLVM_ABI void runDeallocActions(ArrayRef< WrapperFunctionCall > DAs, OnRunDeallocActionsComeleteFn OnComplete)
Run deallocation actions.
LLVM_ABI void runFinalizeActions(AllocActions &AAs, OnRunFinalizeActionsCompleteFn OnComplete)
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
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1770
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:98
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:428
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:442
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:111
LLVM_ABI std::error_code mapWindowsError(unsigned EV)
std::error_code errnoAsErrorCode()
Helper to get errno as an std::error_code.
Definition: Error.h:1240
std::vector< SharedMemorySegFinalizeRequest > Segments