From aea500d5d76864bb1a3918e338ca6806e1766e41 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 9 Jan 2019 11:00:01 +0100 Subject: Use QBasicMutex instead of QMutex in the signalSlockLock() Add a simple private QBasicMutexLocker class, and let the QOrderedMutexLocker operate on a QBasicMutex. This allows the compiler to inline more things when handling connections and speeds up activate() a bit more. without change with change string based connect: 3621 3368 pointer based connect: 4341 3919 not connected: 433 437 disconnected: 551 538 Change-Id: If979337891178aaeb0b3340b6d4f68b6f86b0260 Reviewed-by: Qt CI Bot Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qmetaobject_p.h | 4 +- src/corelib/kernel/qobject.cpp | 47 +++++++++++----------- src/corelib/thread/qorderedmutexlocker_p.h | 62 +++++++++++++++++++++++++++--- 3 files changed, 81 insertions(+), 32 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index 522bd78e42..5b412b5140 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -54,6 +54,7 @@ #include #include +#include #ifndef QT_NO_QOBJECT #include // For QObjectPrivate::Connection #endif @@ -168,7 +169,6 @@ Q_DECLARE_TYPEINFO(QArgumentType, Q_MOVABLE_TYPE); typedef QVarLengthArray QArgumentTypeArray; class QMetaMethodPrivate; -class QMutex; struct QMetaObjectPrivate { @@ -234,7 +234,7 @@ struct QMetaObjectPrivate DisconnectType = DisconnectAll); static inline bool disconnectHelper(QObjectPrivate::Connection *c, const QObject *receiver, int method_index, void **slot, - QMutex *senderMutex, DisconnectType = DisconnectAll); + QBasicMutex *senderMutex, DisconnectType = DisconnectAll); #endif }; diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index c3271b2c35..3db43ba1c4 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -152,10 +152,9 @@ static QBasicMutex _q_ObjectMutexPool[131]; * \internal * mutex to be locked when accessing the connectionlists or the senders list */ -static inline QMutex *signalSlotLock(const QObject *o) +static inline QBasicMutex *signalSlotLock(const QObject *o) { - return static_cast(&_q_ObjectMutexPool[ - uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]); + return &_q_ObjectMutexPool[uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]; } #if QT_VERSION < 0x60000 @@ -265,7 +264,7 @@ bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const ConnectionData *cd = connections.load(); if (signal_index < 0 || !cd) return false; - QMutexLocker locker(signalSlotLock(q)); + QBasicMutexLocker locker(signalSlotLock(q)); if (signal_index < cd->signalVector.count()) { const QObjectPrivate::Connection *c = cd->signalVector.at(signal_index).first; @@ -287,7 +286,7 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const ConnectionData *cd = connections.load(); if (signal_index < 0 || !cd) return returnValue; - QMutexLocker locker(signalSlotLock(q)); + QBasicMutexLocker locker(signalSlotLock(q)); if (signal_index < cd->signalVector.count()) { const QObjectPrivate::Connection *c = cd->signalVector.at(signal_index).first; @@ -306,7 +305,7 @@ QObjectList QObjectPrivate::senderList() const QObjectList returnValue; ConnectionData *cd = connections.load(); if (cd) { - QMutexLocker locker(signalSlotLock(q_func())); + QBasicMutexLocker locker(signalSlotLock(q_func())); for (Connection *c = cd->senders; c; c = c->next) returnValue << c->sender; } @@ -881,8 +880,8 @@ QObject::~QObject() cd->currentSender = nullptr; } - QMutex *signalSlotMutex = signalSlotLock(this); - QMutexLocker locker(signalSlotMutex); + QBasicMutex *signalSlotMutex = signalSlotLock(this); + QBasicMutexLocker locker(signalSlotMutex); // disconnect all receivers int receiverCount = cd->signalVector.count(); @@ -896,7 +895,7 @@ QObject::~QObject() continue; } - QMutex *m = signalSlotLock(c->receiver); + QBasicMutex *m = signalSlotLock(c->receiver); bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); if (c->receiver) { @@ -937,7 +936,7 @@ QObject::~QObject() // This ensures any eventual destructor of sender will block on getting receiver's lock // and not finish until we release it. sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index)); - QMutex *m = signalSlotLock(sender); + QBasicMutex *m = signalSlotLock(sender); node->prev = &node; bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); //the node has maybe been removed while the mutex was unlocked in relock? @@ -1205,7 +1204,7 @@ bool QObject::event(QEvent *e) QMetaCallEvent *mce = static_cast(e); if (!d_func()->connections.load()) { - QMutexLocker locker(signalSlotLock(this)); + QBasicMutexLocker locker(signalSlotLock(this)); d_func()->ensureConnectionData(); } QObjectPrivate::Sender sender(this, const_cast(mce->sender()), mce->signalId()); @@ -2323,7 +2322,7 @@ QObject *QObject::sender() const { Q_D(const QObject); - QMutexLocker locker(signalSlotLock(this)); + QBasicMutexLocker locker(signalSlotLock(this)); QObjectPrivate::ConnectionData *cd = d->connections.load(); if (!cd || !cd->currentSender) return nullptr; @@ -2365,7 +2364,7 @@ int QObject::senderSignalIndex() const { Q_D(const QObject); - QMutexLocker locker(signalSlotLock(this)); + QBasicMutexLocker locker(signalSlotLock(this)); QObjectPrivate::ConnectionData *cd = d->connections.load(); if (!cd || !cd->currentSender) return -1; @@ -2430,7 +2429,7 @@ int QObject::receivers(const char *signal) const signal_index); } - QMutexLocker locker(signalSlotLock(this)); + QBasicMutexLocker locker(signalSlotLock(this)); if (signal_index < cd->signalVector.count()) { const QObjectPrivate::Connection *c = cd->signalVector.at(signal_index).first; @@ -2476,7 +2475,7 @@ bool QObject::isSignalConnected(const QMetaMethod &signal) const signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj); - QMutexLocker locker(signalSlotLock(this)); + QBasicMutexLocker locker(signalSlotLock(this)); return d->isSignalConnected(signalIndex, true); } @@ -3318,7 +3317,7 @@ bool QMetaObject::disconnectOne(const QObject *sender, int signal_index, */ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, const QObject *receiver, int method_index, void **slot, - QMutex *senderMutex, DisconnectType disconnectType) + QBasicMutex *senderMutex, DisconnectType disconnectType) { bool success = false; while (c) { @@ -3327,7 +3326,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, && (method_index < 0 || (!c->isSlotObject && c->method() == method_index)) && (slot == 0 || (c->isSlotObject && c->slotObj->compare(slot)))))) { bool needToUnlock = false; - QMutex *receiverMutex = 0; + QBasicMutex *receiverMutex = nullptr; if (c->receiver) { receiverMutex = signalSlotLock(c->receiver); // need to relock this receiver and sender in the correct order @@ -3375,8 +3374,8 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, QObject *s = const_cast(sender); - QMutex *senderMutex = signalSlotLock(sender); - QMutexLocker locker(senderMutex); + QBasicMutex *senderMutex = signalSlotLock(sender); + QBasicMutexLocker locker(senderMutex); QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.load(); if (!scd) @@ -3523,7 +3522,7 @@ void QMetaObject::connectSlotsByName(QObject *o) \a signal must be in the signal index range (see QObjectPrivate::signalIndex()). */ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv, - QMutexLocker &locker) + QBasicMutexLocker &locker) { const int *argumentTypes = c->argumentTypes.load(); if (!argumentTypes) { @@ -3614,7 +3613,7 @@ void doActivate(QObject *sender, int signal_index, void **argv) Q_TRACE(QMetaObject_activate_begin_signal, sender, signal_index); { - QMutexLocker locker(signalSlotLock(sender)); + QBasicMutexLocker locker(signalSlotLock(sender)); Q_ASSERT(sp->connections); QObjectPrivate::ConnectionDataPointer connections(sp->connections.load()); @@ -4015,7 +4014,7 @@ void QObject::dumpObjectInfo() const objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data()); Q_D(const QObject); - QMutexLocker locker(signalSlotLock(this)); + QBasicMutexLocker locker(signalSlotLock(this)); // first, look for connections where this object is the sender qDebug(" SIGNALS OUT"); @@ -4845,8 +4844,8 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) if (!c || !c->receiver) return false; - QMutex *senderMutex = signalSlotLock(c->sender); - QMutex *receiverMutex = signalSlotLock(c->receiver); + QBasicMutex *senderMutex = signalSlotLock(c->sender); + QBasicMutex *receiverMutex = signalSlotLock(c->receiver); { QOrderedMutexLocker locker(senderMutex, receiverMutex); diff --git a/src/corelib/thread/qorderedmutexlocker_p.h b/src/corelib/thread/qorderedmutexlocker_p.h index ded102d32d..5b2c7ab112 100644 --- a/src/corelib/thread/qorderedmutexlocker_p.h +++ b/src/corelib/thread/qorderedmutexlocker_p.h @@ -58,6 +58,8 @@ QT_BEGIN_NAMESPACE +#if QT_CONFIG(thread) + /* Locks 2 mutexes in a defined order, avoiding a recursive lock if we're trying to lock the same mutex twice. @@ -65,9 +67,9 @@ QT_BEGIN_NAMESPACE class QOrderedMutexLocker { public: - QOrderedMutexLocker(QMutex *m1, QMutex *m2) - : mtx1((m1 == m2) ? m1 : (std::less()(m1, m2) ? m1 : m2)), - mtx2((m1 == m2) ? 0 : (std::less()(m1, m2) ? m2 : m1)), + QOrderedMutexLocker(QBasicMutex *m1, QBasicMutex *m2) + : mtx1((m1 == m2) ? m1 : (std::less()(m1, m2) ? m1 : m2)), + mtx2((m1 == m2) ? 0 : (std::less()(m1, m2) ? m2 : m1)), locked(false) { relock(); @@ -95,12 +97,12 @@ public: } } - static bool relock(QMutex *mtx1, QMutex *mtx2) + static bool relock(QBasicMutex *mtx1, QBasicMutex *mtx2) { // mtx1 is already locked, mtx2 not... do we need to unlock and relock? if (mtx1 == mtx2) return false; - if (std::less()(mtx1, mtx2)) { + if (std::less()(mtx1, mtx2)) { mtx2->lock(); return true; } @@ -113,10 +115,58 @@ public: } private: - QMutex *mtx1, *mtx2; + QBasicMutex *mtx1, *mtx2; bool locked; }; +class QBasicMutexLocker +{ +public: + inline explicit QBasicMutexLocker(QBasicMutex *m) QT_MUTEX_LOCK_NOEXCEPT + : m(m), isLocked(true) + { + m->lock(); + } + inline ~QBasicMutexLocker() { if (isLocked) unlock(); } + + inline void unlock() Q_DECL_NOTHROW + { + isLocked = false; + m->unlock(); + } + + inline void relock() QT_MUTEX_LOCK_NOEXCEPT + { + isLocked = true; + m->lock(); + } + +private: + Q_DISABLE_COPY(QBasicMutexLocker) + + QBasicMutex *m; + bool isLocked; +}; + +#else + +class QOrderedMutexLocker +{ +public: + QOrderedMutexLocker(QBasicMutex *, QBasicMutex *) {} + ~QOrderedMutexLocker() {} + + void relock() {} + void unlock() {} + + static bool relock(QBasicMutex *, QBasicMutex *) {} +}; + +using QBasicMutexLocker = QMutexLocker; + +#endif + + QT_END_NAMESPACE #endif -- cgit v1.2.3