diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -407,7 +407,7 @@ Result.push_back(replacementToEdit(Code, R)); return CB(Result); }; - WorkScheduler.run("FormatOnType", File, std::move(Action)); + WorkScheduler.runQuick("FormatOnType", File, std::move(Action)); } void ClangdServer::prepareRename(PathRef File, Position Pos, @@ -635,7 +635,7 @@ tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges), File))); }; - WorkScheduler.run("Format", File, std::move(Action)); + WorkScheduler.runQuick("Format", File, std::move(Action)); } void ClangdServer::findDocumentHighlights( diff --git a/clang-tools-extra/clangd/TUScheduler.h b/clang-tools-extra/clangd/TUScheduler.h --- a/clang-tools-extra/clangd/TUScheduler.h +++ b/clang-tools-extra/clangd/TUScheduler.h @@ -247,6 +247,13 @@ void run(llvm::StringRef Name, llvm::StringRef Path, llvm::unique_function Action); + /// Similar to run, except the task is expected to be quick. + /// This function will not honor AsyncThreadsCount (except + /// if threading is disabled with AsyncThreadsCount=0) + /// It is intended to run quick tasks that need to run ASAP + void runQuick(llvm::StringRef Name, llvm::StringRef Path, + llvm::unique_function Action); + /// Defines how a runWithAST action is implicitly cancelled by other actions. enum ASTActionInvalidation { /// The request will run unless explicitly cancelled. @@ -319,10 +326,14 @@ void profile(MemoryTree &MT) const; private: + void runWithSemaphore(llvm::StringRef Name, llvm::StringRef Path, + llvm::unique_function Action, Semaphore &Sem); + const GlobalCompilationDatabase &CDB; Options Opts; std::unique_ptr Callbacks; // not nullptr Semaphore Barrier; + Semaphore QuickRunBarrier; llvm::StringMap> Files; std::unique_ptr IdleASTs; // None when running tasks synchronously and non-None when running tasks diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp --- a/clang-tools-extra/clangd/TUScheduler.cpp +++ b/clang-tools-extra/clangd/TUScheduler.cpp @@ -1265,7 +1265,7 @@ : CDB(CDB), Opts(Opts), Callbacks(Callbacks ? move(Callbacks) : std::make_unique()), - Barrier(Opts.AsyncThreadsCount), + Barrier(Opts.AsyncThreadsCount), QuickRunBarrier(Opts.AsyncThreadsCount), IdleASTs( std::make_unique(Opts.RetentionPolicy.MaxRetainedASTs)) { // Avoid null checks everywhere. @@ -1339,14 +1339,27 @@ void TUScheduler::run(llvm::StringRef Name, llvm::StringRef Path, llvm::unique_function Action) { + runWithSemaphore(Name, Path, std::move(Action), Barrier); +} + +void TUScheduler::runQuick(llvm::StringRef Name, llvm::StringRef Path, + llvm::unique_function Action) { + // Use QuickRunBarrier to serialize quick tasks: we are ignoring + // the parallelism level set by the user, don't abuse it + runWithSemaphore(Name, Path, std::move(Action), QuickRunBarrier); +} + +void TUScheduler::runWithSemaphore(llvm::StringRef Name, llvm::StringRef Path, + llvm::unique_function Action, + Semaphore &Sem) { if (!PreambleTasks) { WithContext WithProvidedContext(Opts.ContextProvider(Path)); return Action(); } - PreambleTasks->runAsync(Name, [this, Ctx = Context::current().clone(), + PreambleTasks->runAsync(Name, [this, &Sem, Ctx = Context::current().clone(), Path(Path.str()), Action = std::move(Action)]() mutable { - std::lock_guard BarrierLock(Barrier); + std::lock_guard BarrierLock(Sem); WithContext WC(std::move(Ctx)); WithContext WithProvidedContext(Opts.ContextProvider(Path)); Action();