195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor//===--- LockFileManager.cpp - File-level Locking Utility------------------===// 295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor// 395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor// The LLVM Compiler Infrastructure 495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor// 595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor// This file is distributed under the University of Illinois Open Source 695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor// License. See LICENSE.TXT for details. 795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor// 895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor//===----------------------------------------------------------------------===// 995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include "llvm/Support/LockFileManager.h" 1047cfec02842f885b46ea0d3c812793e660691640Reid Kleckner#include "llvm/ADT/StringExtras.h" 11c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines#include "llvm/Support/Errc.h" 1295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include "llvm/Support/FileSystem.h" 1347cfec02842f885b46ea0d3c812793e660691640Reid Kleckner#include "llvm/Support/MemoryBuffer.h" 1495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include "llvm/Support/raw_ostream.h" 15f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#include "llvm/Support/Signals.h" 1695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include <sys/stat.h> 17d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include <sys/types.h> 1895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32 1995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include <windows.h> 2095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif 2195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_UNIX 2295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include <unistd.h> 2395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif 24f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 25f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) 26f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#define USE_OSX_GETHOSTUUID 1 27f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#else 28f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#define USE_OSX_GETHOSTUUID 0 29f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#endif 30f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 31f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#if USE_OSX_GETHOSTUUID 32f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#include <uuid/uuid.h> 33f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#endif 3495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregorusing namespace llvm; 3595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 3695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor/// \brief Attempt to read the lock file with the given name, if it exists. 3795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor/// 3895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor/// \param LockFileName The name of the lock file to read. 3995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor/// 4095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor/// \returns The process ID of the process that owns this lock file 4195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorOptional<std::pair<std::string, int> > 4295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorLockFileManager::readLockFile(StringRef LockFileName) { 4395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // Read the owning host and PID out of the lock file. If it appears that the 4495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // owning process is dead, the lock file is invalid. 45c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = 46c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines MemoryBuffer::getFile(LockFileName); 47c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (!MBOrErr) { 4836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines sys::fs::remove(LockFileName); 4997c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner return None; 5036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 5137ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines MemoryBuffer &MB = *MBOrErr.get(); 5297c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner 5397c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner StringRef Hostname; 5497c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner StringRef PIDStr; 5537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines std::tie(Hostname, PIDStr) = getToken(MB.getBuffer(), " "); 5697c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" ")); 5797c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner int PID; 58dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines if (!PIDStr.getAsInteger(10, PID)) { 59dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines auto Owner = std::make_pair(std::string(Hostname), PID); 60dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines if (processStillExecuting(Owner.first, Owner.second)) 61dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines return Owner; 62dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines } 6395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 6495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // Delete the lock file. It's invalid anyway. 6547cfec02842f885b46ea0d3c812793e660691640Reid Kleckner sys::fs::remove(LockFileName); 665c43245bf459c77077b607e1b55e6928cfbe464eDavid Blaikie return None; 6795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor} 6895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 69f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarstatic std::error_code getHostID(SmallVectorImpl<char> &HostID) { 70f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar HostID.clear(); 71f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 72f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#if USE_OSX_GETHOSTUUID 73f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar // On OS X, use the more stable hardware UUID instead of hostname. 74f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar struct timespec wait = {1, 0}; // 1 second. 75f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar uuid_t uuid; 76f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar if (gethostuuid(uuid, &wait) != 0) 77f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar return std::error_code(errno, std::system_category()); 78f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 79f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar uuid_string_t UUIDStr; 80f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar uuid_unparse(uuid, UUIDStr); 81f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar StringRef UUIDRef(UUIDStr); 82f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar HostID.append(UUIDRef.begin(), UUIDRef.end()); 83f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 84f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#elif LLVM_ON_UNIX 85f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar char HostName[256]; 86f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar HostName[255] = 0; 87f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar HostName[0] = 0; 88f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar gethostname(HostName, 255); 89f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar StringRef HostNameRef(HostName); 90f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar HostID.append(HostNameRef.begin(), HostNameRef.end()); 91f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 92f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#else 93f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar StringRef Dummy("localhost"); 94f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar HostID.append(Dummy.begin(), Dummy.end()); 95f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#endif 96f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 97f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar return std::error_code(); 98f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar} 99f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 100f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarbool LockFileManager::processStillExecuting(StringRef HostID, int PID) { 10168d92bdcc99e647546f40cfce5cfbeb904be2985Evgeniy Stepanov#if LLVM_ON_UNIX && !defined(__ANDROID__) 102f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar SmallString<256> StoredHostID; 103f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar if (getHostID(StoredHostID)) 104f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar return true; // Conservatively assume it's executing on error. 105f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 10695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // Check whether the process is dead. If so, we're done. 107f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar if (StoredHostID == HostID && getsid(PID) == -1 && errno == ESRCH) 10895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor return false; 10995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif 11095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 11195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor return true; 11295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor} 11395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 114f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarnamespace { 115f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// An RAII helper object ensure that the unique lock file is removed. 116f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// 117f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// Ensures that if there is an error or a signal before we finish acquiring the 118f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// lock, the unique file will be removed. And if we successfully take the lock, 119f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// the signal handler is left in place so that signals while the lock is held 120f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// will remove the unique lock file. The caller should ensure there is a 121f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// matching call to sys::DontRemoveFileOnSignal when the lock is released. 122f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarclass RemoveUniqueLockFileOnSignal { 123f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar StringRef Filename; 124f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar bool RemoveImmediately; 125f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarpublic: 126f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar RemoveUniqueLockFileOnSignal(StringRef Name) 127f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar : Filename(Name), RemoveImmediately(true) { 128f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar sys::RemoveFileOnSignal(Filename, nullptr); 129f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar } 130f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar ~RemoveUniqueLockFileOnSignal() { 131f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar if (!RemoveImmediately) { 132f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar // Leave the signal handler enabled. It will be removed when the lock is 133f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar // released. 134f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar return; 135f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar } 136f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar sys::fs::remove(Filename); 137f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar sys::DontRemoveFileOnSignal(Filename); 138f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar } 139f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar void lockAcquired() { RemoveImmediately = false; } 140f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar}; 141f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar} // end anonymous namespace 142f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 14395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorLockFileManager::LockFileManager(StringRef FileName) 14495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor{ 14569a2d6f55afb2bc42bc19e754bcebee39ecdb8bcDouglas Gregor this->FileName = FileName; 146c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (std::error_code EC = sys::fs::make_absolute(this->FileName)) { 147de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar std::string S("failed to obtain absolute path for "); 148de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar S.append(this->FileName.str()); 149de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar setError(EC, S); 15036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines return; 15136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 15236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines LockFileName = this->FileName; 15395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor LockFileName += ".lock"; 15495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 15595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // If the lock file already exists, don't bother to try to create our own 15695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // lock file; it won't work anyway. Just figure out who owns this lock file. 15795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor if ((Owner = readLockFile(LockFileName))) 15895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor return; 15995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 16095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // Create a lock file that is unique to this instance. 16195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor UniqueLockFileName = LockFileName; 16295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor UniqueLockFileName += "-%%%%%%%%"; 16395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor int UniqueLockFileID; 164c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (std::error_code EC = sys::fs::createUniqueFile( 1654c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) { 166de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar std::string S("failed to create unique file "); 167de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar S.append(UniqueLockFileName.str()); 168de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar setError(EC, S); 16995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor return; 17095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor } 17195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 17295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // Write our process ID to our unique lock file. 17395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor { 174f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar SmallString<256> HostID; 175f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar if (auto EC = getHostID(HostID)) { 176de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar setError(EC, "failed to get host id"); 177f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar return; 178f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar } 17995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 180f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true); 181f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar Out << HostID << ' '; 18295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_UNIX 183f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar Out << getpid(); 18495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else 185f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar Out << "1"; 18695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif 18795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Out.close(); 18895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 18995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor if (Out.has_error()) { 19095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // We failed to write out PID, so make up an excuse, remove the 19195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // unique lock file, and fail. 192de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar auto EC = make_error_code(errc::no_space_on_device); 193de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar std::string S("failed to write to "); 194de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar S.append(UniqueLockFileName.str()); 195de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar setError(EC, S); 1964c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar sys::fs::remove(UniqueLockFileName); 19795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor return; 19895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor } 19995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor } 20095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 201f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar // Clean up the unique file on signal, which also releases the lock if it is 202f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar // held since the .lock symlink will point to a nonexistent file. 203f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar RemoveUniqueLockFileOnSignal RemoveUniqueFile(UniqueLockFileName); 204f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar 20536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines while (1) { 20636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines // Create a link from the lock file name. If this succeeds, we're done. 207c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines std::error_code EC = 2084c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar sys::fs::create_link(UniqueLockFileName, LockFileName); 209f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar if (!EC) { 210f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar RemoveUniqueFile.lockAcquired(); 21136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines return; 212f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar } 21395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 21436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines if (EC != errc::file_exists) { 215de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar std::string S("failed to create link "); 216de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar raw_string_ostream OSS(S); 217de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar OSS << LockFileName.str() << " to " << UniqueLockFileName.str(); 218de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar setError(EC, OSS.str()); 21936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines return; 22036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 22195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 22236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines // Someone else managed to create the lock file first. Read the process ID 22336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines // from the lock file. 22436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines if ((Owner = readLockFile(LockFileName))) { 22536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines // Wipe out our unique lock file (it's useless now) 2264c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar sys::fs::remove(UniqueLockFileName); 22736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines return; 22836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 22995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 2304c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar if (!sys::fs::exists(LockFileName)) { 23136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines // The previous owner released the lock file before we could read it. 23236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines // Try to get ownership again. 23336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines continue; 23436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 23595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 23636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines // There is a lock file that nobody owns; try to clean it up and get 23736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines // ownership. 2384c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar if ((EC = sys::fs::remove(LockFileName))) { 239de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar std::string S("failed to remove lockfile "); 240de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar S.append(UniqueLockFileName.str()); 241de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar setError(EC, S); 24236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines return; 24336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 24436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 24595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor} 24695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 24795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorLockFileManager::LockFileState LockFileManager::getState() const { 24895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor if (Owner) 24995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor return LFS_Shared; 25095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 25195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor if (Error) 25295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor return LFS_Error; 25395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 25495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor return LFS_Owned; 25595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor} 25695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 257de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstd::string LockFileManager::getErrorMessage() const { 258de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar if (Error) { 259de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar std::string Str(ErrorDiagMsg); 260de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar std::string ErrCodeMsg = Error->message(); 261de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar raw_string_ostream OSS(Str); 262de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar if (!ErrCodeMsg.empty()) 263de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar OSS << ": " << Error->message(); 264de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar OSS.flush(); 265de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar return Str; 266de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar } 267de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar return ""; 268de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar} 269de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar 27095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorLockFileManager::~LockFileManager() { 27195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor if (getState() != LFS_Owned) 27295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor return; 27395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 27495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // Since we own the lock, remove the lock file and our own unique lock file. 2754c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar sys::fs::remove(LockFileName); 2764c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar sys::fs::remove(UniqueLockFileName); 277f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar // The unique file is now gone, so remove it from the signal handler. This 278f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar // matches a sys::RemoveFileOnSignal() in LockFileManager(). 279f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar sys::DontRemoveFileOnSignal(UniqueLockFileName); 28095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor} 28195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 282dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen HinesLockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { 28395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor if (getState() != LFS_Shared) 284dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines return Res_Success; 28595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 28695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32 28795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor unsigned long Interval = 1; 28895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else 28995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor struct timespec Interval; 29095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Interval.tv_sec = 0; 29195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Interval.tv_nsec = 1000000; 29295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif 2934c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar // Don't wait more than five minutes per iteration. Total timeout for the file 2944c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar // to appear is ~8.5 mins. 2954c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar const unsigned MaxSeconds = 5*60; 29695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor do { 29795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // Sleep for the designated interval, to allow the owning process time to 29895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // finish up and remove the lock file. 29995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // FIXME: Should we hook in to system APIs to get a notification when the 30095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // lock file is deleted? 30195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32 30295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Sleep(Interval); 30395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else 304dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines nanosleep(&Interval, nullptr); 30595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif 306e76fe51fe1bfe437aba5e619dae58706d35b3a58Douglas Gregor 307ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) == 308ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines errc::no_such_file_or_directory) { 309ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines // If the original file wasn't created, somone thought the lock was dead. 3104c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar if (!sys::fs::exists(FileName)) 311ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines return Res_OwnerDied; 312ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines return Res_Success; 31369a2d6f55afb2bc42bc19e754bcebee39ecdb8bcDouglas Gregor } 314e76fe51fe1bfe437aba5e619dae58706d35b3a58Douglas Gregor 315ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines // If the process owning the lock died without cleaning up, just bail out. 316ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines if (!processStillExecuting((*Owner).first, (*Owner).second)) 317dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines return Res_OwnerDied; 31895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 31995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // Exponentially increase the time we wait for the lock to be removed. 32095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32 32195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Interval *= 2; 32295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else 32395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Interval.tv_sec *= 2; 32495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Interval.tv_nsec *= 2; 32595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor if (Interval.tv_nsec >= 1000000000) { 32695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor ++Interval.tv_sec; 32795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Interval.tv_nsec -= 1000000000; 32895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor } 32995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif 33095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor } while ( 33195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32 33295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Interval < MaxSeconds * 1000 33395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else 33495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor Interval.tv_sec < (time_t)MaxSeconds 33595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif 33695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor ); 33795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor 33895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor // Give up. 339dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines return Res_Timeout; 34095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor} 341ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines 342ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesstd::error_code LockFileManager::unsafeRemoveLockFile() { 3434c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar return sys::fs::remove(LockFileName); 344ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines} 345