cleanOrphanedConnectionsImpl: Allow to skip locking
This function is/will be used in a few places where we already have a lock. Temporarily unlocking and relocking invites all kinds of troubles. By adding a flag we can instead tell the function that we already hold the lock. Pick-to: 6.2 6.1 5.15 Change-Id: Ibca089de61133661d5cd75290f2a55c22c5d013c Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
This commit is contained in:
parent
7fefce7328
commit
556fc646cf
@ -70,6 +70,7 @@
|
||||
#include <qtcore_tracepoints_p.h>
|
||||
|
||||
#include <new>
|
||||
#include <mutex>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
@ -404,11 +405,14 @@ void QObjectPrivate::ConnectionData::removeConnection(QObjectPrivate::Connection
|
||||
|
||||
}
|
||||
|
||||
void QObjectPrivate::ConnectionData::cleanOrphanedConnectionsImpl(QObject *sender)
|
||||
void QObjectPrivate::ConnectionData::cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy)
|
||||
{
|
||||
QBasicMutex *senderMutex = signalSlotLock(sender);
|
||||
ConnectionOrSignalVector *c = nullptr;
|
||||
{
|
||||
QBasicMutexLocker l(signalSlotLock(sender));
|
||||
std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
|
||||
if (lockPolicy == NeedToLock)
|
||||
lock.lock();
|
||||
if (ref.loadAcquire() > 1)
|
||||
return;
|
||||
|
||||
@ -418,7 +422,16 @@ void QObjectPrivate::ConnectionData::cleanOrphanedConnectionsImpl(QObject *sende
|
||||
c = orphaned.loadRelaxed();
|
||||
orphaned.storeRelaxed(nullptr);
|
||||
}
|
||||
deleteOrphaned(c);
|
||||
if (c) {
|
||||
// Deleting c might run arbitrary user code, so we must not hold the lock
|
||||
if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
|
||||
senderMutex->unlock();
|
||||
deleteOrphaned(c);
|
||||
senderMutex->lock();
|
||||
} else {
|
||||
deleteOrphaned(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QObjectPrivate::ConnectionData::deleteOrphaned(QObjectPrivate::ConnectionOrSignalVector *o)
|
||||
|
@ -280,12 +280,19 @@ public:
|
||||
// must be called on the senders connection data
|
||||
// assumes the senders and receivers lock are held
|
||||
void removeConnection(Connection *c);
|
||||
void cleanOrphanedConnections(QObject *sender)
|
||||
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);
|
||||
cleanOrphanedConnectionsImpl(sender, lockPolicy);
|
||||
}
|
||||
void cleanOrphanedConnectionsImpl(QObject *sender);
|
||||
void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy);
|
||||
|
||||
ConnectionList &connectionsForSignal(int signal)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user