qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,2 @@
[tryAcquireWithTimeout]
macos

View File

@ -0,0 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qsemaphore Test:
#####################################################################
qt_internal_add_test(tst_qsemaphore
SOURCES
tst_qsemaphore.cpp
)

View File

@ -0,0 +1,612 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qcoreapplication.h>
#include <qthread.h>
#include <qsemaphore.h>
#include <chrono>
using namespace std::chrono_literals;
class tst_QSemaphore : public QObject
{
Q_OBJECT
private slots:
void acquire();
void multiRelease();
void multiAcquireRelease();
void tryAcquire();
void tryAcquireWithTimeout_data();
void tryAcquireWithTimeout();
void tryAcquireWithTimeoutStarvation();
void tryAcquireWithTimeoutForever_data();
void tryAcquireWithTimeoutForever();
void producerConsumer();
void raii();
void stdCompat();
};
static QSemaphore *semaphore = nullptr;
class ThreadOne : public QThread
{
public:
ThreadOne() {}
protected:
void run() override
{
int i = 0;
while ( i < 100 ) {
semaphore->acquire();
i++;
semaphore->release();
}
}
};
class ThreadN : public QThread
{
int N;
public:
ThreadN(int n) :N(n) { }
protected:
void run() override
{
int i = 0;
while ( i < 100 ) {
semaphore->acquire(N);
i++;
semaphore->release(N);
}
}
};
void tst_QSemaphore::acquire()
{
{
// old incrementOne() test
QVERIFY(!semaphore);
semaphore = new QSemaphore;
// make some "thing" available
semaphore->release();
ThreadOne t1;
ThreadOne t2;
t1.start();
t2.start();
QVERIFY(t1.wait(4000));
QVERIFY(t2.wait(4000));
delete semaphore;
semaphore = nullptr;
}
// old incrementN() test
{
QVERIFY(!semaphore);
semaphore = new QSemaphore;
// make 4 "things" available
semaphore->release(4);
ThreadN t1(2);
ThreadN t2(3);
t1.start();
t2.start();
QVERIFY(t1.wait(4000));
QVERIFY(t2.wait(4000));
delete semaphore;
semaphore = nullptr;
}
QSemaphore semaphore;
QCOMPARE(semaphore.available(), 0);
semaphore.release();
QCOMPARE(semaphore.available(), 1);
semaphore.release();
QCOMPARE(semaphore.available(), 2);
semaphore.release(10);
QCOMPARE(semaphore.available(), 12);
semaphore.release(10);
QCOMPARE(semaphore.available(), 22);
semaphore.acquire();
QCOMPARE(semaphore.available(), 21);
semaphore.acquire();
QCOMPARE(semaphore.available(), 20);
semaphore.acquire(10);
QCOMPARE(semaphore.available(), 10);
semaphore.acquire(10);
QCOMPARE(semaphore.available(), 0);
}
void tst_QSemaphore::multiRelease()
{
class Thread : public QThread
{
public:
QSemaphore &sem;
Thread(QSemaphore &sem) : sem(sem) {}
void run() override
{
sem.acquire();
}
};
QSemaphore sem;
QList<Thread *> threads;
threads.resize(4);
for (Thread *&t : threads)
t = new Thread(sem);
for (Thread *&t : threads)
t->start();
// wait for all threads to reach the sem.acquire() and then
// release them all
QTest::qSleep(1);
sem.release(int(threads.size()));
for (Thread *&t : threads)
t->wait();
qDeleteAll(threads);
}
void tst_QSemaphore::multiAcquireRelease()
{
class Thread : public QThread
{
public:
QSemaphore &sem;
Thread(QSemaphore &sem) : sem(sem) {}
void run() override
{
sem.acquire();
sem.release();
}
};
QSemaphore sem;
QList<Thread *> threads;
threads.resize(4);
for (Thread *&t : threads)
t = new Thread(sem);
for (Thread *&t : threads)
t->start();
// wait for all threads to reach the sem.acquire() and then
// release them all
QTest::qSleep(1);
sem.release();
for (Thread *&t : threads)
t->wait();
qDeleteAll(threads);
}
void tst_QSemaphore::tryAcquire()
{
QSemaphore semaphore;
QCOMPARE(semaphore.available(), 0);
semaphore.release();
QCOMPARE(semaphore.available(), 1);
QVERIFY(!semaphore.tryAcquire(2));
QVERIFY(!semaphore.tryAcquire(2, 0));
QCOMPARE(semaphore.available(), 1);
semaphore.release();
QCOMPARE(semaphore.available(), 2);
QVERIFY(!semaphore.tryAcquire(3));
QVERIFY(!semaphore.tryAcquire(3, 0));
QCOMPARE(semaphore.available(), 2);
semaphore.release(10);
QCOMPARE(semaphore.available(), 12);
QVERIFY(!semaphore.tryAcquire(100));
QVERIFY(!semaphore.tryAcquire(100, 0));
QCOMPARE(semaphore.available(), 12);
semaphore.release(10);
QCOMPARE(semaphore.available(), 22);
QVERIFY(!semaphore.tryAcquire(100));
QVERIFY(!semaphore.tryAcquire(100, 0));
QCOMPARE(semaphore.available(), 22);
QVERIFY(semaphore.tryAcquire());
QCOMPARE(semaphore.available(), 21);
QVERIFY(semaphore.tryAcquire());
QCOMPARE(semaphore.available(), 20);
semaphore.release(2);
QVERIFY(semaphore.tryAcquire(1, 0));
QCOMPARE(semaphore.available(), 21);
QVERIFY(semaphore.tryAcquire(1, 0));
QCOMPARE(semaphore.available(), 20);
QVERIFY(semaphore.tryAcquire(10));
QCOMPARE(semaphore.available(), 10);
semaphore.release(10);
QVERIFY(semaphore.tryAcquire(10, 0));
QCOMPARE(semaphore.available(), 10);
QVERIFY(semaphore.tryAcquire(10));
QCOMPARE(semaphore.available(), 0);
// should not be able to acquire more
QVERIFY(!semaphore.tryAcquire());
QVERIFY(!semaphore.tryAcquire(1, 0));
QCOMPARE(semaphore.available(), 0);
QVERIFY(!semaphore.tryAcquire());
QVERIFY(!semaphore.tryAcquire(1, 0));
QCOMPARE(semaphore.available(), 0);
QVERIFY(!semaphore.tryAcquire(10));
QVERIFY(!semaphore.tryAcquire(10, 0));
QCOMPARE(semaphore.available(), 0);
QVERIFY(!semaphore.tryAcquire(10));
QVERIFY(!semaphore.tryAcquire(10, 0));
QCOMPARE(semaphore.available(), 0);
}
void tst_QSemaphore::tryAcquireWithTimeout_data()
{
QTest::addColumn<int>("timeout");
QTest::newRow("0.2s") << 200;
QTest::newRow("2s") << 2000;
}
void tst_QSemaphore::tryAcquireWithTimeout()
{
QFETCH(int, timeout);
// timers are not guaranteed to be accurate down to the last millisecond,
// so we permit the elapsed times to be up to this far from the expected value.
int fuzz = 50 + (timeout / 20);
QSemaphore semaphore;
QElapsedTimer time;
#define FUZZYCOMPARE(a,e) \
do { \
int a1 = a; \
int e1 = e; \
QVERIFY2(qAbs(a1-e1) < fuzz, \
qPrintable(QString("(%1=%2) is more than %3 milliseconds different from (%4=%5)") \
.arg(#a).arg(a1).arg(fuzz).arg(#e).arg(e1))); \
} while (0)
QCOMPARE(semaphore.available(), 0);
semaphore.release();
QCOMPARE(semaphore.available(), 1);
time.start();
QVERIFY(!semaphore.tryAcquire(2, timeout));
FUZZYCOMPARE(int(time.elapsed()), timeout);
QCOMPARE(semaphore.available(), 1);
semaphore.release();
QCOMPARE(semaphore.available(), 2);
time.start();
QVERIFY(!semaphore.tryAcquire(3, timeout));
FUZZYCOMPARE(int(time.elapsed()), timeout);
QCOMPARE(semaphore.available(), 2);
semaphore.release(10);
QCOMPARE(semaphore.available(), 12);
time.start();
QVERIFY(!semaphore.tryAcquire(100, timeout));
FUZZYCOMPARE(int(time.elapsed()), timeout);
QCOMPARE(semaphore.available(), 12);
semaphore.release(10);
QCOMPARE(semaphore.available(), 22);
time.start();
QVERIFY(!semaphore.tryAcquire(100, timeout));
FUZZYCOMPARE(int(time.elapsed()), timeout);
QCOMPARE(semaphore.available(), 22);
time.start();
QVERIFY(semaphore.tryAcquire(1, timeout));
FUZZYCOMPARE(int(time.elapsed()), 0);
QCOMPARE(semaphore.available(), 21);
time.start();
QVERIFY(semaphore.tryAcquire(1, timeout));
FUZZYCOMPARE(int(time.elapsed()), 0);
QCOMPARE(semaphore.available(), 20);
time.start();
QVERIFY(semaphore.tryAcquire(10, timeout));
FUZZYCOMPARE(int(time.elapsed()), 0);
QCOMPARE(semaphore.available(), 10);
time.start();
QVERIFY(semaphore.tryAcquire(10, timeout));
FUZZYCOMPARE(int(time.elapsed()), 0);
QCOMPARE(semaphore.available(), 0);
// should not be able to acquire more
time.start();
QVERIFY(!semaphore.tryAcquire(1, timeout));
FUZZYCOMPARE(int(time.elapsed()), timeout);
QCOMPARE(semaphore.available(), 0);
time.start();
QVERIFY(!semaphore.tryAcquire(1, timeout));
FUZZYCOMPARE(int(time.elapsed()), timeout);
QCOMPARE(semaphore.available(), 0);
time.start();
QVERIFY(!semaphore.tryAcquire(10, timeout));
FUZZYCOMPARE(int(time.elapsed()), timeout);
QCOMPARE(semaphore.available(), 0);
time.start();
QVERIFY(!semaphore.tryAcquire(10, timeout));
FUZZYCOMPARE(int(time.elapsed()), timeout);
QCOMPARE(semaphore.available(), 0);
#undef FUZZYCOMPARE
}
void tst_QSemaphore::tryAcquireWithTimeoutStarvation()
{
class Thread : public QThread
{
public:
QSemaphore startup;
QSemaphore *semaphore;
int amountToConsume, timeout;
void run() override
{
startup.release();
forever {
if (!semaphore->tryAcquire(amountToConsume, timeout))
break;
semaphore->release(amountToConsume);
}
}
};
QSemaphore semaphore;
semaphore.release(1);
Thread consumer;
consumer.semaphore = &semaphore;
consumer.amountToConsume = 1;
consumer.timeout = 1000;
// start the thread and wait for it to start consuming
consumer.start();
consumer.startup.acquire();
// try to consume more than the thread we started is, and provide a longer
// timeout... we should timeout, not wait indefinitely
QVERIFY(!semaphore.tryAcquire(consumer.amountToConsume * 2, consumer.timeout * 2));
// the consumer should still be running
QVERIFY(consumer.isRunning() && !consumer.isFinished());
// acquire, and wait for smallConsumer to timeout
semaphore.acquire();
QVERIFY(consumer.wait());
}
void tst_QSemaphore::tryAcquireWithTimeoutForever_data()
{
QTest::addColumn<int>("timeout");
QTest::newRow("-1") << -1;
// tryAcquire is documented to take any negative value as "forever"
QTest::newRow("INT_MIN") << INT_MIN;
}
void tst_QSemaphore::tryAcquireWithTimeoutForever()
{
enum { WaitTime = 1000 };
struct Thread : public QThread {
QSemaphore sem;
void run() override
{
QTest::qWait(WaitTime);
sem.release(2);
}
};
QFETCH(int, timeout);
Thread t;
// sanity check it works if we can immediately acquire
t.sem.release(11);
QVERIFY(t.sem.tryAcquire(1, timeout));
QVERIFY(t.sem.tryAcquire(10, timeout));
// verify that we do wait for at least WaitTime if we can't acquire immediately
QElapsedTimer timer;
timer.start();
t.start();
QVERIFY(t.sem.tryAcquire(1, timeout));
QVERIFY(timer.elapsed() >= WaitTime);
QVERIFY(t.wait());
QCOMPARE(t.sem.available(), 1);
}
const char alphabet[] = "ACGTH";
const int AlphabetSize = sizeof(alphabet) - 1;
const int BufferSize = 4096; // GCD of BufferSize and alphabet size must be 1
static char buffer[BufferSize];
const int ProducerChunkSize = 3;
const int ConsumerChunkSize = 7;
const int Multiplier = 10;
// note: the code depends on the fact that DataSize is a multiple of
// ProducerChunkSize, ConsumerChunkSize, and BufferSize
const int DataSize = ProducerChunkSize * ConsumerChunkSize * BufferSize * Multiplier;
static QSemaphore freeSpace(BufferSize);
static QSemaphore usedSpace;
class Producer : public QThread
{
public:
void run() override;
};
static const auto Timeout = 1min;
void Producer::run()
{
for (int i = 0; i < DataSize; ++i) {
QVERIFY(freeSpace.tryAcquire(1, Timeout));
buffer[i % BufferSize] = alphabet[i % AlphabetSize];
usedSpace.release();
}
for (int i = 0; i < DataSize; ++i) {
if ((i % ProducerChunkSize) == 0)
QVERIFY(freeSpace.tryAcquire(ProducerChunkSize, Timeout));
buffer[i % BufferSize] = alphabet[i % AlphabetSize];
if ((i % ProducerChunkSize) == (ProducerChunkSize - 1))
usedSpace.release(ProducerChunkSize);
}
}
class Consumer : public QThread
{
public:
void run() override;
};
void Consumer::run()
{
for (int i = 0; i < DataSize; ++i) {
usedSpace.acquire();
QCOMPARE(buffer[i % BufferSize], alphabet[i % AlphabetSize]);
freeSpace.release();
}
for (int i = 0; i < DataSize; ++i) {
if ((i % ConsumerChunkSize) == 0)
usedSpace.acquire(ConsumerChunkSize);
QCOMPARE(buffer[i % BufferSize], alphabet[i % AlphabetSize]);
if ((i % ConsumerChunkSize) == (ConsumerChunkSize - 1))
freeSpace.release(ConsumerChunkSize);
}
}
void tst_QSemaphore::producerConsumer()
{
Producer producer;
Consumer consumer;
producer.start();
consumer.start();
producer.wait();
consumer.wait();
}
void tst_QSemaphore::raii()
{
QSemaphore sem;
QCOMPARE(sem.available(), 0);
// basic operation:
{
QSemaphoreReleaser r0;
const QSemaphoreReleaser r1(sem);
const QSemaphoreReleaser r2(sem, 2);
QCOMPARE(r0.semaphore(), nullptr);
QCOMPARE(r1.semaphore(), &sem);
QCOMPARE(r2.semaphore(), &sem);
}
QCOMPARE(sem.available(), 3);
// cancel:
{
const QSemaphoreReleaser r1(sem);
QSemaphoreReleaser r2(sem, 2);
QCOMPARE(r2.cancel(), &sem);
QCOMPARE(r2.semaphore(), nullptr);
}
QCOMPARE(sem.available(), 4);
// move-assignment:
{
const QSemaphoreReleaser r1(sem);
QSemaphoreReleaser r2(sem, 2);
QCOMPARE(sem.available(), 4);
r2 = QSemaphoreReleaser();
QCOMPARE(sem.available(), 6);
r2 = QSemaphoreReleaser(sem, 42);
QCOMPARE(sem.available(), 6);
}
QCOMPARE(sem.available(), 49);
}
void tst_QSemaphore::stdCompat()
{
QSemaphore sem(1);
auto now = [] { return std::chrono::steady_clock::now(); };
QVERIFY(sem.try_acquire());
QCOMPARE(sem.available(), 0);
QVERIFY(!sem.try_acquire_for(10ms));
QCOMPARE(sem.available(), 0);
QVERIFY(!sem.try_acquire_until(now() + 10ms));
QCOMPARE(sem.available(), 0);
sem.release(2);
QVERIFY(sem.try_acquire());
QVERIFY(sem.try_acquire_for(5ms));
QCOMPARE(sem.available(), 0);
QVERIFY(!sem.try_acquire_until(now() + 5ms));
QCOMPARE(sem.available(), 0);
sem.release(3);
QVERIFY(sem.try_acquire());
QVERIFY(sem.try_acquire_for(5s));
QVERIFY(sem.try_acquire_until(now() + 5s));
QCOMPARE(sem.available(), 0);
}
QTEST_MAIN(tst_QSemaphore)
#include "tst_qsemaphore.moc"