From 2f41886c4bffa000bc5d661d7e9c6baa3b0c44ae Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 27 Aug 2018 15:54:08 +0200 Subject: [PATCH] ClangRefactoring: Process tasks after a task has been finished It could be that processTasks is executed before the future is finished but in that case there are other tasks which will be called later. Change-Id: I9b1bfb6fdd642f23842b9c70d60d5b1552193b99 Reviewed-by: Ivan Donchevskii --- .../source/clangrefactoringbackend-source.pri | 3 +- .../source/symbolindexertaskqueue.cpp | 5 ++ .../source/symbolindexertaskqueue.h | 4 ++ .../source/symbolindexertaskqueueinterface.h | 38 ++++++++++++ .../source/symbolindexertaskscheduler.cpp | 62 +++++++++++++++++-- .../source/symbolindexertaskscheduler.h | 4 ++ .../unittest/mocksymbolindexertaskqueue.h | 36 +++++++++++ .../symbolindexertaskscheduler-test.cpp | 20 +++++- tests/unit/unittest/unittest.pro | 3 +- 9 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h create mode 100644 tests/unit/unittest/mocksymbolindexertaskqueue.h diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index 9e26d66c38c..b77118bb983 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -26,7 +26,8 @@ HEADERS += \ $$PWD/sourcesmanager.h \ $$PWD/symbolindexertaskqueue.h \ $$PWD/symbolindexertaskscheduler.h \ - $$PWD/symbolscollectormanagerinterface.h + $$PWD/symbolscollectormanagerinterface.h \ + $$PWD/symbolindexertaskqueueinterface.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp index 7335a6ecdd9..aa4fd382157 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp @@ -131,4 +131,9 @@ std::vector SymbolIndexerTaskQueue::projectPartNumberIds(const Util return ids; } +void SymbolIndexerTaskQueue::processTasks() +{ + +} + } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h index c1386b98d35..a4fb44de0ac 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h @@ -25,6 +25,8 @@ #pragma once +#include "symbolindexertaskqueueinterface.h" + #include #include @@ -92,6 +94,8 @@ public: std::vector projectPartNumberIds(const Utils::SmallStringVector &projectPartIds) /* [[ensures result: std::is_sorted(result)]] */; + void processTasks() ; + private: std::vector m_projectPartIds; std::vector m_tasks; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h new file mode 100644 index 00000000000..09b760d0a32 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +namespace ClangBackEnd { + +class SymbolIndexerTaskQueueInterface +{ +public: + virtual void processTasks() = 0; + +protected: + ~SymbolIndexerTaskQueueInterface() = default; +}; +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp index bccbd2fe783..bd065311055 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp @@ -25,28 +25,78 @@ #include "symbolindexertaskscheduler.h" +#include #include #include +#include +#include +#include +#include + #include #include namespace ClangBackEnd { +namespace { +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) +template +class CallableEvent : public QEvent { +public: + using Callable = std::decay_t; + CallableEvent(Callable &&callable) + : QEvent(QEvent::None), + callable(std::move(callable)) + {} + CallableEvent(const Callable &callable) + : QEvent(QEvent::None), + callable(callable) + {} + + ~CallableEvent() + { + callable(); + } +public: + Callable callable; +}; + +template +void executeInLoop(Callable &&callable, QObject *object = QCoreApplication::instance()) { + if (QThread *thread = qobject_cast(object)) + object = QAbstractEventDispatcher::instance(thread); + + QCoreApplication::postEvent(object, + new CallableEvent(std::forward(callable)), + Qt::HighEventPriority); +} +#else +template +void executeInLoop(Callable &&callable, QObject *object = QCoreApplication::instance()) { + if (QThread *thread = qobject_cast(object)) + object = QAbstractEventDispatcher::instance(thread); + + QMetaObject::invokeMethod(object, std::forward(callable)); +} +#endif +} void SymbolIndexerTaskScheduler::addTasks(std::vector &&tasks) { for (auto &task : tasks) { - auto callWrapper = [task=std::move(task)] ( - std::reference_wrapper symbolsCollector, - std::reference_wrapper symbolStorage) + auto callWrapper = [&, task=std::move(task)] ( + std::reference_wrapper symbolsCollector) -> SymbolsCollectorInterface& { - task(symbolsCollector.get(), symbolStorage.get()); + task(symbolsCollector.get(), m_symbolStorage); + executeInLoop([&] { + m_symbolIndexerTaskQueue.processTasks(); + }); + return symbolsCollector; }; m_futures.emplace_back(std::async(m_launchPolicy, std::move(callWrapper), - std::ref(m_symbolsCollectorManager.unusedSymbolsCollector()), - std::ref(m_symbolStorage))); + std::ref(m_symbolsCollectorManager.unusedSymbolsCollector()))); } } diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h index b85dfbb88ef..919b8c1fd7b 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h @@ -34,6 +34,7 @@ namespace ClangBackEnd { class FilePathCachingInterface; class SymbolsCollectorInterface; class SymbolsCollectorManagerInterface; +class SymbolIndexerTaskQueueInterface; class SymbolStorageInterface; class SymbolIndexerTaskScheduler @@ -45,10 +46,12 @@ public: SymbolIndexerTaskScheduler(SymbolsCollectorManagerInterface &symbolsCollectorManager, SymbolStorageInterface &symbolStorage, + SymbolIndexerTaskQueueInterface &symbolIndexerTaskQueue, int hardware_concurrency, std::launch launchPolicy = std::launch::async) : m_symbolsCollectorManager(symbolsCollectorManager), m_symbolStorage(symbolStorage), + m_symbolIndexerTaskQueue(symbolIndexerTaskQueue), m_hardware_concurrency(hardware_concurrency), m_launchPolicy(launchPolicy) {} @@ -68,6 +71,7 @@ private: std::vector m_futures; SymbolsCollectorManagerInterface &m_symbolsCollectorManager; SymbolStorageInterface &m_symbolStorage; + SymbolIndexerTaskQueueInterface &m_symbolIndexerTaskQueue; int m_hardware_concurrency; std::launch m_launchPolicy; }; diff --git a/tests/unit/unittest/mocksymbolindexertaskqueue.h b/tests/unit/unittest/mocksymbolindexertaskqueue.h new file mode 100644 index 00000000000..1eca733ade4 --- /dev/null +++ b/tests/unit/unittest/mocksymbolindexertaskqueue.h @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include + +class MockSymbolIndexerTaskQueue : public ClangBackEnd::SymbolIndexerTaskQueueInterface +{ +public: + MOCK_METHOD0(processTasks, void()); +}; diff --git a/tests/unit/unittest/symbolindexertaskscheduler-test.cpp b/tests/unit/unittest/symbolindexertaskscheduler-test.cpp index f7d4be201a7..d4dff54a388 100644 --- a/tests/unit/unittest/symbolindexertaskscheduler-test.cpp +++ b/tests/unit/unittest/symbolindexertaskscheduler-test.cpp @@ -25,12 +25,15 @@ #include "googletest.h" +#include "mocksymbolindexertaskqueue.h" #include "mocksymbolscollectormanager.h" #include "mocksymbolscollector.h" #include "mocksymbolstorage.h" #include +#include + namespace { using ClangBackEnd::SymbolsCollectorInterface; @@ -43,6 +46,11 @@ protected: { ON_CALL(mockSymbolsCollectorManager, unusedSymbolsCollector()).WillByDefault(ReturnRef(mockSymbolsCollector)); } + void TearDown() + { + scheduler.syncTasks(); + QCoreApplication::processEvents(); + } protected: MockFunction mock; @@ -56,8 +64,9 @@ protected: NiceMock mockSymbolsCollectorManager; NiceMock mockSymbolsCollector; MockSymbolStorage mockSymbolStorage; - ClangBackEnd::SymbolIndexerTaskScheduler scheduler{mockSymbolsCollectorManager, mockSymbolStorage, 4}; - ClangBackEnd::SymbolIndexerTaskScheduler deferedScheduler{mockSymbolsCollectorManager, mockSymbolStorage, 4, std::launch::deferred}; + NiceMock mockSymbolIndexerTaskQueue; + ClangBackEnd::SymbolIndexerTaskScheduler scheduler{mockSymbolsCollectorManager, mockSymbolStorage, mockSymbolIndexerTaskQueue, 4}; + ClangBackEnd::SymbolIndexerTaskScheduler deferedScheduler{mockSymbolsCollectorManager, mockSymbolStorage, mockSymbolIndexerTaskQueue, 4, std::launch::deferred}; }; TEST_F(SymbolIndexerTaskScheduler, AddTasks) @@ -128,4 +137,11 @@ TEST_F(SymbolIndexerTaskScheduler, AddTaskCallSymbolsCollectorManagerUnusedSymbo scheduler.addTasks({nocall, nocall}); } + +TEST_F(SymbolIndexerTaskScheduler, CallProcessTasksInQueueAfterFinishedTasks) +{ + EXPECT_CALL(mockSymbolIndexerTaskQueue, processTasks()).Times(2); + + scheduler.addTasks({nocall, nocall}); +} } diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 6dd27b53ddc..126113d9a45 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -234,7 +234,8 @@ HEADERS += \ mockprojectpartprovider.h \ mockprecompiledheaderstorage.h \ mockeditormanager.h \ - mocksymbolscollectormanager.h + mocksymbolscollectormanager.h \ + mocksymbolindexertaskqueue.h !isEmpty(LIBCLANG_LIBS) { HEADERS += \ chunksreportedmonitor.h \