clang-tools  15.0.0git
Threading.h
Go to the documentation of this file.
1 //===--- Threading.h - Abstractions for multithreading -----------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_THREADING_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_THREADING_H
11 
12 #include "support/Context.h"
13 #include "llvm/ADT/FunctionExtras.h"
14 #include "llvm/ADT/Twine.h"
15 #include <atomic>
16 #include <cassert>
17 #include <condition_variable>
18 #include <future>
19 #include <memory>
20 #include <mutex>
21 #include <thread>
22 #include <vector>
23 
24 namespace clang {
25 namespace clangd {
26 
27 /// Limits the number of threads that can acquire the lock at the same time.
28 class Semaphore {
29 public:
30  Semaphore(std::size_t MaxLocks);
31 
32  bool try_lock();
33  void lock();
34  void unlock();
35 
36 private:
37  std::mutex Mutex;
38  std::condition_variable SlotsChanged;
39  std::size_t FreeSlots;
40 };
41 
42 /// A point in time we can wait for.
43 /// Can be zero (don't wait) or infinity (wait forever).
44 /// (Not time_point::max(), because many std::chrono implementations overflow).
45 class Deadline {
46 public:
47  Deadline(std::chrono::steady_clock::time_point Time)
48  : Type(Finite), Time(Time) {}
49  static Deadline zero() { return Deadline(Zero); }
50  static Deadline infinity() { return Deadline(Infinite); }
51 
52  std::chrono::steady_clock::time_point time() const {
53  assert(Type == Finite);
54  return Time;
55  }
56  bool expired() const {
57  return (Type == Zero) ||
58  (Type == Finite && Time < std::chrono::steady_clock::now());
59  }
60  bool operator==(const Deadline &Other) const {
61  return (Type == Other.Type) && (Type != Finite || Time == Other.Time);
62  }
63 
64 private:
65  enum Type { Zero, Infinite, Finite };
66 
67  Deadline(enum Type Type) : Type(Type) {}
68  enum Type Type;
69  std::chrono::steady_clock::time_point Time;
70 };
71 
72 /// Makes a deadline from a timeout in seconds. None means wait forever.
73 Deadline timeoutSeconds(llvm::Optional<double> Seconds);
74 /// Wait once on CV for the specified duration.
75 void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
76  Deadline D);
77 /// Waits on a condition variable until F() is true or D expires.
78 template <typename Func>
79 LLVM_NODISCARD bool wait(std::unique_lock<std::mutex> &Lock,
80  std::condition_variable &CV, Deadline D, Func F) {
81  while (!F()) {
82  if (D.expired())
83  return false;
84  wait(Lock, CV, D);
85  }
86  return true;
87 }
88 
89 /// A threadsafe flag that is initially clear.
90 class Notification {
91 public:
92  // Sets the flag. No-op if already set.
93  void notify();
94  // Blocks until flag is set.
95  void wait() const { (void)wait(Deadline::infinity()); }
96  LLVM_NODISCARD bool wait(Deadline D) const;
97 
98 private:
99  bool Notified = false;
100  mutable std::condition_variable CV;
101  mutable std::mutex Mu;
102 };
103 
104 /// Runs tasks on separate (detached) threads and wait for all tasks to finish.
105 /// Objects that need to spawn threads can own an AsyncTaskRunner to ensure they
106 /// all complete on destruction.
108 public:
109  /// Destructor waits for all pending tasks to finish.
111 
112  void wait() const { (void)wait(Deadline::infinity()); }
113  LLVM_NODISCARD bool wait(Deadline D) const;
114  // The name is used for tracing and debugging (e.g. to name a spawned thread).
115  void runAsync(const llvm::Twine &Name, llvm::unique_function<void()> Action);
116 
117 private:
118  mutable std::mutex Mutex;
119  mutable std::condition_variable TasksReachedZero;
120  std::size_t InFlightTasks = 0;
121 };
122 
123 /// Runs \p Action asynchronously with a new std::thread. The context will be
124 /// propagated.
125 template <typename T>
126 std::future<T> runAsync(llvm::unique_function<T()> Action) {
127  return std::async(
128  std::launch::async,
129  [](llvm::unique_function<T()> &&Action, Context Ctx) {
130  WithContext WithCtx(std::move(Ctx));
131  return Action();
132  },
133  std::move(Action), Context::current().clone());
134 }
135 
136 /// Memoize is a cache to store and reuse computation results based on a key.
137 ///
138 /// Memoize<DenseMap<int, bool>> PrimeCache;
139 /// for (int I : RepetitiveNumbers)
140 /// if (PrimeCache.get(I, [&] { return expensiveIsPrime(I); }))
141 /// llvm::errs() << "Prime: " << I << "\n";
142 ///
143 /// The computation will only be run once for each key.
144 /// This class is threadsafe. Concurrent calls for the same key may run the
145 /// computation multiple times, but each call will return the same result.
146 template <typename Container> class Memoize {
147  mutable Container Cache;
148  std::unique_ptr<std::mutex> Mu;
149 
150 public:
151  Memoize() : Mu(std::make_unique<std::mutex>()) {}
152 
153  template <typename T, typename Func>
154  typename Container::mapped_type get(T &&Key, Func Compute) const {
155  {
156  std::lock_guard<std::mutex> Lock(*Mu);
157  auto It = Cache.find(Key);
158  if (It != Cache.end())
159  return It->second;
160  }
161  // Don't hold the mutex while computing.
162  auto V = Compute();
163  {
164  std::lock_guard<std::mutex> Lock(*Mu);
165  auto R = Cache.try_emplace(std::forward<T>(Key), V);
166  // Insert into cache may fail if we raced with another thread.
167  if (!R.second)
168  return R.first->second; // Canonical value, from other thread.
169  }
170  return V;
171  }
172 };
173 
174 /// Used to guard an operation that should run at most every N seconds.
175 ///
176 /// Usage:
177 /// mutable PeriodicThrottler ShouldLog(std::chrono::seconds(1));
178 /// void calledFrequently() {
179 /// if (ShouldLog())
180 /// log("this is not spammy");
181 /// }
182 ///
183 /// This class is threadsafe. If multiple threads are involved, then the guarded
184 /// operation still needs to be threadsafe!
186  using Stopwatch = std::chrono::steady_clock;
187  using Rep = Stopwatch::duration::rep;
188 
189  Rep Period;
190  std::atomic<Rep> Next;
191 
192 public:
193  /// If Period is zero, the throttler will return true every time.
194  PeriodicThrottler(Stopwatch::duration Period, Stopwatch::duration Delay = {})
195  : Period(Period.count()),
196  Next((Stopwatch::now() + Delay).time_since_epoch().count()) {}
197 
198  /// Returns whether the operation should run at this time.
199  /// operator() is safe to call concurrently.
200  bool operator()();
201 };
202 
203 } // namespace clangd
204 } // namespace clang
205 #endif
clang::clangd::Semaphore::unlock
void unlock()
Definition: Threading.cpp:64
clang::clangd::runAsync
std::future< T > runAsync(llvm::unique_function< T()> Action)
Runs Action asynchronously with a new std::thread.
Definition: Threading.h:126
clang::clangd::timeoutSeconds
Deadline timeoutSeconds(llvm::Optional< double > Seconds)
Makes a deadline from a timeout in seconds. None means wait forever.
Definition: Threading.cpp:112
clang::clangd::Deadline::infinity
static Deadline infinity()
Definition: Threading.h:50
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::clangd::AsyncTaskRunner::wait
void wait() const
Definition: Threading.h:112
clang::clangd::Context::current
static const Context & current()
Returns the context for the current thread, creating it if needed.
Definition: Context.cpp:27
clang::clangd::Context::clone
Context clone() const
Clone this context object.
Definition: Context.cpp:20
clang::clangd::Notification::wait
void wait() const
Definition: Threading.h:95
clang::clangd::Semaphore::try_lock
bool try_lock()
Definition: Threading.cpp:44
Ctx
Context Ctx
Definition: TUScheduler.cpp:495
clang::clangd::PeriodicThrottler::PeriodicThrottler
PeriodicThrottler(Stopwatch::duration Period, Stopwatch::duration Delay={})
If Period is zero, the throttler will return true every time.
Definition: Threading.h:194
clang::clangd::PeriodicThrottler
Used to guard an operation that should run at most every N seconds.
Definition: Threading.h:185
clang::clangd::AsyncTaskRunner::~AsyncTaskRunner
~AsyncTaskRunner()
Destructor waits for all pending tasks to finish.
Definition: Threading.cpp:72
clang::clangd::Semaphore
Limits the number of threads that can acquire the lock at the same time.
Definition: Threading.h:28
clang::clangd::Deadline
A point in time we can wait for.
Definition: Threading.h:45
clang::clangd::Semaphore::Semaphore
Semaphore(std::size_t MaxLocks)
Definition: Threading.cpp:42
clang::clangd::wait
void wait(std::unique_lock< std::mutex > &Lock, std::condition_variable &CV, Deadline D)
Wait once on CV for the specified duration.
Definition: Threading.cpp:120
clang::clangd::Notification
A threadsafe flag that is initially clear.
Definition: Threading.h:90
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
clang::clangd::PeriodicThrottler::operator()
bool operator()()
Returns whether the operation should run at this time.
Definition: Threading.cpp:129
clang::clangd::Deadline::time
std::chrono::steady_clock::time_point time() const
Definition: Threading.h:52
clang::clangd::Memoize::get
Container::mapped_type get(T &&Key, Func Compute) const
Definition: Threading.h:154
clang::clangd::Key
Values in a Context are indexed by typed keys.
Definition: Context.h:40
Name
Token Name
Definition: MacroToEnumCheck.cpp:89
clang::clangd::Semaphore::lock
void lock()
Definition: Threading.cpp:53
clang::clangd::WithContext
WithContext replaces Context::current() with a provided scope.
Definition: Context.h:187
clang::clangd::Deadline::Deadline
Deadline(std::chrono::steady_clock::time_point Time)
Definition: Threading.h:47
clang::clangd::Notification::notify
void notify()
Definition: Threading.cpp:27
clang::clangd::Deadline::expired
bool expired() const
Definition: Threading.h:56
clang::clangd::Memoize
Memoize is a cache to store and reuse computation results based on a key.
Definition: Threading.h:146
clang::clangd::AsyncTaskRunner::runAsync
void runAsync(const llvm::Twine &Name, llvm::unique_function< void()> Action)
Definition: Threading.cpp:80
clang::clangd::Deadline::operator==
bool operator==(const Deadline &Other) const
Definition: Threading.h:60
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::AsyncTaskRunner
Runs tasks on separate (detached) threads and wait for all tasks to finish.
Definition: Threading.h:107
clang::clangd::Deadline::zero
static Deadline zero()
Definition: Threading.h:49
clang::clangd::Memoize::Memoize
Memoize()
Definition: Threading.h:151
clang::clangd::Context
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition: Context.h:69
Context.h
Action
FieldAction Action
Definition: MemberwiseConstructor.cpp:261