//===--- ThreadPool.h --------------------------------------------*- C++-*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_THREADING_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_THREADING_H #include "Context.h" #include "Function.h" #include "llvm/ADT/Twine.h" #include #include #include #include #include #include namespace clang { namespace clangd { /// A threadsafe flag that is initially clear. class Notification { public: // Sets the flag. No-op if already set. void notify(); // Blocks until flag is set. void wait() const; private: bool Notified = false; mutable std::condition_variable CV; mutable std::mutex Mu; }; /// Limits the number of threads that can acquire the lock at the same time. class Semaphore { public: Semaphore(std::size_t MaxLocks); bool try_lock(); void lock(); void unlock(); private: std::mutex Mutex; std::condition_variable SlotsChanged; std::size_t FreeSlots; }; /// A point in time we can wait for. /// Can be zero (don't wait) or infinity (wait forever). /// (Not time_point::max(), because many std::chrono implementations overflow). class Deadline { public: Deadline(std::chrono::steady_clock::time_point Time) : Type(Finite), Time(Time) {} static Deadline zero() { return Deadline(Zero); } static Deadline infinity() { return Deadline(Infinite); } std::chrono::steady_clock::time_point time() const { assert(Type == Finite); return Time; } bool expired() const { return (Type == Zero) || (Type == Finite && Time < std::chrono::steady_clock::now()); } bool operator==(const Deadline &Other) const { return (Type == Other.Type) && (Type != Finite || Time == Other.Time); } private: enum Type { Zero, Infinite, Finite }; Deadline(enum Type Type) : Type(Type) {} enum Type Type; std::chrono::steady_clock::time_point Time; }; /// Makes a deadline from a timeout in seconds. None means wait forever. Deadline timeoutSeconds(llvm::Optional Seconds); /// Wait once on CV for the specified duration. void wait(std::unique_lock &Lock, std::condition_variable &CV, Deadline D); /// Waits on a condition variable until F() is true or D expires. template LLVM_NODISCARD bool wait(std::unique_lock &Lock, std::condition_variable &CV, Deadline D, Func F) { while (!F()) { if (D.expired()) return false; wait(Lock, CV, D); } return true; } /// Runs tasks on separate (detached) threads and wait for all tasks to finish. /// Objects that need to spawn threads can own an AsyncTaskRunner to ensure they /// all complete on destruction. class AsyncTaskRunner { public: /// Destructor waits for all pending tasks to finish. ~AsyncTaskRunner(); void wait() const { (void)wait(Deadline::infinity()); } LLVM_NODISCARD bool wait(Deadline D) const; // The name is used for tracing and debugging (e.g. to name a spawned thread). void runAsync(const llvm::Twine &Name, llvm::unique_function Action); private: mutable std::mutex Mutex; mutable std::condition_variable TasksReachedZero; std::size_t InFlightTasks = 0; }; enum class ThreadPriority { Low = 0, Normal = 1, }; void setCurrentThreadPriority(ThreadPriority Priority); // Avoid the use of scheduler policies that may starve low-priority threads. // This prevents tests from timing out on loaded systems. // Affects subsequent setThreadPriority() calls. void preventThreadStarvationInTests(); } // namespace clangd } // namespace clang #endif