195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor//===--- LockFileManager.cpp - File-level Locking Utility------------------===//
295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor//
395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor//                     The LLVM Compiler Infrastructure
495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor//
595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor// This file is distributed under the University of Illinois Open Source
695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor// License. See LICENSE.TXT for details.
795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor//
895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor//===----------------------------------------------------------------------===//
995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include "llvm/Support/LockFileManager.h"
1047cfec02842f885b46ea0d3c812793e660691640Reid Kleckner#include "llvm/ADT/StringExtras.h"
11c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines#include "llvm/Support/Errc.h"
1295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include "llvm/Support/FileSystem.h"
1347cfec02842f885b46ea0d3c812793e660691640Reid Kleckner#include "llvm/Support/MemoryBuffer.h"
1495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include "llvm/Support/raw_ostream.h"
15f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#include "llvm/Support/Signals.h"
1695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include <sys/stat.h>
17d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include <sys/types.h>
1895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32
1995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include <windows.h>
2095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif
2195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_UNIX
2295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#include <unistd.h>
2395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif
24f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
25f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED > 1050)
26f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#define USE_OSX_GETHOSTUUID 1
27f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#else
28f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#define USE_OSX_GETHOSTUUID 0
29f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#endif
30f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
31f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#if USE_OSX_GETHOSTUUID
32f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#include <uuid/uuid.h>
33f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#endif
3495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregorusing namespace llvm;
3595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
3695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor/// \brief Attempt to read the lock file with the given name, if it exists.
3795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor///
3895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor/// \param LockFileName The name of the lock file to read.
3995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor///
4095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor/// \returns The process ID of the process that owns this lock file
4195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorOptional<std::pair<std::string, int> >
4295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorLockFileManager::readLockFile(StringRef LockFileName) {
4395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // Read the owning host and PID out of the lock file. If it appears that the
4495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // owning process is dead, the lock file is invalid.
45c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
46c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines      MemoryBuffer::getFile(LockFileName);
47c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  if (!MBOrErr) {
4836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    sys::fs::remove(LockFileName);
4997c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner    return None;
5036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
5137ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  MemoryBuffer &MB = *MBOrErr.get();
5297c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner
5397c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner  StringRef Hostname;
5497c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner  StringRef PIDStr;
5537ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines  std::tie(Hostname, PIDStr) = getToken(MB.getBuffer(), " ");
5697c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner  PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" "));
5797c57dfcb4c76ede59443fe4c03e415ee7fa358aReid Kleckner  int PID;
58dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  if (!PIDStr.getAsInteger(10, PID)) {
59dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    auto Owner = std::make_pair(std::string(Hostname), PID);
60dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    if (processStillExecuting(Owner.first, Owner.second))
61dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      return Owner;
62dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  }
6395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
6495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // Delete the lock file. It's invalid anyway.
6547cfec02842f885b46ea0d3c812793e660691640Reid Kleckner  sys::fs::remove(LockFileName);
665c43245bf459c77077b607e1b55e6928cfbe464eDavid Blaikie  return None;
6795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor}
6895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
69f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarstatic std::error_code getHostID(SmallVectorImpl<char> &HostID) {
70f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  HostID.clear();
71f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
72f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#if USE_OSX_GETHOSTUUID
73f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  // On OS X, use the more stable hardware UUID instead of hostname.
74f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  struct timespec wait = {1, 0}; // 1 second.
75f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  uuid_t uuid;
76f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  if (gethostuuid(uuid, &wait) != 0)
77f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    return std::error_code(errno, std::system_category());
78f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
79f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  uuid_string_t UUIDStr;
80f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  uuid_unparse(uuid, UUIDStr);
81f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  StringRef UUIDRef(UUIDStr);
82f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  HostID.append(UUIDRef.begin(), UUIDRef.end());
83f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
84f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#elif LLVM_ON_UNIX
85f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  char HostName[256];
86f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  HostName[255] = 0;
87f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  HostName[0] = 0;
88f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  gethostname(HostName, 255);
89f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  StringRef HostNameRef(HostName);
90f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  HostID.append(HostNameRef.begin(), HostNameRef.end());
91f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
92f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#else
93f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  StringRef Dummy("localhost");
94f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  HostID.append(Dummy.begin(), Dummy.end());
95f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar#endif
96f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
97f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  return std::error_code();
98f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar}
99f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
100f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarbool LockFileManager::processStillExecuting(StringRef HostID, int PID) {
10168d92bdcc99e647546f40cfce5cfbeb904be2985Evgeniy Stepanov#if LLVM_ON_UNIX && !defined(__ANDROID__)
102f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  SmallString<256> StoredHostID;
103f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  if (getHostID(StoredHostID))
104f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    return true; // Conservatively assume it's executing on error.
105f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
10695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // Check whether the process is dead. If so, we're done.
107f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  if (StoredHostID == HostID && getsid(PID) == -1 && errno == ESRCH)
10895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    return false;
10995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif
11095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
11195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  return true;
11295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor}
11395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
114f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarnamespace {
115f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// An RAII helper object ensure that the unique lock file is removed.
116f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar///
117f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// Ensures that if there is an error or a signal before we finish acquiring the
118f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// lock, the unique file will be removed. And if we successfully take the lock,
119f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// the signal handler is left in place so that signals while the lock is held
120f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// will remove the unique lock file. The caller should ensure there is a
121f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar/// matching call to sys::DontRemoveFileOnSignal when the lock is released.
122f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarclass RemoveUniqueLockFileOnSignal {
123f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  StringRef Filename;
124f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  bool RemoveImmediately;
125f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainarpublic:
126f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  RemoveUniqueLockFileOnSignal(StringRef Name)
127f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  : Filename(Name), RemoveImmediately(true) {
128f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    sys::RemoveFileOnSignal(Filename, nullptr);
129f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  }
130f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  ~RemoveUniqueLockFileOnSignal() {
131f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    if (!RemoveImmediately) {
132f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar      // Leave the signal handler enabled. It will be removed when the lock is
133f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar      // released.
134f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar      return;
135f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    }
136f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    sys::fs::remove(Filename);
137f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    sys::DontRemoveFileOnSignal(Filename);
138f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  }
139f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  void lockAcquired() { RemoveImmediately = false; }
140f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar};
141f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar} // end anonymous namespace
142f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
14395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorLockFileManager::LockFileManager(StringRef FileName)
14495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor{
14569a2d6f55afb2bc42bc19e754bcebee39ecdb8bcDouglas Gregor  this->FileName = FileName;
146c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  if (std::error_code EC = sys::fs::make_absolute(this->FileName)) {
147de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    std::string S("failed to obtain absolute path for ");
148de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    S.append(this->FileName.str());
149de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    setError(EC, S);
15036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    return;
15136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
15236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  LockFileName = this->FileName;
15395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  LockFileName += ".lock";
15495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
15595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // If the lock file already exists, don't bother to try to create our own
15695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // lock file; it won't work anyway. Just figure out who owns this lock file.
15795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  if ((Owner = readLockFile(LockFileName)))
15895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    return;
15995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
16095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // Create a lock file that is unique to this instance.
16195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  UniqueLockFileName = LockFileName;
16295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  UniqueLockFileName += "-%%%%%%%%";
16395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  int UniqueLockFileID;
164c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines  if (std::error_code EC = sys::fs::createUniqueFile(
1654c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar          UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) {
166de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    std::string S("failed to create unique file ");
167de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    S.append(UniqueLockFileName.str());
168de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    setError(EC, S);
16995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    return;
17095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  }
17195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
17295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // Write our process ID to our unique lock file.
17395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  {
174f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    SmallString<256> HostID;
175f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    if (auto EC = getHostID(HostID)) {
176de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      setError(EC, "failed to get host id");
177f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar      return;
178f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    }
17995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
180f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
181f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    Out << HostID << ' ';
18295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_UNIX
183f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    Out << getpid();
18495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else
185f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    Out << "1";
18695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif
18795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    Out.close();
18895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
18995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    if (Out.has_error()) {
19095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor      // We failed to write out PID, so make up an excuse, remove the
19195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor      // unique lock file, and fail.
192de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      auto EC = make_error_code(errc::no_space_on_device);
193de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      std::string S("failed to write to ");
194de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      S.append(UniqueLockFileName.str());
195de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      setError(EC, S);
1964c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar      sys::fs::remove(UniqueLockFileName);
19795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor      return;
19895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    }
19995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  }
20095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
201f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  // Clean up the unique file on signal, which also releases the lock if it is
202f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  // held since the .lock symlink will point to a nonexistent file.
203f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  RemoveUniqueLockFileOnSignal RemoveUniqueFile(UniqueLockFileName);
204f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar
20536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  while (1) {
20636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    // Create a link from the lock file name. If this succeeds, we're done.
207c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines    std::error_code EC =
2084c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar        sys::fs::create_link(UniqueLockFileName, LockFileName);
209f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    if (!EC) {
210f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar      RemoveUniqueFile.lockAcquired();
21136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return;
212f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar    }
21395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
21436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if (EC != errc::file_exists) {
215de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      std::string S("failed to create link ");
216de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      raw_string_ostream OSS(S);
217de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      OSS << LockFileName.str() << " to " << UniqueLockFileName.str();
218de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      setError(EC, OSS.str());
21936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return;
22036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
22195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
22236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    // Someone else managed to create the lock file first. Read the process ID
22336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    // from the lock file.
22436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    if ((Owner = readLockFile(LockFileName))) {
22536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      // Wipe out our unique lock file (it's useless now)
2264c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar      sys::fs::remove(UniqueLockFileName);
22736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return;
22836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
22995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
2304c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar    if (!sys::fs::exists(LockFileName)) {
23136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      // The previous owner released the lock file before we could read it.
23236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      // Try to get ownership again.
23336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      continue;
23436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
23595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
23636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    // There is a lock file that nobody owns; try to clean it up and get
23736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    // ownership.
2384c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar    if ((EC = sys::fs::remove(LockFileName))) {
239de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      std::string S("failed to remove lockfile ");
240de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      S.append(UniqueLockFileName.str());
241de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      setError(EC, S);
24236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines      return;
24336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    }
24436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines  }
24595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor}
24695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
24795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorLockFileManager::LockFileState LockFileManager::getState() const {
24895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  if (Owner)
24995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    return LFS_Shared;
25095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
25195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  if (Error)
25295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    return LFS_Error;
25395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
25495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  return LFS_Owned;
25595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor}
25695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
257de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainarstd::string LockFileManager::getErrorMessage() const {
258de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  if (Error) {
259de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    std::string Str(ErrorDiagMsg);
260de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    std::string ErrCodeMsg = Error->message();
261de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    raw_string_ostream OSS(Str);
262de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    if (!ErrCodeMsg.empty())
263de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar      OSS << ": " << Error->message();
264de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    OSS.flush();
265de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar    return Str;
266de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  }
267de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar  return "";
268de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar}
269de2d8694e25a814696358e95141f4b1aa4d8847ePirama Arumuga Nainar
27095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas GregorLockFileManager::~LockFileManager() {
27195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  if (getState() != LFS_Owned)
27295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    return;
27395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
27495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // Since we own the lock, remove the lock file and our own unique lock file.
2754c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar  sys::fs::remove(LockFileName);
2764c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar  sys::fs::remove(UniqueLockFileName);
277f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  // The unique file is now gone, so remove it from the signal handler. This
278f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  // matches a sys::RemoveFileOnSignal() in LockFileManager().
279f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  sys::DontRemoveFileOnSignal(UniqueLockFileName);
28095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor}
28195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
282dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen HinesLockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
28395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  if (getState() != LFS_Shared)
284dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    return Res_Success;
28595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
28695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32
28795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  unsigned long Interval = 1;
28895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else
28995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  struct timespec Interval;
29095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  Interval.tv_sec = 0;
29195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  Interval.tv_nsec = 1000000;
29295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif
2934c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar  // Don't wait more than five minutes per iteration. Total timeout for the file
2944c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar  // to appear is ~8.5 mins.
2954c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar  const unsigned MaxSeconds = 5*60;
29695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  do {
29795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    // Sleep for the designated interval, to allow the owning process time to
29895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    // finish up and remove the lock file.
29995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    // FIXME: Should we hook in to system APIs to get a notification when the
30095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    // lock file is deleted?
30195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32
30295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    Sleep(Interval);
30395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else
304dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    nanosleep(&Interval, nullptr);
30595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif
306e76fe51fe1bfe437aba5e619dae58706d35b3a58Douglas Gregor
307ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines    if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) ==
308ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines        errc::no_such_file_or_directory) {
309ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines      // If the original file wasn't created, somone thought the lock was dead.
3104c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar      if (!sys::fs::exists(FileName))
311ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines        return Res_OwnerDied;
312ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines      return Res_Success;
31369a2d6f55afb2bc42bc19e754bcebee39ecdb8bcDouglas Gregor    }
314e76fe51fe1bfe437aba5e619dae58706d35b3a58Douglas Gregor
315ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines    // If the process owning the lock died without cleaning up, just bail out.
316ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines    if (!processStillExecuting((*Owner).first, (*Owner).second))
317dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      return Res_OwnerDied;
31895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
31995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    // Exponentially increase the time we wait for the lock to be removed.
32095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32
32195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    Interval *= 2;
32295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else
32395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    Interval.tv_sec *= 2;
32495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    Interval.tv_nsec *= 2;
32595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    if (Interval.tv_nsec >= 1000000000) {
32695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor      ++Interval.tv_sec;
32795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor      Interval.tv_nsec -= 1000000000;
32895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor    }
32995fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif
33095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  } while (
33195fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#if LLVM_ON_WIN32
33295fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor           Interval < MaxSeconds * 1000
33395fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#else
33495fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor           Interval.tv_sec < (time_t)MaxSeconds
33595fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor#endif
33695fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor           );
33795fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor
33895fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor  // Give up.
339dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  return Res_Timeout;
34095fa4005f5aa99878c4053e95b230f0b8b6a4d6dDouglas Gregor}
341ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines
342ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesstd::error_code LockFileManager::unsafeRemoveLockFile() {
3434c5e43da7792f75567b693105cc53e3f1992ad98Pirama Arumuga Nainar  return sys::fs::remove(LockFileName);
344ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines}
345