Move all connection related data into one data structure

Adn create that data structure on demand on the heap.

This reduces the size of QObjectPrivate if there are no
connections. If we have connections, it'll use the same
amount of allocations and memory as before.

Change-Id: I900f6980a2cd8a5f72c3ad18697b5dd49100217d
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Lars Knoll 2019-01-07 15:05:06 +01:00
parent ab92b9e400
commit 5cc6f90910
3 changed files with 215 additions and 212 deletions

View File

@ -182,7 +182,7 @@ QMetaObject *QObjectData::dynamicMetaObject() const
}
QObjectPrivate::QObjectPrivate(int version)
: threadData(0), connectionLists(0), senders(0), currentSender(0), currentChildBeingDeleted(0)
: threadData(0), currentChildBeingDeleted(0)
{
#ifdef QT_BUILD_INTERNAL
// Don't check the version parameter in internal builds.
@ -257,59 +257,22 @@ static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int
}
}
/*
This vector contains the all connections from an object.
Each object may have one vector containing the lists of
connections for a given signal. The index in the vector correspond
to the signal index. The signal index is the one returned by
QObjectPrivate::signalIndex (not QMetaObject::indexOfSignal).
Negative index means connections to all signals.
This vector is protected by the object mutex (signalSlotMutexes())
Each Connection is also part of a 'senders' linked list. The mutex
of the receiver must be locked when touching the pointers of this
linked list.
*/
class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList>
{
public:
bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse
bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet
int inUse; //number of functions that are currently accessing this object or its connections
QObjectPrivate::ConnectionList allsignals;
QObjectConnectionListVector()
: QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0)
{ }
QObjectPrivate::ConnectionList &operator[](int at)
{
if (at < 0)
return allsignals;
return QVector<QObjectPrivate::ConnectionList>::operator[](at);
}
};
// Used by QAccessibleWidget
bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const
{
Q_Q(const QObject);
int signal_index = signalIndex(signal);
if (signal_index < 0)
ConnectionData *cd = connections.load();
if (signal_index < 0 || !cd)
return false;
QMutexLocker locker(signalSlotLock(q));
if (connectionLists) {
if (signal_index < connectionLists->count()) {
const QObjectPrivate::Connection *c =
connectionLists->at(signal_index).first;
if (signal_index < cd->signalVector.count()) {
const QObjectPrivate::Connection *c = cd->signalVector.at(signal_index).first;
while (c) {
if (c->receiver == receiver)
return true;
c = c->nextConnectionList;
}
while (c) {
if (c->receiver == receiver)
return true;
c = c->nextConnectionList;
}
}
return false;
@ -321,18 +284,17 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const
Q_Q(const QObject);
QObjectList returnValue;
int signal_index = signalIndex(signal);
if (signal_index < 0)
ConnectionData *cd = connections.load();
if (signal_index < 0 || !cd)
return returnValue;
QMutexLocker locker(signalSlotLock(q));
if (connectionLists) {
if (signal_index < connectionLists->count()) {
const QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;
if (signal_index < cd->signalVector.count()) {
const QObjectPrivate::Connection *c = cd->signalVector.at(signal_index).first;
while (c) {
if (c->receiver)
returnValue << c->receiver;
c = c->nextConnectionList;
}
while (c) {
if (c->receiver)
returnValue << c->receiver;
c = c->nextConnectionList;
}
}
return returnValue;
@ -342,9 +304,12 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const
QObjectList QObjectPrivate::senderList() const
{
QObjectList returnValue;
QMutexLocker locker(signalSlotLock(q_func()));
for (Connection *c = senders; c; c = c->next)
returnValue << c->sender;
ConnectionData *cd = connections.load();
if (cd) {
QMutexLocker locker(signalSlotLock(q_func()));
for (Connection *c = cd->senders; c; c = c->next)
returnValue << c->sender;
}
return returnValue;
}
@ -361,12 +326,12 @@ QObjectList QObjectPrivate::senderList() const
void QObjectPrivate::addConnection(int signal, Connection *c)
{
Q_ASSERT(c->sender == q_ptr);
if (!connectionLists)
connectionLists = new QObjectConnectionListVector();
if (signal >= connectionLists->count())
connectionLists->resize(signal + 1);
ensureConnectionData();
ConnectionData *cd = connections.load();
if (signal >= cd->signalVector.count())
cd->signalVector.resize(signal + 1);
ConnectionList &connectionList = (*connectionLists)[signal];
ConnectionList &connectionList = cd->connectionsForSignal(signal);
if (connectionList.last) {
connectionList.last->nextConnectionList = c;
} else {
@ -376,7 +341,10 @@ void QObjectPrivate::addConnection(int signal, Connection *c)
cleanConnectionLists();
c->prev = &(QObjectPrivate::get(c->receiver)->senders);
QObjectPrivate *rd = QObjectPrivate::get(c->receiver);
rd->ensureConnectionData();
c->prev = &(rd->connections.load()->senders);
c->next = *c->prev;
*c->prev = c;
if (c->next)
@ -385,11 +353,11 @@ void QObjectPrivate::addConnection(int signal, Connection *c)
void QObjectPrivate::cleanConnectionLists()
{
if (connectionLists->dirty && !connectionLists->inUse) {
ConnectionData *cd = connections.load();
if (cd->dirty && !cd->inUse) {
// remove broken connections
for (int signal = -1; signal < connectionLists->count(); ++signal) {
QObjectPrivate::ConnectionList &connectionList =
(*connectionLists)[signal];
for (int signal = -1; signal < cd->signalVector.count(); ++signal) {
ConnectionList &connectionList = cd->connectionsForSignal(signal);
// Set to the last entry in the connection list that was *not*
// deleted. This is needed to update the list's last pointer
@ -415,7 +383,7 @@ void QObjectPrivate::cleanConnectionLists()
// As conectionList.last could equal last, this could be a noop
connectionList.last = last;
}
connectionLists->dirty = false;
cd->dirty = false;
}
}
@ -430,14 +398,15 @@ bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative)
if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
return true;
if (!connectionLists)
ConnectionData *cd = connections.load();
if (!cd)
return false;
if (connectionLists->allsignals.first)
if (cd->allsignals.first)
return true;
if (signalIndex < uint(connectionLists->count())) {
const QObjectPrivate::Connection *c = connectionLists->at(signalIndex).first;
if (signalIndex < uint(cd->signalVector.count())) {
const QObjectPrivate::Connection *c = cd->signalVector.at(signalIndex).first;
while (c) {
if (c->receiver)
return true;
@ -905,60 +874,51 @@ QObject::~QObject()
}
}
if (d->currentSender) {
d->currentSender->receiverDeleted();
d->currentSender = nullptr;
}
QObjectPrivate::ConnectionData *cd = d->connections.load();
if (cd) {
if (cd->currentSender) {
cd->currentSender->receiverDeleted();
cd->currentSender = nullptr;
}
if (d->connectionLists || d->senders) {
QMutex *signalSlotMutex = signalSlotLock(this);
QMutexLocker locker(signalSlotMutex);
++cd->inUse;
// disconnect all receivers
if (d->connectionLists) {
++d->connectionLists->inUse;
int connectionListsCount = d->connectionLists->count();
for (int signal = -1; signal < connectionListsCount; ++signal) {
QObjectPrivate::ConnectionList &connectionList =
(*d->connectionLists)[signal];
while (QObjectPrivate::Connection *c = connectionList.first) {
if (!c->receiver) {
connectionList.first = c->nextConnectionList;
c->deref();
continue;
}
QMutex *m = signalSlotLock(c->receiver);
bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
if (c->receiver) {
*c->prev = c->next;
if (c->next) c->next->prev = c->prev;
}
c->receiver = 0;
if (needToUnlock)
m->unlock();
int receiverCount = cd->signalVector.count();
for (int signal = -1; signal < receiverCount; ++signal) {
QObjectPrivate::ConnectionList &connectionList = cd->connectionsForSignal(signal);
while (QObjectPrivate::Connection *c = connectionList.first) {
if (!c->receiver) {
connectionList.first = c->nextConnectionList;
// The destroy operation must happen outside the lock
if (c->isSlotObject) {
c->isSlotObject = false;
locker.unlock();
c->slotObj->destroyIfLastRef();
locker.relock();
}
c->deref();
continue;
}
}
if (!--d->connectionLists->inUse) {
delete d->connectionLists;
} else {
d->connectionLists->orphaned = true;
QMutex *m = signalSlotLock(c->receiver);
bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
if (c->receiver) {
*c->prev = c->next;
if (c->next) c->next->prev = c->prev;
}
c->receiver = 0;
if (needToUnlock)
m->unlock();
connectionList.first = c->nextConnectionList;
// The destroy operation must happen outside the lock
if (c->isSlotObject) {
c->isSlotObject = false;
locker.unlock();
c->slotObj->destroyIfLastRef();
locker.relock();
}
c->deref();
}
d->connectionLists = 0;
}
/* Disconnect all senders:
@ -970,8 +930,9 @@ QObject::~QObject()
* thread. That's why we set node->prev to &node, that way, if node is destroyed, node will
* be updated.
*/
QObjectPrivate::Connection *node = d->senders;
QObjectPrivate::Connection *node = cd->senders;
while (node) {
Q_ASSERT(node->receiver);
QObject *sender = node->sender;
// Send disconnectNotify before removing the connection from sender's connection list.
// This ensures any eventual destructor of sender will block on getting receiver's lock
@ -988,9 +949,9 @@ QObject::~QObject()
continue;
}
node->receiver = 0;
QObjectConnectionListVector *senderLists = sender->d_func()->connectionLists;
if (senderLists)
senderLists->dirty = true;
QObjectPrivate::ConnectionData *senderData = sender->d_func()->connections;
if (senderData)
senderData->dirty = true;
QtPrivate::QSlotObjectBase *slotObj = nullptr;
if (node->isSlotObject) {
@ -1010,6 +971,13 @@ QObject::~QObject()
locker.relock();
}
}
if (!--cd->inUse) {
delete cd;
} else {
cd->orphaned = true;
}
d->connections.store(nullptr);
}
if (!d->children.isEmpty())
@ -1239,6 +1207,10 @@ bool QObject::event(QEvent *e)
{
QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e);
if (!d_func()->connections.load()) {
QMutexLocker locker(signalSlotLock(this));
d_func()->ensureConnectionData();
}
QObjectPrivate::Sender sender(this, const_cast<QObject*>(mce->sender()), mce->signalId());
mce->placeMetaCall(this);
@ -1543,9 +1515,10 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData
}
// the current emitting thread shouldn't restore currentSender after calling moveToThread()
if (currentSender) {
currentSender->receiverDeleted();
currentSender = nullptr;
ConnectionData *cd = connections.load();
if (cd && cd->currentSender) {
cd->currentSender->receiverDeleted();
cd->currentSender = nullptr;
}
// set new thread data
@ -2354,12 +2327,13 @@ QObject *QObject::sender() const
Q_D(const QObject);
QMutexLocker locker(signalSlotLock(this));
if (!d->currentSender)
return 0;
QObjectPrivate::ConnectionData *cd = d->connections.load();
if (!cd || !cd->currentSender)
return nullptr;
for (QObjectPrivate::Connection *c = d->senders; c; c = c->next) {
if (c->sender == d->currentSender->sender)
return d->currentSender->sender;
for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
if (c->sender == cd->currentSender->sender)
return cd->currentSender->sender;
}
return 0;
@ -2395,13 +2369,14 @@ int QObject::senderSignalIndex() const
Q_D(const QObject);
QMutexLocker locker(signalSlotLock(this));
if (!d->currentSender)
QObjectPrivate::ConnectionData *cd = d->connections.load();
if (!cd || !cd->currentSender)
return -1;
for (QObjectPrivate::Connection *c = d->senders; c; c = c->next) {
if (c->sender == d->currentSender->sender) {
for (QObjectPrivate::Connection *c = cd->senders; c; c = c->next) {
if (c->sender == cd->currentSender->sender) {
// Convert from signal range to method range
return QMetaObjectPrivate::signal(c->sender->metaObject(), d->currentSender->signal).methodIndex();
return QMetaObjectPrivate::signal(c->sender->metaObject(), cd->currentSender->signal).methodIndex();
}
}
@ -2433,7 +2408,8 @@ int QObject::receivers(const char *signal) const
{
Q_D(const QObject);
int receivers = 0;
if (signal) {
QObjectPrivate::ConnectionData *cd = d->connections.load();
if (signal && cd) {
QByteArray signal_name = QMetaObject::normalizedSignature(signal);
signal = signal_name;
#ifndef QT_NO_DEBUG
@ -2458,14 +2434,12 @@ int QObject::receivers(const char *signal) const
}
QMutexLocker locker(signalSlotLock(this));
if (d->connectionLists) {
if (signal_index < d->connectionLists->count()) {
const QObjectPrivate::Connection *c =
d->connectionLists->at(signal_index).first;
while (c) {
receivers += c->receiver ? 1 : 0;
c = c->nextConnectionList;
}
if (signal_index < cd->signalVector.count()) {
const QObjectPrivate::Connection *c =
cd->signalVector.at(signal_index).first;
while (c) {
receivers += c->receiver ? 1 : 0;
c = c->nextConnectionList;
}
}
}
@ -3269,23 +3243,21 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
int method_offset = rmeta ? rmeta->methodOffset() : 0;
Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
QObjectPrivate::StaticMetaCallFunction callFunction =
rmeta ? rmeta->d.static_metacall : 0;
QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : nullptr;
QOrderedMutexLocker locker(signalSlotLock(sender),
signalSlotLock(receiver));
if (type & Qt::UniqueConnection) {
QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
if (connectionLists && connectionLists->count() > signal_index) {
const QObjectPrivate::Connection *c2 =
(*connectionLists)[signal_index].first;
QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.load();
if (type & Qt::UniqueConnection && scd) {
if (scd->signalVector.count() > signal_index) {
const QObjectPrivate::Connection *c2 = scd->signalVector.at(signal_index).first;
int method_index_absolute = method_index + method_offset;
while (c2) {
if (!c2->isSlotObject && c2->receiver == receiver && c2->method() == method_index_absolute)
return 0;
return nullptr;
c2 = c2->nextConnectionList;
}
}
@ -3409,37 +3381,35 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender,
QMutex *senderMutex = signalSlotLock(sender);
QMutexLocker locker(senderMutex);
QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
if (!connectionLists)
QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.load();
if (!scd)
return false;
// prevent incoming connections changing the connectionLists while unlocked
++connectionLists->inUse;
// prevent incoming connections changing the connections->receivers while unlocked
++scd->inUse;
bool success = false;
if (signal_index < 0) {
// remove from all connection lists
for (int sig_index = -1; sig_index < connectionLists->count(); ++sig_index) {
QObjectPrivate::Connection *c =
(*connectionLists)[sig_index].first;
for (int sig_index = -1; sig_index < scd->signalVector.count(); ++sig_index) {
QObjectPrivate::Connection *c = scd->connectionsForSignal(sig_index).first;
if (disconnectHelper(c, receiver, method_index, slot, senderMutex, disconnectType)) {
success = true;
connectionLists->dirty = true;
scd->dirty = true;
}
}
} else if (signal_index < connectionLists->count()) {
QObjectPrivate::Connection *c =
(*connectionLists)[signal_index].first;
} else if (signal_index < scd->signalVector.count()) {
QObjectPrivate::Connection *c = scd->signalVector.at(signal_index).first;
if (disconnectHelper(c, receiver, method_index, slot, senderMutex, disconnectType)) {
success = true;
connectionLists->dirty = true;
scd->dirty = true;
}
}
--connectionLists->inUse;
Q_ASSERT(connectionLists->inUse >= 0);
if (connectionLists->orphaned && !connectionLists->inUse)
delete connectionLists;
--scd->inUse;
Q_ASSERT(scd->inUse >= 0);
if (scd->orphaned && !scd->inUse)
delete scd;
locker.unlock();
if (success) {
@ -3651,35 +3621,36 @@ void doActivate(QObject *sender, int signal_index, void **argv)
{
QMutexLocker locker(signalSlotLock(sender));
struct ConnectionListsRef {
QObjectConnectionListVector *connectionLists;
ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists)
struct ConnectionDataRef {
QObjectPrivate::ConnectionData *connections;
ConnectionDataRef(QObjectPrivate::ConnectionData *connections) : connections(connections)
{
if (connectionLists)
++connectionLists->inUse;
if (connections)
++connections->inUse;
}
~ConnectionListsRef()
~ConnectionDataRef()
{
if (!connectionLists)
if (!connections)
return;
--connectionLists->inUse;
Q_ASSERT(connectionLists->inUse >= 0);
if (connectionLists->orphaned) {
if (!connectionLists->inUse)
delete connectionLists;
--connections->inUse;
Q_ASSERT(connections->inUse >= 0);
if (connections->orphaned) {
if (!connections->inUse)
delete connections;
}
}
QObjectConnectionListVector *operator->() const { return connectionLists; }
QObjectPrivate::ConnectionData *operator->() const { return connections; }
};
ConnectionListsRef connectionLists = sp->connectionLists;
Q_ASSERT(sp->connections.load());
ConnectionDataRef connections = sp->connections.load();
const QObjectPrivate::ConnectionList *list;
if (signal_index < connectionLists->count())
list = &connectionLists->at(signal_index);
if (signal_index < connections->signalVector.count())
list = &connections->signalVector.at(signal_index);
else
list = &connectionLists->allsignals;
list = &connections->allsignals;
Qt::HANDLE currentThreadId = QThread::currentThreadId();
@ -3773,15 +3744,15 @@ void doActivate(QObject *sender, int signal_index, void **argv)
locker.relock();
}
if (connectionLists->orphaned)
if (connections->orphaned)
break;
} while (c != last && (c = c->nextConnectionList) != 0);
if (connectionLists->orphaned)
if (connections->orphaned)
break;
} while (list != &connectionLists->allsignals &&
} while (list != &connections->allsignals &&
//start over for all signals;
((list = &connectionLists->allsignals), true));
((list = &connections->allsignals), true));
}
@ -3832,7 +3803,7 @@ void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
/*!
\internal
Returns the signal index used in the internal connectionLists vector.
Returns the signal index used in the internal connections->receivers vector.
It is different from QMetaObject::indexOfSignal(): indexOfSignal is the same as indexOfMethod
while QObjectPrivate::signalIndex is smaller because it doesn't give index to slots.
@ -4077,14 +4048,14 @@ void QObject::dumpObjectInfo() const
// first, look for connections where this object is the sender
qDebug(" SIGNALS OUT");
if (d->connectionLists) {
for (int signal_index = 0; signal_index < d->connectionLists->count(); ++signal_index) {
QObjectPrivate::ConnectionData *cd = d->connections.load();
if (cd && cd->signalVector.count()) {
for (int signal_index = 0; signal_index < cd->signalVector.count(); ++signal_index) {
const QMetaMethod signal = QMetaObjectPrivate::signal(metaObject(), signal_index);
qDebug(" signal: %s", signal.methodSignature().constData());
// receivers
const QObjectPrivate::Connection *c =
d->connectionLists->at(signal_index).first;
const QObjectPrivate::Connection *c = cd->signalVector.at(signal_index).first;
while (c) {
if (!c->receiver) {
qDebug(" <Disconnected receiver>");
@ -4112,8 +4083,8 @@ void QObject::dumpObjectInfo() const
// now look for connections where this object is the receiver
qDebug(" SIGNALS IN");
if (d->senders) {
for (QObjectPrivate::Connection *s = d->senders; s; s = s->next) {
if (cd && cd->senders) {
for (QObjectPrivate::Connection *s = cd->senders; s; s = s->next) {
QByteArray slotName = QByteArrayLiteral("<unknown>");
if (!s->isSlotObject) {
const QMetaMethod slot = metaObject()->method(s->method());
@ -4848,11 +4819,10 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s
QOrderedMutexLocker locker(signalSlotLock(sender),
signalSlotLock(receiver));
if (type & Qt::UniqueConnection && slot) {
QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
if (connectionLists && connectionLists->count() > signal_index) {
const QObjectPrivate::Connection *c2 =
(*connectionLists)[signal_index].first;
if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.load()) {
QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.load();
if (connections->signalVector.count() > signal_index) {
const QObjectPrivate::Connection *c2 = connections->signalVector.at(signal_index).first;
while (c2) {
if (c2->receiver == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {
@ -4909,14 +4879,14 @@ bool QObject::disconnect(const QMetaObject::Connection &connection)
{
QOrderedMutexLocker locker(senderMutex, receiverMutex);
QObjectConnectionListVector *connectionLists = QObjectPrivate::get(c->sender)->connectionLists;
Q_ASSERT(connectionLists);
connectionLists->dirty = true;
QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(c->sender)->connections.load();
Q_ASSERT(connections);
connections->dirty = true;
*c->prev = c->next;
if (c->next)
c->next->prev = c->prev;
c->receiver = 0;
c->receiver = nullptr;
}
// destroy the QSlotObject, if possible
@ -4928,7 +4898,7 @@ bool QObject::disconnect(const QMetaObject::Connection &connection)
c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(),
c->signal_index));
const_cast<QMetaObject::Connection &>(connection).d_ptr = 0;
const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
c->deref(); // has been removed from the QMetaObject::Connection object
return true;

View File

@ -171,14 +171,15 @@ public:
: receiver(receiver), sender(sender), signal(signal)
{
if (receiver) {
previous = receiver->d_func()->currentSender;
receiver->d_func()->currentSender = this;
ConnectionData *cd = receiver->d_func()->connections.load();
previous = cd->currentSender;
cd->currentSender = this;
}
}
~Sender()
{
if (receiver)
receiver->d_func()->currentSender = previous;
receiver->d_func()->connections.load()->currentSender = previous;
}
void receiverDeleted()
{
@ -194,6 +195,34 @@ public:
int signal;
};
/*
This contains the all connections from and to an object.
The signalVector contains the lists of connections for a given signal. The index in the vector correspond
to the signal index. The signal index is the one returned by QObjectPrivate::signalIndex (not
QMetaObject::indexOfSignal). allsignals contains a list of special connections that will get invoked on
any signal emission. This is done by connecting to signal index -1.
This vector is protected by the object mutex (signalSlotLock())
Each Connection is also part of a 'senders' linked list. This one contains all connections connected
to a slot in this object. The mutex of the receiver must be locked when touching the pointers of this
linked list.
*/
struct ConnectionData {
bool orphaned = false; //the QObject owner of this vector has been destroyed while the vector was inUse
bool dirty = false; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet
int inUse = 0; //number of functions that are currently accessing this object or its connections
ConnectionList allsignals;
QVector<ConnectionList> signalVector;
Connection *senders = nullptr;
Sender *currentSender = nullptr; // object currently activating the object
ConnectionList &connectionsForSignal(int signal)
{
return signal < 0 ? allsignals : signalVector[signal];
}
};
QObjectPrivate(int version = QObjectPrivateVersion);
virtual ~QObjectPrivate();
@ -240,14 +269,18 @@ public:
const int *types, const QMetaObject *senderMetaObject);
static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
static bool disconnect(const QObject *sender, int signal_index, void **slot);
void ensureConnectionData()
{
if (connections.load())
return;
connections.store(new ConnectionData);
}
public:
ExtraData *extraData; // extra data set by the user
QThreadData *threadData; // id of the thread that owns the object
QObjectConnectionListVector *connectionLists;
Connection *senders; // linked list of connections connected to this object
Sender *currentSender; // object currently activating the object
QAtomicPointer<ConnectionData> connections;
union {
QObject *currentChildBeingDeleted; // should only be used when QObjectData::isDeletingChildren is set

View File

@ -126,9 +126,9 @@ void tst_toolsupport::offsets_data()
#ifdef Q_PROCESSOR_X86
// x86 32-bit has weird alignment rules. Refer to QtPrivate::AlignOf in
// qglobal.h for more details.
data << 160 << 240;
data << 152 << 224;
#else
data << 164 << 240;
data << 156 << 224;
#endif
}
#endif