diff options
Diffstat (limited to 'llvm/lib/Support/LockFileManager.cpp')
-rw-r--r-- | llvm/lib/Support/LockFileManager.cpp | 80 |
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; |