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,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qthreadonce Test:
#####################################################################
qt_internal_add_test(tst_qthreadonce
SOURCES
qthreadonce.cpp
tst_qthreadonce.cpp
LIBRARIES
Qt::TestPrivate
)

View File

@ -0,0 +1,80 @@
// 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 "qplatformdefs.h"
#include "qthreadonce.h"
#include "qmutex.h"
Q_GLOBAL_STATIC(QRecursiveMutex, onceInitializationMutex)
enum QOnceExtra {
MustRunCode = 0x01,
MustUnlockMutex = 0x02
};
/*!
\internal
Initialize the Q_ONCE structure.
Q_ONCE consists of two variables:
- a static POD QOnceControl::ControlVariable (it's a QBasicAtomicInt)
- an automatic QOnceControl that controls the former
The POD is initialized to 0.
When QOnceControl's constructor starts, it'll lock the global
initialization mutex. It'll then check if it's the first to up
the control variable and will take note.
The QOnceControl's destructor will unlock the global
initialization mutex.
*/
QOnceControl::QOnceControl(QBasicAtomicInt *control)
{
d = 0;
gv = control;
// check if code has already run once
if (gv->loadAcquire() == 2) {
// uncontended case: it has already initialized
// no waiting
return;
}
// acquire the path
onceInitializationMutex()->lock();
extra = MustUnlockMutex;
if (gv->testAndSetAcquire(0, 1)) {
// path acquired, we're the first
extra |= MustRunCode;
}
}
QOnceControl::~QOnceControl()
{
if (mustRunCode())
// code wasn't run!
gv->testAndSetRelease(1, 0);
else
gv->testAndSetRelease(1, 2);
if (extra & MustUnlockMutex)
onceInitializationMutex()->unlock();
}
/*!
\internal
Returns true if the initialization code must be run.
Obviously, the initialization code must be run only once...
*/
bool QOnceControl::mustRunCode()
{
return extra & MustRunCode;
}
void QOnceControl::done()
{
extra &= ~MustRunCode;
}

View File

@ -0,0 +1,67 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTHREADONCE_H
#define QTHREADONCE_H
#include <QtCore/qglobal.h>
#include <QtCore/qatomic.h>
class QOnceControl
{
public:
QOnceControl(QBasicAtomicInt *);
~QOnceControl();
bool mustRunCode();
void done();
private:
QBasicAtomicInt *gv;
union {
qint32 extra;
void *d;
};
};
#define Q_ONCE_GV_NAME2(prefix, line) prefix ## line
#define Q_ONCE_GV_NAME(prefix, line) Q_ONCE_GV_NAME2(prefix, line)
#define Q_ONCE_GV Q_ONCE_GV_NAME(_q_once_, __LINE__)
#define Q_ONCE \
static QBasicAtomicInt Q_ONCE_GV = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (0){} else \
for (QOnceControl _control_(&Q_ONCE_GV); _control_.mustRunCode(); _control_.done())
template<typename T>
class QSingleton
{
// this is a POD-like class
struct Destructor
{
T *&pointer;
Destructor(T *&ptr) : pointer(ptr) {}
~Destructor() { delete pointer; }
};
public:
T *_q_value;
QBasicAtomicInt _q_guard;
inline T *value()
{
for (QOnceControl control(&_q_guard); control.mustRunCode(); control.done()) {
_q_value = new T();
static Destructor cleanup(_q_value);
}
return _q_value;
}
inline T& operator*() { return *value(); }
inline T* operator->() { return value(); }
inline operator T*() { return value(); }
};
#endif

View File

@ -0,0 +1,203 @@
// 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 <QSemaphore>
#include <qcoreapplication.h>
#include <qmutex.h>
#include <qthread.h>
#include <qwaitcondition.h>
#include "qthreadonce.h"
#include <QtTest/private/qemulationdetector_p.h>
class tst_QThreadOnce : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void sameThread();
void sameThread_data();
void multipleThreads();
void nesting();
void reentering();
#ifndef QT_NO_EXCEPTIONS
void exception();
#endif
};
void tst_QThreadOnce::initTestCase()
{
if (QTestPrivate::isRunningArmOnX86())
QSKIP("Flaky on QEMU, QTBUG-94737");
}
class SingletonObject: public QObject
{
Q_OBJECT
public:
static int runCount;
SingletonObject() { val.storeRelaxed(42); ++runCount; }
~SingletonObject() { }
QBasicAtomicInt val;
};
class IncrementThread: public QThread
{
public:
static QBasicAtomicInt runCount;
static QSingleton<SingletonObject> singleton;
QSemaphore &sem1, &sem2;
int &var;
IncrementThread(QSemaphore *psem1, QSemaphore *psem2, int *pvar, QObject *parent)
: QThread(parent), sem1(*psem1), sem2(*psem2), var(*pvar)
{ start(); }
~IncrementThread() { wait(); }
protected:
void run() override
{
sem2.release();
sem1.acquire(); // synchronize
Q_ONCE {
++var;
}
runCount.ref();
singleton->val.ref();
}
};
int SingletonObject::runCount = 0;
QBasicAtomicInt IncrementThread::runCount = Q_BASIC_ATOMIC_INITIALIZER(0);
QSingleton<SingletonObject> IncrementThread::singleton;
void tst_QThreadOnce::sameThread_data()
{
SingletonObject::runCount = 0;
QTest::addColumn<int>("expectedValue");
QTest::newRow("first") << 42;
QTest::newRow("second") << 43;
}
void tst_QThreadOnce::sameThread()
{
static int controlVariable = 0;
Q_ONCE {
QCOMPARE(controlVariable, 0);
++controlVariable;
}
QCOMPARE(controlVariable, 1);
static QSingleton<SingletonObject> s;
QTEST(int(s->val.loadRelaxed()), "expectedValue");
s->val.ref();
QCOMPARE(SingletonObject::runCount, 1);
}
void tst_QThreadOnce::multipleThreads()
{
#if defined(Q_OS_VXWORKS)
const int NumberOfThreads = 20;
#else
const int NumberOfThreads = 100;
#endif
int controlVariable = 0;
QSemaphore sem1, sem2(NumberOfThreads);
QObject *parent = new QObject;
for (int i = 0; i < NumberOfThreads; ++i)
new IncrementThread(&sem1, &sem2, &controlVariable, parent);
QCOMPARE(controlVariable, 0); // nothing must have set them yet
SingletonObject::runCount = 0;
IncrementThread::runCount.storeRelaxed(0);
// wait for all of them to be ready
sem2.acquire(NumberOfThreads);
// unleash the threads
sem1.release(NumberOfThreads);
// wait for all of them to terminate:
delete parent;
QCOMPARE(controlVariable, 1);
QCOMPARE(int(IncrementThread::runCount.loadRelaxed()), NumberOfThreads);
QCOMPARE(SingletonObject::runCount, 1);
}
void tst_QThreadOnce::nesting()
{
int variable = 0;
Q_ONCE {
Q_ONCE {
++variable;
}
}
QCOMPARE(variable, 1);
}
static void reentrant(int control, int &counter)
{
Q_ONCE {
if (counter)
reentrant(--control, counter);
++counter;
}
static QSingleton<SingletonObject> s;
s->val.ref();
}
void tst_QThreadOnce::reentering()
{
const int WantedRecursions = 5;
int count = 0;
SingletonObject::runCount = 0;
reentrant(WantedRecursions, count);
// reentrancy is undefined behavior:
QVERIFY(count == 1 || count == WantedRecursions);
QCOMPARE(SingletonObject::runCount, 1);
}
#if !defined(QT_NO_EXCEPTIONS)
static void exception_helper(int &val)
{
Q_ONCE {
if (val++ == 0) throw 0;
}
}
#endif
#ifndef QT_NO_EXCEPTIONS
void tst_QThreadOnce::exception()
{
int count = 0;
try {
exception_helper(count);
} catch (...) {
// nothing
}
QCOMPARE(count, 1);
try {
exception_helper(count);
} catch (...) {
QVERIFY2(false, "Exception shouldn't have been thrown...");
}
QCOMPARE(count, 2);
}
#endif
QTEST_MAIN(tst_QThreadOnce)
#include "tst_qthreadonce.moc"