LockFileManager.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //===--- LockFileManager.cpp - File-level Locking Utility------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/Support/LockFileManager.h"
  9. #include "llvm/ADT/None.h"
  10. #include "llvm/ADT/SmallVector.h"
  11. #include "llvm/ADT/StringExtras.h"
  12. #include "llvm/Support/Errc.h"
  13. #include "llvm/Support/ErrorOr.h"
  14. #include "llvm/Support/FileSystem.h"
  15. #include "llvm/Support/MemoryBuffer.h"
  16. #include "llvm/Support/Process.h"
  17. #include "llvm/Support/Signals.h"
  18. #include "llvm/Support/raw_ostream.h"
  19. #include <cerrno>
  20. #include <chrono>
  21. #include <ctime>
  22. #include <memory>
  23. #include <random>
  24. #include <sys/stat.h>
  25. #include <sys/types.h>
  26. #include <system_error>
  27. #include <thread>
  28. #include <tuple>
  29. #ifdef _WIN32
  30. #include <windows.h>
  31. #endif
  32. #if LLVM_ON_UNIX
  33. #include <unistd.h>
  34. #endif
  35. #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1050)
  36. #define USE_OSX_GETHOSTUUID 1
  37. #else
  38. #define USE_OSX_GETHOSTUUID 0
  39. #endif
  40. #if USE_OSX_GETHOSTUUID
  41. #include <uuid/uuid.h>
  42. #endif
  43. using namespace llvm;
  44. /// Attempt to read the lock file with the given name, if it exists.
  45. ///
  46. /// \param LockFileName The name of the lock file to read.
  47. ///
  48. /// \returns The process ID of the process that owns this lock file
  49. Optional<std::pair<std::string, int> >
  50. LockFileManager::readLockFile(StringRef LockFileName) {
  51. // Read the owning host and PID out of the lock file. If it appears that the
  52. // owning process is dead, the lock file is invalid.
  53. ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
  54. MemoryBuffer::getFile(LockFileName);
  55. if (!MBOrErr) {
  56. sys::fs::remove(LockFileName);
  57. return None;
  58. }
  59. MemoryBuffer &MB = *MBOrErr.get();
  60. StringRef Hostname;
  61. StringRef PIDStr;
  62. std::tie(Hostname, PIDStr) = getToken(MB.getBuffer(), " ");
  63. PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" "));
  64. int PID;
  65. if (!PIDStr.getAsInteger(10, PID)) {
  66. auto Owner = std::make_pair(std::string(Hostname), PID);
  67. if (processStillExecuting(Owner.first, Owner.second))
  68. return Owner;
  69. }
  70. // Delete the lock file. It's invalid anyway.
  71. sys::fs::remove(LockFileName);
  72. return None;
  73. }
  74. static std::error_code getHostID(SmallVectorImpl<char> &HostID) {
  75. HostID.clear();
  76. #if USE_OSX_GETHOSTUUID
  77. // On OS X, use the more stable hardware UUID instead of hostname.
  78. struct timespec wait = {1, 0}; // 1 second.
  79. uuid_t uuid;
  80. if (gethostuuid(uuid, &wait) != 0)
  81. return std::error_code(errno, std::system_category());
  82. uuid_string_t UUIDStr;
  83. uuid_unparse(uuid, UUIDStr);
  84. StringRef UUIDRef(UUIDStr);
  85. HostID.append(UUIDRef.begin(), UUIDRef.end());
  86. #elif LLVM_ON_UNIX
  87. char HostName[256];
  88. HostName[255] = 0;
  89. HostName[0] = 0;
  90. gethostname(HostName, 255);
  91. StringRef HostNameRef(HostName);
  92. HostID.append(HostNameRef.begin(), HostNameRef.end());
  93. #else
  94. StringRef Dummy("localhost");
  95. HostID.append(Dummy.begin(), Dummy.end());
  96. #endif
  97. return std::error_code();
  98. }
  99. bool LockFileManager::processStillExecuting(StringRef HostID, int PID) {
  100. #if LLVM_ON_UNIX && !defined(__ANDROID__)
  101. SmallString<256> StoredHostID;
  102. if (getHostID(StoredHostID))
  103. return true; // Conservatively assume it's executing on error.
  104. // Check whether the process is dead. If so, we're done.
  105. if (StoredHostID == HostID && getsid(PID) == -1 && errno == ESRCH)
  106. return false;
  107. #endif
  108. return true;
  109. }
  110. namespace {
  111. /// An RAII helper object ensure that the unique lock file is removed.
  112. ///
  113. /// Ensures that if there is an error or a signal before we finish acquiring the
  114. /// lock, the unique file will be removed. And if we successfully take the lock,
  115. /// the signal handler is left in place so that signals while the lock is held
  116. /// will remove the unique lock file. The caller should ensure there is a
  117. /// matching call to sys::DontRemoveFileOnSignal when the lock is released.
  118. class RemoveUniqueLockFileOnSignal {
  119. StringRef Filename;
  120. bool RemoveImmediately;
  121. public:
  122. RemoveUniqueLockFileOnSignal(StringRef Name)
  123. : Filename(Name), RemoveImmediately(true) {
  124. sys::RemoveFileOnSignal(Filename, nullptr);
  125. }
  126. ~RemoveUniqueLockFileOnSignal() {
  127. if (!RemoveImmediately) {
  128. // Leave the signal handler enabled. It will be removed when the lock is
  129. // released.
  130. return;
  131. }
  132. sys::fs::remove(Filename);
  133. sys::DontRemoveFileOnSignal(Filename);
  134. }
  135. void lockAcquired() { RemoveImmediately = false; }
  136. };
  137. } // end anonymous namespace
  138. LockFileManager::LockFileManager(StringRef FileName)
  139. {
  140. this->FileName = FileName;
  141. if (std::error_code EC = sys::fs::make_absolute(this->FileName)) {
  142. std::string S("failed to obtain absolute path for ");
  143. S.append(std::string(this->FileName.str()));
  144. setError(EC, S);
  145. return;
  146. }
  147. LockFileName = this->FileName;
  148. LockFileName += ".lock";
  149. // If the lock file already exists, don't bother to try to create our own
  150. // lock file; it won't work anyway. Just figure out who owns this lock file.
  151. if ((Owner = readLockFile(LockFileName)))
  152. return;
  153. // Create a lock file that is unique to this instance.
  154. UniqueLockFileName = LockFileName;
  155. UniqueLockFileName += "-%%%%%%%%";
  156. int UniqueLockFileID;
  157. if (std::error_code EC = sys::fs::createUniqueFile(
  158. UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) {
  159. std::string S("failed to create unique file ");
  160. S.append(std::string(UniqueLockFileName.str()));
  161. setError(EC, S);
  162. return;
  163. }
  164. // Write our process ID to our unique lock file.
  165. {
  166. SmallString<256> HostID;
  167. if (auto EC = getHostID(HostID)) {
  168. setError(EC, "failed to get host id");
  169. return;
  170. }
  171. raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
  172. Out << HostID << ' ' << sys::Process::getProcessId();
  173. Out.close();
  174. if (Out.has_error()) {
  175. // We failed to write out PID, so report the error, remove the
  176. // unique lock file, and fail.
  177. std::string S("failed to write to ");
  178. S.append(std::string(UniqueLockFileName.str()));
  179. setError(Out.error(), S);
  180. sys::fs::remove(UniqueLockFileName);
  181. return;
  182. }
  183. }
  184. // Clean up the unique file on signal, which also releases the lock if it is
  185. // held since the .lock symlink will point to a nonexistent file.
  186. RemoveUniqueLockFileOnSignal RemoveUniqueFile(UniqueLockFileName);
  187. while (true) {
  188. // Create a link from the lock file name. If this succeeds, we're done.
  189. std::error_code EC =
  190. sys::fs::create_link(UniqueLockFileName, LockFileName);
  191. if (!EC) {
  192. RemoveUniqueFile.lockAcquired();
  193. return;
  194. }
  195. if (EC != errc::file_exists) {
  196. std::string S("failed to create link ");
  197. raw_string_ostream OSS(S);
  198. OSS << LockFileName.str() << " to " << UniqueLockFileName.str();
  199. setError(EC, OSS.str());
  200. return;
  201. }
  202. // Someone else managed to create the lock file first. Read the process ID
  203. // from the lock file.
  204. if ((Owner = readLockFile(LockFileName))) {
  205. // Wipe out our unique lock file (it's useless now)
  206. sys::fs::remove(UniqueLockFileName);
  207. return;
  208. }
  209. if (!sys::fs::exists(LockFileName)) {
  210. // The previous owner released the lock file before we could read it.
  211. // Try to get ownership again.
  212. continue;
  213. }
  214. // There is a lock file that nobody owns; try to clean it up and get
  215. // ownership.
  216. if ((EC = sys::fs::remove(LockFileName))) {
  217. std::string S("failed to remove lockfile ");
  218. S.append(std::string(UniqueLockFileName.str()));
  219. setError(EC, S);
  220. return;
  221. }
  222. }
  223. }
  224. LockFileManager::LockFileState LockFileManager::getState() const {
  225. if (Owner)
  226. return LFS_Shared;
  227. if (ErrorCode)
  228. return LFS_Error;
  229. return LFS_Owned;
  230. }
  231. std::string LockFileManager::getErrorMessage() const {
  232. if (ErrorCode) {
  233. std::string Str(ErrorDiagMsg);
  234. std::string ErrCodeMsg = ErrorCode.message();
  235. raw_string_ostream OSS(Str);
  236. if (!ErrCodeMsg.empty())
  237. OSS << ": " << ErrCodeMsg;
  238. return OSS.str();
  239. }
  240. return "";
  241. }
  242. LockFileManager::~LockFileManager() {
  243. if (getState() != LFS_Owned)
  244. return;
  245. // Since we own the lock, remove the lock file and our own unique lock file.
  246. sys::fs::remove(LockFileName);
  247. sys::fs::remove(UniqueLockFileName);
  248. // The unique file is now gone, so remove it from the signal handler. This
  249. // matches a sys::RemoveFileOnSignal() in LockFileManager().
  250. sys::DontRemoveFileOnSignal(UniqueLockFileName);
  251. }
  252. LockFileManager::WaitForUnlockResult
  253. LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
  254. if (getState() != LFS_Shared)
  255. return Res_Success;
  256. // Since we don't yet have an event-based method to wait for the lock file,
  257. // implement randomized exponential backoff, similar to Ethernet collision
  258. // algorithm. This improves performance on machines with high core counts
  259. // when the file lock is heavily contended by multiple clang processes
  260. const unsigned long MinWaitDurationMS = 10;
  261. const unsigned long MaxWaitMultiplier = 50; // 500ms max wait
  262. unsigned long WaitMultiplier = 1;
  263. unsigned long ElapsedTimeSeconds = 0;
  264. std::random_device Device;
  265. std::default_random_engine Engine(Device());
  266. auto StartTime = std::chrono::steady_clock::now();
  267. do {
  268. // FIXME: implement event-based waiting
  269. // Sleep for the designated interval, to allow the owning process time to
  270. // finish up and remove the lock file.
  271. std::uniform_int_distribution<unsigned long> Distribution(1,
  272. WaitMultiplier);
  273. unsigned long WaitDurationMS = MinWaitDurationMS * Distribution(Engine);
  274. std::this_thread::sleep_for(std::chrono::milliseconds(WaitDurationMS));
  275. if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) ==
  276. errc::no_such_file_or_directory) {
  277. // If the original file wasn't created, somone thought the lock was dead.
  278. if (!sys::fs::exists(FileName))
  279. return Res_OwnerDied;
  280. return Res_Success;
  281. }
  282. // If the process owning the lock died without cleaning up, just bail out.
  283. if (!processStillExecuting((*Owner).first, (*Owner).second))
  284. return Res_OwnerDied;
  285. WaitMultiplier *= 2;
  286. if (WaitMultiplier > MaxWaitMultiplier) {
  287. WaitMultiplier = MaxWaitMultiplier;
  288. }
  289. ElapsedTimeSeconds = std::chrono::duration_cast<std::chrono::seconds>(
  290. std::chrono::steady_clock::now() - StartTime)
  291. .count();
  292. } while (ElapsedTimeSeconds < MaxSeconds);
  293. // Give up.
  294. return Res_Timeout;
  295. }
  296. std::error_code LockFileManager::unsafeRemoveLockFile() {
  297. return sys::fs::remove(LockFileName);
  298. }