mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-05 16:55:25 +08:00
qt 6.6.0 clean
This commit is contained in:
@ -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)
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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`:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
{
|
||||
|
Reference in New Issue
Block a user