summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2021-06-08 17:47:46 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2021-06-17 08:56:17 +0200
commit556fc646cfac4dca43a34f5c4a4f7e6e3ef9104d (patch)
tree707c40f2ee6be502584798d6684b43a619332e3d /src/corelib
parent7fefce73284de4204d64c7e4129f39004a13cdad (diff)
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>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/kernel/qobject.cpp19
-rw-r--r--src/corelib/kernel/qobject_p.h13
2 files changed, 26 insertions, 6 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 1659573009..4c2a787173 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -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)
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 6d5044e99c..f945b79ca1 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -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)
{