From f5d68398d51116bb8dc61e8699dd607076862d96 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 26 Jun 2017 14:00:32 +0200 Subject: Clang: Fix canceling of clang query Every AST unit is created and queried asynchronously, like before, but we don't wait anymore but use a timer to process new sources. So the server will not be blocked and can process other messages like cancel. Change-Id: If0e69466c78f628190f59fd32a03cab1c3a4d0a3 Reviewed-by: Tim Jenssen --- .../source/refactoringserver.cpp | 117 ++++++--------------- 1 file changed, 35 insertions(+), 82 deletions(-) (limited to 'src/tools/clangrefactoringbackend/source/refactoringserver.cpp') diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.cpp b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp index 4468c5e13d..58e944784d 100644 --- a/src/tools/clangrefactoringbackend/source/refactoringserver.cpp +++ b/src/tools/clangrefactoringbackend/source/refactoringserver.cpp @@ -36,16 +36,17 @@ #include -#include -#include -#include -#include +#include namespace ClangBackEnd { RefactoringServer::RefactoringServer() { - pollEventLoop = [] () { QCoreApplication::processEvents(); }; + m_pollTimer.setInterval(100); + + QObject::connect(&m_pollTimer, + &QTimer::timeout, + std::bind(&RefactoringServer::pollSourceRangesAndDiagnosticsForQueryMessages, this)); } void RefactoringServer::end() @@ -72,110 +73,62 @@ void RefactoringServer::requestSourceLocationsForRenamingMessage(RequestSourceLo void RefactoringServer::requestSourceRangesAndDiagnosticsForQueryMessage( RequestSourceRangesAndDiagnosticsForQueryMessage &&message) { - gatherSourceRangesAndDiagnosticsForQueryMessage(message.takeSources(), - message.takeUnsavedContent(), - message.takeQuery()); + gatherSourceRangesAndDiagnosticsForQueryMessages(message.takeSources(), + message.takeUnsavedContent(), + message.takeQuery()); } void RefactoringServer::cancel() { - cancelWork = true; + m_gatherer.waitForFinished(); + m_gatherer = ClangQueryGatherer(); + m_pollTimer.stop(); } bool RefactoringServer::isCancelingJobs() const { - return cancelWork; + return m_gatherer.isFinished(); } -void RefactoringServer::supersedePollEventLoop(std::function &&pollEventLoop) +void RefactoringServer::pollSourceRangesAndDiagnosticsForQueryMessages() { - this->pollEventLoop = std::move(pollEventLoop); -} - -namespace { - -SourceRangesAndDiagnosticsForQueryMessage createSourceRangesAndDiagnosticsForQueryMessage( - V2::FileContainer &&source, - std::vector &&unsaved, - Utils::SmallString &&query, - const std::atomic_bool &cancelWork) { - ClangQuery clangQuery(std::move(query)); - - if (!cancelWork) { - clangQuery.addFile(source.filePath().directory(), - source.filePath().name(), - source.takeUnsavedFileContent(), - source.takeCommandLineArguments()); + for (auto &&message : m_gatherer.finishedMessages()) + client()->sourceRangesAndDiagnosticsForQueryMessage(std::move(message)); - clangQuery.addUnsavedFiles(std::move(unsaved)); + if (!m_gatherer.isFinished()) + m_gatherer.startCreateNextSourceRangesAndDiagnosticsMessages(); + else + m_pollTimer.stop(); +} - clangQuery.findLocations(); +void RefactoringServer::waitThatSourceRangesAndDiagnosticsForQueryMessagesAreFinished() +{ + while (!m_gatherer.isFinished()) { + m_gatherer.waitForFinished(); + pollSourceRangesAndDiagnosticsForQueryMessages(); } - - return {clangQuery.takeSourceRanges(), clangQuery.takeDiagnosticContainers()}; } - +bool RefactoringServer::pollTimerIsActive() const +{ + return m_pollTimer.isActive(); } -void RefactoringServer::gatherSourceRangesAndDiagnosticsForQueryMessage( +void RefactoringServer::gatherSourceRangesAndDiagnosticsForQueryMessages( std::vector &&sources, std::vector &&unsaved, Utils::SmallString &&query) { - std::vector futures; - #ifdef _WIN32 - std::size_t freeProcessors = 1; + uint freeProcessors = 1; #else - std::size_t freeProcessors = std::thread::hardware_concurrency(); + uint freeProcessors = std::thread::hardware_concurrency(); #endif - while (!sources.empty() || !futures.empty()) { - --freeProcessors; + m_gatherer = ClangQueryGatherer(std::move(sources), std::move(unsaved), std::move(query)); + m_gatherer.setProcessingSlotCount(freeProcessors); - if (!sources.empty()) { - Future &&future = std::async(std::launch::async, - createSourceRangesAndDiagnosticsForQueryMessage, - std::move(sources.back()), - Utils::clone(unsaved), - query.clone(), - std::ref(cancelWork)); - sources.pop_back(); - - futures.emplace_back(std::move(future)); - } - - if (freeProcessors == 0 || sources.empty()) - freeProcessors += waitForNewSourceRangesAndDiagnosticsForQueryMessage(futures); - } -} - -std::size_t RefactoringServer::waitForNewSourceRangesAndDiagnosticsForQueryMessage(std::vector &futures) -{ - while (true) { - pollEventLoop(); - - std::vector readyFutures; - readyFutures.reserve(futures.size()); - - auto beginReady = std::partition(futures.begin(), - futures.end(), - [] (const Future &future) { - return future.wait_for(std::chrono::duration::zero()) != std::future_status::ready; - }); - - std::move(beginReady, futures.end(), std::back_inserter(readyFutures)); - futures.erase(beginReady, futures.end()); - - for (Future &readyFuture : readyFutures) - client()->sourceRangesAndDiagnosticsForQueryMessage(readyFuture.get()); - - if (readyFutures.empty()) - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - else - return readyFutures.size(); - } + m_pollTimer.start(); } } // namespace ClangBackEnd -- cgit v1.2.1