LockFileManager.cpp 11 KB

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