diff options
Diffstat (limited to 'src/corelib/kernel/qobject_p.h')
-rw-r--r-- | src/corelib/kernel/qobject_p.h | 382 |
1 files changed, 94 insertions, 288 deletions
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index ac77d898da..0ab9bf02ed 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> -** 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) 2019 The Qt Company Ltd. +// Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QOBJECT_P_H #define QOBJECT_P_H @@ -54,17 +18,27 @@ #include <QtCore/private/qglobal_p.h> #include "QtCore/qcoreevent.h" +#include <QtCore/qfunctionaltools_impl.h> #include "QtCore/qlist.h" #include "QtCore/qobject.h" #include "QtCore/qpointer.h" -#include "QtCore/qreadwritelock.h" -#include "QtCore/qsharedpointer.h" #include "QtCore/qvariant.h" #include "QtCore/qproperty.h" +#include <QtCore/qshareddata.h> #include "QtCore/private/qproperty_p.h" +#include <string> + QT_BEGIN_NAMESPACE +#ifdef Q_MOC_RUN +#define QT_ANONYMOUS_PROPERTY(text) QT_ANONYMOUS_PROPERTY(text) +#define QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) +#elif !defined QT_NO_META_MACROS +#define QT_ANONYMOUS_PROPERTY(...) QT_ANNOTATE_CLASS(qt_anonymous_property, __VA_ARGS__) +#define QT_ANONYMOUS_PRIVATE_PROPERTY(d, text) QT_ANNOTATE_CLASS2(qt_anonymous_private_property, d, text) +#endif + class QVariant; class QThreadData; class QObjectConnectionListVector; @@ -117,7 +91,7 @@ public: QList<QByteArray> propertyNames; QList<QVariant> propertyValues; - QList<int> runningTimers; + QList<Qt::TimerId> runningTimers; QList<QPointer<QObject>> eventFilters; Q_OBJECT_COMPAT_PROPERTY(QObjectPrivate::ExtraData, QString, objectName, &QObjectPrivate::ExtraData::setObjectNameForwarder, @@ -125,125 +99,20 @@ public: QObjectPrivate *parent; }; + void ensureExtraData() + { + if (!extraData) + extraData = new ExtraData(this); + } + typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **); struct Connection; + struct ConnectionData; + struct ConnectionList; + struct ConnectionOrSignalVector; struct SignalVector; - - struct ConnectionOrSignalVector { - union { - // linked list of orphaned connections that need cleaning up - ConnectionOrSignalVector *nextInOrphanList; - // linked list of connections connected to slots in this object - Connection *next; - }; - - static SignalVector *asSignalVector(ConnectionOrSignalVector *c) - { - if (reinterpret_cast<quintptr>(c) & 1) - return reinterpret_cast<SignalVector *>(reinterpret_cast<quintptr>(c) & ~quintptr(1u)); - return nullptr; - } - static Connection *fromSignalVector(SignalVector *v) { - return reinterpret_cast<Connection *>(reinterpret_cast<quintptr>(v) | quintptr(1u)); - } - }; - - struct Connection : public ConnectionOrSignalVector - { - // linked list of connections connected to slots in this object, next is in base class - Connection **prev; - // linked list of connections connected to signals in this object - QAtomicPointer<Connection> nextConnectionList; - Connection *prevConnectionList; - - QObject *sender; - QAtomicPointer<QObject> receiver; - QAtomicPointer<QThreadData> receiverThreadData; - union { - StaticMetaCallFunction callFunction; - QtPrivate::QSlotObjectBase *slotObj; - }; - QAtomicPointer<const int> argumentTypes; - QAtomicInt ref_; - uint id = 0; - ushort method_offset; - ushort method_relative; - signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex()) - ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking - ushort isSlotObject : 1; - ushort ownArgumentTypes : 1; - ushort isSingleShot : 1; - Connection() : ref_(2), ownArgumentTypes(true) { - //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection - } - ~Connection(); - int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; } - void ref() { ref_.ref(); } - void freeSlotObject() - { - if (isSlotObject) { - slotObj->destroyIfLastRef(); - isSlotObject = false; - } - } - void deref() - { - if (!ref_.deref()) { - Q_ASSERT(!receiver.loadRelaxed()); - Q_ASSERT(!isSlotObject); - delete this; - } - } - }; - // ConnectionList is a singly-linked list - struct ConnectionList { - QAtomicPointer<Connection> first; - QAtomicPointer<Connection> last; - }; - - struct Sender - { - Sender(QObject *receiver, QObject *sender, int signal) - : receiver(receiver), sender(sender), signal(signal) - { - if (receiver) { - ConnectionData *cd = receiver->d_func()->connections.loadRelaxed(); - previous = cd->currentSender; - cd->currentSender = this; - } - } - ~Sender() - { - if (receiver) - receiver->d_func()->connections.loadRelaxed()->currentSender = previous; - } - void receiverDeleted() - { - Sender *s = this; - while (s) { - s->receiver = nullptr; - s = s->previous; - } - } - Sender *previous; - QObject *receiver; - QObject *sender; - int signal; - }; - - struct SignalVector : public ConnectionOrSignalVector { - quintptr allocated; - // ConnectionList signals[] - ConnectionList &at(int i) - { - return reinterpret_cast<ConnectionList *>(this + 1)[i + 1]; - } - const ConnectionList &at(int i) const - { - return reinterpret_cast<const ConnectionList *>(this + 1)[i + 1]; - } - int count() const { return static_cast<int>(allocated); } - }; + struct Sender; + struct TaggedSignalVector; /* This contains the all connections from and to an object. @@ -259,86 +128,6 @@ public: to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this linked list. */ - struct ConnectionData { - // the id below is used to avoid activating new connections. When the object gets - // deleted it's set to 0, so that signal emission stops - QAtomicInteger<uint> currentConnectionId; - QAtomicInt ref; - QAtomicPointer<SignalVector> signalVector; - Connection *senders = nullptr; - Sender *currentSender = nullptr; // object currently activating the object - QAtomicPointer<Connection> orphaned; - - ~ConnectionData() - { - Q_ASSERT(ref.loadRelaxed() == 0); - auto *c = orphaned.fetchAndStoreRelaxed(nullptr); - if (c) - deleteOrphaned(c); - SignalVector *v = signalVector.loadRelaxed(); - if (v) - free(v); - } - - // must be called on the senders connection data - // assumes the senders and receivers lock are held - void removeConnection(Connection *c); - enum LockPolicy { - NeedToLock, - // Beware that we need to temporarily release the lock - // and thus calling code must carefully consider whether - // invariants still hold. - AlreadyLockedAndTemporarilyReleasingLock - }; - void cleanOrphanedConnections(QObject *sender, LockPolicy lockPolicy = NeedToLock) - { - if (orphaned.loadRelaxed() && ref.loadAcquire() == 1) - cleanOrphanedConnectionsImpl(sender, lockPolicy); - } - void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy); - - ConnectionList &connectionsForSignal(int signal) - { - return signalVector.loadRelaxed()->at(signal); - } - - void resizeSignalVector(uint size) - { - SignalVector *vector = this->signalVector.loadRelaxed(); - if (vector && vector->allocated > size) - return; - size = (size + 7) & ~7; - SignalVector *newVector = reinterpret_cast<SignalVector *>(malloc(sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList))); - int start = -1; - if (vector) { - memcpy(newVector, vector, sizeof(SignalVector) + (vector->allocated + 1) * sizeof(ConnectionList)); - start = vector->count(); - } - for (int i = start; i < int(size); ++i) - newVector->at(i) = ConnectionList(); - newVector->next = nullptr; - newVector->allocated = size; - - signalVector.storeRelaxed(newVector); - if (vector) { - Connection *o = nullptr; - /* No ABA issue here: When adding a node, we only care about the list head, it doesn't - * matter if the tail changes. - */ - do { - o = orphaned.loadRelaxed(); - vector->nextInOrphanList = o; - } while (!orphaned.testAndSetRelease(o, ConnectionOrSignalVector::fromSignalVector(vector))); - - } - } - int signalVectorCount() const - { - return signalVector.loadAcquire() ? signalVector.loadRelaxed()->count() : -1; - } - - static void deleteOrphaned(ConnectionOrSignalVector *c); - }; QObjectPrivate(int version = QObjectPrivateVersion); virtual ~QObjectPrivate(); @@ -350,14 +139,13 @@ public: void setParent_helper(QObject *); void moveToThread_helper(); - void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); - void _q_reregisterTimers(void *pointer); + void setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status); - bool isSender(const QObject *receiver, const char *signal) const; QObjectList receiverList(const char *signal) const; - QObjectList senderList() const; - void addConnection(int signal, Connection *c); + inline void ensureConnectionData(); + inline void addConnection(int signal, Connection *c); + static inline bool removeConnection(Connection *c); static QObjectPrivate *get(QObject *o) { return o->d_func(); } static const QObjectPrivate *get(const QObject *o) { return o->d_func(); } @@ -372,6 +160,8 @@ public: inline void connectNotify(const QMetaMethod &signal); inline void disconnectNotify(const QMetaMethod &signal); + void reinitBindingStorageAfterThreadMove(); + template <typename Func1, typename Func2> static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot, @@ -393,16 +183,15 @@ public: static bool disconnect(const QObject *sender, int signal_index, void **slot); static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, void **slot); - static bool disconnect(Connection *c); - void ensureConnectionData() - { - if (connections.loadRelaxed()) - return; - ConnectionData *cd = new ConnectionData; - cd->ref.ref(); - connections.storeRelaxed(cd); - } + virtual std::string flagsForDumping() const; + +#ifndef QT_NO_DEBUG_STREAM + virtual void writeToDebugStream(QDebug &) const; +#endif + + QtPrivate::QPropertyAdaptorSlotObject * + getPropertyAdaptorSlotObject(const QMetaProperty &property); public: mutable ExtraData *extraData; // extra data set by the user @@ -426,8 +215,6 @@ public: QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount; }; -Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_RELOCATABLE_TYPE); - /* Catch mixing of incompatible library versions. @@ -452,7 +239,7 @@ inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) cons inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const { - return declarativeData && QAbstractDeclarativeData::isSignalConnected + return !isDeletingChildren && declarativeData && QAbstractDeclarativeData::isSignalConnected && QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index); } @@ -467,30 +254,10 @@ inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal) } namespace QtPrivate { +inline const QObject *getQObject(const QObjectPrivate *d) { return d->q_func(); } template <typename Func> -struct FunctionStorageByValue -{ - Func f; - Func &func() noexcept { return f; } -}; - -template <typename Func> -struct FunctionStorageEmptyBaseClassOptimization : Func -{ - Func &func() noexcept { return *this; } - using Func::Func; -}; - -template <typename Func> -using FunctionStorage = typename std::conditional_t< - std::conjunction_v< - std::is_empty<Func>, - std::negation<std::is_final<Func>> - >, - FunctionStorageEmptyBaseClassOptimization<Func>, - FunctionStorageByValue<Func> - >; +using FunctionStorage = QtPrivate::CompactStorage<Func>; template <typename ObjPrivate> inline void assertObjectType(QObjectPrivate *d) { @@ -502,18 +269,23 @@ template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase, private FunctionStorage<Func> { typedef QtPrivate::FunctionPointer<Func> FuncType; +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret) +#else + static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret) +#endif { + const auto that = static_cast<QPrivateSlotObject*>(this_); switch (which) { case Destroy: - delete static_cast<QPrivateSlotObject*>(this_); + delete that; break; case Call: - FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->func(), + FuncType::template call<Args, R>(that->object(), static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a); break; case Compare: - *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->func(); + *ret = *reinterpret_cast<Func *>(a) == that->object(); break; case NumOperations: ; } @@ -546,7 +318,7 @@ inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate: types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal), - receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot), + QtPrivate::getQObject(receiverPrivate), reinterpret_cast<void **>(&slot), new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value, typename SignalType::ReturnType>(slot), type, types, &SignalType::Object::staticMetaObject); @@ -568,9 +340,6 @@ bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 &SignalType::Object::staticMetaObject); } -Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_RELOCATABLE_TYPE); -Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_RELOCATABLE_TYPE); - class QSemaphore; class Q_CORE_EXPORT QAbstractMetaCallEvent : public QEvent { @@ -607,6 +376,9 @@ public: QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId, void **args, QSemaphore *semaphore); + QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj, + const QObject *sender, int signalId, + void **args, QSemaphore *semaphore); // queued - args allocated by event, copied by caller QMetaCallEvent(ushort method_offset, ushort method_relative, @@ -616,9 +388,31 @@ public: QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId, int nargs); + QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj, + const QObject *sender, int signalId, + int nargs); ~QMetaCallEvent() override; + template<typename ...Args> + static QMetaCallEvent *create(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, + int signal_index, const Args &...argv) + { + const void* const argp[] = { nullptr, std::addressof(argv)... }; + const QMetaType metaTypes[] = { QMetaType::fromType<void>(), QMetaType::fromType<Args>()... }; + constexpr auto argc = sizeof...(Args) + 1; + return create_impl(slotObj, sender, signal_index, argc, argp, metaTypes); + } + template<typename ...Args> + static QMetaCallEvent *create(QtPrivate::SlotObjUniquePtr slotObj, const QObject *sender, + int signal_index, const Args &...argv) + { + const void* const argp[] = { nullptr, std::addressof(argv)... }; + const QMetaType metaTypes[] = { QMetaType::fromType<void>(), QMetaType::fromType<Args>()... }; + constexpr auto argc = sizeof...(Args) + 1; + return create_impl(std::move(slotObj), sender, signal_index, argc, argp, metaTypes); + } + inline int id() const { return d.method_offset_ + d.method_relative_; } inline const void * const* args() const { return d.args_; } inline void ** args() { return d.args_; } @@ -628,10 +422,22 @@ public: virtual void placeMetaCall(QObject *object) override; private: + static QMetaCallEvent *create_impl(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, + int signal_index, size_t argc, const void * const argp[], + const QMetaType metaTypes[]) + { + if (slotObj) + slotObj->ref(); + return create_impl(QtPrivate::SlotObjUniquePtr{slotObj}, sender, + signal_index, argc, argp, metaTypes); + } + static QMetaCallEvent *create_impl(QtPrivate::SlotObjUniquePtr slotObj, const QObject *sender, + int signal_index, size_t argc, const void * const argp[], + const QMetaType metaTypes[]); inline void allocArgs(); struct Data { - QtPrivate::QSlotObjectBase *slotObj_; + QtPrivate::SlotObjUniquePtr slotObj_; void **args_; QObjectPrivate::StaticMetaCallFunction callFunction_; int nargs_; @@ -646,7 +452,9 @@ class QBoolBlocker { Q_DISABLE_COPY_MOVE(QBoolBlocker) public: - explicit inline QBoolBlocker(bool &b, bool value = true) : block(b), reset(b) { block = value; } + Q_NODISCARD_CTOR explicit QBoolBlocker(bool &b, bool value = true) + : block(b), reset(b) + { block = value; } inline ~QBoolBlocker() { block = reset; } private: @@ -654,8 +462,6 @@ private: bool reset; }; -void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o); - struct QAbstractDynamicMetaObject; struct Q_CORE_EXPORT QDynamicMetaObjectData { |