mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-19 11:35:51 -04:00

Summary: LSP has asynchronous semantics, being able to block on an async operation completing is unneccesary and leads to tighter coupling with the threading. In practice only tests depend on this, so we add a general-purpose "block until idle" function to the scheduler which will work for all operations. To get this working, fix a latent condition-variable bug in ASTWorker, and make AsyncTaskRunner const-correct. Reviewers: ilya-biryukov Subscribers: klimek, jkorous-apple, ioeric, cfe-commits Differential Revision: https://reviews.llvm.org/D43127 llvm-svn: 324990
74 lines
1.9 KiB
C++
74 lines
1.9 KiB
C++
#include "Threading.h"
|
|
#include "llvm/ADT/ScopeExit.h"
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
#include "llvm/Support/Threading.h"
|
|
#include <thread>
|
|
|
|
namespace clang {
|
|
namespace clangd {
|
|
|
|
CancellationFlag::CancellationFlag()
|
|
: WasCancelled(std::make_shared<std::atomic<bool>>(false)) {}
|
|
|
|
Semaphore::Semaphore(std::size_t MaxLocks) : FreeSlots(MaxLocks) {}
|
|
|
|
void Semaphore::lock() {
|
|
std::unique_lock<std::mutex> Lock(Mutex);
|
|
SlotsChanged.wait(Lock, [&]() { return FreeSlots > 0; });
|
|
--FreeSlots;
|
|
}
|
|
|
|
void Semaphore::unlock() {
|
|
std::unique_lock<std::mutex> Lock(Mutex);
|
|
++FreeSlots;
|
|
Lock.unlock();
|
|
|
|
SlotsChanged.notify_one();
|
|
}
|
|
|
|
AsyncTaskRunner::~AsyncTaskRunner() { wait(); }
|
|
|
|
bool AsyncTaskRunner::wait(Deadline D) const {
|
|
std::unique_lock<std::mutex> Lock(Mutex);
|
|
return clangd::wait(Lock, TasksReachedZero, D,
|
|
[&] { return InFlightTasks == 0; });
|
|
}
|
|
|
|
void AsyncTaskRunner::runAsync(UniqueFunction<void()> Action) {
|
|
{
|
|
std::lock_guard<std::mutex> Lock(Mutex);
|
|
++InFlightTasks;
|
|
}
|
|
|
|
auto CleanupTask = llvm::make_scope_exit([this]() {
|
|
std::lock_guard<std::mutex> Lock(Mutex);
|
|
int NewTasksCnt = --InFlightTasks;
|
|
if (NewTasksCnt == 0) {
|
|
// Note: we can't unlock here because we don't want the object to be
|
|
// destroyed before we notify.
|
|
TasksReachedZero.notify_one();
|
|
}
|
|
});
|
|
|
|
std::thread(
|
|
[](decltype(Action) Action, decltype(CleanupTask)) {
|
|
Action();
|
|
// Make sure function stored by Action is destroyed before CleanupTask
|
|
// is run.
|
|
Action = nullptr;
|
|
},
|
|
std::move(Action), std::move(CleanupTask))
|
|
.detach();
|
|
}
|
|
|
|
Deadline timeoutSeconds(llvm::Optional<double> Seconds) {
|
|
using namespace std::chrono;
|
|
if (!Seconds)
|
|
return llvm::None;
|
|
return steady_clock::now() +
|
|
duration_cast<steady_clock::duration>(duration<double>(*Seconds));
|
|
}
|
|
|
|
} // namespace clangd
|
|
} // namespace clang
|