clang-tools  11.0.0
Threading.cpp
Go to the documentation of this file.
1 #include "support/Threading.h"
2 #include "support/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  // Broadcast with the lock held. This ensures that it's safe to destroy
24  // a Notification after wait() returns, even from another thread.
25  CV.notify_all();
26  }
27 }
28 
29 void Notification::wait() const {
30  std::unique_lock<std::mutex> Lock(Mu);
31  CV.wait(Lock, [this] { return Notified; });
32 }
33 
34 Semaphore::Semaphore(std::size_t MaxLocks) : FreeSlots(MaxLocks) {}
35 
37  std::unique_lock<std::mutex> Lock(Mutex);
38  if (FreeSlots > 0) {
39  --FreeSlots;
40  return true;
41  }
42  return false;
43 }
44 
46  trace::Span Span("WaitForFreeSemaphoreSlot");
47  // trace::Span can also acquire locks in ctor and dtor, we make sure it
48  // happens when Semaphore's own lock is not held.
49  {
50  std::unique_lock<std::mutex> Lock(Mutex);
51  SlotsChanged.wait(Lock, [&]() { return FreeSlots > 0; });
52  --FreeSlots;
53  }
54 }
55 
57  std::unique_lock<std::mutex> Lock(Mutex);
58  ++FreeSlots;
59  Lock.unlock();
60 
61  SlotsChanged.notify_one();
62 }
63 
65 
67  std::unique_lock<std::mutex> Lock(Mutex);
68  return clangd::wait(Lock, TasksReachedZero, D,
69  [&] { return InFlightTasks == 0; });
70 }
71 
72 void AsyncTaskRunner::runAsync(const llvm::Twine &Name,
73  llvm::unique_function<void()> Action) {
74  {
75  std::lock_guard<std::mutex> Lock(Mutex);
76  ++InFlightTasks;
77  }
78 
79  auto CleanupTask = llvm::make_scope_exit([this]() {
80  std::lock_guard<std::mutex> Lock(Mutex);
81  int NewTasksCnt = --InFlightTasks;
82  if (NewTasksCnt == 0) {
83  // Note: we can't unlock here because we don't want the object to be
84  // destroyed before we notify.
85  TasksReachedZero.notify_one();
86  }
87  });
88 
89  auto Task = [Name = Name.str(), Action = std::move(Action),
90  Cleanup = std::move(CleanupTask)]() mutable {
91  llvm::set_thread_name(Name);
92  Action();
93  // Make sure function stored by ThreadFunc is destroyed before Cleanup runs.
94  Action = nullptr;
95  };
96 
97  // Ensure our worker threads have big enough stacks to run clang.
98  llvm::llvm_execute_on_thread_async(std::move(Task),
99  /*clang::DesiredStackSize*/ 8 << 20);
100 }
101 
102 Deadline timeoutSeconds(llvm::Optional<double> Seconds) {
103  using namespace std::chrono;
104  if (!Seconds)
105  return Deadline::infinity();
106  return steady_clock::now() +
107  duration_cast<steady_clock::duration>(duration<double>(*Seconds));
108 }
109 
110 void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
111  Deadline D) {
112  if (D == Deadline::zero())
113  return;
114  if (D == Deadline::infinity())
115  return CV.wait(Lock);
116  CV.wait_until(Lock, D.time());
117 }
118 
119 } // namespace clangd
120 } // namespace clang
clang::clangd::Semaphore::unlock
void unlock()
Definition: Threading.cpp:56
clang::clangd::timeoutSeconds
Deadline timeoutSeconds(llvm::Optional< double > Seconds)
Makes a deadline from a timeout in seconds. None means wait forever.
Definition: Threading.cpp:102
clang::clangd::Deadline::infinity
static Deadline infinity()
Definition: Threading.h:63
clang::clangd::AsyncTaskRunner::wait
void wait() const
Definition: Threading.h:110
clang::clangd::Notification::wait
void wait() const
Definition: Threading.cpp:29
clang::clangd::Semaphore::try_lock
bool try_lock()
Definition: Threading.cpp:36
Trace.h
Action
llvm::unique_function< void()> Action
Definition: TUScheduler.cpp:447
clang::clangd::AsyncTaskRunner::~AsyncTaskRunner
~AsyncTaskRunner()
Destructor waits for all pending tasks to finish.
Definition: Threading.cpp:64
clang::clangd::Deadline
A point in time we can wait for.
Definition: Threading.h:58
clang::clangd::Semaphore::Semaphore
Semaphore(std::size_t MaxLocks)
Definition: Threading.cpp:34
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:110
Threading.h
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::clangd::Deadline::time
std::chrono::steady_clock::time_point time() const
Definition: Threading.h:65
clang::clangd::Semaphore::lock
void lock()
Definition: Threading.cpp:45
clang::clangd::Notification::notify
void notify()
Definition: Threading.cpp:19
clang::clangd::AsyncTaskRunner::runAsync
void runAsync(const llvm::Twine &Name, llvm::unique_function< void()> Action)
Definition: Threading.cpp:72
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::Deadline::zero
static Deadline zero()
Definition: Threading.h:62
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:135