1234285Sdim//===--- LockFileManager.cpp - File-level Locking Utility------------------===// 2234285Sdim// 3234285Sdim// The LLVM Compiler Infrastructure 4234285Sdim// 5234285Sdim// This file is distributed under the University of Illinois Open Source 6234285Sdim// License. See LICENSE.TXT for details. 7234285Sdim// 8234285Sdim//===----------------------------------------------------------------------===// 9234285Sdim#include "llvm/Support/LockFileManager.h" 10263509Sdim#include "llvm/ADT/STLExtras.h" 11263509Sdim#include "llvm/ADT/StringExtras.h" 12234285Sdim#include "llvm/Support/FileSystem.h" 13263509Sdim#include "llvm/Support/MemoryBuffer.h" 14234285Sdim#include "llvm/Support/raw_ostream.h" 15252723Sdim#include <sys/stat.h> 16234285Sdim#include <sys/types.h> 17234285Sdim#if LLVM_ON_WIN32 18234285Sdim#include <windows.h> 19234285Sdim#endif 20234285Sdim#if LLVM_ON_UNIX 21234285Sdim#include <unistd.h> 22234285Sdim#endif 23234285Sdimusing namespace llvm; 24234285Sdim 25234285Sdim/// \brief Attempt to read the lock file with the given name, if it exists. 26234285Sdim/// 27234285Sdim/// \param LockFileName The name of the lock file to read. 28234285Sdim/// 29234285Sdim/// \returns The process ID of the process that owns this lock file 30234285SdimOptional<std::pair<std::string, int> > 31234285SdimLockFileManager::readLockFile(StringRef LockFileName) { 32234285Sdim // Check whether the lock file exists. If not, clearly there's nothing 33234285Sdim // to read, so we just return. 34234285Sdim bool Exists = false; 35234285Sdim if (sys::fs::exists(LockFileName, Exists) || !Exists) 36252723Sdim return None; 37234285Sdim 38234285Sdim // Read the owning host and PID out of the lock file. If it appears that the 39234285Sdim // owning process is dead, the lock file is invalid. 40263509Sdim OwningPtr<MemoryBuffer> MB; 41263509Sdim if (MemoryBuffer::getFile(LockFileName, MB)) 42263509Sdim return None; 43234285Sdim 44263509Sdim StringRef Hostname; 45263509Sdim StringRef PIDStr; 46263509Sdim tie(Hostname, PIDStr) = getToken(MB->getBuffer(), " "); 47263509Sdim PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" ")); 48263509Sdim int PID; 49263509Sdim if (!PIDStr.getAsInteger(10, PID)) 50263509Sdim return std::make_pair(std::string(Hostname), PID); 51263509Sdim 52234285Sdim // Delete the lock file. It's invalid anyway. 53263509Sdim sys::fs::remove(LockFileName); 54252723Sdim return None; 55234285Sdim} 56234285Sdim 57234285Sdimbool LockFileManager::processStillExecuting(StringRef Hostname, int PID) { 58245431Sdim#if LLVM_ON_UNIX && !defined(__ANDROID__) 59234285Sdim char MyHostname[256]; 60234285Sdim MyHostname[255] = 0; 61234285Sdim MyHostname[0] = 0; 62234285Sdim gethostname(MyHostname, 255); 63234285Sdim // Check whether the process is dead. If so, we're done. 64234285Sdim if (MyHostname == Hostname && getsid(PID) == -1 && errno == ESRCH) 65234285Sdim return false; 66234285Sdim#endif 67234285Sdim 68234285Sdim return true; 69234285Sdim} 70234285Sdim 71234285SdimLockFileManager::LockFileManager(StringRef FileName) 72234285Sdim{ 73252723Sdim this->FileName = FileName; 74234285Sdim LockFileName = FileName; 75234285Sdim LockFileName += ".lock"; 76234285Sdim 77234285Sdim // If the lock file already exists, don't bother to try to create our own 78234285Sdim // lock file; it won't work anyway. Just figure out who owns this lock file. 79234285Sdim if ((Owner = readLockFile(LockFileName))) 80234285Sdim return; 81234285Sdim 82234285Sdim // Create a lock file that is unique to this instance. 83234285Sdim UniqueLockFileName = LockFileName; 84234285Sdim UniqueLockFileName += "-%%%%%%%%"; 85234285Sdim int UniqueLockFileID; 86234285Sdim if (error_code EC 87263509Sdim = sys::fs::createUniqueFile(UniqueLockFileName.str(), 88263509Sdim UniqueLockFileID, 89263509Sdim UniqueLockFileName)) { 90234285Sdim Error = EC; 91234285Sdim return; 92234285Sdim } 93234285Sdim 94234285Sdim // Write our process ID to our unique lock file. 95234285Sdim { 96234285Sdim raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true); 97234285Sdim 98234285Sdim#if LLVM_ON_UNIX 99234285Sdim // FIXME: move getpid() call into LLVM 100234285Sdim char hostname[256]; 101234285Sdim hostname[255] = 0; 102234285Sdim hostname[0] = 0; 103234285Sdim gethostname(hostname, 255); 104234285Sdim Out << hostname << ' ' << getpid(); 105234285Sdim#else 106234285Sdim Out << "localhost 1"; 107234285Sdim#endif 108234285Sdim Out.close(); 109234285Sdim 110234285Sdim if (Out.has_error()) { 111234285Sdim // We failed to write out PID, so make up an excuse, remove the 112234285Sdim // unique lock file, and fail. 113234285Sdim Error = make_error_code(errc::no_space_on_device); 114234285Sdim bool Existed; 115234285Sdim sys::fs::remove(UniqueLockFileName.c_str(), Existed); 116234285Sdim return; 117234285Sdim } 118234285Sdim } 119234285Sdim 120234285Sdim // Create a hard link from the lock file name. If this succeeds, we're done. 121234285Sdim error_code EC 122234285Sdim = sys::fs::create_hard_link(UniqueLockFileName.str(), 123234285Sdim LockFileName.str()); 124234285Sdim if (EC == errc::success) 125234285Sdim return; 126234285Sdim 127234285Sdim // Creating the hard link failed. 128234285Sdim 129234285Sdim#ifdef LLVM_ON_UNIX 130234285Sdim // The creation of the hard link may appear to fail, but if stat'ing the 131234285Sdim // unique file returns a link count of 2, then we can still declare success. 132234285Sdim struct stat StatBuf; 133234285Sdim if (stat(UniqueLockFileName.c_str(), &StatBuf) == 0 && 134234285Sdim StatBuf.st_nlink == 2) 135234285Sdim return; 136234285Sdim#endif 137234285Sdim 138234285Sdim // Someone else managed to create the lock file first. Wipe out our unique 139234285Sdim // lock file (it's useless now) and read the process ID from the lock file. 140234285Sdim bool Existed; 141234285Sdim sys::fs::remove(UniqueLockFileName.str(), Existed); 142234285Sdim if ((Owner = readLockFile(LockFileName))) 143234285Sdim return; 144234285Sdim 145234285Sdim // There is a lock file that nobody owns; try to clean it up and report 146234285Sdim // an error. 147234285Sdim sys::fs::remove(LockFileName.str(), Existed); 148234285Sdim Error = EC; 149234285Sdim} 150234285Sdim 151234285SdimLockFileManager::LockFileState LockFileManager::getState() const { 152234285Sdim if (Owner) 153234285Sdim return LFS_Shared; 154234285Sdim 155234285Sdim if (Error) 156234285Sdim return LFS_Error; 157234285Sdim 158234285Sdim return LFS_Owned; 159234285Sdim} 160234285Sdim 161234285SdimLockFileManager::~LockFileManager() { 162234285Sdim if (getState() != LFS_Owned) 163234285Sdim return; 164234285Sdim 165234285Sdim // Since we own the lock, remove the lock file and our own unique lock file. 166234285Sdim bool Existed; 167234285Sdim sys::fs::remove(LockFileName.str(), Existed); 168234285Sdim sys::fs::remove(UniqueLockFileName.str(), Existed); 169234285Sdim} 170234285Sdim 171234285Sdimvoid LockFileManager::waitForUnlock() { 172234285Sdim if (getState() != LFS_Shared) 173234285Sdim return; 174234285Sdim 175234285Sdim#if LLVM_ON_WIN32 176234285Sdim unsigned long Interval = 1; 177234285Sdim#else 178234285Sdim struct timespec Interval; 179234285Sdim Interval.tv_sec = 0; 180234285Sdim Interval.tv_nsec = 1000000; 181234285Sdim#endif 182252723Sdim // Don't wait more than five minutes for the file to appear. 183252723Sdim unsigned MaxSeconds = 300; 184252723Sdim bool LockFileGone = false; 185234285Sdim do { 186234285Sdim // Sleep for the designated interval, to allow the owning process time to 187234285Sdim // finish up and remove the lock file. 188234285Sdim // FIXME: Should we hook in to system APIs to get a notification when the 189234285Sdim // lock file is deleted? 190234285Sdim#if LLVM_ON_WIN32 191234285Sdim Sleep(Interval); 192234285Sdim#else 193234285Sdim nanosleep(&Interval, NULL); 194234285Sdim#endif 195234285Sdim bool Exists = false; 196252723Sdim bool LockFileJustDisappeared = false; 197234285Sdim 198252723Sdim // If the lock file is still expected to be there, check whether it still 199252723Sdim // is. 200252723Sdim if (!LockFileGone) { 201252723Sdim if (!sys::fs::exists(LockFileName.str(), Exists) && !Exists) { 202252723Sdim LockFileGone = true; 203252723Sdim LockFileJustDisappeared = true; 204252723Sdim Exists = false; 205252723Sdim } 206252723Sdim } 207252723Sdim 208252723Sdim // If the lock file is no longer there, check if the original file is 209252723Sdim // available now. 210252723Sdim if (LockFileGone) { 211252723Sdim if (!sys::fs::exists(FileName.str(), Exists) && Exists) { 212252723Sdim return; 213252723Sdim } 214252723Sdim 215252723Sdim // The lock file is gone, so now we're waiting for the original file to 216252723Sdim // show up. If this just happened, reset our waiting intervals and keep 217252723Sdim // waiting. 218252723Sdim if (LockFileJustDisappeared) { 219252723Sdim MaxSeconds = 5; 220252723Sdim 221252723Sdim#if LLVM_ON_WIN32 222252723Sdim Interval = 1; 223252723Sdim#else 224252723Sdim Interval.tv_sec = 0; 225252723Sdim Interval.tv_nsec = 1000000; 226252723Sdim#endif 227252723Sdim continue; 228252723Sdim } 229252723Sdim } 230252723Sdim 231252723Sdim // If we're looking for the lock file to disappear, but the process 232252723Sdim // owning the lock died without cleaning up, just bail out. 233252723Sdim if (!LockFileGone && 234252723Sdim !processStillExecuting((*Owner).first, (*Owner).second)) { 235234285Sdim return; 236252723Sdim } 237234285Sdim 238234285Sdim // Exponentially increase the time we wait for the lock to be removed. 239234285Sdim#if LLVM_ON_WIN32 240234285Sdim Interval *= 2; 241234285Sdim#else 242234285Sdim Interval.tv_sec *= 2; 243234285Sdim Interval.tv_nsec *= 2; 244234285Sdim if (Interval.tv_nsec >= 1000000000) { 245234285Sdim ++Interval.tv_sec; 246234285Sdim Interval.tv_nsec -= 1000000000; 247234285Sdim } 248234285Sdim#endif 249234285Sdim } while ( 250234285Sdim#if LLVM_ON_WIN32 251234285Sdim Interval < MaxSeconds * 1000 252234285Sdim#else 253234285Sdim Interval.tv_sec < (time_t)MaxSeconds 254234285Sdim#endif 255234285Sdim ); 256234285Sdim 257234285Sdim // Give up. 258234285Sdim} 259