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