LLVM: lib/Support/VirtualOutputBackends.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

29

30using namespace llvm;

32

33void ProxyOutputBackend::anchor() {}

34void OnDiskOutputBackend::anchor() {}

35

39 return const_cast<NullOutputBackend *>(this);

40 }

42 createFileImpl(StringRef Path, std::optional) override {

43 return std::make_unique();

44 }

45 };

46

48}

49

52 std::function<bool(StringRef, std::optional)> Filter) {

56 std::optional Config) override {

57 if (Filter(Path, Config))

59 return std::make_unique();

60 }

61

64 getUnderlyingBackend().clone(), Filter);

65 }

66

67 FilteringOutputBackend(

69 std::function<bool(StringRef, std::optional)> Filter)

72 assert(this->Filter && "Expected a non-null function");

73 }

75 };

76

78 std::move(UnderlyingBackend), std::move(Filter));

79}

80

86 };

89 };

91 Error keep() final {

92 flush();

93 return joinErrors(F1->keep(), F2->keep());

94 }

95 Error discard() final {

96 flush();

97 return joinErrors(F1->discard(), F2->discard());

98 }

100

101 void write_impl(const char *Ptr, size_t Size) override {

104 }

105 void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override {

106 this->flush();

107 F1->getOS().pwrite(Ptr, Size, Offset);

108 F2->getOS().pwrite(Ptr, Size, Offset);

109 }

110 uint64_t current_pos() const override { return F1->getOS().tell(); }

111 size_t preferred_buffer_size() const override {

112 return PreferredBufferSize;

113 }

114 void reserveExtraSpace(uint64_t ExtraSize) override {

115 F1->getOS().reserveExtraSpace(ExtraSize);

116 F2->getOS().reserveExtraSpace(ExtraSize);

117 }

118 bool is_displayed() const override {

119 return F1->getOS().is_displayed() && F2->getOS().is_displayed();

120 }

121 bool has_colors() const override {

122 return F1->getOS().has_colors() && F2->getOS().has_colors();

123 }

124 void enable_colors(bool enable) override {

126 F1->getOS().enable_colors(enable);

127 F2->getOS().enable_colors(enable);

128 }

129

130 MirroringOutput(std::unique_ptr F1,

131 std::unique_ptr F2)

132 : PreferredBufferSize(std::max(F1->getOS().GetBufferSize(),

133 F1->getOS().GetBufferSize())),

134 F1(std::move(F1)), F2(std::move(F2)) {

135

136 this->F1->getOS().SetUnbuffered();

137 this->F2->getOS().SetUnbuffered();

138 }

139 size_t PreferredBufferSize;

140 std::unique_ptr F1;

141 std::unique_ptr F2;

142 };

143 struct MirroringOutputBackend : public ProxyOutputBackend1,

144 public ProxyOutputBackend2 {

147 std::optional Config) override {

148 std::unique_ptr File1;

149 std::unique_ptr File2;

151 ProxyOutputBackend1::createFileImpl(Path, Config).moveInto(File1))

152 return std::move(E);

154 ProxyOutputBackend2::createFileImpl(Path, Config).moveInto(File2))

155 return joinErrors(std::move(E), File1->discard());

156

157

160 return std::move(File2);

161 }

164 return std::move(File1);

165 }

166 return std::make_unique(std::move(File1),

167 std::move(File2));

168 }

169

173 ProxyOutputBackend1::getUnderlyingBackend().clone(),

174 ProxyOutputBackend2::getUnderlyingBackend().clone()));

175 }

176 void Retain() const { ProxyOutputBackend1::Retain(); }

177 void Release() const { ProxyOutputBackend1::Release(); }

178

181 : ProxyOutputBackend1(std::move(Backend1)),

182 ProxyOutputBackend2(std::move(Backend2)) {}

183 };

184

185 assert(Backend1 && "Expected actual backend");

186 assert(Backend2 && "Expected actual backend");

189 std::move(Backend2)));

190}

191

195 if (!Config)

198 Config->setNoAtomicWrite();

200 Config->setNoDiscardOnSignal();

201 return *Config;

202}

203

204namespace {

205class OnDiskOutputFile final : public OutputFileImpl {

206public:

207 Error keep() override;

208 Error discard() override;

209 raw_pwrite_stream &getOS() override {

210 assert(FileOS && "Expected valid file");

211 if (BufferOS)

212 return *BufferOS;

213 return *FileOS;

214 }

215

216

217

218

219

220

221

222

223

224 Error tryToCreateTemporary(std::optional &FD);

225

226 Error initializeFile(std::optional &FD);

227 Error initializeStream();

229

230 OnDiskOutputFile(StringRef OutputPath, std::optional Config,

231 const OnDiskOutputBackend::OutputSettings &Settings)

233 OutputPath(OutputPath.str()) {}

234

235 OutputConfig Config;

236 const std::string OutputPath;

237 std::optionalstd::string TempPath;

238 std::optional<raw_fd_ostream> FileOS;

239 std::optional<buffer_ostream> BufferOS;

240};

241}

242

246 return handleErrors(CreateFile(), [&](std::unique_ptr EC) {

247 if (EC->convertToErrorCode() != std::errc::no_such_file_or_directory ||

248 Config.getNoImplyCreateDirectories())

249 return Error(std::move(EC));

250

254 return CreateFile();

255 });

256}

257

262 else if (Config.getText())

264

265

266 if (Config.getAppend() && !Config.getAtomicWrite())

268

269 return OF;

270}

271

272Error OnDiskOutputFile::tryToCreateTemporary(std::optional &FD) {

274

275

276

277

278

280 SmallString<128> ModelPath =

281 StringRef(OutputPath).drop_back(OutputExtension.size());

282 ModelPath += "-%%%%%%%%";

283 ModelPath += OutputExtension;

284 ModelPath += ".tmp";

285

287 int NewFD;

288 SmallString<128> UniquePath;

290 if (std::error_code EC =

293

294 if (Config.getDiscardOnSignal())

296

297 TempPath = UniquePath.str().str();

298 FD.emplace(NewFD);

300 });

301}

302

303Error OnDiskOutputFile::initializeFile(std::optional &FD) {

305

306 assert(OutputPath != "-" && "Unexpected request for FD of stdout");

307

308

309

310

311 if (Config.getAtomicWrite()) {

312 sys::fs::file_status Status;

316 Config.setNoAtomicWrite();

317

318

321 OutputPath,

322 std::make_error_code(std::errc::operation_not_permitted));

323 }

324 }

325

326

327

328 if (Config.getAtomicWrite())

329 if (errorToBool(tryToCreateTemporary(FD)))

331

332

334 int NewFD;

339 FD.emplace(NewFD);

340

341 if (Config.getDiscardOnSignal())

344 });

345}

346

347Error OnDiskOutputFile::initializeStream() {

349

350

351 if (OutputPath == "-") {

352 std::error_code EC;

353 FileOS.emplace(OutputPath, EC);

354 if (EC)

356 } else {

357 std::optional FD;

358 if (Error E = initializeFile(FD))

359 return E;

360 FileOS.emplace(*FD, true);

361 }

362

363

364 if (!FileOS->supportsSeeking() && !Config.getText())

365 BufferOS.emplace(*FileOS);

366

368}

369

370namespace {

371class OpenFileRAII {

372 static const int InvalidFd = -1;

373

374public:

375 int Fd = InvalidFd;

376

377 ~OpenFileRAII() {

378 if (Fd != InvalidFd)

380 }

381};

382

383enum class FileDifference : uint8_t {

384

385 IdenticalFile,

386

387

388 SameContents,

389

390

391 DifferentContents

392};

393}

394

395static Expected

398 return FileDifference::IdenticalFile;

399

400 OpenFileRAII SourceFile;

402

405

406

407 if (std::error_code EC = sys::fs::status(SourceFile.Fd, SourceStatus))

409

410 OpenFileRAII DestFile;

412

413 if (std::error_code Error =

415 return FileDifference::DifferentContents;

416

417

419 return FileDifference::DifferentContents;

420

421

424 return FileDifference::DifferentContents;

425

426

427 if (Size == 0)

428 return FileDifference::SameContents;

429

430

431

432 std::error_code SourceRegionErr;

436 if (SourceRegionErr)

438

439 std::error_code DestRegionErr;

443

444 if (DestRegionErr)

445 return FileDifference::DifferentContents;

446

448 return FileDifference::DifferentContents;

449

450 return FileDifference::SameContents;

451}

452

453Error OnDiskOutputFile::reset() {

455

456

457 BufferOS.reset();

458 if (!FileOS)

460

461

462 std::error_code EC = FileOS->error();

463

464 FileOS->clear_error();

465 FileOS.reset();

467}

468

469Error OnDiskOutputFile::keep() {

471

472 if (auto E = reset())

473 return E;

474

475

477 if (Config.getDiscardOnSignal())

479 });

480

481 if (!TempPath)

483

484

485 if (Config.getAppend() && OutputPath != "-") {

486

488 if (!Content)

490 Content.getError());

491 while (1) {

492

493

494 llvm::LockFileManager Lock(OutputPath);

495 bool Owned;

496 if (Error Err = Lock.tryLock().moveInto(Owned)) {

497

498

499 Lock.unsafeMaybeUnlock();

501 OutputPath, std::make_error_code(std::errc::no_lock_available));

502 }

503 if (Owned) {

504

505 std::error_code EC;

507 if (EC)

509 Out << (*Content)->getBuffer();

510 Out.close();

511 Lock.unsafeMaybeUnlock();

512 if (Out.has_error())

514

517 }

518

519 switch (Lock.waitForUnlockFor(std::chrono::seconds(256))) {

521 [[fallthrough]];

523 continue;

524 }

526

527

528

529

530

531 Lock.unsafeMaybeUnlock();

532 continue;

533 }

534 }

535 break;

536 }

537 }

538

539 if (Config.getOnlyIfDifferent()) {

541 if (!Result)

542 return Result.takeError();

543 switch (*Result) {

544 case FileDifference::IdenticalFile:

545

547

548 case FileDifference::SameContents:

549

552

553 case FileDifference::DifferentContents:

554 break;

555 }

556 }

557

558

559 std::error_code RenameEC = sys::fs::rename(*TempPath, OutputPath);

560 if (!RenameEC)

562

563

564

565

568

569 if (!RenameEC)

571

573}

574

575Error OnDiskOutputFile::discard() {

577

578

579 if (auto E = reset())

580 return E;

581

582

583 if (OutputPath == "-")

585

586 auto discardPath = [&](StringRef Path) {

589 return EC;

590 };

591

592

593 if (!TempPath)

596 discardPath(*TempPath));

597}

598

605

608 std::optional Config) {

610

612 if (Path != "-") {

613 AbsPath = Path;

615 return std::move(E);

616 Path = AbsPath;

617 }

618

619 auto File = std::make_unique(Path, Config, Settings);

620 if (Error E = File->initializeStream())

621 return std::move(E);

622

623 return std::move(File);

624}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

Merge contiguous icmps into a memcmp

Provides a library for accessing information about this process and other processes on the operating ...

This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...

static Error createDirectoriesOnDemand(StringRef OutputPath, OutputConfig Config, llvm::function_ref< Error()> CreateFile)

Definition VirtualOutputBackends.cpp:243

static Expected< FileDifference > areFilesDifferent(const llvm::Twine &Source, const llvm::Twine &Destination)

Definition VirtualOutputBackends.cpp:396

static sys::fs::OpenFlags generateFlagsFromConfig(OutputConfig Config)

Definition VirtualOutputBackends.cpp:258

static OutputConfig applySettings(std::optional< OutputConfig > &&Config, const OnDiskOutputBackend::OutputSettings &Settings)

Definition VirtualOutputBackends.cpp:193

This file contains the declarations of the concrete VirtualOutputBackend classes, which are the imple...

This file contains the declarations of the OutputConfig class.

This file contains the declarations of the OutputError class.

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.

A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...

static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)

Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...

SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...

StringRef str() const

Explicit conversion to StringRef.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

StringRef - Represent a constant reference to a string, i.e.

std::string str() const

str - Get the contents as an std::string.

constexpr size_t size() const

size - Get the string size.

Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...

An efficient, type-erasing, non-owning reference to a callable.

raw_ostream & write(unsigned char C)

virtual void enable_colors(bool enable)

An abstract base class for streams implementations that also support a pwrite operation.

static LLVM_ABI std::error_code SafelyCloseFileDescriptor(int FD)

Represents the result of a call to sys::fs::status().

This class represents a memory mapped file.

@ readonly

May only access map via const_data as read only.

LLVM_ABI const char * const_data() const

Get a const view of the data.

LLVM_ABI Expected< std::unique_ptr< OutputFileImpl > > createFileImpl(StringRef Path, std::optional< OutputConfig > Config) override

Create a file for Path.

Definition VirtualOutputBackends.cpp:607

OutputSettings Settings

Settings for this backend.

Error makeAbsolute(SmallVectorImpl< char > &Path) const

Resolve an absolute path.

Definition VirtualOutputBackends.cpp:599

Interface for virtualized outputs.

A helper class for proxying another backend, with the default implementation to forward to the underl...

ProxyOutputBackend(IntrusiveRefCntPtr< OutputBackend > UnderlyingBackend)

Expected< std::unique_ptr< OutputFileImpl > > createFileImpl(StringRef Path, std::optional< OutputConfig > Config) override

Create a file for Path.

The result of a status operation.

LLVM_ABI bool is_regular_file(const basic_file_status &status)

Does status represent a regular file?

LLVM_ABI std::error_code rename(const Twine &from, const Twine &to)

Rename from to to.

bool can_write(const Twine &Path)

Can we write this file?

LLVM_ABI bool exists(const basic_file_status &status)

Does file exist?

@ OF_Text

The file should be opened in text mode on platforms like z/OS that make this distinction.

@ OF_TextWithCRLF

The file should be opened in text mode and use a carriage linefeed '\r '.

@ OF_Append

The file should be opened in append mode.

LLVM_ABI std::error_code createUniqueFile(const Twine &Model, int &ResultFD, SmallVectorImpl< char > &ResultPath, OpenFlags Flags=OF_None, unsigned Mode=all_read|all_write)

Create a uniquely named file.

LLVM_ABI std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)

Remove path.

@ CD_CreateAlways

CD_CreateAlways - When opening a file:

std::error_code openFileForWrite(const Twine &Name, int &ResultFD, CreationDisposition Disp=CD_CreateAlways, OpenFlags Flags=OF_None, unsigned Mode=0666)

Opens the file with the given name in a write-only or read-write mode, returning its open file descri...

LLVM_ABI std::error_code create_directories(const Twine &path, bool IgnoreExisting=true, perms Perms=owner_all|group_all)

Create all the non-existent directories in path.

LLVM_ABI std::error_code make_absolute(SmallVectorImpl< char > &path)

Make path an absolute path.

LLVM_ABI std::error_code copy_file(const Twine &From, const Twine &To)

Copy the contents of From to To.

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().

LLVM_ABI std::error_code openFileForRead(const Twine &Name, int &ResultFD, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)

Opens the file with the given name in a read-only mode, returning its open file descriptor.

LLVM_ABI bool equivalent(file_status A, file_status B)

Do file_status's represent the same thing?

LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Get parent path.

LLVM_ABI StringRef extension(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Get extension.

ScopedSetting scopedDisable()

LLVM_ABI void DontRemoveFileOnSignal(StringRef Filename)

This function removes a file from the list of files to be removed on signal delivery.

LLVM_ABI bool RemoveFileOnSignal(StringRef Filename, std::string *ErrMsg=nullptr)

This function registers signal handlers to ensure that if a signal gets delivered that the named file...

Error convertToOutputError(const Twine &OutputPath, std::error_code EC)

Return Error::success() or use OutputPath to create an OutputError, depending on EC.

LLVM_ABI IntrusiveRefCntPtr< OutputBackend > makeNullOutputBackend()

Create a backend that ignores all output.

Definition VirtualOutputBackends.cpp:36

LLVM_ABI IntrusiveRefCntPtr< OutputBackend > makeFilteringOutputBackend(IntrusiveRefCntPtr< OutputBackend > UnderlyingBackend, std::function< bool(StringRef, std::optional< OutputConfig >)> Filter)

Make a backend where OutputBackend::createFile() forwards to UnderlyingBackend when Filter is true,...

Definition VirtualOutputBackends.cpp:50

LLVM_ABI IntrusiveRefCntPtr< OutputBackend > makeMirroringOutputBackend(IntrusiveRefCntPtr< OutputBackend > Backend1, IntrusiveRefCntPtr< OutputBackend > Backend2)

Create a backend that forwards OutputBackend::createFile() to both Backend1 and Backend2.

Definition VirtualOutputBackends.cpp:82

Error convertToTempFileOutputError(const Twine &TempPath, const Twine &OutputPath, std::error_code EC)

Return Error::success() or use TempPath and OutputPath to create a TempFileOutputError,...

This is an optimization pass for GlobalISel generic memory operations.

bool errorToBool(Error Err)

Helper for converting an Error to a bool.

detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)

Error handleErrors(Error E, HandlerTs &&... Hs)

Pass the ErrorInfo(s) contained in E to their respective handlers.

IntrusiveRefCntPtr< T > makeIntrusiveRefCnt(Args &&...A)

Factory function for creating intrusive ref counted pointers.

Error joinErrors(Error E1, Error E2)

Concatenate errors.

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

@ Success

The lock was released successfully.

@ OwnerDied

Owner died while holding the lock.

@ Timeout

Reached timeout while waiting for the owner to release the lock.

Error make_error(ArgTs &&... Args)

Make a Error instance representing failure using the given error info type.

OutputIt move(R &&Range, OutputIt Out)

Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.

LLVM_ABI Error errorCodeToError(std::error_code EC)

Helper for converting an std::error_code to a Error.

void consumeError(Error Err)

Consume a Error without doing anything.

OutputConfig DefaultConfig

bool RemoveOnSignal

Register output files to be deleted if a signal is received.

bool UseTemporaries

Use temporary files.

Full configuration for an output for use by the OutputBackend.

constexpr bool getTextWithCRLF() const