blob: 6dad841da58dd0c16cd6d8e57af352e1ae5ca3b1 [file] [log] [blame]
Ilya Biryukov75f1dd92018-01-31 08:51:16 +00001//===--- 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
Sam McCalld1a7a372018-01-31 13:40:48 +000013#include "Context.h"
Ilya Biryukov75f1dd92018-01-31 08:51:16 +000014#include "Function.h"
Sam McCallc901c5d2018-02-19 09:56:28 +000015#include "llvm/ADT/Twine.h"
Ilya Biryukov7e5ee262018-02-08 07:37:35 +000016#include <cassert>
Ilya Biryukov75f1dd92018-01-31 08:51:16 +000017#include <condition_variable>
Ilya Biryukov7e5ee262018-02-08 07:37:35 +000018#include <memory>
Ilya Biryukov75f1dd92018-01-31 08:51:16 +000019#include <mutex>
Ilya Biryukov75f1dd92018-01-31 08:51:16 +000020#include <vector>
21
22namespace clang {
23namespace clangd {
Ilya Biryukov7e5ee262018-02-08 07:37:35 +000024
Sam McCall568e17f2018-02-22 13:11:12 +000025/// A threadsafe flag that is initially clear.
26class Notification {
Ilya Biryukov75f1dd92018-01-31 08:51:16 +000027public:
Sam McCall568e17f2018-02-22 13:11:12 +000028 // Sets the flag. No-op if already set.
29 void notify();
30 // Blocks until flag is set.
31 void wait() const;
Ilya Biryukov75f1dd92018-01-31 08:51:16 +000032
33private:
Sam McCall568e17f2018-02-22 13:11:12 +000034 bool Notified = false;
35 mutable std::condition_variable CV;
36 mutable std::mutex Mu;
Ilya Biryukov7e5ee262018-02-08 07:37:35 +000037};
38
39/// Limits the number of threads that can acquire the lock at the same time.
40class Semaphore {
41public:
42 Semaphore(std::size_t MaxLocks);
43
44 void lock();
45 void unlock();
46
47private:
48 std::mutex Mutex;
49 std::condition_variable SlotsChanged;
50 std::size_t FreeSlots;
51};
52
Sam McCalld1e0deb2018-03-02 08:56:37 +000053/// A point in time we can wait for.
54/// Can be zero (don't wait) or infinity (wait forever).
Sam McCall0bb24cd2018-02-13 08:59:23 +000055/// (Not time_point::max(), because many std::chrono implementations overflow).
Sam McCalld1e0deb2018-03-02 08:56:37 +000056class Deadline {
57public:
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
75private:
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.
Sam McCall0bb24cd2018-02-13 08:59:23 +000084Deadline timeoutSeconds(llvm::Optional<double> Seconds);
Sam McCalld1e0deb2018-03-02 08:56:37 +000085/// Wait once on CV for the specified duration.
86void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
87 Deadline D);
Sam McCall0bb24cd2018-02-13 08:59:23 +000088/// Waits on a condition variable until F() is true or D expires.
89template <typename Func>
90LLVM_NODISCARD bool wait(std::unique_lock<std::mutex> &Lock,
91 std::condition_variable &CV, Deadline D, Func F) {
Sam McCalld1e0deb2018-03-02 08:56:37 +000092 while (!F()) {
93 if (D.expired())
94 return false;
95 wait(Lock, CV, D);
96 }
Sam McCall0bb24cd2018-02-13 08:59:23 +000097 return true;
98}
99
Ilya Biryukov7e5ee262018-02-08 07:37:35 +0000100/// 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.
103class AsyncTaskRunner {
104public:
105 /// Destructor waits for all pending tasks to finish.
106 ~AsyncTaskRunner();
107
Sam McCalld1e0deb2018-03-02 08:56:37 +0000108 void wait() const { (void)wait(Deadline::infinity()); }
Sam McCall0bb24cd2018-02-13 08:59:23 +0000109 LLVM_NODISCARD bool wait(Deadline D) const;
Sam McCallc901c5d2018-02-19 09:56:28 +0000110 // The name is used for tracing and debugging (e.g. to name a spawned thread).
Ilya Biryukov1d5e6402018-07-26 16:13:52 +0000111 void runAsync(const llvm::Twine &Name, llvm::unique_function<void()> Action);
Ilya Biryukov7e5ee262018-02-08 07:37:35 +0000112
113private:
Sam McCall0bb24cd2018-02-13 08:59:23 +0000114 mutable std::mutex Mutex;
115 mutable std::condition_variable TasksReachedZero;
Ilya Biryukov7e5ee262018-02-08 07:37:35 +0000116 std::size_t InFlightTasks = 0;
Ilya Biryukov75f1dd92018-01-31 08:51:16 +0000117};
118} // namespace clangd
119} // namespace clang
120#endif