diff options
Diffstat (limited to 'src/corelib/thread/qthread_p.h')
-rw-r--r-- | src/corelib/thread/qthread_p.h | 213 |
1 files changed, 121 insertions, 92 deletions
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index c853bd1de4..c39e21ec9a 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** Contact: https://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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QTHREAD_P_H #define QTHREAD_P_H @@ -85,7 +49,7 @@ public: : receiver(r), event(e), priority(p) { } }; -Q_DECLARE_TYPEINFO(QPostEvent, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(QPostEvent, Q_RELOCATABLE_TYPE); inline bool operator<(const QPostEvent &first, const QPostEvent &second) { @@ -94,6 +58,7 @@ inline bool operator<(const QPostEvent &first, const QPostEvent &second) // This class holds the list of posted events. // The list has to be kept sorted by priority +// It's used in a virtual in QCoreApplication, so ELFVERSION:ignore-next class QPostEventList : public QList<QPostEvent> { public: @@ -101,36 +66,101 @@ public: int recursion; // sendOffset == the current event to start sending - int startOffset; + qsizetype startOffset; // insertionOffset == set by sendPostedEvents to tell postEvent() where to start insertions - int insertionOffset; + qsizetype insertionOffset; QMutex mutex; inline QPostEventList() : QList<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0) { } - void addEvent(const QPostEvent &ev) { - int priority = ev.priority; - if (isEmpty() || - constLast().priority >= priority || - insertionOffset >= size()) { - // optimization: we can simply append if the last event in - // the queue has higher or equal priority - append(ev); - } else { - // insert event in descending priority order, using upper - // bound for a given priority (to ensure proper ordering - // of events with the same priority) - QPostEventList::iterator at = std::upper_bound(begin() + insertionOffset, end(), ev); - insert(at, ev); - } - } + void addEvent(const QPostEvent &ev); + private: //hides because they do not keep that list sorted. addEvent must be used using QList<QPostEvent>::append; using QList<QPostEvent>::insert; }; +namespace QtPrivate { + +/* BindingStatusOrList is basically a QBiPointer (as found in declarative) + with some helper methods to manipulate the list. BindingStatusOrList starts + its life in a null state and supports the following transitions + + 0 state (initial) + / \ + / \ + v v + pending object list----------->binding status + Note that binding status is the final state, and we never transition away + from it +*/ +class BindingStatusOrList +{ + Q_DISABLE_COPY_MOVE(BindingStatusOrList) +public: + using List = std::vector<QObject *>; + + constexpr BindingStatusOrList() noexcept : data(0) {} + explicit BindingStatusOrList(QBindingStatus *status) noexcept : + data(encodeBindingStatus(status)) {} + explicit BindingStatusOrList(List *list) noexcept : data(encodeList(list)) {} + + // requires external synchronization: + QBindingStatus *addObjectUnlessAlreadyStatus(QObject *object); + void removeObject(QObject *object); + void setStatusAndClearList(QBindingStatus *status) noexcept; + + + static bool isBindingStatus(quintptr data) noexcept + { + return !isNull(data) && !isList(data); + } + static bool isList(quintptr data) noexcept { return data & 1; } + static bool isNull(quintptr data) noexcept { return data == 0; } + + // thread-safe: + QBindingStatus *bindingStatus() const noexcept + { + // synchronizes-with the store-release in setStatusAndClearList(): + const auto d = data.load(std::memory_order_acquire); + if (isBindingStatus(d)) + return reinterpret_cast<QBindingStatus *>(d); + else + return nullptr; + } + + // requires external synchronization: + List *list() const noexcept + { + return decodeList(data.load(std::memory_order_relaxed)); + } + +private: + static List *decodeList(quintptr ptr) noexcept + { + if (isList(ptr)) + return reinterpret_cast<List *>(ptr & ~1); + else + return nullptr; + } + + static quintptr encodeBindingStatus(QBindingStatus *status) noexcept + { + return quintptr(status); + } + + static quintptr encodeList(List *list) noexcept + { + return quintptr(list) | 1; + } + + std::atomic<quintptr> data; +}; + +} // namespace QtPrivate + #if QT_CONFIG(thread) class Q_CORE_EXPORT QDaemonThread : public QThread @@ -140,7 +170,7 @@ public: ~QDaemonThread(); }; -class QThreadPrivate : public QObjectPrivate +class Q_AUTOTEST_EXPORT QThreadPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QThread) @@ -149,6 +179,7 @@ public: ~QThreadPrivate(); void setPriority(QThread::Priority prio); + Qt::HANDLE threadId() const; mutable QMutex mutex; QAtomicInt quitLockRef; @@ -162,9 +193,7 @@ public: int returnCode; uint stackSize; - QThread::Priority priority; - - static QThread *threadForId(int id); + std::underlying_type_t<QThread::Priority> priority; #ifdef Q_OS_UNIX QWaitCondition thread_done; @@ -176,7 +205,7 @@ public: #ifdef Q_OS_WIN static unsigned int __stdcall start(void *) noexcept; - static void finish(void *, bool lockAnyway=true) noexcept; + static void finish(void *, bool lockAnyway = true) noexcept; Qt::HANDLE handle; unsigned int id; @@ -201,6 +230,26 @@ public: QCoreApplication::instance()->postEvent(q_ptr, new QEvent(QEvent::Quit)); } } + + QBindingStatus *bindingStatus() + { + return m_statusOrPendingObjects.bindingStatus(); + } + + /* Returns nullptr if the object has been added, or the binding status + if that one has been set in the meantime + */ + QBindingStatus *addObjectWithPendingBindingStatusChange(QObject *obj); + void removeObjectWithPendingBindingStatusChange(QObject *obj); + + // manipulating m_statusOrPendingObjects requires mutex to be locked + QtPrivate::BindingStatusOrList m_statusOrPendingObjects = {}; +#ifndef Q_OS_INTEGRITY +private: + // Used in QThread(Private)::start to avoid racy access to QObject::objectName, + // unset afterwards. On INTEGRITY we set the thread name before starting it. + QString objectName; +#endif }; #else // QT_CONFIG(thread) @@ -208,15 +257,19 @@ public: class QThreadPrivate : public QObjectPrivate { public: - QThreadPrivate(QThreadData *d = 0); + QThreadPrivate(QThreadData *d = nullptr); ~QThreadPrivate(); mutable QMutex mutex; QThreadData *data; + QBindingStatus* m_bindingStatus; bool running = false; - static void setCurrentThread(QThread*) {} - static QThread *threadForId(int) { return QThread::currentThread(); } + QBindingStatus* bindingStatus() { return m_bindingStatus; } + QBindingStatus *addObjectWithPendingBindingStatusChange(QObject *) { return nullptr; } + void removeObjectWithPendingBindingStatusChange(QObject *) {} + + static void setCurrentThread(QThread *) { } static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data); void ref() {} @@ -258,26 +311,6 @@ public: return canWait; } - // This class provides per-thread (by way of being a QThreadData - // member) storage for qFlagLocation() - class FlaggedDebugSignatures - { - static const uint Count = 2; - - uint idx; - const char* locations[Count]; - - public: - FlaggedDebugSignatures() : idx(0) - { std::fill_n(locations, Count, static_cast<char*>(nullptr)); } - - void store(const char* method) - { locations[idx++ % Count] = method; } - - bool contains(const char *method) const - { return std::find(locations, locations + Count, method) != locations + Count; } - }; - private: QAtomicInt _ref; @@ -291,7 +324,6 @@ public: QAtomicPointer<void> threadId; QAtomicPointer<QAbstractEventDispatcher> eventDispatcher; QList<void *> tls; - FlaggedDebugSignatures flaggedSignatures; bool quitNow; bool canWait; @@ -303,11 +335,8 @@ class QScopedScopeLevelCounter { QThreadData *threadData; public: - inline QScopedScopeLevelCounter(QThreadData *threadData) - : threadData(threadData) - { ++threadData->scopeLevel; } - inline ~QScopedScopeLevelCounter() - { --threadData->scopeLevel; } + QScopedScopeLevelCounter(QThreadData *threadData); + ~QScopedScopeLevelCounter(); }; // thread wrapper for the main() thread |