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.