From e24c387413b9707622060f381b2a007aa5c814a0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 20 Sep 2019 09:32:25 +0200 Subject: [PATCH] Short live QtPrivate::{condition_variable,mutex}! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a temporary measure to work around an implementation bug on Integrity: For all other platforms, QtPrivate::condition_variable is just std::condition_variable. On Integrity, it's a class that wraps QWaitCondition to provide the interface of std::condition_variable. This allows the use of std::condition_variable across Qt without running into the Integrity issue. Once we can depend on an more modern Integrity toolchain, removing QtPrivate::condition_variable is a simple mechanical change: s/QtPrivate::condition_variable/std::condition_variable/g; s/QtPrivate::mutex/std::mutex/g; Task-number: QTBUG-78450 Change-Id: I293a99d1cdc48691817b926aa51ecd84556e5e90 Reviewed-by: MÄrten Nordheim Reviewed-by: Thiago Macieira --- src/corelib/thread/qwaitcondition_p.h | 153 ++++++++++++++++++++++++++ src/corelib/thread/thread.pri | 1 + src/testlib/qtestcase.cpp | 17 +-- 3 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 src/corelib/thread/qwaitcondition_p.h diff --git a/src/corelib/thread/qwaitcondition_p.h b/src/corelib/thread/qwaitcondition_p.h new file mode 100644 index 00000000000..5133e52e92b --- /dev/null +++ b/src/corelib/thread/qwaitcondition_p.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2019 KlarÀlvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QWAITCONDITION_P_H +#define QWAITCONDITION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qmutex.cpp, qmutex_unix.cpp, and qmutex_win.cpp. This header +// file may change from version to version without notice, or even be +// removed. +// +// We mean it. +// + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QtPrivate +{ + +#if defined(Q_OS_INTEGRITY) + +class condition_variable; + +class mutex : private QMutex +{ + friend class QtPrivate::condition_variable; +public: + // all special member functions are ok! + // do not expose the (QMutex::Recursive) ctor + // don't use 'using QMutex::lock;' etc as those have the wrong noexcept + + void lock() { return QMutex::lock(); } + void unlock() { return QMutex::unlock(); } + bool try_lock() { return QMutex::tryLock(); } +}; + +class condition_variable : private QWaitCondition +{ +public: + // all special member functions are ok! + + void notify_one() { QWaitCondition::wakeOne(); } + void notify_all() { QWaitCondition::wakeAll(); } + + void wait(std::unique_lock &lock) { QWaitCondition::wait(lock.mutex()); } + template + void wait(std::unique_lock &lock, Predicate p) + { + while (!p()) + wait(lock); + } + + template + std::cv_status wait_for(std::unique_lock &lock, + const std::chrono::duration &d) + { + return QWaitCondition::wait(lock.mutex(), QDeadlineTimer{d}) + ? std::cv_status::no_timeout + : std::cv_status::timeout; + } + template + bool wait_for(std::unique_lock &lock, + const std::chrono::duration &d, Predicate p) + { + const auto timer = QDeadlineTimer{d}; + while (!p()) { + if (!QWaitCondition::wait(lock.mutex(), timer)) + return p(); + } + return true; + } + + template + std::cv_status wait_until(std::unique_lock &lock, + const std::chrono::time_point &t) + { + return QWaitCondition::wait(lock.mutex(), QDeadlineTimer{t}) + ? std::cv_status::no_timeout + : std::cv_status::timeout; + } + + template + bool wait_until(std::unique_lock &lock, + const std::chrono::time_point &t, Predicate p) + { + const auto timer = QDeadlineTimer{t}; + while (!p()) { + if (!QWaitCondition::wait(lock.mutex(), timer)) + return p(); + } + return true; + } + +}; + +#else // Integrity + +using mutex = std::mutex; +using condition_variable = std::condition_variable; + +#endif // Integrity + +} // namespace QtPrivate + +QT_END_NAMESPACE + +#endif /* QWAITCONDITION_P_H */ diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri index 9fc9af0e655..25cf68a324d 100644 --- a/src/corelib/thread/thread.pri +++ b/src/corelib/thread/thread.pri @@ -6,6 +6,7 @@ HEADERS += \ thread/qrunnable.h \ thread/qthread.h \ thread/qthreadstorage.h \ + thread/qwaitcondition_p.h \ thread/qwaitcondition.h SOURCES += \ diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index e29897abeee..5c87844fcd9 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include @@ -1017,15 +1018,15 @@ class WatchDog : public QThread ThreadEnd, }; - bool waitFor(std::unique_lock &m, Expectation e) { - auto expectation = [this, e] { return expecting != e; }; + bool waitFor(std::unique_lock &m, Expectation e) { + auto expectationChanged = [this, e] { return expecting != e; }; switch (e) { case TestFunctionEnd: - return waitCondition.wait_for(m, defaultTimeout(), expectation); + return waitCondition.wait_for(m, defaultTimeout(), expectationChanged); case ThreadStart: case ThreadEnd: case TestFunctionStart: - waitCondition.wait(m, expectation); + waitCondition.wait(m, expectationChanged); return true; } Q_UNREACHABLE(); @@ -1035,7 +1036,7 @@ class WatchDog : public QThread public: WatchDog() { - std::unique_lock locker(mutex); + auto locker = qt_unique_lock(mutex); expecting = ThreadStart; start(); waitFor(locker, ThreadStart); @@ -1062,7 +1063,7 @@ public: } void run() override { - std::unique_lock locker(mutex); + auto locker = qt_unique_lock(mutex); expecting = TestFunctionStart; waitCondition.notify_all(); while (true) { @@ -1082,8 +1083,8 @@ public: } private: - std::mutex mutex; - std::condition_variable waitCondition; + QtPrivate::mutex mutex; + QtPrivate::condition_variable waitCondition; Expectation expecting; };