mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
Use TempFile in the implementation of LockFileManager.
This move some of the complexity over to the lower level TempFile. It also makes it a bit more explicit where errors are ignored since we now have a call to consumeError. llvm-svn: 318550
This commit is contained in:
parent
74564c24f8
commit
b74fa89001
@ -11,6 +11,7 @@
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include <system_error>
|
||||
#include <utility> // for std::pair
|
||||
|
||||
@ -53,7 +54,7 @@ public:
|
||||
private:
|
||||
SmallString<128> FileName;
|
||||
SmallString<128> LockFileName;
|
||||
SmallString<128> UniqueLockFileName;
|
||||
Optional<sys::fs::TempFile> UniqueLockFile;
|
||||
|
||||
Optional<std::pair<std::string, int> > Owner;
|
||||
std::error_code ErrorCode;
|
||||
|
@ -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<void()> Fn;
|
||||
bool Canceled = false;
|
||||
|
||||
public:
|
||||
RemoveUniqueLockFileOnSignal(StringRef Name)
|
||||
: Filename(Name), RemoveImmediately(true) {
|
||||
sys::RemoveFileOnSignal(Filename, nullptr);
|
||||
}
|
||||
RAIICleanup(std::function<void()> 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<sys::fs::TempFile> 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() {
|
||||
|
Loading…
Reference in New Issue
Block a user