qt 6.6.0 clean

This commit is contained in:
kleuter
2023-11-01 22:23:55 +01:00
parent 7b5ada15e7
commit 5d8194efa7
1449 changed files with 134276 additions and 31391 deletions

View File

@ -15,12 +15,10 @@ if(QT_FEATURE_thread)
add_subdirectory(qreadlocker)
add_subdirectory(qreadwritelock)
add_subdirectory(qsemaphore)
# special case begin
# QTBUG-85364
if(NOT CMAKE_CROSSCOMPILING)
add_subdirectory(qthread)
endif()
# special case end
add_subdirectory(qthreadonce)
add_subdirectory(qthreadpool)
add_subdirectory(qthreadstorage)

View File

@ -1,30 +1,6 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifdef QT_ATOMIC_FORCE_CXX11
// We need to check if this compiler has C++11 atomics and constexpr support.
// We can't rely on qcompilerdetection.h because it forces all of qglobal.h to
// be included, which causes qbasicatomic.h to be included too.
// Incomplete, but ok
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1500 && (__cplusplus >= 201103L || defined(__INTEL_CXX11_MODE__))
# elif defined(__clang__) && (__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
# if !__has_feature(cxx_constexpr) || !__has_feature(cxx_atomic) || !__has_include(<atomic>)
# undef QT_ATOMIC_FORCE_CXX11
# endif
# elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && (__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
# elif defined(_MSC_VER)
// We need MSVC 2015 because of: atomics (2012), constexpr (2015), and unrestricted unions (2015).
// Support for constexpr is not working completely on MSVC 2015 but it's enough for the test.
# else
# undef QT_ATOMIC_FORCE_CXX11
# endif
# ifndef QT_ATOMIC_FORCE_CXX11
# undef QATOMIC_TEST_TYPE
# define QATOMIC_TEST_TYPE unsupported
# endif
#endif
#include <QTest>
#include <QAtomicInt>

View File

@ -11,6 +11,7 @@
#include <QVarLengthArray>
#include <QSet>
#include <QList>
#include <private/qobject_p.h>
#include <QTest>
#include <qfuture.h>
@ -22,14 +23,20 @@
#include <QtConcurrent/qtconcurrentrun.h>
#include <private/qfutureinterface_p.h>
#include <forward_list>
#include <list>
#include <vector>
#include <memory>
#include <set>
// COM interface macro.
#if defined(Q_OS_WIN) && defined(interface)
# undef interface
#endif
using namespace std::chrono_literals;
static constexpr auto DefaultWaitTime = 2s;
using namespace Qt::StringLiterals;
class SenderObject : public QObject
@ -133,6 +140,18 @@ private:
std::function<void ()> m_fn;
};
// Emulates QWidget behavior by deleting its children early in the destructor
// instead of leaving it to ~QObject()
class FakeQWidget : public QObject
{
Q_OBJECT
public:
~FakeQWidget() override {
auto *d = QObjectPrivate::get(this);
d->deleteChildren();
}
};
using UniquePtr = std::unique_ptr<int>;
class tst_QFuture: public QObject
@ -203,6 +222,7 @@ private slots:
void rejectPendingResultOverwrite();
void createReadyFutures();
void continuationsAfterReadyFutures();
void getFutureInterface();
void convertQMetaType();
@ -1957,7 +1977,7 @@ void tst_QFuture::nonGlobalThreadPool()
void run() override
{
const int ms = 100 + (QRandomGenerator::global()->bounded(100) - 100/2);
QThread::msleep(ulong(ms));
QThread::sleep(std::chrono::milliseconds{ms});
reportResult(Answer);
reportFinished();
}
@ -3046,7 +3066,7 @@ void tst_QFuture::cancelContinuations()
// The chain is cancelled before the execution of continuations
{
auto f = QtFuture::makeReadyFuture(42);
auto f = QtFuture::makeReadyValueFuture(42);
f.cancel();
int checkpoint = 0;
@ -3257,6 +3277,40 @@ void tst_QFuture::continuationsWithContext()
QCOMPARE(future.result(), 2);
}
// Cancellation when the context object is destroyed
{
// Use something like QWidget which deletes its children early, i.e.
// before ~QObject() runs. This behavior can lead to side-effects
// like QPointers to the parent not being set to nullptr during child
// object destruction.
QPointer shortLivedContext = new FakeQWidget();
shortLivedContext->moveToThread(&thread);
QPromise<int> promise;
auto future = promise.future()
.then(shortLivedContext, [&](int val) {
if (QThread::currentThread() != &thread)
return 0;
return val + 1000;
})
.onCanceled([&, ptr=QPointer(shortLivedContext)] {
if (QThread::currentThread() != &thread)
return 0;
if (ptr)
return 1;
return 2;
});
promise.start();
QMetaObject::invokeMethod(shortLivedContext, [&]() {
delete shortLivedContext;
}, Qt::BlockingQueuedConnection);
promise.finish();
QCOMPARE(future.result(), 2);
}
#ifndef QT_NO_EXCEPTIONS
// .onFaled()
{
@ -3295,7 +3349,8 @@ void tst_QFuture::continuationsWithMoveOnlyLambda()
// .then()
{
std::unique_ptr<int> uniquePtr(new int(42));
auto future = QtFuture::makeReadyFuture().then([p = std::move(uniquePtr)] { return *p; });
auto future = QtFuture::makeReadyVoidFuture()
.then([p = std::move(uniquePtr)] { return *p; });
QCOMPARE(future.result(), 42);
}
// .then() with thread pool
@ -3303,8 +3358,8 @@ void tst_QFuture::continuationsWithMoveOnlyLambda()
QThreadPool pool;
std::unique_ptr<int> uniquePtr(new int(42));
auto future =
QtFuture::makeReadyFuture().then(&pool, [p = std::move(uniquePtr)] { return *p; });
auto future = QtFuture::makeReadyVoidFuture()
.then(&pool, [p = std::move(uniquePtr)] { return *p; });
QCOMPARE(future.result(), 42);
}
// .then() with context
@ -3312,8 +3367,8 @@ void tst_QFuture::continuationsWithMoveOnlyLambda()
QObject object;
std::unique_ptr<int> uniquePtr(new int(42));
auto future = QtFuture::makeReadyFuture().then(&object,
[p = std::move(uniquePtr)] { return *p; });
auto future = QtFuture::makeReadyVoidFuture()
.then(&object, [p = std::move(uniquePtr)] { return *p; });
QCOMPARE(future.result(), 42);
}
@ -3464,7 +3519,7 @@ void tst_QFuture::runAndTake()
auto rabbit = [](){
// Let's wait a bit to give the test below some time
// to sync up with us with its watcher.
QThread::currentThread()->msleep(100);
QThread::currentThread()->sleep(std::chrono::milliseconds{100});
return UniquePtr(new int(10));
};
@ -3477,7 +3532,7 @@ void tst_QFuture::runAndTake()
auto gotcha = QtConcurrent::run(rabbit);
watcha.setFuture(gotcha);
loop.enterLoopMSecs(500);
loop.enterLoop(500ms);
if (loop.timeout())
QSKIP("Failed to run the task, nothing to test");
@ -3548,7 +3603,7 @@ void tst_QFuture::resultsReadyAt()
// Run event loop, QCoreApplication::postEvent is in use
// in QFutureInterface:
eventProcessor.enterLoopMSecs(2000);
eventProcessor.enterLoop(DefaultWaitTime);
QVERIFY(!eventProcessor.timeout());
if (QTest::currentTestFailed()) // Failed in our lambda observing 'ready at'
return;
@ -3921,7 +3976,7 @@ void tst_QFuture::rejectResultOverwrite()
});
// Run event loop, QCoreApplication::postEvent is in use
// in QFutureInterface:
eventProcessor.enterLoopMSecs(2000);
eventProcessor.enterLoop(DefaultWaitTime);
QVERIFY(!eventProcessor.timeout());
QCOMPARE(resultCounter.size(), 1);
f.resume();
@ -3960,7 +4015,7 @@ void tst_QFuture::rejectResultOverwrite()
QTimer::singleShot(50, [&f]() {
f.suspend(); // should exit the loop
});
eventProcessor.enterLoopMSecs(2000);
eventProcessor.enterLoop(DefaultWaitTime);
QVERIFY(!eventProcessor.timeout());
QCOMPARE(resultCounter.size(), 1);
f.resume();
@ -3999,7 +4054,7 @@ void tst_QFuture::rejectPendingResultOverwrite()
});
// Run event loop, QCoreApplication::postEvent is in use
// in QFutureInterface:
eventProcessor.enterLoopMSecs(2000);
eventProcessor.enterLoop(DefaultWaitTime);
QVERIFY(!eventProcessor.timeout());
QCOMPARE(resultCounter.size(), 1);
f.resume();
@ -4043,7 +4098,7 @@ void tst_QFuture::rejectPendingResultOverwrite()
QTimer::singleShot(50, [&f]() {
f.suspend(); // should exit the loop
});
eventProcessor.enterLoopMSecs(2000);
eventProcessor.enterLoop(DefaultWaitTime);
QVERIFY(!eventProcessor.timeout());
QCOMPARE(resultCounter.size(), 1);
f.resume();
@ -4058,6 +4113,9 @@ void tst_QFuture::rejectPendingResultOverwrite()
void tst_QFuture::createReadyFutures()
{
#if QT_DEPRECATED_SINCE(6, 10)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
// using const T &
{
const int val = 42;
@ -4093,6 +4151,30 @@ void tst_QFuture::createReadyFutures()
QCOMPARE(f.resultCount(), 3);
QCOMPARE(f.results(), values);
}
QT_WARNING_POP
#endif // QT_DEPRECATED_SINCE(6, 10)
// test makeReadyValueFuture<T>()
{
const int val = 42;
auto f = QtFuture::makeReadyValueFuture(val);
QCOMPARE_EQ(f.result(), val);
int otherVal = 42;
f = QtFuture::makeReadyValueFuture(otherVal);
QCOMPARE_EQ(f.result(), otherVal);
}
{
auto f = QtFuture::makeReadyValueFuture(std::make_unique<int>(42));
QCOMPARE(*f.takeResult(), 42);
}
// test makeReadyVoidFuture()
{
auto f = QtFuture::makeReadyVoidFuture();
QVERIFY(f.isStarted());
QVERIFY(!f.isRunning());
QVERIFY(f.isFinished());
}
#ifndef QT_NO_EXCEPTIONS
// using QException
@ -4121,12 +4203,205 @@ void tst_QFuture::createReadyFutures()
QVERIFY(caught);
}
#endif
// testing makeReadyRangeFuture with various containers
{
const QList<int> expectedResult{1, 2, 3};
const QList<int> list{1, 2, 3};
auto f = QtFuture::makeReadyRangeFuture(list);
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
QVarLengthArray<int> varArray{1, 2, 3};
f = QtFuture::makeReadyRangeFuture(varArray);
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
std::vector<int> vec{1, 2, 3};
f = QtFuture::makeReadyRangeFuture(std::move(vec));
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
f = QtFuture::makeReadyRangeFuture(std::array<int, 3>{1, 2, 3});
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
f = QtFuture::makeReadyRangeFuture(std::list<int>{1, 2, 3});
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
std::forward_list<int> fwdlist{1, 2, 3};
f = QtFuture::makeReadyRangeFuture(fwdlist);
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
const QSet<int> qset{1, 2, 3};
f = QtFuture::makeReadyRangeFuture(qset);
QCOMPARE_EQ(f.resultCount(), 3);
auto result = f.results();
std::sort(result.begin(), result.end());
QCOMPARE_EQ(result, expectedResult);
const QMap<QString, int> qmap{
{"one", 1},
{"two", 2},
{"three", 3}
};
f = QtFuture::makeReadyRangeFuture(qmap);
QCOMPARE_EQ(f.resultCount(), 3);
result = f.results();
std::sort(result.begin(), result.end());
QCOMPARE_EQ(result, expectedResult);
std::set<int> stdset{1, 2, 3};
f = QtFuture::makeReadyRangeFuture(stdset);
QCOMPARE_EQ(f.resultCount(), 3);
result = f.results();
std::sort(result.begin(), result.end());
QCOMPARE_EQ(result, expectedResult);
// testing ValueType[N] overload
const int c_array[] = {1, 2, 3};
f = QtFuture::makeReadyRangeFuture(c_array);
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
f = QtFuture::makeReadyRangeFuture({1, 2, 3});
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
}
// testing makeReadyRangeFuture with a more complex underlying type
{
QObject obj1;
QObject obj2;
QObject obj3;
const QList<QObject*> expectedResult{&obj1, &obj2, &obj3};
const QList<QObject*> list{&obj1, &obj2, &obj3};
auto f = QtFuture::makeReadyRangeFuture(list);
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
std::list<QObject*> stdlist{&obj1, &obj2, &obj3};
f = QtFuture::makeReadyRangeFuture(std::move(stdlist));
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
QObject* const c_array[] = {&obj1, &obj2, &obj3};
f = QtFuture::makeReadyRangeFuture(c_array);
QCOMPARE_EQ(f.resultCount(), 3);
QCOMPARE_EQ(f.results(), expectedResult);
}
}
void tst_QFuture::continuationsAfterReadyFutures()
{
// continuations without a context
{
QFuture<int> f = QtFuture::makeReadyValueFuture(42)
.then([](int val) {
return val + 10;
})
.onCanceled([]() {
return -1;
});
QCOMPARE(f.result(), 52);
}
{
auto rangeF = QtFuture::makeReadyRangeFuture({1, 2, 3});
QFuture<int> f = rangeF
.then([vals = rangeF.results()](auto) {
return vals.last();
})
.onCanceled([]() {
return -1;
});
QCOMPARE(f.result(), 3);
}
{
QFuture<int> f = QtFuture::makeReadyVoidFuture()
.then([]() {
return 1;
})
.onCanceled([]() {
return -1;
});
QCOMPARE(f.result(), 1);
}
#ifndef QT_NO_EXCEPTIONS
{
QException e;
QFuture<int> f = QtFuture::makeExceptionalFuture<int>(e)
.then([](int) {
return 1;
})
.onCanceled([]() {
return -1;
})
.onFailed([](const QException &) {
return -2;
});
QCOMPARE(f.result(), -2);
}
#endif
// continuations with a context
QObject context;
{
QFuture<int> f = QtFuture::makeReadyValueFuture(42)
.then(&context, [](int val) {
return val + 10;
})
.onCanceled([]() {
return -1;
});
QCOMPARE(f.result(), 52);
}
{
auto rangeF = QtFuture::makeReadyRangeFuture({1, 2, 3});
QFuture<int> f = rangeF
.then(&context, [vals = rangeF.results()](auto) {
return vals.last();
})
.onCanceled([]() {
return -1;
});
QCOMPARE(f.result(), 3);
}
{
QFuture<int> f = QtFuture::makeReadyVoidFuture()
.then(&context, []() {
return 1;
})
.onCanceled([]() {
return -1;
});
QCOMPARE(f.result(), 1);
}
#ifndef QT_NO_EXCEPTIONS
{
QException e;
QFuture<int> f = QtFuture::makeExceptionalFuture<int>(e)
.then(&context, [](int) {
return 1;
})
.onCanceled([]() {
return -1;
})
.onFailed([](const QException &) {
return -2;
});
QCOMPARE(f.result(), -2);
}
#endif
}
void tst_QFuture::getFutureInterface()
{
const int val = 42;
QFuture<int> f = QtFuture::makeReadyFuture(val);
QFuture<int> f = QtFuture::makeReadyValueFuture(val);
auto interface = QFutureInterfaceBase::get(f);
QCOMPARE(interface.resultCount(), 1);
@ -4140,7 +4415,7 @@ void tst_QFuture::convertQMetaType()
QVERIFY(QMetaType::canConvert(intType, voidType));
const int val = 42;
QFuture<int> f = QtFuture::makeReadyFuture(val);
QFuture<int> f = QtFuture::makeReadyValueFuture(val);
auto variant = QVariant::fromValue(f);
QVERIFY(variant.convert(voidType));
@ -4737,6 +5012,40 @@ void tst_QFuture::continuationsDontLeak()
QVERIFY(continuationIsRun);
}
QCOMPARE(InstanceCounter::count, 0);
{
// QTBUG-116731: Must pass with ASan enabled
bool continuationIsRun = false;
auto f = QtFuture::makeReadyValueFuture(42);
QtFuture::whenAll(f).then([&](auto) { continuationIsRun = true; });
QVERIFY(continuationIsRun);
}
{
// QTBUG-116731: Must pass with ASan enabled
bool continuationIsRun = false;
auto f = QtFuture::makeReadyValueFuture(42);
QList fs{f};
QtFuture::whenAll(fs.begin(), fs.end()).then([&](auto) { continuationIsRun = true; });
QVERIFY(continuationIsRun);
}
{
// QTBUG-116731: Must pass with ASan enabled
bool continuationIsRun = false;
auto f = QtFuture::makeReadyValueFuture(42);
QtFuture::whenAny(f).then([&](auto) { continuationIsRun = true; });
QVERIFY(continuationIsRun);
}
{
// QTBUG-116731: Must pass with ASan enabled
bool continuationIsRun = false;
auto f = QtFuture::makeReadyValueFuture(42);
QList fs{f};
QtFuture::whenAny(fs.begin(), fs.end()).then([&](auto) { continuationIsRun = true; });
QVERIFY(continuationIsRun);
}
}
// This test checks that we do not get use-after-free

View File

@ -39,7 +39,7 @@ void tst_QFutureSynchronizer::setFutureAliasingExistingMember()
//
// GIVEN: a QFutureSynchronizer with one QFuture:
//
QFutureSynchronizer synchronizer(QtFuture::makeReadyFuture(42));
QFutureSynchronizer synchronizer(QtFuture::makeReadyValueFuture(42));
//
// WHEN: calling setFuture() with an alias of the QFuture already in `synchronizer`:

View File

@ -9,6 +9,7 @@
#include <private/qfutureinterface_p.h>
using namespace QtConcurrent;
using namespace std::chrono_literals;
#include <QTest>
@ -900,13 +901,13 @@ QT_WARNING_POP
QFuture<int> future = QtConcurrent::mapped(&pool, values, [&](int value) {
++count;
// Sleep, to make sure not all threads will start at once.
QThread::msleep(50);
QThread::sleep(50ms);
return value;
});
watcher.setFuture(future);
// Allow some threads to start before suspending.
QThread::msleep(200);
QThread::sleep(200ms);
watcher.suspend();
watcher.suspend();
@ -921,7 +922,7 @@ QT_WARNING_POP
QCOMPARE(resultReadyAfterPaused, count);
// Make sure no more results are reported before resuming.
QThread::msleep(200);
QThread::sleep(200ms);
QCOMPARE(resultReadyAfterPaused, resultReadySpy.size());
resultReadySpy.clear();
@ -1139,7 +1140,7 @@ public:
void tst_QFutureWatcher::warnRace()
{
#ifndef Q_OS_MAC //I don't know why it is not working on mac
#ifndef Q_OS_DARWIN // I don't know why it is not working on mac
#ifndef QT_NO_DEBUG
QTest::ignoreMessage(QtWarningMsg, "QFutureWatcher::connect: connecting after calling setFuture() is likely to produce race");
#endif

View File

@ -14,6 +14,8 @@
#include <qwaitcondition.h>
#include <private/qvolatile_p.h>
using namespace std::chrono_literals;
class tst_QMutex : public QObject
{
Q_OBJECT
@ -27,8 +29,6 @@ public:
Q_ENUM(TimeUnit)
private slots:
void convertToMilliseconds_data();
void convertToMilliseconds();
void tryLock_non_recursive();
void try_lock_for_non_recursive();
void try_lock_until_non_recursive();
@ -69,104 +69,6 @@ enum {
static constexpr std::chrono::milliseconds waitTimeAsDuration(waitTime);
void tst_QMutex::convertToMilliseconds_data()
{
QTest::addColumn<TimeUnit>("unit");
QTest::addColumn<double>("doubleValue");
QTest::addColumn<qint64>("intValue");
QTest::addColumn<qint64>("expected");
auto add = [](TimeUnit unit, double d, long long i, qint64 expected) {
const QScopedArrayPointer<char> enumName(QTest::toString(unit));
QTest::addRow("%s:%f:%lld", enumName.data(), d, i)
<< unit << d << qint64(i) << expected;
};
auto forAllUnitsAdd = [=](double d, long long i, qint64 expected) {
for (auto unit : {TimeUnit::Nanoseconds, TimeUnit::Microseconds, TimeUnit::Milliseconds, TimeUnit::Seconds})
add(unit, d, i, expected);
};
forAllUnitsAdd(-0.5, -1, 0); // all negative values result in 0
forAllUnitsAdd(0, 0, 0);
add(TimeUnit::Nanoseconds, 1, 1, 1);
add(TimeUnit::Nanoseconds, 1000 * 1000, 1000 * 1000, 1);
add(TimeUnit::Nanoseconds, 1000 * 1000 + 0.5, 1000 * 1000 + 1, 2);
add(TimeUnit::Microseconds, 1, 1, 1);
add(TimeUnit::Microseconds, 1000, 1000, 1);
add(TimeUnit::Microseconds, 1000 + 0.5, 1000 + 1, 2);
add(TimeUnit::Milliseconds, 1, 1, 1);
add(TimeUnit::Milliseconds, 1.5, 2, 2);
add(TimeUnit::Seconds, 0.9991, 1, 1000);
//
// overflowing int results in INT_MAX (equivalent to a spurious wakeup after ~24 days); check it:
//
// spot on:
add(TimeUnit::Nanoseconds, INT_MAX * 1000. * 1000, INT_MAX * Q_INT64_C(1000) * 1000, INT_MAX);
add(TimeUnit::Microseconds, INT_MAX * 1000., INT_MAX * Q_INT64_C(1000), INT_MAX);
add(TimeUnit::Milliseconds, INT_MAX, INT_MAX, INT_MAX);
// minimally above:
add(TimeUnit::Nanoseconds, INT_MAX * 1000. * 1000 + 1, INT_MAX * Q_INT64_C(1000) * 1000 + 1, INT_MAX);
add(TimeUnit::Microseconds, INT_MAX * 1000. + 1, INT_MAX * Q_INT64_C(1000) + 1, INT_MAX);
add(TimeUnit::Milliseconds, INT_MAX + 1., INT_MAX + Q_INT64_C(1), INT_MAX);
add(TimeUnit::Seconds, INT_MAX / 1000. + 1, INT_MAX / 1000 + 1, INT_MAX);
// minimally below:
add(TimeUnit::Nanoseconds, INT_MAX * 1000. * 1000 - 1, INT_MAX * Q_INT64_C(1000) * 1000 - 1, INT_MAX);
add(TimeUnit::Microseconds, INT_MAX * 1000. - 1, INT_MAX * Q_INT64_C(1000) - 1, INT_MAX);
add(TimeUnit::Milliseconds, INT_MAX - 0.1, INT_MAX , INT_MAX);
}
void tst_QMutex::convertToMilliseconds()
{
QFETCH(TimeUnit, unit);
QFETCH(double, doubleValue);
QFETCH(qint64, intValue);
QFETCH(qint64, expected);
constexpr qint64 maxShort = std::numeric_limits<short>::max();
constexpr qint64 maxInt = std::numeric_limits<int>::max();
constexpr qint64 maxUInt = std::numeric_limits<uint>::max();
switch (unit) {
#define CASE(Unit, Period) \
case TimeUnit::Unit: \
DO(double, Period, doubleValue); \
if (intValue < maxShort) \
DO(short, Period, short(intValue)); \
if (intValue < maxInt) \
DO(int, Period, int(intValue)); \
DO(qint64, Period, intValue); \
if (intValue >= 0) { \
if (intValue < maxUInt) \
DO(uint, Period, uint(intValue)); \
DO(quint64, Period, quint64(intValue)); \
} \
break
#define DO(Rep, Period, val) \
do { \
const std::chrono::duration<Rep, Period> wait((val)); \
QCOMPARE(QtPrivate::convertToMilliseconds(wait), expected); \
} while (0)
CASE(Nanoseconds, std::nano);
CASE(Microseconds, std::micro);
CASE(Milliseconds, std::milli);
CASE(Seconds, std::ratio<1>);
#undef DO
#undef CASE
}
}
void tst_QMutex::tryLock_non_recursive()
{
class Thread : public QThread
@ -283,7 +185,7 @@ void tst_QMutex::tryLock_non_recursive()
testsTurn.acquire();
normalMutex.lock();
threadsTurn.release();
QThread::msleep(100);
QThread::sleep(100ms);
normalMutex.unlock();
// wait for thread to finish
@ -408,7 +310,7 @@ void tst_QMutex::try_lock_for_non_recursive()
testsTurn.acquire();
normalMutex.lock();
threadsTurn.release();
QThread::msleep(100);
QThread::sleep(100ms);
normalMutex.unlock();
// wait for thread to finish
@ -533,7 +435,7 @@ void tst_QMutex::try_lock_until_non_recursive()
testsTurn.acquire();
normalMutex.lock();
threadsTurn.release();
QThread::msleep(100);
QThread::sleep(100ms);
normalMutex.unlock();
// wait for thread to finish

View File

@ -14,6 +14,8 @@
#include <memory>
#include <chrono>
using namespace std::chrono_literals;
class tst_QPromise : public QObject
{
Q_OBJECT
@ -22,6 +24,7 @@ private slots:
void promise();
void futureFromPromise();
void addResult();
void addResultWithBracedInitializer();
void addResultOutOfOrder();
#ifndef QT_NO_EXCEPTIONS
void setException();
@ -170,6 +173,15 @@ void tst_QPromise::addResult()
QCOMPARE(f.resultCount(), 3);
QCOMPARE(f.resultAt(2), result);
}
// add multiple results in one go:
{
QList results = {42, 4242, 424242};
QVERIFY(promise.addResults(results));
QCOMPARE(f.resultCount(), 6);
QCOMPARE(f.resultAt(3), 42);
QCOMPARE(f.resultAt(4), 4242);
QCOMPARE(f.resultAt(5), 424242);
}
// add as lvalue at position and overwrite
{
int result = -1;
@ -187,6 +199,28 @@ void tst_QPromise::addResult()
}
}
void tst_QPromise::addResultWithBracedInitializer() // QTBUG-111826
{
struct MyClass
{
QString strValue;
int intValue = 0;
#ifndef __cpp_aggregate_paren_init // make emplacement work with MyClass
MyClass(QString s, int i) : strValue(std::move(s)), intValue(i) {}
#endif
};
{
QPromise<MyClass> myPromise;
myPromise.addResult({"bar", 1});
}
{
QPromise<MyClass> myPromise;
myPromise.emplaceResult("bar", 1);
}
}
void tst_QPromise::addResultOutOfOrder()
{
// Compare results available in QFuture to expected results
@ -483,7 +517,7 @@ void tst_QPromise::cancelWhenReassigned()
promise.start();
ThreadWrapper thr([p = std::move(promise)] () mutable {
QThread::msleep(100);
QThread::sleep(100ms);
p = QPromise<int>(); // assign new promise, old must be correctly destroyed
});
@ -618,7 +652,7 @@ void tst_QPromise::finishWhenSwapped()
promise2.start();
ThreadWrapper thr([&promise1, &promise2] () mutable {
QThread::msleep(100);
QThread::sleep(100ms);
promise1.addResult(0);
promise2.addResult(1);
swap(promise1, promise2); // ADL must resolve this
@ -662,7 +696,7 @@ void testCancelWhenMoved()
// Move promises to local scope to test cancellation behavior
ThreadWrapper thr([p1 = std::move(promise1), p2 = std::move(promise2)] () mutable {
QThread::msleep(100);
QThread::sleep(100ms);
p1 = std::move(p2);
p1.finish(); // this finish is for future #2
});
@ -706,7 +740,7 @@ void tst_QPromise::waitUntilResumed()
while (!f.isSuspended()) { // busy wait until worker thread suspends
QCOMPARE(f.isFinished(), false); // exit condition in case of failure
QThread::msleep(50); // allow another thread to actually carry on
QThread::sleep(50ms); // allow another thread to actually carry on
}
f.resume();
@ -735,7 +769,7 @@ void tst_QPromise::waitUntilCanceled()
while (!f.isSuspended()) { // busy wait until worker thread suspends
QCOMPARE(f.isFinished(), false); // exit condition in case of failure
QThread::msleep(50); // allow another thread to actually carry on
QThread::sleep(50ms); // allow another thread to actually carry on
}
f.cancel();

View File

@ -15,10 +15,6 @@
#ifdef Q_OS_UNIX
#include <unistd.h>
#endif
#if defined(Q_OS_WIN)
# include <qt_windows.h>
# define sleep(X) Sleep(X)
#endif
//on solaris, threads that loop on the release bool variable
//needs to sleep more than 1 usec.
@ -30,6 +26,8 @@
#include <stdio.h>
using namespace std::chrono_literals;
class tst_QReadWriteLock : public QObject
{
Q_OBJECT
@ -472,8 +470,8 @@ class ReadLockLoopThread : public QThread
public:
QReadWriteLock &testRwlock;
int runTime;
int holdTime;
int waitTime;
std::chrono::milliseconds holdTime;
std::chrono::milliseconds waitTime;
bool print;
QElapsedTimer t;
inline ReadLockLoopThread(QReadWriteLock &l, int runTime, int holdTime=0, int waitTime=0, bool print=false)
@ -489,9 +487,9 @@ public:
while (t.elapsed()<runTime) {
testRwlock.lockForRead();
if(print) printf("reading\n");
if (holdTime) msleep(ulong(holdTime));
if (holdTime > 0ms) sleep(holdTime);
testRwlock.unlock();
if (waitTime) msleep(ulong(waitTime));
if (waitTime > 0ms) sleep(waitTime);
}
}
};
@ -508,8 +506,8 @@ class WriteLockLoopThread : public QThread
public:
QReadWriteLock &testRwlock;
int runTime;
int holdTime;
int waitTime;
std::chrono::milliseconds holdTime;
std::chrono::milliseconds waitTime;
bool print;
QElapsedTimer t;
inline WriteLockLoopThread(QReadWriteLock &l, int runTime, int holdTime=0, int waitTime=0, bool print=false)
@ -525,9 +523,9 @@ public:
while (t.elapsed() < runTime) {
testRwlock.lockForWrite();
if (print) printf(".");
if (holdTime) msleep(ulong(holdTime));
if (holdTime > 0ms) sleep(holdTime);
testRwlock.unlock();
if (waitTime) msleep(ulong(waitTime));
if (waitTime > 0ms) sleep(waitTime);
}
}
};
@ -547,7 +545,7 @@ class WriteLockCountThread : public QThread
public:
QReadWriteLock &testRwlock;
int runTime;
int waitTime;
std::chrono::milliseconds waitTime;
int maxval;
QElapsedTimer t;
inline WriteLockCountThread(QReadWriteLock &l, int runTime, int waitTime, int maxval)
@ -568,7 +566,7 @@ public:
QtPrivate::volatilePreIncrement(count);
count=0;
testRwlock.unlock();
msleep(ulong(waitTime));
sleep(waitTime);
}
}
};
@ -585,7 +583,7 @@ class ReadLockCountThread : public QThread
public:
QReadWriteLock &testRwlock;
int runTime;
int waitTime;
std::chrono::milliseconds waitTime;
QElapsedTimer t;
inline ReadLockCountThread(QReadWriteLock &l, int runTime, int waitTime)
:testRwlock(l)
@ -600,7 +598,7 @@ public:
if(count)
qFatal("Non-zero count at Read! (%d)",count );
testRwlock.unlock();
msleep(ulong(waitTime));
sleep(waitTime);
}
}
};
@ -617,7 +615,7 @@ void tst_QReadWriteLock::readLockBlockRelease()
threadDone=false;
ReadLockThread rlt(testLock);
rlt.start();
sleep(1);
QThread::sleep(1s);
testLock.unlock();
rlt.wait();
QVERIFY(threadDone);
@ -634,7 +632,7 @@ void tst_QReadWriteLock::writeLockBlockRelease()
threadDone=false;
WriteLockThread wlt(testLock);
wlt.start();
sleep(1);
QThread::sleep(1s);
testLock.unlock();
wlt.wait();
QVERIFY(threadDone);
@ -653,10 +651,10 @@ void tst_QReadWriteLock::multipleReadersBlockRelease()
ReadLockReleasableThread rlt2(testLock);
rlt1.start();
rlt2.start();
sleep(1);
QThread::sleep(1s);
WriteLockThread wlt(testLock);
wlt.start();
sleep(1);
QThread::sleep(1s);
release.storeRelaxed(true);
wlt.wait();
rlt1.wait();

View File

@ -38,6 +38,8 @@
#include <QtTest/private/qemulationdetector_p.h>
using namespace std::chrono_literals;
class tst_QThread : public QObject
{
Q_OBJECT
@ -245,17 +247,19 @@ public:
elapsed = 0;
QElapsedTimer timer;
timer.start();
std::chrono::nanoseconds dur{0};
switch (sleepType) {
case Second:
sleep(interval);
dur = std::chrono::seconds{interval};
break;
case Millisecond:
msleep(interval);
dur = std::chrono::milliseconds{interval};
break;
case Microsecond:
usleep(interval);
dur = std::chrono::microseconds{interval};
break;
}
sleep(dur);
elapsed = timer.elapsed();
cond.wakeOne();
@ -1603,7 +1607,7 @@ void tst_QThread::createDestruction()
for (;;) {
if (QThread::currentThread()->isInterruptionRequested())
return;
QThread::msleep(1);
QThread::sleep(1ms);
}
};
@ -1722,7 +1726,7 @@ void tst_QThread::threadIdReuse()
bool threadIdReused = false;
for (int i = 0; i < 42; i++) {
QThread::msleep(1);
QThread::sleep(1ms);
Qt::HANDLE threadId2;
bool waitOk = false;

View File

@ -6,6 +6,7 @@
#include <QSemaphore>
#include <qelapsedtimer.h>
#include <qrunnable.h>
#include <qthreadpool.h>
#include <qstring.h>
#include <qmutex.h>
@ -14,6 +15,8 @@
#include <unistd.h>
#endif
using namespace std::chrono_literals;
typedef void (*FunctionPointer)();
class FunctionPointerTask : public QRunnable
@ -43,6 +46,7 @@ public:
private slots:
void runFunction();
void runFunction2();
void runFunction3();
void createThreadRunFunction();
void runMultiple();
void waitcomplete();
@ -83,6 +87,7 @@ private slots:
void takeAllAndIncreaseMaxThreadCount();
void waitForDoneAfterTake();
void threadReuse();
void nullFunctions();
private:
QMutex m_functionTestMutex;
@ -171,6 +176,23 @@ void tst_QThreadPool::runFunction2()
QCOMPARE(localCount, 1);
}
struct DeleteCheck
{
static bool s_deleted;
~DeleteCheck() { s_deleted = true; }
};
bool DeleteCheck::s_deleted = false;
void tst_QThreadPool::runFunction3()
{
std::unique_ptr<DeleteCheck> ptr(new DeleteCheck);
{
TestThreadPool manager;
manager.start([my_ptr = std::move(ptr)]() { });
}
QVERIFY(DeleteCheck::s_deleted);
}
void tst_QThreadPool::createThreadRunFunction()
{
{
@ -407,7 +429,7 @@ void tst_QThreadPool::expiryTimeoutRace() // QTBUG-3786
const int numTasks = 20;
for (int i = 0; i < numTasks; ++i) {
threadPool.start(&task);
QThread::msleep(50); // exactly the same as the expiry timeout
QThread::sleep(50ms); // exactly the same as the expiry timeout
}
QVERIFY(task.semaphore.tryAcquire(numTasks, 10000));
QCOMPARE(task.runCount.loadRelaxed(), numTasks);
@ -1102,7 +1124,7 @@ void tst_QThreadPool::clearWithAutoDelete()
{
public:
MyRunnable() {}
void run() override { QThread::usleep(30); }
void run() override { QThread::sleep(30us); }
};
TestThreadPool threadPool;
@ -1444,5 +1466,30 @@ void tst_QThreadPool::threadReuse()
}
}
void tst_QThreadPool::nullFunctions()
{
const auto expectWarning = [] {
QTest::ignoreMessage(QtMsgType::QtWarningMsg,
"Trying to create null QRunnable. This may stop working.");
};
// Note this is not necessarily testing intended behavior, only undocumented behavior.
// If this is changed it should be noted in Behavioral Changes.
FunctionPointer nullFunction = nullptr;
std::function<void()> nullStdFunction(nullptr);
{
TestThreadPool manager;
// should not crash:
expectWarning();
manager.start(nullFunction);
expectWarning();
manager.start(nullStdFunction);
// should fail (and not leak):
expectWarning();
QVERIFY(!manager.tryStart(nullStdFunction));
expectWarning();
QVERIFY(!manager.tryStart(nullFunction));
}
}
QTEST_MAIN(tst_QThreadPool);
#include "tst_qthreadpool.moc"

View File

@ -372,7 +372,7 @@ public:
{ }
static inline void sleep(ulong s)
{ QThread::sleep(s); }
{ QThread::sleep(std::chrono::seconds{s}); }
void run() override
{
@ -404,7 +404,7 @@ public:
{ }
static inline void sleep(ulong s)
{ QThread::sleep(s); }
{ QThread::sleep(std::chrono::seconds{s}); }
void run() override
{