Fix QTimer::crossThreadSingleShotToFunctor test

Amends 4d90c4e74a6aa34d5aabfb91ec304da1f02df3e3, after which the test
became flaky. We need to wait for the functor to be called before
quitting the thread, otherwise we have no guarnatee that any of the
queued metacall events have been processed by the thread. Since
QThread::quit is thread-safe, we can just call it from within the
functor. This guarantees that at least one of the single-shot timers
is processed before we quit.

And since QTimer::singleShot has special code paths for 0-ms timers
(going through an explicitly queued QMetaObject::invokeMethod call
rather than through an actual QSingleShotTimer object), we need to run
the test logic with different timeouts to cover both code paths.

Task-number: QTBUG-112162
Change-Id: Ide1e7b4b74dcbda72144a0d73ef5f64b0694ddbc
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit fc319a8f8b030af82613a79959d95ae800d1b2c9)
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Volker Hilsheimer 2023-03-29 20:25:45 +02:00
parent d3bc8c79bb
commit 01ddd9ec59

View File

@ -56,6 +56,7 @@ private slots:
void singleShotToFunctors();
void singleShot_chrono();
void singleShot_static();
void crossThreadSingleShotToFunctor_data();
void crossThreadSingleShotToFunctor();
void timerOrder();
void timerOrder_data();
@ -1007,28 +1008,39 @@ void tst_QTimer::postedEventsShouldNotStarveTimers()
struct DummyFunctor {
static QThread *callThread;
void operator()() { callThread = QThread::currentThread(); }
void operator()() {
callThread = QThread::currentThread();
callThread->quit();
}
};
QThread *DummyFunctor::callThread = nullptr;
void tst_QTimer::crossThreadSingleShotToFunctor_data()
{
QTest::addColumn<int>("timeout");
QTest::addRow("zero-timer") << 0;
QTest::addRow("1ms") << 1;
}
void tst_QTimer::crossThreadSingleShotToFunctor()
{
QFETCH(int, timeout);
// We're also testing for crashes here, so the test simply running to
// completion is part of the success
DummyFunctor::callThread = nullptr;
QThread t;
t.start();
QObject* o = new QObject();
std::unique_ptr<QObject> o(new QObject());
o->moveToThread(&t);
DummyFunctor::callThread = nullptr;
for (int i = 0; i < 10000; i++) {
QTimer::singleShot(0, o, DummyFunctor());
}
for (int i = 0; i < 10000; i++)
QTimer::singleShot(timeout, o.get(), DummyFunctor());
t.quit();
t.wait();
delete o;
o.reset();
QCOMPARE(DummyFunctor::callThread, &t);
}