2018-01-31 16:51:16 +08:00
|
|
|
//===--- ThreadPool.h --------------------------------------------*- C++-*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_THREADING_H
|
|
|
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_THREADING_H
|
|
|
|
|
[clangd] Pass Context implicitly using TLS.
Summary:
Instead of passing Context explicitly around, we now have a thread-local
Context object `Context::current()` which is an implicit argument to
every function.
Most manipulation of this should use the WithContextValue helper, which
augments the current Context to add a single KV pair, and restores the
old context on destruction.
Advantages are:
- less boilerplate in functions that just propagate contexts
- reading most code doesn't require understanding context at all, and
using context as values in fewer places still
- fewer options to pass the "wrong" context when it changes within a
scope (e.g. when using Span)
- contexts pass through interfaces we can't modify, such as VFS
- propagating contexts across threads was slightly tricky (e.g.
copy vs move, no move-init in lambdas), and is now encapsulated in
the threadpool
Disadvantages are all the usual TLS stuff - hidden magic, and
potential for higher memory usage on threads that don't use the
context. (In practice, it's just one pointer)
Reviewers: ilya-biryukov
Subscribers: klimek, jkorous-apple, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D42517
llvm-svn: 323872
2018-01-31 21:40:48 +08:00
|
|
|
#include "Context.h"
|
2018-01-31 16:51:16 +08:00
|
|
|
#include "Function.h"
|
2018-02-19 17:56:28 +08:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2018-02-08 15:37:35 +08:00
|
|
|
#include <cassert>
|
2018-01-31 16:51:16 +08:00
|
|
|
#include <condition_variable>
|
2018-02-08 15:37:35 +08:00
|
|
|
#include <memory>
|
2018-01-31 16:51:16 +08:00
|
|
|
#include <mutex>
|
2018-10-30 20:13:27 +08:00
|
|
|
#include <thread>
|
2018-01-31 16:51:16 +08:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
2018-02-08 15:37:35 +08:00
|
|
|
|
2018-02-22 21:11:12 +08:00
|
|
|
/// A threadsafe flag that is initially clear.
|
|
|
|
class Notification {
|
2018-01-31 16:51:16 +08:00
|
|
|
public:
|
2018-02-22 21:11:12 +08:00
|
|
|
// Sets the flag. No-op if already set.
|
|
|
|
void notify();
|
|
|
|
// Blocks until flag is set.
|
|
|
|
void wait() const;
|
2018-01-31 16:51:16 +08:00
|
|
|
|
2018-02-08 15:37:35 +08:00
|
|
|
private:
|
2018-02-22 21:11:12 +08:00
|
|
|
bool Notified = false;
|
|
|
|
mutable std::condition_variable CV;
|
|
|
|
mutable std::mutex Mu;
|
2018-02-08 15:37:35 +08:00
|
|
|
};
|
2018-02-06 23:53:42 +08:00
|
|
|
|
2018-02-08 15:37:35 +08:00
|
|
|
/// Limits the number of threads that can acquire the lock at the same time.
|
|
|
|
class Semaphore {
|
|
|
|
public:
|
|
|
|
Semaphore(std::size_t MaxLocks);
|
|
|
|
|
|
|
|
void lock();
|
|
|
|
void unlock();
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::mutex Mutex;
|
|
|
|
std::condition_variable SlotsChanged;
|
|
|
|
std::size_t FreeSlots;
|
|
|
|
};
|
|
|
|
|
2018-03-02 16:56:37 +08:00
|
|
|
/// A point in time we can wait for.
|
|
|
|
/// Can be zero (don't wait) or infinity (wait forever).
|
2018-02-13 16:59:23 +08:00
|
|
|
/// (Not time_point::max(), because many std::chrono implementations overflow).
|
2018-03-02 16:56:37 +08:00
|
|
|
class Deadline {
|
|
|
|
public:
|
|
|
|
Deadline(std::chrono::steady_clock::time_point Time)
|
|
|
|
: Type(Finite), Time(Time) {}
|
|
|
|
static Deadline zero() { return Deadline(Zero); }
|
|
|
|
static Deadline infinity() { return Deadline(Infinite); }
|
|
|
|
|
|
|
|
std::chrono::steady_clock::time_point time() const {
|
|
|
|
assert(Type == Finite);
|
|
|
|
return Time;
|
|
|
|
}
|
|
|
|
bool expired() const {
|
|
|
|
return (Type == Zero) ||
|
|
|
|
(Type == Finite && Time < std::chrono::steady_clock::now());
|
|
|
|
}
|
|
|
|
bool operator==(const Deadline &Other) const {
|
|
|
|
return (Type == Other.Type) && (Type != Finite || Time == Other.Time);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
enum Type { Zero, Infinite, Finite };
|
|
|
|
|
|
|
|
Deadline(enum Type Type) : Type(Type) {}
|
|
|
|
enum Type Type;
|
|
|
|
std::chrono::steady_clock::time_point Time;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Makes a deadline from a timeout in seconds. None means wait forever.
|
2018-02-13 16:59:23 +08:00
|
|
|
Deadline timeoutSeconds(llvm::Optional<double> Seconds);
|
2018-03-02 16:56:37 +08:00
|
|
|
/// Wait once on CV for the specified duration.
|
|
|
|
void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
|
|
|
|
Deadline D);
|
2018-02-13 16:59:23 +08:00
|
|
|
/// Waits on a condition variable until F() is true or D expires.
|
|
|
|
template <typename Func>
|
|
|
|
LLVM_NODISCARD bool wait(std::unique_lock<std::mutex> &Lock,
|
|
|
|
std::condition_variable &CV, Deadline D, Func F) {
|
2018-03-02 16:56:37 +08:00
|
|
|
while (!F()) {
|
|
|
|
if (D.expired())
|
|
|
|
return false;
|
|
|
|
wait(Lock, CV, D);
|
|
|
|
}
|
2018-02-13 16:59:23 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-08 15:37:35 +08:00
|
|
|
/// Runs tasks on separate (detached) threads and wait for all tasks to finish.
|
|
|
|
/// Objects that need to spawn threads can own an AsyncTaskRunner to ensure they
|
|
|
|
/// all complete on destruction.
|
|
|
|
class AsyncTaskRunner {
|
|
|
|
public:
|
|
|
|
/// Destructor waits for all pending tasks to finish.
|
|
|
|
~AsyncTaskRunner();
|
|
|
|
|
2018-03-02 16:56:37 +08:00
|
|
|
void wait() const { (void)wait(Deadline::infinity()); }
|
2018-02-13 16:59:23 +08:00
|
|
|
LLVM_NODISCARD bool wait(Deadline D) const;
|
2018-02-19 17:56:28 +08:00
|
|
|
// The name is used for tracing and debugging (e.g. to name a spawned thread).
|
2018-07-27 00:13:52 +08:00
|
|
|
void runAsync(const llvm::Twine &Name, llvm::unique_function<void()> Action);
|
2018-01-31 16:51:16 +08:00
|
|
|
|
|
|
|
private:
|
2018-02-13 16:59:23 +08:00
|
|
|
mutable std::mutex Mutex;
|
|
|
|
mutable std::condition_variable TasksReachedZero;
|
2018-02-08 15:37:35 +08:00
|
|
|
std::size_t InFlightTasks = 0;
|
2018-01-31 16:51:16 +08:00
|
|
|
};
|
2018-10-30 20:13:27 +08:00
|
|
|
|
|
|
|
enum class ThreadPriority {
|
|
|
|
Low = 0,
|
|
|
|
Normal = 1,
|
|
|
|
};
|
|
|
|
void setThreadPriority(std::thread &T, ThreadPriority Priority);
|
2018-11-27 20:09:13 +08:00
|
|
|
// Avoid the use of scheduler policies that may starve low-priority threads.
|
|
|
|
// This prevents tests from timing out on loaded systems.
|
|
|
|
// Affects subsequent setThreadPriority() calls.
|
|
|
|
void preventThreadStarvationInTests();
|
2018-10-30 20:13:27 +08:00
|
|
|
|
2018-01-31 16:51:16 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|
|
|
|
#endif
|