summaryrefslogtreecommitdiff
path: root/gnu/packages/patches
diff options
context:
space:
mode:
authorBrennan Vincent <brennan@umanwizard.com>2025-07-21 14:23:43 -0700
committerAndreas Enge <andreas@enge.fr>2025-07-22 10:49:07 +0200
commite7a87d59b84f20307f22f6878b39e0210496104e (patch)
tree0f6b947ede1fcad0d932fe61cca966aa58c78a5e /gnu/packages/patches
parent355b6125c02790bf24a39a90e155e68f577d4982 (diff)
gnu: qtbase: Backport fix for flaky test.
* gnu/packages/qt.scm (qtbase)[#:phases]: Add 'patch-aarch64-tests, which backports an upstream commit improving a flaky test. * gnu/packages/patches/qtbase-fix-thread-test.patch: New file. * gnu/local.mk (dist_patch_DATA): Register patch. Change-Id: Ibf9b95d7225ed42c9edad03a550d1c6e6f86be54
Diffstat (limited to 'gnu/packages/patches')
-rw-r--r--gnu/packages/patches/qtbase-fix-thread-test.patch154
1 files changed, 154 insertions, 0 deletions
diff --git a/gnu/packages/patches/qtbase-fix-thread-test.patch b/gnu/packages/patches/qtbase-fix-thread-test.patch
new file mode 100644
index 0000000000..d54386ccc7
--- /dev/null
+++ b/gnu/packages/patches/qtbase-fix-thread-test.patch
@@ -0,0 +1,154 @@
+From 2bce75a6b53cccbf9c813581b64eea87f3ab55fc Mon Sep 17 00:00:00 2001
+From: Thiago Macieira <thiago.macieira@intel.com>
+Date: Fri, 1 Nov 2024 11:59:10 -0700
+Subject: [PATCH] tst_QThread: improve test on multiple threads waiting on
+ wait()
+
+Amends commit 5b5297fe87859f59a7aaf5e86a8915c00714fefa to make it more
+reliable against CI timeouts and flakiness. Now, we wait for the threads
+that are expected to timeout to actually timeout before releasing the
+target thread they were waiting on. It should be impossible now for this
+to go wrong. There should also be no problem of their handing off to a
+thread that will wait forever.
+
+I've added two more tests that could, possibly, have a problem in the
+CI: when timing-out threads hand off to a timed wait that is expected to
+succeed (the > 1s wait cases). Though this should be a rare occurrence,
+if ever: the target thread's runtime is the longest of the timing out
+threads' wait, plus 5 ms. That is 30 ms in the examples I wrote, so the
+additional extra time they're waiting on should be more than enough.
+
+An extra benefit is that this test now runs much faster, at 10 to 60 ms
+per test row, instead of 800 ms previously. The drawback is that a
+failure condition is likely going to be noticed by the QSemaphores
+deadlocking.
+
+Change-Id: I360d7e9c7accc1216291fffd743c88a362cf66ac
+Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
+---
+ .../corelib/thread/qthread/tst_qthread.cpp | 63 +++++++++++++------
+ 1 file changed, 43 insertions(+), 20 deletions(-)
+
+diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp
+index 99602098fac..beb843b0d8c 100644
+--- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp
++++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp
+@@ -36,6 +36,8 @@
+ #include <exception>
+ #endif
+
++#include <thread>
++
+ #include <QtTest/private/qemulationdetector_p.h>
+
+ using namespace std::chrono_literals;
+@@ -1226,21 +1228,28 @@ void tst_QThread::multiThreadWait_data()
+ // this is probably too fast and the Forever gets in too quickly
+ addRow(0, -1);
+
+- addRow(100, -1);
+- addRow(100, 200, -1);
+- addRow(200, 100, -1);
+- addRow(-1, 100, 100, 100);
++ // any time below 100ms (see below) is expected to timeout
++ addRow(25, -1);
++ addRow(25, 50, -1);
++ addRow(50, 25, -1);
++ addRow(-1, 25, 25, 25);
++ addRow(25, 2000);
++ addRow(25, 2000, 25, -1);
+ }
+
+ void tst_QThread::multiThreadWait()
+ {
++ static constexpr auto TimeoutThreshold = 100ms;
++ auto isExpectedToTimeout = [](unsigned value) {
++ return value < TimeoutThreshold.count();
++ };
++
+ class TargetThread : public QThread {
+ public:
+ QSemaphore sync;
+ void run() override
+ {
+ sync.acquire();
+- msleep(Waiting_Thread::WaitTime);
+ }
+ };
+
+@@ -1265,43 +1274,57 @@ void tst_QThread::multiThreadWait()
+ QFETCH(QList<int>, deadlines);
+ TargetThread target;
+ target.start();
++ QElapsedTimer elapsedTimer;
++ elapsedTimer.start();
+
+- QSemaphore startSema, endSema;
++ // we use a QSemaphore to wait on the WaiterThread::run() instead of
++ // QThread::wait() so it's easier to debug when the latter has a problem
++ QSemaphore startSema, timeoutSema, successSema;
+ std::array<std::unique_ptr<WaiterThread>, 5> threads; // 5 threads is enough
++ int expectedTimeoutCount = 0;
+ for (int i = 0; i < deadlines.size(); ++i) {
+ threads[i] = std::make_unique<WaiterThread>();
+ threads[i]->startSema = &startSema;
+- threads[i]->endSema = &endSema;
++ if (isExpectedToTimeout(deadlines.at(i))) {
++ ++expectedTimeoutCount;
++ threads[i]->endSema = &timeoutSema;
++ } else {
++ threads[i]->endSema = &successSema;
++ }
+ threads[i]->target = &target;
+ threads[i]->deadline = QDeadlineTimer(deadlines.at(i));
+ threads[i]->start();
+ }
+
+- // release the waiting threads first, then the target thread they're waiting on
++ // release the waiting threads first, so they begin waiting
+ startSema.release(deadlines.size());
+- target.sync.release();
+
+- // wait for our waiting threads on a semaphore instead of QThread::wait()
+- // to make debugging easier
+- QVERIFY(endSema.tryAcquire(deadlines.size(), QDeadlineTimer::Forever));
++ // then wait for the threads that are expected to timeout to do so
++ QVERIFY(timeoutSema.tryAcquire(expectedTimeoutCount, QDeadlineTimer::Forever));
++
++ // compute the elapsed time for timing comparisons
++ std::this_thread::sleep_for(5ms); // short, but long enough to avoid rounding errors
++ auto elapsed = elapsedTimer.durationElapsed();
++ std::this_thread::sleep_for(5ms);
++
++ // cause the target thread to exit, so the successful threads do succeed
++ target.sync.release();
++ int expectedSuccessCount = deadlines.size() - expectedTimeoutCount;
++ QVERIFY(successSema.tryAcquire(expectedSuccessCount, QDeadlineTimer::Forever));
+
+ // wait for all the threads to end, before QVERIFY/QCOMPAREs
+ for (int i = 0; i < deadlines.size(); ++i)
+ threads[i]->wait();
+ target.wait();
+
+- std::chrono::milliseconds expectedDuration{Waiting_Thread::WaitTime};
+ for (int i = 0; i < deadlines.size(); ++i) {
+ auto printI = qScopeGuard([i] { qWarning("i = %i", i); });
+- if (unsigned(deadlines.at(i)) < Waiting_Thread::WaitTime / 2) {
++ if (isExpectedToTimeout(deadlines.at(i))) {
++ QCOMPARE_LT(threads[i]->waitedDuration, elapsed);
+ QCOMPARE(threads[i]->result, false);
+- QCOMPARE_LT(threads[i]->waitedDuration, expectedDuration);
+- } else if (unsigned(deadlines.at(i)) > Waiting_Thread::WaitTime * 3 / 2) {
+- QCOMPARE(threads[i]->result, true);
+- QCOMPARE_GE(threads[i]->waitedDuration, expectedDuration);
+ } else {
+- qWarning("Wait time %i (index %i) is too close to the target time; test would be flaky",
+- deadlines.at(i), i);
++ QCOMPARE_GE(threads[i]->waitedDuration, elapsed);
++ QCOMPARE(threads[i]->result, true);
+ }
+ printI.dismiss();
+ threads[i].reset();
+--
+2.50.1
+