summaryrefslogtreecommitdiff
path: root/lib/LTO/Caching.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/LTO/Caching.cpp')
-rw-r--r--lib/LTO/Caching.cpp80
1 files changed, 53 insertions, 27 deletions
diff --git a/lib/LTO/Caching.cpp b/lib/LTO/Caching.cpp
index e32e46c4c3c8..dd47eb584b7f 100644
--- a/lib/LTO/Caching.cpp
+++ b/lib/LTO/Caching.cpp
@@ -14,9 +14,9 @@
#include "llvm/LTO/Caching.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Errc.h"
-#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -36,7 +36,7 @@ Expected<NativeObjectCache> lto::localCache(StringRef CacheDirectoryPath,
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
MemoryBuffer::getFile(EntryPath);
if (MBOrErr) {
- AddBuffer(Task, std::move(*MBOrErr));
+ AddBuffer(Task, std::move(*MBOrErr), EntryPath);
return AddStreamFn();
}
@@ -48,54 +48,80 @@ Expected<NativeObjectCache> lto::localCache(StringRef CacheDirectoryPath,
// file to the cache and calling AddBuffer to add it to the link.
struct CacheStream : NativeObjectStream {
AddBufferFn AddBuffer;
- std::string TempFilename;
+ sys::fs::TempFile TempFile;
std::string EntryPath;
unsigned Task;
CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddBufferFn AddBuffer,
- std::string TempFilename, std::string EntryPath,
+ sys::fs::TempFile TempFile, std::string EntryPath,
unsigned Task)
: NativeObjectStream(std::move(OS)), AddBuffer(std::move(AddBuffer)),
- TempFilename(std::move(TempFilename)),
- EntryPath(std::move(EntryPath)), Task(Task) {}
+ TempFile(std::move(TempFile)), EntryPath(std::move(EntryPath)),
+ Task(Task) {}
~CacheStream() {
- // FIXME: This code could race with the cache pruner, but it is unlikely
- // that the cache pruner will choose to remove a newly created file.
-
- // Make sure the file is closed before committing it.
+ // Make sure the stream is closed before committing it.
OS.reset();
- // This is atomic on POSIX systems.
- if (auto EC = sys::fs::rename(TempFilename, EntryPath))
- report_fatal_error(Twine("Failed to rename temporary file ") +
- TempFilename + ": " + EC.message() + "\n");
+ // Open the file first to avoid racing with a cache pruner.
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
- MemoryBuffer::getFile(EntryPath);
+ MemoryBuffer::getOpenFile(TempFile.FD, TempFile.TmpName,
+ /*FileSize*/ -1,
+ /*RequiresNullTerminator*/ false);
if (!MBOrErr)
- report_fatal_error(Twine("Failed to open cache file ") + EntryPath +
- ": " + MBOrErr.getError().message() + "\n");
- AddBuffer(Task, std::move(*MBOrErr));
+ report_fatal_error(Twine("Failed to open new cache file ") +
+ TempFile.TmpName + ": " +
+ MBOrErr.getError().message() + "\n");
+
+ // On POSIX systems, this will atomically replace the destination if
+ // it already exists. We try to emulate this on Windows, but this may
+ // fail with a permission denied error (for example, if the destination
+ // is currently opened by another process that does not give us the
+ // sharing permissions we need). Since the existing file should be
+ // semantically equivalent to the one we are trying to write, we give
+ // AddBuffer a copy of the bytes we wrote in that case. We do this
+ // instead of just using the existing file, because the pruner might
+ // delete the file before we get a chance to use it.
+ Error E = TempFile.keep(EntryPath);
+ E = handleErrors(std::move(E), [&](const ECError &E) -> Error {
+ std::error_code EC = E.convertToErrorCode();
+ if (EC != errc::permission_denied)
+ return errorCodeToError(EC);
+
+ auto MBCopy = MemoryBuffer::getMemBufferCopy((*MBOrErr)->getBuffer(),
+ EntryPath);
+ MBOrErr = std::move(MBCopy);
+
+ // FIXME: should we consume the discard error?
+ consumeError(TempFile.discard());
+
+ return Error::success();
+ });
+
+ if (E)
+ report_fatal_error(Twine("Failed to rename temporary file ") +
+ TempFile.TmpName + " to " + EntryPath + ": " +
+ toString(std::move(E)) + "\n");
+
+ AddBuffer(Task, std::move(*MBOrErr), EntryPath);
}
};
return [=](size_t Task) -> std::unique_ptr<NativeObjectStream> {
// Write to a temporary to avoid race condition
- int TempFD;
- SmallString<64> TempFilenameModel, TempFilename;
+ SmallString<64> TempFilenameModel;
sys::path::append(TempFilenameModel, CacheDirectoryPath, "Thin-%%%%%%.tmp.o");
- std::error_code EC =
- sys::fs::createUniqueFile(TempFilenameModel, TempFD, TempFilename,
- sys::fs::owner_read | sys::fs::owner_write);
- if (EC) {
- errs() << "Error: " << EC.message() << "\n";
+ Expected<sys::fs::TempFile> Temp = sys::fs::TempFile::create(
+ TempFilenameModel, sys::fs::owner_read | sys::fs::owner_write);
+ if (!Temp) {
+ errs() << "Error: " << toString(Temp.takeError()) << "\n";
report_fatal_error("ThinLTO: Can't get a temporary file");
}
// This CacheStream will move the temporary file into the cache when done.
return llvm::make_unique<CacheStream>(
- llvm::make_unique<raw_fd_ostream>(TempFD, /* ShouldClose */ true),
- AddBuffer, TempFilename.str(), EntryPath.str(), Task);
+ llvm::make_unique<raw_fd_ostream>(Temp->FD, /* ShouldClose */ false),
+ AddBuffer, std::move(*Temp), EntryPath.str(), Task);
};
};
}