[clangd][NFC] Explode ReceivedPreamble into a CV
Summary: Instead of a notification, we make use of a CV and store the boolean on LatestPreamble by converting it into an optional. Depends on D80293. Reviewers: sammccall Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D80784
This commit is contained in:
parent
55c365d247
commit
406ac49fb0
|
|
@ -76,6 +76,7 @@
|
||||||
#include "llvm/Support/Threading.h"
|
#include "llvm/Support/Threading.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
@ -458,9 +459,6 @@ private:
|
||||||
const GlobalCompilationDatabase &CDB;
|
const GlobalCompilationDatabase &CDB;
|
||||||
/// Callback invoked when preamble or main file AST is built.
|
/// Callback invoked when preamble or main file AST is built.
|
||||||
ParsingCallbacks &Callbacks;
|
ParsingCallbacks &Callbacks;
|
||||||
/// Latest build preamble for current TU.
|
|
||||||
std::shared_ptr<const PreambleData> LatestPreamble;
|
|
||||||
Notification BuiltFirstPreamble;
|
|
||||||
|
|
||||||
Semaphore &Barrier;
|
Semaphore &Barrier;
|
||||||
/// Whether the 'onMainAST' callback ran for the current FileInputs.
|
/// Whether the 'onMainAST' callback ran for the current FileInputs.
|
||||||
|
|
@ -477,10 +475,18 @@ private:
|
||||||
/// Set to true to signal run() to finish processing.
|
/// Set to true to signal run() to finish processing.
|
||||||
bool Done; /* GUARDED_BY(Mutex) */
|
bool Done; /* GUARDED_BY(Mutex) */
|
||||||
std::deque<Request> Requests; /* GUARDED_BY(Mutex) */
|
std::deque<Request> Requests; /* GUARDED_BY(Mutex) */
|
||||||
std::queue<Request> PreambleRequests; /* GUARDED_BY(Mutex) */
|
|
||||||
llvm::Optional<Request> CurrentRequest; /* GUARDED_BY(Mutex) */
|
llvm::Optional<Request> CurrentRequest; /* GUARDED_BY(Mutex) */
|
||||||
|
/// Signalled whenever a new request has been scheduled or processing of a
|
||||||
|
/// request has completed.
|
||||||
mutable std::condition_variable RequestsCV;
|
mutable std::condition_variable RequestsCV;
|
||||||
Notification ReceivedPreamble;
|
/// Latest build preamble for current TU.
|
||||||
|
/// None means no builds yet, null means there was an error while building.
|
||||||
|
/// Only written by ASTWorker's thread.
|
||||||
|
llvm::Optional<std::shared_ptr<const PreambleData>> LatestPreamble;
|
||||||
|
std::queue<Request> PreambleRequests; /* GUARDED_BY(Mutex) */
|
||||||
|
/// Signaled whenever LatestPreamble changes state or there's a new
|
||||||
|
/// PreambleRequest.
|
||||||
|
mutable std::condition_variable PreambleCV;
|
||||||
/// Guards the callback that publishes results of AST-related computations
|
/// Guards the callback that publishes results of AST-related computations
|
||||||
/// (diagnostics, highlightings) and file statuses.
|
/// (diagnostics, highlightings) and file statuses.
|
||||||
std::mutex PublishMu;
|
std::mutex PublishMu;
|
||||||
|
|
@ -643,20 +649,26 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) {
|
||||||
if (CanPublishResults)
|
if (CanPublishResults)
|
||||||
Publish();
|
Publish();
|
||||||
});
|
});
|
||||||
|
// Note that this might throw away a stale preamble that might still be
|
||||||
|
// useful, but this is how we communicate a build error.
|
||||||
|
LatestPreamble.emplace();
|
||||||
// Make sure anyone waiting for the preamble gets notified it could not be
|
// Make sure anyone waiting for the preamble gets notified it could not be
|
||||||
// built.
|
// built.
|
||||||
BuiltFirstPreamble.notify();
|
PreambleCV.notify_all();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PreamblePeer.update(std::move(Invocation), std::move(Inputs),
|
PreamblePeer.update(std::move(Invocation), std::move(Inputs),
|
||||||
std::move(CompilerInvocationDiags), WantDiags);
|
std::move(CompilerInvocationDiags), WantDiags);
|
||||||
// Block until first preamble is ready, as patching an empty preamble would
|
std::unique_lock<std::mutex> Lock(Mutex);
|
||||||
// imply rebuilding it from scratch.
|
PreambleCV.wait(Lock, [this] {
|
||||||
// This isn't the natural place to block, rather where the preamble would be
|
// Block until we reiceve a preamble request, unless a preamble already
|
||||||
// consumed. But that's too late, we'd be running on the worker thread with
|
// exists, as patching an empty preamble would imply rebuilding it from
|
||||||
// the PreambleTask scheduled and so we'd deadlock.
|
// scratch.
|
||||||
ReceivedPreamble.wait();
|
// We block here instead of the consumer to prevent any deadlocks. Since
|
||||||
|
// LatestPreamble is only populated by ASTWorker thread.
|
||||||
|
return LatestPreamble || !PreambleRequests.empty() || Done;
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
startTask(TaskName, std::move(Task), WantDiags, TUScheduler::NoInvalidation);
|
startTask(TaskName, std::move(Task), WantDiags, TUScheduler::NoInvalidation);
|
||||||
|
|
@ -756,7 +768,7 @@ void ASTWorker::updatePreamble(std::unique_ptr<CompilerInvocation> CI,
|
||||||
// Update the preamble inside ASTWorker queue to ensure atomicity. As a task
|
// Update the preamble inside ASTWorker queue to ensure atomicity. As a task
|
||||||
// running inside ASTWorker assumes internals won't change until it
|
// running inside ASTWorker assumes internals won't change until it
|
||||||
// finishes.
|
// finishes.
|
||||||
if (Preamble != LatestPreamble) {
|
if (!LatestPreamble || Preamble != *LatestPreamble) {
|
||||||
++PreambleBuildCount;
|
++PreambleBuildCount;
|
||||||
// Cached AST is no longer valid.
|
// Cached AST is no longer valid.
|
||||||
IdleASTs.take(this);
|
IdleASTs.take(this);
|
||||||
|
|
@ -764,12 +776,16 @@ void ASTWorker::updatePreamble(std::unique_ptr<CompilerInvocation> CI,
|
||||||
std::lock_guard<std::mutex> Lock(Mutex);
|
std::lock_guard<std::mutex> Lock(Mutex);
|
||||||
// LatestPreamble might be the last reference to old preamble, do not
|
// LatestPreamble might be the last reference to old preamble, do not
|
||||||
// trigger destructor while holding the lock.
|
// trigger destructor while holding the lock.
|
||||||
std::swap(LatestPreamble, Preamble);
|
if (LatestPreamble)
|
||||||
|
std::swap(*LatestPreamble, Preamble);
|
||||||
|
else
|
||||||
|
LatestPreamble = std::move(Preamble);
|
||||||
}
|
}
|
||||||
|
// Notify anyone waiting for a preamble.
|
||||||
|
PreambleCV.notify_all();
|
||||||
// Give up our ownership to old preamble before starting expensive AST
|
// Give up our ownership to old preamble before starting expensive AST
|
||||||
// build.
|
// build.
|
||||||
Preamble.reset();
|
Preamble.reset();
|
||||||
BuiltFirstPreamble.notify();
|
|
||||||
// We only need to build the AST if diagnostics were requested.
|
// We only need to build the AST if diagnostics were requested.
|
||||||
if (WantDiags == WantDiagnostics::No)
|
if (WantDiags == WantDiagnostics::No)
|
||||||
return;
|
return;
|
||||||
|
|
@ -780,7 +796,6 @@ void ASTWorker::updatePreamble(std::unique_ptr<CompilerInvocation> CI,
|
||||||
};
|
};
|
||||||
if (RunSync) {
|
if (RunSync) {
|
||||||
Task();
|
Task();
|
||||||
ReceivedPreamble.notify();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -789,7 +804,7 @@ void ASTWorker::updatePreamble(std::unique_ptr<CompilerInvocation> CI,
|
||||||
steady_clock::now(), Context::current().clone(),
|
steady_clock::now(), Context::current().clone(),
|
||||||
llvm::None, TUScheduler::NoInvalidation, nullptr});
|
llvm::None, TUScheduler::NoInvalidation, nullptr});
|
||||||
}
|
}
|
||||||
ReceivedPreamble.notify();
|
PreambleCV.notify_all();
|
||||||
RequestsCV.notify_all();
|
RequestsCV.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -800,6 +815,7 @@ void ASTWorker::generateDiagnostics(
|
||||||
static constexpr trace::Metric ASTAccessForDiag(
|
static constexpr trace::Metric ASTAccessForDiag(
|
||||||
"ast_access_diag", trace::Metric::Counter, "result");
|
"ast_access_diag", trace::Metric::Counter, "result");
|
||||||
assert(Invocation);
|
assert(Invocation);
|
||||||
|
assert(LatestPreamble);
|
||||||
// No need to rebuild the AST if we won't send the diagnostics.
|
// No need to rebuild the AST if we won't send the diagnostics.
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> Lock(PublishMu);
|
std::lock_guard<std::mutex> Lock(PublishMu);
|
||||||
|
|
@ -832,7 +848,7 @@ void ASTWorker::generateDiagnostics(
|
||||||
if (!AST || !InputsAreLatest) {
|
if (!AST || !InputsAreLatest) {
|
||||||
auto RebuildStartTime = DebouncePolicy::clock::now();
|
auto RebuildStartTime = DebouncePolicy::clock::now();
|
||||||
llvm::Optional<ParsedAST> NewAST = ParsedAST::build(
|
llvm::Optional<ParsedAST> NewAST = ParsedAST::build(
|
||||||
FileName, Inputs, std::move(Invocation), CIDiags, LatestPreamble);
|
FileName, Inputs, std::move(Invocation), CIDiags, *LatestPreamble);
|
||||||
auto RebuildDuration = DebouncePolicy::clock::now() - RebuildStartTime;
|
auto RebuildDuration = DebouncePolicy::clock::now() - RebuildStartTime;
|
||||||
++ASTBuildCount;
|
++ASTBuildCount;
|
||||||
// Try to record the AST-build time, to inform future update debouncing.
|
// Try to record the AST-build time, to inform future update debouncing.
|
||||||
|
|
@ -890,10 +906,13 @@ void ASTWorker::generateDiagnostics(
|
||||||
std::shared_ptr<const PreambleData>
|
std::shared_ptr<const PreambleData>
|
||||||
ASTWorker::getPossiblyStalePreamble() const {
|
ASTWorker::getPossiblyStalePreamble() const {
|
||||||
std::lock_guard<std::mutex> Lock(Mutex);
|
std::lock_guard<std::mutex> Lock(Mutex);
|
||||||
return LatestPreamble;
|
return LatestPreamble ? *LatestPreamble : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTWorker::waitForFirstPreamble() const { BuiltFirstPreamble.wait(); }
|
void ASTWorker::waitForFirstPreamble() const {
|
||||||
|
std::unique_lock<std::mutex> Lock(Mutex);
|
||||||
|
PreambleCV.wait(Lock, [this] { return LatestPreamble.hasValue() || Done; });
|
||||||
|
}
|
||||||
|
|
||||||
tooling::CompileCommand ASTWorker::getCurrentCompileCommand() const {
|
tooling::CompileCommand ASTWorker::getCurrentCompileCommand() const {
|
||||||
std::unique_lock<std::mutex> Lock(Mutex);
|
std::unique_lock<std::mutex> Lock(Mutex);
|
||||||
|
|
@ -925,10 +944,9 @@ void ASTWorker::stop() {
|
||||||
assert(!Done && "stop() called twice");
|
assert(!Done && "stop() called twice");
|
||||||
Done = true;
|
Done = true;
|
||||||
}
|
}
|
||||||
// We are no longer going to build any preambles, let the waiters know that.
|
|
||||||
ReceivedPreamble.notify();
|
|
||||||
BuiltFirstPreamble.notify();
|
|
||||||
PreamblePeer.stop();
|
PreamblePeer.stop();
|
||||||
|
// We are no longer going to build any preambles, let the waiters know that.
|
||||||
|
PreambleCV.notify_all();
|
||||||
Status.stop();
|
Status.stop();
|
||||||
RequestsCV.notify_all();
|
RequestsCV.notify_all();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue