summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qobject.cpp
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2023-12-10 18:12:25 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2023-12-19 19:41:28 +0100
commit46588fbb516b980f0f6b11ce814ecf15d71967d3 (patch)
treedb163b30ec578797293d802417ca953690ae2e90 /src/corelib/kernel/qobject.cpp
parente02dc31fbf3ae460bea2aea068ccc969d6e852fc (diff)
Move QDeferredDeleteEvent loop level/scope handling into deleteLater()
We have all the information we need when deleteLater() is called, so there's no point in deferring it until the event is posted, which requires friended access into the QDeferredDeleteEvent's members. Moving the code focuses QCoreApplication::postEvent() on its primary task, posting of the event (adding to the event list, waking up the event dispatcher). It's also easier to reason about how the action of deleteLater on an object relates to the event loop and scope level when the information is resolved up front. Task-number: QTBUG-120124 Change-Id: If38f601ff653111763004b98915b01ffe8ddc837 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r--src/corelib/kernel/qobject.cpp55
1 files changed, 42 insertions, 13 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 7154664a0b..55a3bd5308 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -2437,24 +2437,53 @@ void QObject::deleteLater()
qWarning("You are deferring the delete of QCoreApplication, this may not work as expected.");
#endif
- {
- // De-bounce QDeferredDeleteEvents. Use the post event list mutex
- // to guard access to deleteLaterCalled, so we don't need a separate
- // mutex in QObjectData.
- auto locker = QCoreApplicationPrivate::lockThreadPostEventList(this);
- // FIXME: The deleteLaterCalled flag is part of a bit field,
- // so we likely have data races here, even with the mutex above,
- // as long as we're not guarding every access to the bit field.
+ // De-bounce QDeferredDeleteEvents. Use the post event list mutex
+ // to guard access to deleteLaterCalled, so we don't need a separate
+ // mutex in QObjectData.
+ auto eventListLocker = QCoreApplicationPrivate::lockThreadPostEventList(this);
+ if (!eventListLocker.threadData)
+ return;
- Q_D(QObject);
- if (d->deleteLaterCalled)
- return;
+ // FIXME: The deleteLaterCalled flag is part of a bit field,
+ // so we likely have data races here, even with the mutex above,
+ // as long as we're not guarding every access to the bit field.
+
+ Q_D(QObject);
+ if (d->deleteLaterCalled)
+ return;
+
+ d->deleteLaterCalled = true;
+
+ int loopLevel = 0;
+ int scopeLevel = 0;
+
+ auto *objectThreadData = eventListLocker.threadData;
+ if (objectThreadData == QThreadData::current()) {
+ // Remember the current running eventloop for deleteLater
+ // calls in the object's own thread.
+
+ // Events sent by non-Qt event handlers (such as glib) may not
+ // have the scopeLevel set correctly. The scope level makes sure that
+ // code like this:
+ // foo->deleteLater();
+ // qApp->processEvents(); // without passing QEvent::DeferredDelete
+ // will not cause "foo" to be deleted before returning to the event loop.
+
+ loopLevel = objectThreadData->loopLevel;
+ scopeLevel = objectThreadData->scopeLevel;
- d->deleteLaterCalled = true;
+ // If the scope level is 0 while loopLevel != 0, we are called from a
+ // non-conformant code path, and our best guess is that the scope level
+ // should be 1. (Loop level 0 is special: it means that no event loops
+ // are running.)
+ if (scopeLevel == 0 && loopLevel != 0)
+ scopeLevel = 1;
}
- QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
+ eventListLocker.unlock();
+ QCoreApplication::postEvent(this,
+ new QDeferredDeleteEvent(loopLevel, scopeLevel));
}
/*!