clang-tools  7.0.0
Threading.cpp
Go to the documentation of this file.
1 #include "Threading.h"
2 #include "Trace.h"
3 #include "llvm/ADT/ScopeExit.h"
4 #include "llvm/Support/FormatVariadic.h"
5 #include "llvm/Support/Threading.h"
6 #include <thread>
7 
8 namespace clang {
9 namespace clangd {
10 
12  {
13  std::lock_guard<std::mutex> Lock(Mu);
14  Notified = true;
15  }
16  CV.notify_all();
17 }
18 
19 void Notification::wait() const {
20  std::unique_lock<std::mutex> Lock(Mu);
21  CV.wait(Lock, [this] { return Notified; });
22 }
23 
24 Semaphore::Semaphore(std::size_t MaxLocks) : FreeSlots(MaxLocks) {}
25 
27  trace::Span Span("WaitForFreeSemaphoreSlot");
28  // trace::Span can also acquire locks in ctor and dtor, we make sure it
29  // happens when Semaphore's own lock is not held.
30  {
31  std::unique_lock<std::mutex> Lock(Mutex);
32  SlotsChanged.wait(Lock, [&]() { return FreeSlots > 0; });
33  --FreeSlots;
34  }
35 }
36 
38  std::unique_lock<std::mutex> Lock(Mutex);
39  ++FreeSlots;
40  Lock.unlock();
41 
42  SlotsChanged.notify_one();
43 }
44 
46 
48  std::unique_lock<std::mutex> Lock(Mutex);
49  return clangd::wait(Lock, TasksReachedZero, D,
50  [&] { return InFlightTasks == 0; });
51 }
52 
53 void AsyncTaskRunner::runAsync(const llvm::Twine &Name,
54  llvm::unique_function<void()> Action) {
55  {
56  std::lock_guard<std::mutex> Lock(Mutex);
57  ++InFlightTasks;
58  }
59 
60  auto CleanupTask = llvm::make_scope_exit([this]() {
61  std::lock_guard<std::mutex> Lock(Mutex);
62  int NewTasksCnt = --InFlightTasks;
63  if (NewTasksCnt == 0) {
64  // Note: we can't unlock here because we don't want the object to be
65  // destroyed before we notify.
66  TasksReachedZero.notify_one();
67  }
68  });
69 
70  std::thread(
71  [](std::string Name, decltype(Action) Action, decltype(CleanupTask)) {
72  llvm::set_thread_name(Name);
73  Action();
74  // Make sure function stored by Action is destroyed before CleanupTask
75  // is run.
76  Action = nullptr;
77  },
78  Name.str(), std::move(Action), std::move(CleanupTask))
79  .detach();
80 }
81 
82 Deadline timeoutSeconds(llvm::Optional<double> Seconds) {
83  using namespace std::chrono;
84  if (!Seconds)
85  return Deadline::infinity();
86  return steady_clock::now() +
87  duration_cast<steady_clock::duration>(duration<double>(*Seconds));
88 }
89 
90 void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
91  Deadline D) {
92  if (D == Deadline::zero())
93  return;
94  if (D == Deadline::infinity())
95  return CV.wait(Lock);
96  CV.wait_until(Lock, D.time());
97 }
98 
99 } // namespace clangd
100 } // namespace clang
llvm::StringRef Name
~AsyncTaskRunner()
Destructor waits for all pending tasks to finish.
Definition: Threading.cpp:45
Semaphore(std::size_t MaxLocks)
Definition: Threading.cpp:24
void runAsync(const llvm::Twine &Name, llvm::unique_function< void()> Action)
Definition: Threading.cpp:53
static Deadline infinity()
Definition: Threading.h:61
llvm::unique_function< void()> Action
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:90
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static Deadline zero()
Definition: Threading.h:60
Deadline timeoutSeconds(llvm::Optional< double > Seconds)
Makes a deadline from a timeout in seconds. None means wait forever.
Definition: Threading.cpp:82
A point in time we can wait for.
Definition: Threading.h:56
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:83
std::chrono::steady_clock::time_point time() const
Definition: Threading.h:63