//===--- Threading.h - Abstractions for multithreading -----------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_THREADING_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_THREADING_H #include "support/Context.h" #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/Twine.h" #include <atomic> #include <cassert> #include <condition_variable> #include <future> #include <memory> #include <mutex> #include <optional> #include <thread> #include <vector> namespace clang { namespace clangd { /// Limits the number of threads that can acquire the lock at the same time. class Semaphore { … }; /// 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 { … }; /// Makes a deadline from a timeout in seconds. std::nullopt means wait forever. Deadline timeoutSeconds(std::optional<double> Seconds); /// Wait once on CV for the specified duration. void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV, Deadline D); /// Waits on a condition variable until F() is true or D expires. template <typename Func> [[nodiscard]] bool wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV, Deadline D, Func F) { … } /// A threadsafe flag that is initially clear. class Notification { … }; /// 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 { … }; /// Runs \p Action asynchronously with a new std::thread. The context will be /// propagated. template <typename T> std::future<T> runAsync(llvm::unique_function<T()> Action) { … } /// Memoize is a cache to store and reuse computation results based on a key. /// /// Memoize<DenseMap<int, bool>> PrimeCache; /// for (int I : RepetitiveNumbers) /// if (PrimeCache.get(I, [&] { return expensiveIsPrime(I); })) /// llvm::errs() << "Prime: " << I << "\n"; /// /// The computation will only be run once for each key. /// This class is threadsafe. Concurrent calls for the same key may run the /// computation multiple times, but each call will return the same result. template <typename Container> class Memoize { … }; /// Used to guard an operation that should run at most every N seconds. /// /// Usage: /// mutable PeriodicThrottler ShouldLog(std::chrono::seconds(1)); /// void calledFrequently() { /// if (ShouldLog()) /// log("this is not spammy"); /// } /// /// This class is threadsafe. If multiple threads are involved, then the guarded /// operation still needs to be threadsafe! class PeriodicThrottler { … }; } // namespace clangd } // namespace clang #endif