Call QObject::disconnectNotify() when receiver is destroyed
Store the signal index in QObjectPrivate::Connection, thereby making it available in "implicit" disconnect contexts (i.e., receiver deletion). This change does not cause the size of QObjectPrivate::Connection to grow (still 40 bytes on 32-bit Linux, 72 bytes on 64-bit Mac). Valgrinding the new benchmark indicates that the percentage of the time spent in the QObject destructor increased from 7.8% to 8.4% on ia32, for that particular stress test; the increase is the combined cost of calling metaObject(), QMetaObjectPrivate::signal(), and disconnectNotify() for one connection. In practice, the measured wallclock time increased by about 3ms for a 500ms run (which repeatedly constructs, connects, and destroys an object). Task-number: QTBUG-4844 Change-Id: I1beb01c753f31542fc0acb62edb4c6d165fcc5b4 Reviewed-by: Olivier Goffart <ogoffart@woboq.com> Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
This commit is contained in:
parent
26c85a5f79
commit
d359b0af2b
@ -831,9 +831,11 @@ QObject::~QObject()
|
|||||||
if (senderLists)
|
if (senderLists)
|
||||||
senderLists->dirty = true;
|
senderLists->dirty = true;
|
||||||
|
|
||||||
|
int signal_index = node->signal_index;
|
||||||
node = node->next;
|
node = node->next;
|
||||||
if (needToUnlock)
|
if (needToUnlock)
|
||||||
m->unlock();
|
m->unlock();
|
||||||
|
sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), signal_index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3021,6 +3023,7 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
|
|||||||
|
|
||||||
QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
|
QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
|
||||||
c->sender = s;
|
c->sender = s;
|
||||||
|
c->signal_index = signal_index;
|
||||||
c->receiver = r;
|
c->receiver = r;
|
||||||
c->method_relative = method_index;
|
c->method_relative = method_index;
|
||||||
c->method_offset = method_offset;
|
c->method_offset = method_offset;
|
||||||
@ -4188,6 +4191,7 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
|
|||||||
|
|
||||||
QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
|
QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
|
||||||
c->sender = s;
|
c->sender = s;
|
||||||
|
c->signal_index = signal_index;
|
||||||
c->receiver = r;
|
c->receiver = r;
|
||||||
c->slotObj = slotObj;
|
c->slotObj = slotObj;
|
||||||
c->connectionType = type;
|
c->connectionType = type;
|
||||||
|
@ -131,6 +131,7 @@ public:
|
|||||||
QAtomicInt ref_;
|
QAtomicInt ref_;
|
||||||
ushort method_offset;
|
ushort method_offset;
|
||||||
ushort method_relative;
|
ushort method_relative;
|
||||||
|
uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
|
||||||
ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
|
ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
|
||||||
ushort isSlotObject : 1;
|
ushort isSlotObject : 1;
|
||||||
ushort ownArgumentTypes : 1;
|
ushort ownArgumentTypes : 1;
|
||||||
|
@ -978,8 +978,26 @@ void tst_QObject::disconnectNotify_receiverDestroyed()
|
|||||||
QVERIFY(QObject::connect((SenderObject*)s, SIGNAL(signal1()), (ReceiverObject*)r, SLOT(slot1())));
|
QVERIFY(QObject::connect((SenderObject*)s, SIGNAL(signal1()), (ReceiverObject*)r, SLOT(slot1())));
|
||||||
|
|
||||||
delete r;
|
delete r;
|
||||||
// disconnectNotify() is not called, but it probably should be.
|
QCOMPARE(s->disconnectedSignals.count(), 1);
|
||||||
QVERIFY(s->disconnectedSignals.isEmpty());
|
QCOMPARE(s->disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal1));
|
||||||
|
|
||||||
|
s->disconnectedSignals.clear();
|
||||||
|
r = new NotifyObject;
|
||||||
|
|
||||||
|
QVERIFY(QObject::connect((SenderObject*)s, SIGNAL(signal3()), (ReceiverObject*)r, SLOT(slot3())));
|
||||||
|
|
||||||
|
delete r;
|
||||||
|
QCOMPARE(s->disconnectedSignals.count(), 1);
|
||||||
|
QCOMPARE(s->disconnectedSignals.at(0), QMetaMethod::fromSignal(&SenderObject::signal3));
|
||||||
|
|
||||||
|
s->disconnectedSignals.clear();
|
||||||
|
r = new NotifyObject;
|
||||||
|
|
||||||
|
QVERIFY(QObject::connect((SenderObject*)s, SIGNAL(destroyed()), (ReceiverObject*)r, SLOT(slot3())));
|
||||||
|
|
||||||
|
delete r;
|
||||||
|
QCOMPARE(s->disconnectedSignals.count(), 1);
|
||||||
|
QCOMPARE(s->disconnectedSignals.at(0), QMetaMethod::fromSignal(&QObject::destroyed));
|
||||||
|
|
||||||
delete s;
|
delete s;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,7 @@ private slots:
|
|||||||
void dynamic_property_benchmark();
|
void dynamic_property_benchmark();
|
||||||
void connect_disconnect_benchmark_data();
|
void connect_disconnect_benchmark_data();
|
||||||
void connect_disconnect_benchmark();
|
void connect_disconnect_benchmark();
|
||||||
|
void receiver_destroyed_benchmark();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Functor {
|
struct Functor {
|
||||||
@ -236,6 +237,15 @@ void QObjectBenchmark::connect_disconnect_benchmark()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QObjectBenchmark::receiver_destroyed_benchmark()
|
||||||
|
{
|
||||||
|
Object sender;
|
||||||
|
QBENCHMARK {
|
||||||
|
Object receiver;
|
||||||
|
QObject::connect(&sender, &Object::signal0, &receiver, &Object::slot0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(QObjectBenchmark)
|
QTEST_MAIN(QObjectBenchmark)
|
||||||
|
|
||||||
#include "main.moc"
|
#include "main.moc"
|
||||||
|
Loading…
Reference in New Issue
Block a user