clang-tools  15.0.0git
Threading.cpp
Go to the documentation of this file.
1 //===--- Threading.cpp - Abstractions for multithreading ------------------===//
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 #include "support/Threading.h"
10 #include "support/Trace.h"
11 #include "llvm/ADT/ScopeExit.h"
12 #include "llvm/Support/Threading.h"
13 #include "llvm/Support/thread.h"
14 #include <atomic>
15 #include <thread>
16 #ifdef __USE_POSIX
17 #include <pthread.h>
18 #elif defined(__APPLE__)
19 #include <sys/resource.h>
20 #elif defined(_WIN32)
21 #include <windows.h>
22 #endif
23 
24 namespace clang {
25 namespace clangd {
26 
28  {
29  std::lock_guard<std::mutex> Lock(Mu);
30  Notified = true;
31  // Broadcast with the lock held. This ensures that it's safe to destroy
32  // a Notification after wait() returns, even from another thread.
33  CV.notify_all();
34  }
35 }
36 
38  std::unique_lock<std::mutex> Lock(Mu);
39  return clangd::wait(Lock, CV, D, [&] { return Notified; });
40 }
41 
42 Semaphore::Semaphore(std::size_t MaxLocks) : FreeSlots(MaxLocks) {}
43 
45  std::unique_lock<std::mutex> Lock(Mutex);
46  if (FreeSlots > 0) {
47  --FreeSlots;
48  return true;
49  }
50  return false;
51 }
52 
54  trace::Span Span("WaitForFreeSemaphoreSlot");
55  // trace::Span can also acquire locks in ctor and dtor, we make sure it
56  // happens when Semaphore's own lock is not held.
57  {
58  std::unique_lock<std::mutex> Lock(Mutex);
59  SlotsChanged.wait(Lock, [&]() { return FreeSlots > 0; });
60  --FreeSlots;
61  }
62 }
63 
65  std::unique_lock<std::mutex> Lock(Mutex);
66  ++FreeSlots;
67  Lock.unlock();
68 
69  SlotsChanged.notify_one();
70 }
71 
73 
75  std::unique_lock<std::mutex> Lock(Mutex);
76  return clangd::wait(Lock, TasksReachedZero, D,
77  [&] { return InFlightTasks == 0; });
78 }
79 
80 void AsyncTaskRunner::runAsync(const llvm::Twine &Name,
81  llvm::unique_function<void()> Action) {
82  {
83  std::lock_guard<std::mutex> Lock(Mutex);
84  ++InFlightTasks;
85  }
86 
87  auto CleanupTask = llvm::make_scope_exit([this]() {
88  std::lock_guard<std::mutex> Lock(Mutex);
89  int NewTasksCnt = --InFlightTasks;
90  if (NewTasksCnt == 0) {
91  // Note: we can't unlock here because we don't want the object to be
92  // destroyed before we notify.
93  TasksReachedZero.notify_one();
94  }
95  });
96 
97  auto Task = [Name = Name.str(), Action = std::move(Action),
98  Cleanup = std::move(CleanupTask)]() mutable {
99  llvm::set_thread_name(Name);
100  Action();
101  // Make sure function stored by ThreadFunc is destroyed before Cleanup runs.
102  Action = nullptr;
103  };
104 
105  // Ensure our worker threads have big enough stacks to run clang.
106  llvm::thread Thread(
107  /*clang::DesiredStackSize*/ llvm::Optional<unsigned>(8 << 20),
108  std::move(Task));
109  Thread.detach();
110 }
111 
112 Deadline timeoutSeconds(llvm::Optional<double> Seconds) {
113  using namespace std::chrono;
114  if (!Seconds)
115  return Deadline::infinity();
116  return steady_clock::now() +
117  duration_cast<steady_clock::duration>(duration<double>(*Seconds));
118 }
119 
120 void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
121  Deadline D) {
122  if (D == Deadline::zero())
123  return;
124  if (D == Deadline::infinity())
125  return CV.wait(Lock);
126  CV.wait_until(Lock, D.time());
127 }
128 
130  Rep Now = Stopwatch::now().time_since_epoch().count();
131  Rep OldNext = Next.load(std::memory_order_acquire);
132  if (Now < OldNext)
133  return false;
134  // We're ready to run (but may be racing other threads).
135  // Work out the updated target time, and run if we successfully bump it.
136  Rep NewNext = Now + Period;
137  return Next.compare_exchange_strong(OldNext, NewNext,
138  std::memory_order_acq_rel);
139 }
140 
141 } // namespace clangd
142 } // namespace clang
clang::clangd::Semaphore::unlock
void unlock()
Definition: Threading.cpp:64
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
clang::clangd::AsyncTaskRunner::wait
void wait() const
Definition: Threading.h:112
clang::clangd::Notification::wait
void wait() const
Definition: Threading.h:95
clang::clangd::Semaphore::try_lock
bool try_lock()
Definition: Threading.cpp:44
Trace.h
clang::clangd::AsyncTaskRunner::~AsyncTaskRunner
~AsyncTaskRunner()
Destructor waits for all pending tasks to finish.
Definition: Threading.cpp:72
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
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
Threading.h
Name
Token Name
Definition: MacroToEnumCheck.cpp:89
clang::clangd::Semaphore::lock
void lock()
Definition: Threading.cpp:53
clang::clangd::Notification::notify
void notify()
Definition: Threading.cpp:27
clang::clangd::AsyncTaskRunner::runAsync
void runAsync(const llvm::Twine &Name, llvm::unique_function< void()> Action)
Definition: Threading.cpp:80
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::Deadline::zero
static Deadline zero()
Definition: Threading.h:49
Action
FieldAction Action
Definition: MemberwiseConstructor.cpp:261
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:143