LLVM API Documentation
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 }