diff --git a/include/llvm/Support/LockFileManager.h b/include/llvm/Support/LockFileManager.h index 3d1446ddb4b..1e417bdd5b2 100644 --- a/include/llvm/Support/LockFileManager.h +++ b/include/llvm/Support/LockFileManager.h @@ -11,6 +11,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" #include #include // for std::pair @@ -53,7 +54,7 @@ public: private: SmallString<128> FileName; SmallString<128> LockFileName; - SmallString<128> UniqueLockFileName; + Optional UniqueLockFile; Optional > Owner; std::error_code ErrorCode; diff --git a/lib/Support/LockFileManager.cpp b/lib/Support/LockFileManager.cpp index 3b5a8b5afb4..ec951f33a36 100644 --- a/lib/Support/LockFileManager.cpp +++ b/lib/Support/LockFileManager.cpp @@ -123,33 +123,21 @@ bool LockFileManager::processStillExecuting(StringRef HostID, int PID) { namespace { -/// An RAII helper object ensure that the unique lock file is removed. -/// -/// Ensures that if there is an error or a signal before we finish acquiring the -/// lock, the unique file will be removed. And if we successfully take the lock, -/// the signal handler is left in place so that signals while the lock is held -/// will remove the unique lock file. The caller should ensure there is a -/// matching call to sys::DontRemoveFileOnSignal when the lock is released. -class RemoveUniqueLockFileOnSignal { - StringRef Filename; - bool RemoveImmediately; +/// An RAII helper object for cleanups. +class RAIICleanup { + std::function Fn; + bool Canceled = false; + public: - RemoveUniqueLockFileOnSignal(StringRef Name) - : Filename(Name), RemoveImmediately(true) { - sys::RemoveFileOnSignal(Filename, nullptr); - } + RAIICleanup(std::function Fn) : Fn(Fn) {} - ~RemoveUniqueLockFileOnSignal() { - if (!RemoveImmediately) { - // Leave the signal handler enabled. It will be removed when the lock is - // released. + ~RAIICleanup() { + if (Canceled) return; - } - sys::fs::remove(Filename); - sys::DontRemoveFileOnSignal(Filename); + Fn(); } - void lockAcquired() { RemoveImmediately = false; } + void cancel() { Canceled = true; } }; } // end anonymous namespace @@ -172,16 +160,22 @@ LockFileManager::LockFileManager(StringRef FileName) return; // Create a lock file that is unique to this instance. - UniqueLockFileName = LockFileName; - UniqueLockFileName += "-%%%%%%%%"; - int UniqueLockFileID; - if (std::error_code EC = sys::fs::createUniqueFile( - UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) { - std::string S("failed to create unique file "); - S.append(UniqueLockFileName.str()); + Expected Temp = + sys::fs::TempFile::create(LockFileName + "-%%%%%%%%"); + if (!Temp) { + std::error_code EC = errorToErrorCode(Temp.takeError()); + std::string S("failed to create unique file with prefix "); + S.append(LockFileName.str()); setError(EC, S); return; } + UniqueLockFile = std::move(*Temp); + + // Make sure we discard the temporary file on exit. + RAIICleanup RemoveTempFile([&]() { + if (Error E = UniqueLockFile->discard()) + setError(errorToErrorCode(std::move(E))); + }); // Write our process ID to our unique lock file. { @@ -191,54 +185,46 @@ LockFileManager::LockFileManager(StringRef FileName) return; } - raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true); + raw_fd_ostream Out(UniqueLockFile->FD, /*shouldClose=*/false); Out << HostID << ' '; #if LLVM_ON_UNIX Out << getpid(); #else Out << "1"; #endif - Out.close(); + Out.flush(); if (Out.has_error()) { // We failed to write out PID, so report the error, remove the // unique lock file, and fail. std::string S("failed to write to "); - S.append(UniqueLockFileName.str()); + S.append(UniqueLockFile->TmpName); setError(Out.error(), S); - sys::fs::remove(UniqueLockFileName); return; } } - // Clean up the unique file on signal, which also releases the lock if it is - // held since the .lock symlink will point to a nonexistent file. - RemoveUniqueLockFileOnSignal RemoveUniqueFile(UniqueLockFileName); - while (true) { // Create a link from the lock file name. If this succeeds, we're done. std::error_code EC = - sys::fs::create_link(UniqueLockFileName, LockFileName); + sys::fs::create_link(UniqueLockFile->TmpName, LockFileName); if (!EC) { - RemoveUniqueFile.lockAcquired(); + RemoveTempFile.cancel(); return; } if (EC != errc::file_exists) { std::string S("failed to create link "); raw_string_ostream OSS(S); - OSS << LockFileName.str() << " to " << UniqueLockFileName.str(); + OSS << LockFileName.str() << " to " << UniqueLockFile->TmpName; setError(EC, OSS.str()); return; } // Someone else managed to create the lock file first. Read the process ID // from the lock file. - if ((Owner = readLockFile(LockFileName))) { - // Wipe out our unique lock file (it's useless now) - sys::fs::remove(UniqueLockFileName); - return; - } + if ((Owner = readLockFile(LockFileName))) + return; // RemoveTempFile will delete out our unique lock file. if (!sys::fs::exists(LockFileName)) { // The previous owner released the lock file before we could read it. @@ -250,7 +236,7 @@ LockFileManager::LockFileManager(StringRef FileName) // ownership. if ((EC = sys::fs::remove(LockFileName))) { std::string S("failed to remove lockfile "); - S.append(UniqueLockFileName.str()); + S.append(LockFileName.str()); setError(EC, S); return; } @@ -285,10 +271,7 @@ LockFileManager::~LockFileManager() { // Since we own the lock, remove the lock file and our own unique lock file. sys::fs::remove(LockFileName); - sys::fs::remove(UniqueLockFileName); - // The unique file is now gone, so remove it from the signal handler. This - // matches a sys::RemoveFileOnSignal() in LockFileManager(). - sys::DontRemoveFileOnSignal(UniqueLockFileName); + consumeError(UniqueLockFile->discard()); } LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {