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