LockFileManager.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. //===--- LockFileManager.cpp - File-level Locking Utility------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "llvm/Support/LockFileManager.h"
  10. #include "llvm/ADT/StringExtras.h"
  11. #include "llvm/Support/Errc.h"
  12. #include "llvm/Support/FileSystem.h"
  13. #include "llvm/Support/MemoryBuffer.h"
  14. #include "llvm/Support/raw_ostream.h"
  15. #include "llvm/Support/Signals.h"
  16. #include <sys/stat.h>
  17. #include <sys/types.h>
  18. #if LLVM_ON_WIN32
  19. #include <windows.h>
  20. #endif
  21. #if LLVM_ON_UNIX
  22. #include <unistd.h>
  23. #endif
  24. // //
  25. ///////////////////////////////////////////////////////////////////////////////
  26. #if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED > 1050)
  27. #define USE_OSX_GETHOSTUUID 1
  28. #else
  29. #define USE_OSX_GETHOSTUUID 0
  30. #endif
  31. #if USE_OSX_GETHOSTUUID
  32. #include <uuid/uuid.h>
  33. #endif
  34. using namespace llvm;
  35. /// \brief Attempt to read the lock file with the given name, if it exists.
  36. ///
  37. /// \param LockFileName The name of the lock file to read.
  38. ///
  39. /// \returns The process ID of the process that owns this lock file
  40. Optional<std::pair<std::string, int> >
  41. LockFileManager::readLockFile(StringRef LockFileName) {
  42. // Read the owning host and PID out of the lock file. If it appears that the
  43. // owning process is dead, the lock file is invalid.
  44. ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
  45. MemoryBuffer::getFile(LockFileName);
  46. if (!MBOrErr) {
  47. sys::fs::remove(LockFileName);
  48. return None;
  49. }
  50. MemoryBuffer &MB = *MBOrErr.get();
  51. StringRef Hostname;
  52. StringRef PIDStr;
  53. std::tie(Hostname, PIDStr) = getToken(MB.getBuffer(), " ");
  54. PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" "));
  55. int PID;
  56. if (!PIDStr.getAsInteger(10, PID)) {
  57. auto Owner = std::make_pair(std::string(Hostname), PID);
  58. if (processStillExecuting(Owner.first, Owner.second))
  59. return Owner;
  60. }
  61. // Delete the lock file. It's invalid anyway.
  62. sys::fs::remove(LockFileName);
  63. return None;
  64. }
  65. static std::error_code getHostID(SmallVectorImpl<char> &HostID) {
  66. HostID.clear();
  67. #if USE_OSX_GETHOSTUUID
  68. // On OS X, use the more stable hardware UUID instead of hostname.
  69. struct timespec wait = {1, 0}; // 1 second.
  70. uuid_t uuid;
  71. if (gethostuuid(uuid, &wait) != 0)
  72. return std::error_code(errno, std::system_category());
  73. uuid_string_t UUIDStr;
  74. uuid_unparse(uuid, UUIDStr);
  75. StringRef UUIDRef(UUIDStr);
  76. HostID.append(UUIDRef.begin(), UUIDRef.end());
  77. #elif LLVM_ON_UNIX
  78. char HostName[256];
  79. HostName[255] = 0;
  80. HostName[0] = 0;
  81. gethostname(HostName, 255);
  82. StringRef HostNameRef(HostName);
  83. HostID.append(HostNameRef.begin(), HostNameRef.end());
  84. #else
  85. StringRef Dummy("localhost");
  86. HostID.append(Dummy.begin(), Dummy.end());
  87. #endif
  88. return std::error_code();
  89. }
  90. bool LockFileManager::processStillExecuting(StringRef HostID, int PID) {
  91. #if LLVM_ON_UNIX && !defined(__ANDROID__)
  92. SmallString<256> StoredHostID;
  93. if (getHostID(StoredHostID))
  94. return true; // Conservatively assume it's executing on error.
  95. // Check whether the process is dead. If so, we're done.
  96. if (StoredHostID == HostID && getsid(PID) == -1 && errno == ESRCH)
  97. return false;
  98. #endif
  99. return true;
  100. }
  101. namespace {
  102. /// An RAII helper object ensure that the unique lock file is removed.
  103. ///
  104. /// Ensures that if there is an error or a signal before we finish acquiring the
  105. /// lock, the unique file will be removed. And if we successfully take the lock,
  106. /// the signal handler is left in place so that signals while the lock is held
  107. /// will remove the unique lock file. The caller should ensure there is a
  108. /// matching call to sys::DontRemoveFileOnSignal when the lock is released.
  109. class RemoveUniqueLockFileOnSignal {
  110. StringRef Filename;
  111. bool RemoveImmediately;
  112. public:
  113. RemoveUniqueLockFileOnSignal(StringRef Name)
  114. : Filename(Name), RemoveImmediately(true) {
  115. sys::RemoveFileOnSignal(Filename, nullptr);
  116. }
  117. ~RemoveUniqueLockFileOnSignal() {
  118. if (!RemoveImmediately) {
  119. // Leave the signal handler enabled. It will be removed when the lock is
  120. // released.
  121. return;
  122. }
  123. sys::fs::remove(Filename);
  124. sys::DontRemoveFileOnSignal(Filename);
  125. }
  126. void lockAcquired() { RemoveImmediately = false; }
  127. };
  128. } // end anonymous namespace
  129. LockFileManager::LockFileManager(StringRef FileName)
  130. {
  131. this->FileName = FileName;
  132. if (std::error_code EC = sys::fs::make_absolute(this->FileName)) {
  133. Error = EC;
  134. return;
  135. }
  136. LockFileName = this->FileName;
  137. LockFileName += ".lock";
  138. // If the lock file already exists, don't bother to try to create our own
  139. // lock file; it won't work anyway. Just figure out who owns this lock file.
  140. if ((Owner = readLockFile(LockFileName)))
  141. return;
  142. // Create a lock file that is unique to this instance.
  143. UniqueLockFileName = LockFileName;
  144. UniqueLockFileName += "-%%%%%%%%";
  145. int UniqueLockFileID;
  146. if (std::error_code EC = sys::fs::createUniqueFile(
  147. UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) {
  148. Error = EC;
  149. return;
  150. }
  151. // Write our process ID to our unique lock file.
  152. {
  153. SmallString<256> HostID;
  154. if (auto EC = getHostID(HostID)) {
  155. Error = EC;
  156. return;
  157. }
  158. raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
  159. Out << HostID << ' ';
  160. #if LLVM_ON_UNIX
  161. Out << getpid();
  162. #else
  163. Out << "1";
  164. #endif
  165. Out.close();
  166. if (Out.has_error()) {
  167. // We failed to write out PID, so make up an excuse, remove the
  168. // unique lock file, and fail.
  169. Error = make_error_code(errc::no_space_on_device);
  170. sys::fs::remove(UniqueLockFileName);
  171. return;
  172. }
  173. }
  174. // Clean up the unique file on signal, which also releases the lock if it is
  175. // held since the .lock symlink will point to a nonexistent file.
  176. RemoveUniqueLockFileOnSignal RemoveUniqueFile(UniqueLockFileName);
  177. while (1) {
  178. // Create a link from the lock file name. If this succeeds, we're done.
  179. std::error_code EC =
  180. sys::fs::create_link(UniqueLockFileName, LockFileName);
  181. if (!EC) {
  182. RemoveUniqueFile.lockAcquired();
  183. return;
  184. }
  185. if (EC != errc::file_exists) {
  186. Error = EC;
  187. return;
  188. }
  189. // Someone else managed to create the lock file first. Read the process ID
  190. // from the lock file.
  191. if ((Owner = readLockFile(LockFileName))) {
  192. // Wipe out our unique lock file (it's useless now)
  193. sys::fs::remove(UniqueLockFileName);
  194. return;
  195. }
  196. if (!sys::fs::exists(LockFileName)) {
  197. // The previous owner released the lock file before we could read it.
  198. // Try to get ownership again.
  199. continue;
  200. }
  201. // There is a lock file that nobody owns; try to clean it up and get
  202. // ownership.
  203. if ((EC = sys::fs::remove(LockFileName))) {
  204. Error = EC;
  205. return;
  206. }
  207. }
  208. }
  209. LockFileManager::LockFileState LockFileManager::getState() const {
  210. if (Owner)
  211. return LFS_Shared;
  212. if (Error)
  213. return LFS_Error;
  214. return LFS_Owned;
  215. }
  216. LockFileManager::~LockFileManager() {
  217. if (getState() != LFS_Owned)
  218. return;
  219. // Since we own the lock, remove the lock file and our own unique lock file.
  220. sys::fs::remove(LockFileName);
  221. sys::fs::remove(UniqueLockFileName);
  222. // The unique file is now gone, so remove it from the signal handler. This
  223. // matches a sys::RemoveFileOnSignal() in LockFileManager().
  224. sys::DontRemoveFileOnSignal(UniqueLockFileName);
  225. }
  226. LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
  227. if (getState() != LFS_Shared)
  228. return Res_Success;
  229. #if LLVM_ON_WIN32
  230. unsigned long Interval = 1;
  231. #else
  232. struct timespec Interval;
  233. Interval.tv_sec = 0;
  234. Interval.tv_nsec = 1000000;
  235. #endif
  236. // Don't wait more than five minutes per iteration. Total timeout for the file
  237. // to appear is ~8.5 mins.
  238. const unsigned MaxSeconds = 5*60;
  239. do {
  240. // Sleep for the designated interval, to allow the owning process time to
  241. // finish up and remove the lock file.
  242. // FIXME: Should we hook in to system APIs to get a notification when the
  243. // lock file is deleted?
  244. #if LLVM_ON_WIN32
  245. Sleep(Interval);
  246. #else
  247. nanosleep(&Interval, nullptr);
  248. #endif
  249. if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) ==
  250. errc::no_such_file_or_directory) {
  251. // If the original file wasn't created, somone thought the lock was dead.
  252. if (!sys::fs::exists(FileName))
  253. return Res_OwnerDied;
  254. return Res_Success;
  255. }
  256. // If the process owning the lock died without cleaning up, just bail out.
  257. if (!processStillExecuting((*Owner).first, (*Owner).second))
  258. return Res_OwnerDied;
  259. // Exponentially increase the time we wait for the lock to be removed.
  260. #if LLVM_ON_WIN32
  261. Interval *= 2;
  262. #else
  263. Interval.tv_sec *= 2;
  264. Interval.tv_nsec *= 2;
  265. if (Interval.tv_nsec >= 1000000000) {
  266. ++Interval.tv_sec;
  267. Interval.tv_nsec -= 1000000000;
  268. }
  269. #endif
  270. } while (
  271. #if LLVM_ON_WIN32
  272. Interval < MaxSeconds * 1000
  273. #else
  274. Interval.tv_sec < (time_t)MaxSeconds
  275. #endif
  276. );
  277. // Give up.
  278. return Res_Timeout;
  279. }
  280. std::error_code LockFileManager::unsafeRemoveLockFile() {
  281. return sys::fs::remove(LockFileName);
  282. }