diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2023-12-10 18:12:25 +0100 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2023-12-19 19:41:28 +0100 |
commit | 46588fbb516b980f0f6b11ce814ecf15d71967d3 (patch) | |
tree | db163b30ec578797293d802417ca953690ae2e90 /src/corelib/kernel/qobject.cpp | |
parent | e02dc31fbf3ae460bea2aea068ccc969d6e852fc (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.cpp | 55 |
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)); } /*! |