From 1c53afb77419ff9d10b710dcf2a6b27b7d3dc31a Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 8 Jul 2024 11:39:43 +0200 Subject: [PATCH] tst_QThread: add a test for self-cancellation Doesn't test anything, just that it doesn't crash. Turns out we have a race between thread cancellation and normal exit (filed as QTBUG-127008). Worked around by adding an infinite loop to run(), after terminate(). Android doesn't support cancellation at all, and our Windows implementation hits QTBUG-127050, so skip the test on those platforms. Pick-to: 6.7 6.5 6.2 5.15 Change-Id: I47a635a31caaf116d3688f31b9b5c5875e9765f5 Reviewed-by: Thiago Macieira (cherry picked from commit a9f7e75a2647732ff998f1c0d112682dbd5c4e28) Reviewed-by: Qt Cherry-pick Bot --- .../corelib/thread/qthread/tst_qthread.cpp | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp index 18c8d5fbd52..9582343a012 100644 --- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp +++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp @@ -100,6 +100,7 @@ private slots: void terminateAndPrematureDestruction(); void terminateAndDoubleDestruction(); + void terminateSelfStressTest(); void bindingListCleanupAfterDelete(); }; @@ -1935,6 +1936,53 @@ void tst_QThread::terminateAndDoubleDestruction() TestObject obj; } +void tst_QThread::terminateSelfStressTest() +{ + // This simply tests that QThread::terminate() doesn't crash or causes + // sanitizer reports when a thread cancels itself. +#ifdef Q_OS_ANDROID + QSKIP("Android cannot cancel threads"); +#endif + +#ifdef Q_OS_WIN + QSKIP("QTBUG-127050"); +#endif + + struct Thread : QThread { + void run() override { + terminate(); + while (true) sleep(1ns); // QTBUG-127008 + } + }; + + { + // first, try with one: + Thread t; + t.start(); + QVERIFY(t.wait(10s)); + } + + constexpr QThread::Priority priorities[] = { + QThread::IdlePriority, + QThread::LowestPriority, + QThread::LowPriority, + QThread::NormalPriority, + QThread::HighPriority, + QThread::HighestPriority, + QThread::TimeCriticalPriority, + QThread::InheritPriority, + }; + + QVarLengthArray threads(3 * QThread::idealThreadCount()); + + size_t i = 0; + for (Thread &t : threads) + t.start(priorities[i++ % std::size(priorities)]); + + for (Thread &t : threads) + QVERIFY2(t.wait(60s), QByteArray::number(&t - threads.data()).constData()); +} + void tst_QThread::bindingListCleanupAfterDelete() { QThread t;