LLVM API Documentation

LockFileManager.cpp
Go to the documentation of this file.
00001 //===--- LockFileManager.cpp - File-level Locking Utility------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 #include "llvm/Support/LockFileManager.h"
00010 #include "llvm/ADT/STLExtras.h"
00011 #include "llvm/ADT/StringExtras.h"
00012 #include "llvm/Support/Errc.h"
00013 #include "llvm/Support/FileSystem.h"
00014 #include "llvm/Support/MemoryBuffer.h"
00015 #include "llvm/Support/Path.h"
00016 #include "llvm/Support/raw_ostream.h"
00017 #include <sys/stat.h>
00018 #include <sys/types.h>
00019 #if LLVM_ON_WIN32
00020 #include <windows.h>
00021 #endif
00022 #if LLVM_ON_UNIX
00023 #include <unistd.h>
00024 #endif
00025 using namespace llvm;
00026 
00027 /// \brief Attempt to read the lock file with the given name, if it exists.
00028 ///
00029 /// \param LockFileName The name of the lock file to read.
00030 ///
00031 /// \returns The process ID of the process that owns this lock file
00032 Optional<std::pair<std::string, int> >
00033 LockFileManager::readLockFile(StringRef LockFileName) {
00034   // Read the owning host and PID out of the lock file. If it appears that the
00035   // owning process is dead, the lock file is invalid.
00036   ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
00037       MemoryBuffer::getFile(LockFileName);
00038   if (!MBOrErr) {
00039     sys::fs::remove(LockFileName);
00040     return None;
00041   }
00042   MemoryBuffer &MB = *MBOrErr.get();
00043 
00044   StringRef Hostname;
00045   StringRef PIDStr;
00046   std::tie(Hostname, PIDStr) = getToken(MB.getBuffer(), " ");
00047   PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" "));
00048   int PID;
00049   if (!PIDStr.getAsInteger(10, PID)) {
00050     auto Owner = std::make_pair(std::string(Hostname), PID);
00051     if (processStillExecuting(Owner.first, Owner.second))
00052       return Owner;
00053   }
00054 
00055   // Delete the lock file. It's invalid anyway.
00056   sys::fs::remove(LockFileName);
00057   return None;
00058 }
00059 
00060 bool LockFileManager::processStillExecuting(StringRef Hostname, int PID) {
00061 #if LLVM_ON_UNIX && !defined(__ANDROID__)
00062   char MyHostname[256];
00063   MyHostname[255] = 0;
00064   MyHostname[0] = 0;
00065   gethostname(MyHostname, 255);
00066   // Check whether the process is dead. If so, we're done.
00067   if (MyHostname == Hostname && getsid(PID) == -1 && errno == ESRCH)
00068     return false;
00069 #endif
00070 
00071   return true;
00072 }
00073 
00074 LockFileManager::LockFileManager(StringRef FileName)
00075 {
00076   this->FileName = FileName;
00077   if (std::error_code EC = sys::fs::make_absolute(this->FileName)) {
00078     Error = EC;
00079     return;
00080   }
00081   LockFileName = this->FileName;
00082   LockFileName += ".lock";
00083 
00084   // If the lock file already exists, don't bother to try to create our own
00085   // lock file; it won't work anyway. Just figure out who owns this lock file.
00086   if ((Owner = readLockFile(LockFileName)))
00087     return;
00088 
00089   // Create a lock file that is unique to this instance.
00090   UniqueLockFileName = LockFileName;
00091   UniqueLockFileName += "-%%%%%%%%";
00092   int UniqueLockFileID;
00093   if (std::error_code EC = sys::fs::createUniqueFile(
00094           UniqueLockFileName.str(), UniqueLockFileID, UniqueLockFileName)) {
00095     Error = EC;
00096     return;
00097   }
00098 
00099   // Write our process ID to our unique lock file.
00100   {
00101     raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
00102 
00103 #if LLVM_ON_UNIX
00104     // FIXME: move getpid() call into LLVM
00105     char hostname[256];
00106     hostname[255] = 0;
00107     hostname[0] = 0;
00108     gethostname(hostname, 255);
00109     Out << hostname << ' ' << getpid();
00110 #else
00111     Out << "localhost 1";
00112 #endif
00113     Out.close();
00114 
00115     if (Out.has_error()) {
00116       // We failed to write out PID, so make up an excuse, remove the
00117       // unique lock file, and fail.
00118       Error = make_error_code(errc::no_space_on_device);
00119       sys::fs::remove(UniqueLockFileName.c_str());
00120       return;
00121     }
00122   }
00123 
00124   while (1) {
00125     // Create a link from the lock file name. If this succeeds, we're done.
00126     std::error_code EC =
00127         sys::fs::create_link(UniqueLockFileName.str(), LockFileName.str());
00128     if (!EC)
00129       return;
00130 
00131     if (EC != errc::file_exists) {
00132       Error = EC;
00133       return;
00134     }
00135 
00136     // Someone else managed to create the lock file first. Read the process ID
00137     // from the lock file.
00138     if ((Owner = readLockFile(LockFileName))) {
00139       // Wipe out our unique lock file (it's useless now)
00140       sys::fs::remove(UniqueLockFileName.str());
00141       return;
00142     }
00143 
00144     if (!sys::fs::exists(LockFileName.str())) {
00145       // The previous owner released the lock file before we could read it.
00146       // Try to get ownership again.
00147       continue;
00148     }
00149 
00150     // There is a lock file that nobody owns; try to clean it up and get
00151     // ownership.
00152     if ((EC = sys::fs::remove(LockFileName.str()))) {
00153       Error = EC;
00154       return;
00155     }
00156   }
00157 }
00158 
00159 LockFileManager::LockFileState LockFileManager::getState() const {
00160   if (Owner)
00161     return LFS_Shared;
00162 
00163   if (Error)
00164     return LFS_Error;
00165 
00166   return LFS_Owned;
00167 }
00168 
00169 LockFileManager::~LockFileManager() {
00170   if (getState() != LFS_Owned)
00171     return;
00172 
00173   // Since we own the lock, remove the lock file and our own unique lock file.
00174   sys::fs::remove(LockFileName.str());
00175   sys::fs::remove(UniqueLockFileName.str());
00176 }
00177 
00178 LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
00179   if (getState() != LFS_Shared)
00180     return Res_Success;
00181 
00182 #if LLVM_ON_WIN32
00183   unsigned long Interval = 1;
00184 #else
00185   struct timespec Interval;
00186   Interval.tv_sec = 0;
00187   Interval.tv_nsec = 1000000;
00188 #endif
00189   // Don't wait more than five minutes for the file to appear.
00190   unsigned MaxSeconds = 300;
00191   bool LockFileGone = false;
00192   do {
00193     // Sleep for the designated interval, to allow the owning process time to
00194     // finish up and remove the lock file.
00195     // FIXME: Should we hook in to system APIs to get a notification when the
00196     // lock file is deleted?
00197 #if LLVM_ON_WIN32
00198     Sleep(Interval);
00199 #else
00200     nanosleep(&Interval, nullptr);
00201 #endif
00202     bool LockFileJustDisappeared = false;
00203 
00204     // If the lock file is still expected to be there, check whether it still
00205     // is.
00206     if (!LockFileGone) {
00207       if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) ==
00208           errc::no_such_file_or_directory) {
00209         LockFileGone = true;
00210         LockFileJustDisappeared = true;
00211       }
00212     }
00213 
00214     // If the lock file is no longer there, check if the original file is
00215     // available now.
00216     if (LockFileGone) {
00217       if (sys::fs::exists(FileName.str())) {
00218         return Res_Success;
00219       }
00220 
00221       // The lock file is gone, so now we're waiting for the original file to
00222       // show up. If this just happened, reset our waiting intervals and keep
00223       // waiting.
00224       if (LockFileJustDisappeared) {
00225         MaxSeconds = 5;
00226 
00227 #if LLVM_ON_WIN32
00228         Interval = 1;
00229 #else
00230         Interval.tv_sec = 0;
00231         Interval.tv_nsec = 1000000;
00232 #endif
00233         continue;
00234       }
00235     }
00236 
00237     // If we're looking for the lock file to disappear, but the process
00238     // owning the lock died without cleaning up, just bail out.
00239     if (!LockFileGone &&
00240         !processStillExecuting((*Owner).first, (*Owner).second)) {
00241       return Res_OwnerDied;
00242     }
00243 
00244     // Exponentially increase the time we wait for the lock to be removed.
00245 #if LLVM_ON_WIN32
00246     Interval *= 2;
00247 #else
00248     Interval.tv_sec *= 2;
00249     Interval.tv_nsec *= 2;
00250     if (Interval.tv_nsec >= 1000000000) {
00251       ++Interval.tv_sec;
00252       Interval.tv_nsec -= 1000000000;
00253     }
00254 #endif
00255   } while (
00256 #if LLVM_ON_WIN32
00257            Interval < MaxSeconds * 1000
00258 #else
00259            Interval.tv_sec < (time_t)MaxSeconds
00260 #endif
00261            );
00262 
00263   // Give up.
00264   return Res_Timeout;
00265 }