From 4f85eed8e3e1bb0ccbbba58e0e731a4052af06bd Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 23 Oct 2024 10:11:30 -0700 Subject: [PATCH] QThread: avoid unlock/lock/unlock in ~QThread if state is Finishing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a corner-case scenario but valid because we tell users they can destroy the QThread object right after finished() has been emitted. But emitting finished() does not mean the launched thread has actually exited: it may still be in Finishing state for an arbitrarily long time. Completely aside from what else may run from other libraries, we only destroy QThreadStorage and the thread's event dispatcher after finished() has been emitted. This commit avoids the unnecessary mutex unlocking in the destructor, then QThread::wait() locking again, only to unlock yet again so that it can perform the necessary low-level wait calls. The same for the return path: wait() locked again to check the state, then unlocked, only for the destructor to lock again. Now, QThreadPrivate::wait() is responsible for returning with a locked mutex. Change-Id: I87adffb89f275accea18fffd6b4293861ea7cf39 Reviewed-by: MÃ¥rten Nordheim Reviewed-by: Edward Welbourne (cherry picked from commit 6bd271cf74d6d57816531f688c82c51d29f1be91) Reviewed-by: Ahmad Samir --- src/corelib/thread/qthread.cpp | 7 ++----- src/corelib/thread/qthread_p.h | 2 ++ src/corelib/thread/qthread_unix.cpp | 8 ++++++++ src/corelib/thread/qthread_win.cpp | 7 +++++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index edfb77f1cf4..005666a7426 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -495,11 +495,8 @@ QThread::~QThread() Q_D(QThread); { QMutexLocker locker(&d->mutex); - if (d->isInFinish) { - locker.unlock(); - wait(); - locker.relock(); - } + if (d->isInFinish) + d->wait(locker, QDeadlineTimer::Forever); if (d->running && !d->finished && !d->data->isAdopted) qFatal("QThread: Destroyed while thread is still running"); diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 69cad23f99a..afb10fbf9ac 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -198,6 +198,8 @@ public: uint stackSize; std::underlying_type_t priority; + bool wait(QMutexLocker &locker, QDeadlineTimer deadline); + #ifdef Q_OS_UNIX QWaitCondition thread_done; diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 4dac10baade..4b6e0d8f3c8 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -837,6 +837,14 @@ bool QThread::wait(QDeadlineTimer deadline) if (d->finished || !d->running) return true; + return d->wait(locker, deadline); +} + +bool QThreadPrivate::wait(QMutexLocker &locker, QDeadlineTimer deadline) +{ + Q_ASSERT(locker.isLocked()); + QThreadPrivate *d = this; + while (d->running) { if (!d->thread_done.wait(locker.mutex(), deadline)) return false; diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 712a6f07041..33dd03166cf 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -495,6 +495,13 @@ bool QThread::wait(QDeadlineTimer deadline) } if (d->finished || !d->running) return true; + return d->wait(locker, deadline); +} + +bool QThreadPrivate::wait(QMutexLocker &locker, QDeadlineTimer deadline) +{ + Q_ASSERT(locker.isLocked()); + QThreadPrivate *d = this; ++d->waiters; locker.mutex()->unlock();