LLVM: lib/CAS/MappedFileRegionArena.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
58
59#if LLVM_ON_UNIX
60#include <sys/stat.h>
61#if __has_include(<sys/param.h>)
62#include <sys/param.h>
63#endif
64#ifdef DEV_BSIZE
65#define MAPPED_FILE_BSIZE DEV_BSIZE
66#elif __linux__
67#define MAPPED_FILE_BSIZE 512
68#endif
69#endif
70
71using namespace llvm;
74
75namespace {
76struct FileWithLock {
77 std::string Path;
78 int FD = -1;
79 std::optionalsys::fs::LockKind Locked;
80
81private:
82 FileWithLock(std::string PathStr, Error &E) : Path(std::move(PathStr)) {
83 ErrorAsOutParameter EOP(&E);
87 }
88
89public:
90 FileWithLock(FileWithLock &) = delete;
91 FileWithLock(FileWithLock &&Other) {
92 Path = std::move(Other.Path);
95 Locked = Other.Locked;
96 Other.Locked = std::nullopt;
97 }
98
100
101 static Expected open(StringRef Path) {
103 FileWithLock Result(Path.str(), E);
104 if (E)
105 return std::move(E);
106 return std::move(Result);
107 }
108
110 assert(!Locked && "already locked");
113 Locked = LK;
115 }
116
118 assert(Locked && "not locked");
119 if (auto E = unlock())
120 return E;
121
122 return lock(LK);
123 }
124
126 if (Locked) {
127 Locked = std::nullopt;
130 }
132 }
133
134
135 bool tryLockExclusive() {
136 assert(!Locked && "can only try to lock if not locked");
138 Locked = sys::fs::LockKind::Exclusive;
139 return true;
140 }
141
142 return false;
143 }
144
145
147 Locked = std::nullopt;
148 FD = -1;
149 }
150};
151
152struct FileSizeInfo {
153 uint64_t Size;
154 uint64_t AllocatedSize;
155
157};
158}
159
163 uint64_t MinCapacity = HeaderOffset + sizeof(Header);
164 if (Capacity < MinCapacity)
166 std::make_error_code(std::errc::invalid_argument),
167 "capacity is too small to hold MappedFileRegionArena");
168
170 Result.Path = Path.str();
171
172
174 SharedFilePath.append(".shared");
175
176 auto SharedFileLock = FileWithLock::open(SharedFilePath);
177 if (!SharedFileLock)
178 return SharedFileLock.takeError();
179 Result.SharedLockFD = SharedFileLock->FD;
180
181
182
184 return std::move(E);
185
186
187 auto MainFile = FileWithLock::open(Result.Path);
188 if (!MainFile)
189 return MainFile.takeError();
191 return std::move(E);
192 Result.FD = MainFile->FD;
193
195 auto FileSize = FileSizeInfo::get(File);
196 if (!FileSize)
197 return createFileError(Result.Path, FileSize.getError());
198
199
200
201 if (FileSize->Size < Capacity) {
202
204 return std::move(E);
205
206 FileSize = FileSizeInfo::get(File);
207 if (!FileSize)
208 return createFileError(Result.Path, FileSize.getError());
209 }
210
211 if (FileSize->Size >= MinCapacity) {
212
213
217 return Size.takeError();
218
220 memcpy(&H, HeaderContent.data(), sizeof(H));
221 if (H.HeaderOffset != HeaderOffset)
223 std::make_error_code(std::errc::invalid_argument),
224 "specified header offset (" + utostr(HeaderOffset) +
225 ") does not match existing config (" + utostr(H.HeaderOffset) +
226 ")");
227
228
229 if (H.Capacity != Capacity)
230 Capacity = H.Capacity;
231 }
232
233
234 if (FileSize->Size < Capacity) {
236 if (std::error_code EC =
239 }
240
241
242 {
243 std::error_code EC;
246 if (EC)
248 Result.Region = std::move(Map);
249 }
250
251
252 Result.initializeHeader(HeaderOffset);
253 if (FileSize->Size < MinCapacity) {
255
256 if (Error E = NewFileConstructor(Result))
257 return std::move(E);
258
259 Result.H->HeaderOffset.exchange(HeaderOffset);
260 Result.H->Capacity.exchange(Capacity);
261 }
262
264
265
266
267
268 FileSize = FileSizeInfo::get(File);
269 if (!FileSize)
270 return createFileError(Result.Path, FileSize.getError());
271 Result.H->AllocatedSize.exchange(FileSize->AllocatedSize);
272 }
273
274
275 SharedFileLock->release();
276 return std::move(Result);
277}
278
279void MappedFileRegionArena::destroyImpl() {
280 if (!FD)
281 return;
282
283
284 if (SharedLockFD)
286
287
288
289 if (H) {
290 assert(SharedLockFD && "Must have shared lock file open");
293
295
296
300 }
301 }
302
303 auto Close = [](std::optional &FD) {
304 if (FD) {
307 FD = std::nullopt;
308 }
309 };
310
311
312 Close(FD);
313 Close(SharedLockFD);
314}
315
316void MappedFileRegionArena::initializeHeader(uint64_t HeaderOffset) {
318 uint64_t HeaderEndOffset = HeaderOffset + sizeof(decltype(*H));
320 "Expected end offset to be pre-allocated");
322 "Expected end offset to be aligned");
323 H = reinterpret_cast<decltype(H)>(data() + HeaderOffset);
324
325 uint64_t ExistingValue = 0;
326 if (!H->BumpPtr.compare_exchange_strong(ExistingValue, HeaderEndOffset))
327 assert(ExistingValue >= HeaderEndOffset &&
328 "Expected 0, or past the end of the header itself");
329}
330
332 return createStringError(std::make_error_code(std::errc::not_enough_memory),
333 "memory mapped file allocator is out of space");
334}
335
338 uint64_t OldEnd = H->BumpPtr.fetch_add(AllocSize);
339 uint64_t NewEnd = OldEnd + AllocSize;
341
342
343
344
345
346
348 (void)H->BumpPtr.exchange(OldEnd);
349
351 }
352
353 uint64_t DiskSize = H->AllocatedSize;
356
359 .moveInto(NewSize))
360 return std::move(E);
362
363
364
365
366
367 while (DiskSize < NewSize)
368 H->AllocatedSize.compare_exchange_strong(DiskSize, NewSize);
369 }
370 return OldEnd;
371}
372
374#if LLVM_ON_UNIX && defined(MAPPED_FILE_BSIZE)
376 int StatRet = ::fstat(File, &Status);
377 if (StatRet)
380 return FileSizeInfo{uint64_t(Status.st_size), AllocatedSize};
381#else
382
383
386 return EC;
387 return FileSizeInfo{Status.getSize(), Status.getSize()};
388#endif
389}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_UNLIKELY(EXPR)
static Error createAllocatorOutOfSpaceError()
Definition MappedFileRegionArena.cpp:331
This file declares interface for MappedFileRegionArena, a bump pointer allocator, backed by a memory-...
Represents either an error or a value T.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void append(StringRef RHS)
Append from a StringRef.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
MappedFileRegionArena()=default
uint64_t capacity() const
LLVM_ABI_FOR_TEST Expected< int64_t > allocateOffset(uint64_t AllocSize)
Allocate, returning the offset from data() instead of a pointer.
Definition MappedFileRegionArena.cpp:336
static LLVM_ABI_FOR_TEST Expected< MappedFileRegionArena > create(const Twine &Path, uint64_t Capacity, uint64_t HeaderOffset, function_ref< Error(MappedFileRegionArena &)> NewFileConstructor)
Create a MappedFileRegionArena.
Definition MappedFileRegionArena.cpp:160
static constexpr Align getAlign()
Minimum alignment for allocations, currently hardcoded to 8B.
An efficient, type-erasing, non-owning reference to a callable.
Represents the result of a call to sys::fs::status().
This class represents a memory mapped file.
@ readwrite
May access map via data and modify it. Written to path.
std::error_code lockFileThreadSafe(int FD, llvm::sys::fs::LockKind Kind)
Thread-safe alternative to sys::fs::lockFile.
std::error_code unlockFileThreadSafe(int FD)
Thread-safe alternative to sys::fs::unlockFile.
std::error_code tryLockFileThreadSafe(int FD, std::chrono::milliseconds Timeout=std::chrono::milliseconds(0), llvm::sys::fs::LockKind Kind=llvm::sys::fs::LockKind::Exclusive)
Thread-safe alternative to sys::fs::tryLockFile.
Expected< size_t > preallocateFileTail(int FD, size_t CurrentSize, size_t NewSize)
Allocate space for the file FD on disk, if the filesystem supports it.
LLVM_ABI std::error_code closeFile(file_t &F)
Close the file object.
std::error_code openFileForReadWrite(const Twine &Name, int &ResultFD, CreationDisposition Disp, OpenFlags Flags, unsigned Mode=0666)
Opens the file with the given name in a write-only or read-write mode, returning its open file descri...
@ CD_OpenAlways
CD_OpenAlways - When opening a file:
LLVM_ABI Expected< size_t > readNativeFileSlice(file_t FileHandle, MutableArrayRef< char > Buf, uint64_t Offset)
Reads Buf.size() bytes from FileHandle at offset Offset into Buf.
LLVM_ABI std::error_code resize_file_sparse(int FD, uint64_t Size)
Resize path to size with sparse files explicitly enabled.
LockKind
An enumeration for the lock kind.
LLVM_ABI std::error_code resize_file(int FD, uint64_t Size)
Resize path to size.
LLVM_ABI file_t convertFDToNativeFile(int FD)
Converts from a Posix file descriptor number to a native file handle.
LLVM_ABI std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
This is an optimization pass for GlobalISel generic memory operations.
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
bool isAligned(Align Lhs, uint64_t SizeInBytes)
Checks that SizeInBytes is a multiple of the alignment.
std::string utostr(uint64_t X, bool isNeg=false)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
@ Increment
Incrementally increasing token ID.
std::error_code errnoAsErrorCode()
Helper to get errno as an std::error_code.
void consumeError(Error Err)
Consume a Error without doing anything.
static constexpr Align Of()
Allow constructions of constexpr Align from types.