summaryrefslogtreecommitdiff
path: root/llvm/lib/Support/LockFileManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support/LockFileManager.cpp')
-rw-r--r--llvm/lib/Support/LockFileManager.cpp80
1 files changed, 39 insertions, 41 deletions
diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp
index 5c6508c3b007b..a2b56ab295c42 100644
--- a/llvm/lib/Support/LockFileManager.cpp
+++ b/llvm/lib/Support/LockFileManager.cpp
@@ -14,15 +14,20 @@
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <cerrno>
+#include <chrono>
#include <ctime>
#include <memory>
+#include <random>
#include <sys/stat.h>
#include <sys/types.h>
#include <system_error>
+#include <thread>
#include <tuple>
+
#ifdef _WIN32
#include <windows.h>
#endif
@@ -158,7 +163,7 @@ LockFileManager::LockFileManager(StringRef FileName)
this->FileName = FileName;
if (std::error_code EC = sys::fs::make_absolute(this->FileName)) {
std::string S("failed to obtain absolute path for ");
- S.append(this->FileName.str());
+ S.append(std::string(this->FileName.str()));
setError(EC, S);
return;
}
@@ -177,7 +182,7 @@ LockFileManager::LockFileManager(StringRef FileName)
if (std::error_code EC = sys::fs::createUniqueFile(
UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) {
std::string S("failed to create unique file ");
- S.append(UniqueLockFileName.str());
+ S.append(std::string(UniqueLockFileName.str()));
setError(EC, S);
return;
}
@@ -191,19 +196,14 @@ LockFileManager::LockFileManager(StringRef FileName)
}
raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
- Out << HostID << ' ';
-#if LLVM_ON_UNIX
- Out << getpid();
-#else
- Out << "1";
-#endif
+ Out << HostID << ' ' << sys::Process::getProcessId();
Out.close();
if (Out.has_error()) {
// We failed to write out PID, so report the error, remove the
// unique lock file, and fail.
std::string S("failed to write to ");
- S.append(UniqueLockFileName.str());
+ S.append(std::string(UniqueLockFileName.str()));
setError(Out.error(), S);
sys::fs::remove(UniqueLockFileName);
return;
@@ -249,7 +249,7 @@ LockFileManager::LockFileManager(StringRef FileName)
// ownership.
if ((EC = sys::fs::remove(LockFileName))) {
std::string S("failed to remove lockfile ");
- S.append(UniqueLockFileName.str());
+ S.append(std::string(UniqueLockFileName.str()));
setError(EC, S);
return;
}
@@ -295,23 +295,29 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
if (getState() != LFS_Shared)
return Res_Success;
-#ifdef _WIN32
- unsigned long Interval = 1;
-#else
- struct timespec Interval;
- Interval.tv_sec = 0;
- Interval.tv_nsec = 1000000;
-#endif
+ // Since we don't yet have an event-based method to wait for the lock file,
+ // implement randomized exponential backoff, similar to Ethernet collision
+ // algorithm. This improves performance on machines with high core counts
+ // when the file lock is heavily contended by multiple clang processes
+ const unsigned long MinWaitDurationMS = 10;
+ const unsigned long MaxWaitMultiplier = 50; // 500ms max wait
+ unsigned long WaitMultiplier = 1;
+ unsigned long ElapsedTimeSeconds = 0;
+
+ std::random_device Device;
+ std::default_random_engine Engine(Device());
+
+ auto StartTime = std::chrono::steady_clock::now();
+
do {
+ // FIXME: implement event-based waiting
+
// Sleep for the designated interval, to allow the owning process time to
// finish up and remove the lock file.
- // FIXME: Should we hook in to system APIs to get a notification when the
- // lock file is deleted?
-#ifdef _WIN32
- Sleep(Interval);
-#else
- nanosleep(&Interval, nullptr);
-#endif
+ std::uniform_int_distribution<unsigned long> Distribution(1,
+ WaitMultiplier);
+ unsigned long WaitDurationMS = MinWaitDurationMS * Distribution(Engine);
+ std::this_thread::sleep_for(std::chrono::milliseconds(WaitDurationMS));
if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) ==
errc::no_such_file_or_directory) {
@@ -325,24 +331,16 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
if (!processStillExecuting((*Owner).first, (*Owner).second))
return Res_OwnerDied;
- // Exponentially increase the time we wait for the lock to be removed.
-#ifdef _WIN32
- Interval *= 2;
-#else
- Interval.tv_sec *= 2;
- Interval.tv_nsec *= 2;
- if (Interval.tv_nsec >= 1000000000) {
- ++Interval.tv_sec;
- Interval.tv_nsec -= 1000000000;
+ WaitMultiplier *= 2;
+ if (WaitMultiplier > MaxWaitMultiplier) {
+ WaitMultiplier = MaxWaitMultiplier;
}
-#endif
- } while (
-#ifdef _WIN32
- Interval < MaxSeconds * 1000
-#else
- Interval.tv_sec < (time_t)MaxSeconds
-#endif
- );
+
+ ElapsedTimeSeconds = std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::steady_clock::now() - StartTime)
+ .count();
+
+ } while (ElapsedTimeSeconds < MaxSeconds);
// Give up.
return Res_Timeout;