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