Line data Source code
1 : //===--- ThreadPool.h --------------------------------------------*- C++-*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 :
10 : #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_THREADING_H
11 : #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_THREADING_H
12 :
13 : #include "Context.h"
14 : #include "Function.h"
15 : #include "llvm/ADT/Twine.h"
16 : #include <cassert>
17 : #include <condition_variable>
18 : #include <memory>
19 : #include <mutex>
20 : #include <vector>
21 :
22 : namespace clang {
23 : namespace clangd {
24 :
25 : /// A threadsafe flag that is initially clear.
26 0 : class Notification {
27 : public:
28 : // Sets the flag. No-op if already set.
29 : void notify();
30 : // Blocks until flag is set.
31 : void wait() const;
32 :
33 : private:
34 : bool Notified = false;
35 : mutable std::condition_variable CV;
36 : mutable std::mutex Mu;
37 : };
38 :
39 : /// Limits the number of threads that can acquire the lock at the same time.
40 : class Semaphore {
41 : public:
42 : Semaphore(std::size_t MaxLocks);
43 :
44 : void lock();
45 : void unlock();
46 :
47 : private:
48 : std::mutex Mutex;
49 : std::condition_variable SlotsChanged;
50 : std::size_t FreeSlots;
51 : };
52 :
53 : /// A point in time we can wait for.
54 : /// Can be zero (don't wait) or infinity (wait forever).
55 : /// (Not time_point::max(), because many std::chrono implementations overflow).
56 : class Deadline {
57 : public:
58 : Deadline(std::chrono::steady_clock::time_point Time)
59 : : Type(Finite), Time(Time) {}
60 : static Deadline zero() { return Deadline(Zero); }
61 : static Deadline infinity() { return Deadline(Infinite); }
62 :
63 : std::chrono::steady_clock::time_point time() const {
64 : assert(Type == Finite);
65 : return Time;
66 : }
67 : bool expired() const {
68 : return (Type == Zero) ||
69 : (Type == Finite && Time < std::chrono::steady_clock::now());
70 : }
71 : bool operator==(const Deadline &Other) const {
72 : return (Type == Other.Type) && (Type != Finite || Time == Other.Time);
73 : }
74 :
75 : private:
76 : enum Type { Zero, Infinite, Finite };
77 :
78 : Deadline(enum Type Type) : Type(Type) {}
79 : enum Type Type;
80 : std::chrono::steady_clock::time_point Time;
81 : };
82 :
83 : /// Makes a deadline from a timeout in seconds. None means wait forever.
84 : Deadline timeoutSeconds(llvm::Optional<double> Seconds);
85 : /// Wait once on CV for the specified duration.
86 : void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
87 : Deadline D);
88 : /// Waits on a condition variable until F() is true or D expires.
89 : template <typename Func>
90 : LLVM_NODISCARD bool wait(std::unique_lock<std::mutex> &Lock,
91 : std::condition_variable &CV, Deadline D, Func F) {
92 : while (!F()) {
93 : if (D.expired())
94 : return false;
95 : wait(Lock, CV, D);
96 : }
97 : return true;
98 : }
99 :
100 : /// Runs tasks on separate (detached) threads and wait for all tasks to finish.
101 : /// Objects that need to spawn threads can own an AsyncTaskRunner to ensure they
102 : /// all complete on destruction.
103 0 : class AsyncTaskRunner {
104 : public:
105 : /// Destructor waits for all pending tasks to finish.
106 : ~AsyncTaskRunner();
107 :
108 0 : void wait() const { (void)wait(Deadline::infinity()); }
109 : LLVM_NODISCARD bool wait(Deadline D) const;
110 : // The name is used for tracing and debugging (e.g. to name a spawned thread).
111 : void runAsync(const llvm::Twine &Name, llvm::unique_function<void()> Action);
112 :
113 : private:
114 : mutable std::mutex Mutex;
115 : mutable std::condition_variable TasksReachedZero;
116 : std::size_t InFlightTasks = 0;
117 : };
118 : } // namespace clangd
119 : } // namespace clang
120 : #endif
|