clang-tools 8.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 <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
19 void Notification::notify() {
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
34 bool Semaphore::try_lock() {
35 std::unique_lock<std::mutex> Lock(Mutex);
36 if (FreeSlots > 0) {
37 --FreeSlots;
38 return true;
39 }
40 return false;
41 }
42
43 void Semaphore::lock() {
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
54 void Semaphore::unlock() {
55 std::unique_lock<std::mutex> Lock(Mutex);
56 ++FreeSlots;
57 Lock.unlock();
58
59 SlotsChanged.notify_one();
60 }
61
62 AsyncTaskRunner::~AsyncTaskRunner() { wait(); }
63
64 bool AsyncTaskRunner::wait(Deadline D) const {
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 static std::atomic<bool> AvoidThreadStarvation = {false};
117
118 void setCurrentThreadPriority(ThreadPriority Priority) {
119 // Some *really* old glibcs are missing SCHED_IDLE.
120 #if defined(__linux__) && defined(SCHED_IDLE)
121 sched_param priority;
122 priority.sched_priority = 0;
123 pthread_setschedparam(
124 pthread_self(),
125 Priority == ThreadPriority::Low && !AvoidThreadStarvation ? SCHED_IDLE
126 : SCHED_OTHER,
127 &priority);
128 #elif defined(__APPLE__)
129 // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getpriority.2.html
130 setpriority(PRIO_DARWIN_THREAD, 0,
131 Priority == ThreadPriority::Low && !AvoidThreadStarvation
132 ? PRIO_DARWIN_BG
133 : 0);
134 #elif defined(_WIN32)
135 SetThreadPriority(GetCurrentThread(),
136 Priority == ThreadPriority::Low && !AvoidThreadStarvation
137 ? THREAD_MODE_BACKGROUND_BEGIN
138 : THREAD_MODE_BACKGROUND_END);
139 #endif
140 }
141
142 void preventThreadStarvationInTests() { AvoidThreadStarvation = true; }
143
144 } // namespace clangd
145 } // namespace clang
clang::clangd::AsyncTaskRunner::~AsyncTaskRunner
~AsyncTaskRunner()
Destructor waits for all pending tasks to finish.
Definition: Threading.cpp:62
clang::clangd::Semaphore::unlock
void unlock()
Definition: Threading.cpp:54
Trace.h
clang::clangd::Semaphore::try_lock
bool try_lock()
Definition: Threading.cpp:34
clang::clangd::preventThreadStarvationInTests
void preventThreadStarvationInTests()
Definition: Threading.cpp:142
clang::clangd::ThreadPriority
ThreadPriority
Definition: Threading.h:121
clang::clangd::AvoidThreadStarvation
static std::atomic< bool > AvoidThreadStarvation
Definition: Threading.cpp:116
clang::clangd::Semaphore::Semaphore
Semaphore(std::size_t MaxLocks)
Definition: Threading.cpp:32
clang::clangd::AsyncTaskRunner::wait
void wait() const
Definition: Threading.h:110
clang::clangd::Semaphore::lock
void lock()
Definition: Threading.cpp:43
clang::clangd::AsyncTaskRunner::runAsync
void runAsync(const llvm::Twine &Name, llvm::unique_function< void()> Action)
Definition: Threading.cpp:70
clang::clangd::Deadline::infinity
static Deadline infinity()
Definition: Threading.h:63
Action
llvm::unique_function< void()> Action
Definition: TUScheduler.cpp:221
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:28
D
const Decl * D
Definition: XRefs.cpp:79
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:107
clang::clangd::Notification::notify
void notify()
Definition: Threading.cpp:19
clang::clangd::setCurrentThreadPriority
void setCurrentThreadPriority(ThreadPriority Priority)
Definition: Threading.cpp:118
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
clang::clangd::Deadline::zero
static Deadline zero()
Definition: Threading.h:62
clang::clangd::timeoutSeconds
Deadline timeoutSeconds(llvm::Optional< double > Seconds)
Makes a deadline from a timeout in seconds. None means wait forever.
Definition: Threading.cpp:99
clang::clangd::Deadline
A point in time we can wait for.
Definition: Threading.h:58
clang::clangd::Notification::wait
void wait() const
Definition: Threading.cpp:27
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:83
clang::clangd::Deadline::time
std::chrono::steady_clock::time_point time() const
Definition: Threading.h:65
clang::clangd::ThreadPriority::Low
Threading.h