diff options
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 214 |
1 files changed, 1 insertions, 213 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index ebdc9e43f0..e3f686d3de 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -5,6 +5,7 @@ #include "qobject.h" #include "qobject_p.h" +#include "qobject_p_p.h" #include "qmetaobject_p.h" #include "qabstracteventdispatcher.h" @@ -49,219 +50,6 @@ Q_LOGGING_CATEGORY(lcConnect, "qt.core.qobject.connect") Q_CORE_EXPORT QBasicAtomicPointer<QSignalSpyCallbackSet> qt_signal_spy_callback_set = Q_BASIC_ATOMIC_INITIALIZER(nullptr); -// ConnectionList is a singly-linked list -struct QObjectPrivate::ConnectionList -{ - QAtomicPointer<Connection> first; - QAtomicPointer<Connection> last; -}; -static_assert(std::is_trivially_destructible_v<QObjectPrivate::ConnectionList>); -Q_DECLARE_TYPEINFO(QObjectPrivate::ConnectionList, Q_RELOCATABLE_TYPE); - -struct QObjectPrivate::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)); - } -}; -static_assert(std::is_trivial_v<QObjectPrivate::ConnectionOrSignalVector>); - -struct QObjectPrivate::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_{2}; //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection - 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() : ownArgumentTypes(true) { } - ~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; - } - } -}; -Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_RELOCATABLE_TYPE); - -struct QObjectPrivate::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); } -}; -static_assert(std::is_trivial_v<QObjectPrivate::SignalVector>); // it doesn't need to be, but it helps - -struct QObjectPrivate::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) { - v->~SignalVector(); - 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; - void *ptr = malloc(sizeof(SignalVector) + (size + 1) * sizeof(ConnectionList)); - auto newVector = new (ptr) SignalVector; - - int start = -1; - if (vector) { - // not (yet) existing trait: - //static_assert(std::is_relocatable_v<SignalVector>); - //static_assert(std::is_relocatable_v<ConnectionList>); - memcpy(newVector, vector, sizeof(SignalVector) + (vector->allocated + 1) * sizeof(ConnectionList)); - start = vector->count(); - } - for (int i = start; i < int(size); ++i) - new (&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); -}; - -struct QObjectPrivate::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; -}; -Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_RELOCATABLE_TYPE); - void qt_register_signal_spy_callbacks(QSignalSpyCallbackSet *callback_set) { qt_signal_spy_callback_set.storeRelease(callback_set); |