tst_QThreadPool: reduce the number of infinite timeouts
... by supplying a TestThreadPool that waitsForDone() with a defined timeout in the dtor. When tests hang, this will now print an intelligible message instead of just the generic watchdog-killed-process one. Also replace all QVERIFY(waitForDone()) with the same code used in TestThreadPool's dtor and add a comment in a place we'd rather not use these tools. Pick-to: 6.5 6.2 Change-Id: Ifd2b3372eb7c7337a3ba77d003e45dcd77e23545 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
eb260c132a
commit
1cc1d39f3e
@ -138,10 +138,25 @@ void noSleepTestFunctionMutex()
|
||||
tst_QThreadPool::functionTestMutex->unlock();
|
||||
}
|
||||
|
||||
constexpr int DefaultWaitForDoneTimeout = 1 * 60 * 1000; // 1min
|
||||
// Using qFatal instead of QVERIFY to force exit if threads are still running after timeout.
|
||||
// Otherwise, QCoreApplication will still wait for the stale threads and never exit the test.
|
||||
#define WAIT_FOR_DONE(manager) \
|
||||
if ((manager).waitForDone(DefaultWaitForDoneTimeout)) {} else \
|
||||
qFatal("waitForDone returned false. Aborting to stop background threads.")
|
||||
|
||||
// uses explicit timeout in dtor's waitForDone() to avoid tests hanging overly long
|
||||
class TestThreadPool : public QThreadPool
|
||||
{
|
||||
public:
|
||||
using QThreadPool::QThreadPool;
|
||||
~TestThreadPool() { WAIT_FOR_DONE(*this); }
|
||||
};
|
||||
|
||||
void tst_QThreadPool::runFunction()
|
||||
{
|
||||
{
|
||||
QThreadPool manager;
|
||||
TestThreadPool manager;
|
||||
testFunctionCount = 0;
|
||||
manager.start(noSleepTestFunction);
|
||||
}
|
||||
@ -152,7 +167,7 @@ void tst_QThreadPool::runFunction2()
|
||||
{
|
||||
int localCount = 0;
|
||||
{
|
||||
QThreadPool manager;
|
||||
TestThreadPool manager;
|
||||
manager.start([&]() { ++localCount; });
|
||||
}
|
||||
QCOMPARE(localCount, 1);
|
||||
@ -161,7 +176,7 @@ void tst_QThreadPool::runFunction2()
|
||||
void tst_QThreadPool::createThreadRunFunction()
|
||||
{
|
||||
{
|
||||
QThreadPool manager;
|
||||
TestThreadPool manager;
|
||||
testFunctionCount = 0;
|
||||
manager.start(noSleepTestFunction);
|
||||
}
|
||||
@ -174,7 +189,7 @@ void tst_QThreadPool::runMultiple()
|
||||
const int runs = 10;
|
||||
|
||||
{
|
||||
QThreadPool manager;
|
||||
TestThreadPool manager;
|
||||
testFunctionCount = 0;
|
||||
for (int i = 0; i < runs; ++i) {
|
||||
manager.start(sleepTestFunctionMutex);
|
||||
@ -183,7 +198,7 @@ void tst_QThreadPool::runMultiple()
|
||||
QCOMPARE(testFunctionCount, runs);
|
||||
|
||||
{
|
||||
QThreadPool manager;
|
||||
TestThreadPool manager;
|
||||
testFunctionCount = 0;
|
||||
for (int i = 0; i < runs; ++i) {
|
||||
manager.start(noSleepTestFunctionMutex);
|
||||
@ -192,7 +207,7 @@ void tst_QThreadPool::runMultiple()
|
||||
QCOMPARE(testFunctionCount, runs);
|
||||
|
||||
{
|
||||
QThreadPool manager;
|
||||
TestThreadPool manager;
|
||||
for (int i = 0; i < 500; ++i)
|
||||
manager.start(emptyFunct);
|
||||
}
|
||||
@ -203,6 +218,7 @@ void tst_QThreadPool::waitcomplete()
|
||||
testFunctionCount = 0;
|
||||
const int runs = 500;
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
// TestThreadPool pool; // no, we're checking ~QThreadPool()'s waitForDone()
|
||||
QThreadPool pool;
|
||||
pool.start(noSleepTestFunction);
|
||||
}
|
||||
@ -221,7 +237,7 @@ public:
|
||||
|
||||
void tst_QThreadPool::runTask()
|
||||
{
|
||||
QThreadPool manager;
|
||||
TestThreadPool manager;
|
||||
ran.storeRelaxed(false);
|
||||
manager.start(new TestTask());
|
||||
QTRY_VERIFY(ran.loadRelaxed());
|
||||
@ -283,7 +299,7 @@ public:
|
||||
*/
|
||||
void tst_QThreadPool::threadRecycling()
|
||||
{
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
|
||||
threadPool.start(new ThreadRecorderTask());
|
||||
threadRecyclingSemaphore.acquire();
|
||||
@ -311,7 +327,7 @@ void tst_QThreadPool::threadRecycling()
|
||||
void tst_QThreadPool::threadPriority()
|
||||
{
|
||||
QThread::Priority priority = QThread::HighPriority;
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setThreadPriority(priority);
|
||||
|
||||
threadPool.start(new ThreadRecorderTask());
|
||||
@ -348,7 +364,7 @@ void tst_QThreadPool::expiryTimeout()
|
||||
{
|
||||
ExpiryTimeoutTask task;
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setMaxThreadCount(1);
|
||||
|
||||
int expiryTimeout = threadPool.expiryTimeout();
|
||||
@ -387,7 +403,7 @@ void tst_QThreadPool::expiryTimeoutRace() // QTBUG-3786
|
||||
#endif
|
||||
ExpiryTimeoutTask task;
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setMaxThreadCount(1);
|
||||
threadPool.setExpiryTimeout(50);
|
||||
const int numTasks = 20;
|
||||
@ -414,7 +430,7 @@ void tst_QThreadPool::exceptions()
|
||||
{
|
||||
ExceptionTask task;
|
||||
{
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
// Uncomment this for a nice crash.
|
||||
// threadPool.start(&task);
|
||||
}
|
||||
@ -458,7 +474,7 @@ void tst_QThreadPool::setMaxThreadCount()
|
||||
|
||||
// setting the limit on children should have no effect on the parent
|
||||
{
|
||||
QThreadPool threadPool2(threadPool);
|
||||
TestThreadPool threadPool2(threadPool);
|
||||
savedLimit = threadPool2.maxThreadCount();
|
||||
|
||||
// maxThreadCount() should always return the previous argument to
|
||||
@ -488,7 +504,7 @@ void tst_QThreadPool::setMaxThreadCountStartsAndStopsThreads()
|
||||
}
|
||||
};
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setMaxThreadCount(-1); // docs say we'll always start at least one
|
||||
|
||||
WaitingTask task;
|
||||
@ -576,7 +592,7 @@ void tst_QThreadPool::reserveThread()
|
||||
|
||||
// reserving threads in children should not effect the parent
|
||||
{
|
||||
QThreadPool threadpool2(threadpool);
|
||||
TestThreadPool threadpool2(threadpool);
|
||||
threadpool2.setMaxThreadCount(limit);
|
||||
|
||||
// reserve up to the limit
|
||||
@ -640,7 +656,7 @@ void tst_QThreadPool::releaseThread()
|
||||
|
||||
// releasing threads in children should not effect the parent
|
||||
{
|
||||
QThreadPool threadpool2(threadpool);
|
||||
TestThreadPool threadpool2(threadpool);
|
||||
threadpool2.setMaxThreadCount(limit);
|
||||
|
||||
// reserve up to the limit
|
||||
@ -841,7 +857,7 @@ void tst_QThreadPool::start()
|
||||
const int runs = 1000;
|
||||
count.storeRelaxed(0);
|
||||
{
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
for (int i = 0; i< runs; ++i) {
|
||||
threadPool.start(new CountingRunnable());
|
||||
}
|
||||
@ -868,13 +884,13 @@ void tst_QThreadPool::tryStart()
|
||||
count.storeRelaxed(0);
|
||||
|
||||
WaitingTask task;
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
for (int i = 0; i < threadPool.maxThreadCount(); ++i) {
|
||||
threadPool.start(&task);
|
||||
}
|
||||
QVERIFY(!threadPool.tryStart(&task));
|
||||
task.semaphore.release(threadPool.maxThreadCount());
|
||||
threadPool.waitForDone();
|
||||
WAIT_FOR_DONE(threadPool);
|
||||
QCOMPARE(count.loadRelaxed(), threadPool.maxThreadCount());
|
||||
}
|
||||
|
||||
@ -905,7 +921,7 @@ void tst_QThreadPool::tryStartPeakThreadCount()
|
||||
};
|
||||
|
||||
CounterTask task;
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
|
||||
for (int i = 0; i < 4*QThread::idealThreadCount(); ++i) {
|
||||
if (threadPool.tryStart(&task) == false)
|
||||
@ -934,7 +950,7 @@ void tst_QThreadPool::tryStartCount()
|
||||
};
|
||||
|
||||
SleeperTask task;
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
const int runs = 5;
|
||||
|
||||
for (int i = 0; i < runs; ++i) {
|
||||
@ -982,7 +998,7 @@ void tst_QThreadPool::priorityStart()
|
||||
QSemaphore sem;
|
||||
QAtomicPointer<QRunnable> firstStarted;
|
||||
QRunnable *expected;
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setMaxThreadCount(1); // start only one thread at a time
|
||||
|
||||
// queue the holder first
|
||||
@ -994,7 +1010,7 @@ void tst_QThreadPool::priorityStart()
|
||||
threadPool.start(expected = new Runner(firstStarted), 1); // priority 1
|
||||
|
||||
sem.release();
|
||||
QVERIFY(threadPool.waitForDone());
|
||||
WAIT_FOR_DONE(threadPool);
|
||||
QCOMPARE(firstStarted.loadRelaxed(), expected);
|
||||
}
|
||||
|
||||
@ -1004,7 +1020,7 @@ void tst_QThreadPool::waitForDone()
|
||||
total.start();
|
||||
pass.start();
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
while (total.elapsed() < 10000) {
|
||||
int runs;
|
||||
count.storeRelaxed(runs = 0);
|
||||
@ -1013,7 +1029,7 @@ void tst_QThreadPool::waitForDone()
|
||||
threadPool.start(new CountingRunnable());
|
||||
++runs;
|
||||
}
|
||||
threadPool.waitForDone();
|
||||
WAIT_FOR_DONE(threadPool);
|
||||
QCOMPARE(count.loadRelaxed(), runs);
|
||||
|
||||
count.storeRelaxed(runs = 0);
|
||||
@ -1023,7 +1039,7 @@ void tst_QThreadPool::waitForDone()
|
||||
threadPool.start(new CountingRunnable());
|
||||
runs += 2;
|
||||
}
|
||||
threadPool.waitForDone();
|
||||
WAIT_FOR_DONE(threadPool);
|
||||
QCOMPARE(count.loadRelaxed(), runs);
|
||||
}
|
||||
}
|
||||
@ -1045,7 +1061,7 @@ void tst_QThreadPool::waitForDoneTimeout()
|
||||
}
|
||||
};
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
|
||||
mutex.lock();
|
||||
threadPool.start(new BlockedTask(mutex));
|
||||
@ -1069,7 +1085,7 @@ void tst_QThreadPool::clear()
|
||||
}
|
||||
};
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setMaxThreadCount(10);
|
||||
int runs = 2 * threadPool.maxThreadCount();
|
||||
count.storeRelaxed(0);
|
||||
@ -1078,7 +1094,7 @@ void tst_QThreadPool::clear()
|
||||
}
|
||||
threadPool.clear();
|
||||
sem.release(threadPool.maxThreadCount());
|
||||
threadPool.waitForDone();
|
||||
WAIT_FOR_DONE(threadPool);
|
||||
QCOMPARE(count.loadRelaxed(), threadPool.maxThreadCount());
|
||||
}
|
||||
|
||||
@ -1091,7 +1107,7 @@ void tst_QThreadPool::clearWithAutoDelete()
|
||||
void run() override { QThread::sleep(30us); }
|
||||
};
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setMaxThreadCount(4);
|
||||
const int loopCount = 20;
|
||||
const int batchSize = 500;
|
||||
@ -1104,7 +1120,6 @@ void tst_QThreadPool::clearWithAutoDelete()
|
||||
threadPool.start(runnable);
|
||||
}
|
||||
}
|
||||
QVERIFY(threadPool.waitForDone());
|
||||
}
|
||||
|
||||
void tst_QThreadPool::tryTake()
|
||||
@ -1144,7 +1159,7 @@ void tst_QThreadPool::tryTake()
|
||||
Runs = MaxThreadCount * OverProvisioning
|
||||
};
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setMaxThreadCount(MaxThreadCount);
|
||||
BlockingRunnable *runnables[Runs];
|
||||
|
||||
@ -1176,7 +1191,7 @@ void tst_QThreadPool::tryTake()
|
||||
runnables[0]->dummy = 0; // valgrind will catch this if tryTake() is crazy enough to delete currently running jobs
|
||||
QCOMPARE(dtorCounter.loadRelaxed(), int(Runs - MaxThreadCount));
|
||||
sem.release(MaxThreadCount);
|
||||
threadPool.waitForDone();
|
||||
WAIT_FOR_DONE(threadPool);
|
||||
QCOMPARE(runCounter.loadRelaxed(), int(MaxThreadCount));
|
||||
QCOMPARE(count.loadRelaxed(), int(MaxThreadCount));
|
||||
QCOMPARE(dtorCounter.loadRelaxed(), int(Runs - 1));
|
||||
@ -1193,7 +1208,7 @@ void tst_QThreadPool::destroyingWaitsForTasksToFinish()
|
||||
int runs;
|
||||
count.storeRelaxed(runs = 0);
|
||||
{
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
pass.restart();
|
||||
while (pass.elapsed() < 100) {
|
||||
threadPool.start(new CountingRunnable());
|
||||
@ -1204,7 +1219,7 @@ void tst_QThreadPool::destroyingWaitsForTasksToFinish()
|
||||
|
||||
count.storeRelaxed(runs = 0);
|
||||
{
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
pass.restart();
|
||||
while (pass.elapsed() < 100) {
|
||||
threadPool.start(new CountingRunnable());
|
||||
@ -1246,10 +1261,10 @@ void tst_QThreadPool::stackSize()
|
||||
}
|
||||
};
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setStackSize(targetStackSize);
|
||||
threadPool.start(new StackSizeChecker(&threadStackSize));
|
||||
QVERIFY(threadPool.waitForDone(30000)); // 30s timeout
|
||||
WAIT_FOR_DONE(threadPool);
|
||||
QCOMPARE(threadStackSize, targetStackSize);
|
||||
}
|
||||
|
||||
@ -1310,7 +1325,7 @@ void tst_QThreadPool::takeAllAndIncreaseMaxThreadCount() {
|
||||
QSemaphore mainBarrier;
|
||||
QSemaphore taskBarrier;
|
||||
|
||||
QThreadPool threadPool;
|
||||
TestThreadPool threadPool;
|
||||
threadPool.setMaxThreadCount(1);
|
||||
|
||||
Task task1(&mainBarrier, &taskBarrier);
|
||||
@ -1341,7 +1356,7 @@ void tst_QThreadPool::takeAllAndIncreaseMaxThreadCount() {
|
||||
|
||||
taskBarrier.release(1);
|
||||
|
||||
threadPool.waitForDone();
|
||||
WAIT_FOR_DONE(threadPool);
|
||||
|
||||
QCOMPARE(threadPool.activeThreadCount(), 0);
|
||||
}
|
||||
@ -1374,7 +1389,7 @@ void tst_QThreadPool::waitForDoneAfterTake()
|
||||
// Blocks the tasks from completing their run function
|
||||
QSemaphore threadBarrier;
|
||||
|
||||
QThreadPool manager;
|
||||
TestThreadPool manager;
|
||||
manager.setMaxThreadCount(threadCount);
|
||||
|
||||
// Fill all the threads with runnables that wait for the threadBarrier
|
||||
@ -1405,12 +1420,6 @@ void tst_QThreadPool::waitForDoneAfterTake()
|
||||
|
||||
// Release runnables that are waiting and expect all runnables to complete
|
||||
threadBarrier.release(threadCount);
|
||||
|
||||
// Using qFatal instead of QVERIFY to force exit if threads are still running after timeout.
|
||||
// Otherwise, QCoreApplication will still wait for the stale threads and never exit the test.
|
||||
if (!manager.waitForDone(5 * 60 * 1000))
|
||||
qFatal("waitForDone returned false. Aborting to stop background threads.");
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1420,7 +1429,7 @@ void tst_QThreadPool::waitForDoneAfterTake()
|
||||
*/
|
||||
void tst_QThreadPool::threadReuse()
|
||||
{
|
||||
QThreadPool manager;
|
||||
TestThreadPool manager;
|
||||
manager.setExpiryTimeout(-1);
|
||||
manager.setMaxThreadCount(1);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user