summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-12-22 00:56:20 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-12-22 00:56:20 (GMT)
commit6db81533a21b08e9dffd7ef4431443732bda2f28 (patch)
treeaaec35a072f3062c8e2335a006ac6a251196f67a /tests
parentd37a3529ec883985b2967265f0797d749db74308 (diff)
parent435eeaac07e50db4938066e36cd1a778c4523493 (diff)
downloadQt-6db81533a21b08e9dffd7ef4431443732bda2f28.zip
Qt-6db81533a21b08e9dffd7ef4431443732bda2f28.tar.gz
Qt-6db81533a21b08e9dffd7ef4431443732bda2f28.tar.bz2
Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1: (33 commits) Add inter-process binary shader cache for MeeGo Track average wait times under our maximum spin time threshold Store and track spin times in nanosecond resolution Optimize adaptive spinning mutex code Improve QMutex contention performance on Linux Improve QMutex contention performance on Mac OS X Disable spinning under lock contention on single CPU machines Remove unnecessary testAndSetAcquire from QMutex::lockInternal() Move contender count maintenance to QMutexPrivate test contention when using 2 mutexes Ensure that every thread does contend in the contention tests Add baseline test data to measure test overhead Test contention performance for long (10ms) critical sections Add a benchmark for contended and uncontended QMutex performance Removed QMutexPrivate::self() declaration Add QElapsedTimer::nsecsElapsed() const Delay creation of the process manager Make the QRasterPaintEngineState copy constructor cheaper. Micro-optimization for QSpanData::setup() define FSCTL_SET_REPARSE_POINT in test header ...
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qcompleter/tst_qcompleter.cpp27
-rw-r--r--tests/auto/qdatastream/tst_qdatastream.cpp51
-rw-r--r--tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp7
-rw-r--r--tests/auto/qprogressbar/tst_qprogressbar.cpp7
-rw-r--r--tests/auto/qtextstream/tst_qtextstream.cpp37
-rw-r--r--tests/auto/qxmlstream/tst_qxmlstream.cpp82
-rw-r--r--tests/benchmarks/corelib/thread/qmutex/qmutex.pro2
-rw-r--r--tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp326
-rw-r--r--tests/shared/filesystem.h3
9 files changed, 510 insertions, 32 deletions
diff --git a/tests/auto/qcompleter/tst_qcompleter.cpp b/tests/auto/qcompleter/tst_qcompleter.cpp
index 650c328..62e64be 100644
--- a/tests/auto/qcompleter/tst_qcompleter.cpp
+++ b/tests/auto/qcompleter/tst_qcompleter.cpp
@@ -49,6 +49,7 @@
#include <QPointer>
#include "../../shared/util.h"
+#include "../../shared/filesystem.h"
//TESTED_CLASS=
//TESTED_FILES=
@@ -1455,24 +1456,16 @@ void tst_QCompleter::task247560_keyboardNavigation()
void tst_QCompleter::QTBUG_14292_filesystem()
{
- QDir tmpDir = QDir::temp();
+ FileSystem fs;
+ QDir tmpDir = QDir::currentPath();
+
qsrand(QTime::currentTime().msec());
QString d = "tst_QCompleter_" + QString::number(qrand());
- QVERIFY(tmpDir.mkdir(d));
-
-#if 0
- struct Cleanup {
- QString dir;
- ~Cleanup() {
- qDebug() << dir <<
- QFile::remove(dir); }
- } cleanup;
- cleanup.dir = tmpDir.absolutePath()+"/" +d;
-#endif
+ QVERIFY(fs.createDirectory(tmpDir.filePath(d)));
QVERIFY(tmpDir.cd(d));
- QVERIFY(tmpDir.mkdir("hello"));
- QVERIFY(tmpDir.mkdir("holla"));
+ QVERIFY(fs.createDirectory(tmpDir.filePath("hello")));
+ QVERIFY(fs.createDirectory(tmpDir.filePath("holla")));
QLineEdit edit;
QCompleter comp;
@@ -1500,12 +1493,12 @@ void tst_QCompleter::QTBUG_14292_filesystem()
QCOMPARE(comp.popup()->model()->rowCount(), 1);
QTest::keyClick(&edit, 'r');
QTRY_VERIFY(!comp.popup()->isVisible());
- QVERIFY(tmpDir.mkdir("hero"));
+ QVERIFY(fs.createDirectory(tmpDir.filePath("hero")));
QTRY_VERIFY(comp.popup()->isVisible());
QCOMPARE(comp.popup()->model()->rowCount(), 1);
QTest::keyClick(comp.popup(), Qt::Key_Escape);
QTRY_VERIFY(!comp.popup()->isVisible());
- QVERIFY(tmpDir.mkdir("nothingThere"));
+ QVERIFY(fs.createDirectory(tmpDir.filePath("nothingThere")));
//there is no reason creating a file should open a popup, it did in Qt 4.7.0
QTest::qWait(60);
QVERIFY(!comp.popup()->isVisible());
@@ -1522,7 +1515,7 @@ void tst_QCompleter::QTBUG_14292_filesystem()
QTest::qWaitForWindowShown(&w);
QTRY_VERIFY(!edit.hasFocus() && !comp.popup()->hasFocus());
- QVERIFY(tmpDir.mkdir("hemo"));
+ QVERIFY(fs.createDirectory(tmpDir.filePath("hemo")));
//there is no reason creating a file should open a popup, it did in Qt 4.7.0
QTest::qWait(60);
QVERIFY(!comp.popup()->isVisible());
diff --git a/tests/auto/qdatastream/tst_qdatastream.cpp b/tests/auto/qdatastream/tst_qdatastream.cpp
index c03bc71..898fb84 100644
--- a/tests/auto/qdatastream/tst_qdatastream.cpp
+++ b/tests/auto/qdatastream/tst_qdatastream.cpp
@@ -168,6 +168,8 @@ private slots:
void stream_atEnd_data();
void stream_atEnd();
+ void stream_writeError();
+
void stream_QByteArray2();
void setVersion_data();
@@ -2345,6 +2347,55 @@ void tst_QDataStream::stream_atEnd()
}
}
+class FakeBuffer : public QBuffer
+{
+protected:
+ qint64 writeData(const char *c, qint64 i) { return m_lock ? 0 : QBuffer::writeData(c, i); }
+public:
+ FakeBuffer(bool locked = false) : m_lock(locked) {}
+ void setLocked(bool locked) { m_lock = locked; }
+private:
+ bool m_lock;
+};
+
+#define TEST_WRITE_ERROR(op) \
+ { \
+ FakeBuffer fb(false); \
+ QVERIFY(fb.open(QBuffer::ReadWrite)); \
+ QDataStream fs(&fb); \
+ fs.writeRawData("hello", 5); \
+ /* first write some initial content */ \
+ QCOMPARE(fs.status(), QDataStream::Ok); \
+ QCOMPARE(fb.data(), QByteArray("hello")); \
+ /* then test that writing can cause an error */ \
+ fb.setLocked(true); \
+ fs op; \
+ QCOMPARE(fs.status(), QDataStream::WriteFailed); \
+ QCOMPARE(fb.data(), QByteArray("hello")); \
+ /* finally test that writing after an error doesn't change the stream any more */ \
+ fb.setLocked(false); \
+ fs op; \
+ QCOMPARE(fs.status(), QDataStream::WriteFailed); \
+ QCOMPARE(fb.data(), QByteArray("hello")); \
+ }
+
+void tst_QDataStream::stream_writeError()
+{
+ TEST_WRITE_ERROR(<< true)
+ TEST_WRITE_ERROR(<< (qint8)1)
+ TEST_WRITE_ERROR(<< (quint8)1)
+ TEST_WRITE_ERROR(<< (qint16)1)
+ TEST_WRITE_ERROR(<< (quint16)1)
+ TEST_WRITE_ERROR(<< (qint32)1)
+ TEST_WRITE_ERROR(<< (quint32)1)
+ TEST_WRITE_ERROR(<< (qint64)1)
+ TEST_WRITE_ERROR(<< (quint64)1)
+ TEST_WRITE_ERROR(<< "hello")
+ TEST_WRITE_ERROR(<< (float)1.0)
+ TEST_WRITE_ERROR(<< (double)1.0)
+ TEST_WRITE_ERROR(.writeRawData("test", 4))
+}
+
void tst_QDataStream::stream_QByteArray2()
{
QByteArray ba;
diff --git a/tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp b/tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp
index 87df57d..bc61f52 100644
--- a/tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp
+++ b/tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp
@@ -122,11 +122,13 @@ void tst_QElapsedTimer::basics()
quint64 value1 = t1.msecsSinceReference();
qDebug() << value1 << t1;
+ qint64 nsecs = t1.nsecsElapsed();
qint64 elapsed = t1.restart();
QVERIFY(elapsed < minResolution);
+ QVERIFY(nsecs / 1000000 < minResolution);
quint64 value2 = t1.msecsSinceReference();
- qDebug() << value2 << t1 << elapsed;
+ qDebug() << value2 << t1 << elapsed << nsecs;
// in theory, elapsed == value2 - value1
// However, since QElapsedTimer keeps internally the full resolution,
@@ -150,7 +152,10 @@ void tst_QElapsedTimer::elapsed()
// don't check: t1.secsTo(t2)
// QVERIFY(t1 - t2 < 0);
+ QVERIFY(t1.nsecsElapsed() > 0);
QVERIFY(t1.elapsed() > 0);
+ // the number of elapsed nanoseconds and milliseconds should match
+ QVERIFY(t1.nsecsElapsed() - t1.elapsed() * 1000000 < 1000000);
QVERIFY(t1.hasExpired(minResolution));
QVERIFY(!t1.hasExpired(8*minResolution));
QVERIFY(!t2.hasExpired(minResolution));
diff --git a/tests/auto/qprogressbar/tst_qprogressbar.cpp b/tests/auto/qprogressbar/tst_qprogressbar.cpp
index 7d94e3c..e042fb8 100644
--- a/tests/auto/qprogressbar/tst_qprogressbar.cpp
+++ b/tests/auto/qprogressbar/tst_qprogressbar.cpp
@@ -179,10 +179,15 @@ void tst_QProgressBar::format()
bar.repainted = false;
bar.setFormat("%v of %m (%p%)");
qApp->processEvents();
+
#ifndef Q_WS_MAC
- // The Mac scroll bar is animated, which means we get paint events all the time.
+ // Animated scroll bars get paint events all the time
+#ifdef Q_OS_WIN
+ if (QSysInfo::WindowsVersion < QSysInfo::WV_VISTA)
+#endif
QVERIFY(!bar.repainted);
#endif
+
QCOMPARE(bar.text(), QString("1 of 10 (10%)"));
bar.setRange(5, 5);
bar.setValue(5);
diff --git a/tests/auto/qtextstream/tst_qtextstream.cpp b/tests/auto/qtextstream/tst_qtextstream.cpp
index 4c78ef0..005f686 100644
--- a/tests/auto/qtextstream/tst_qtextstream.cpp
+++ b/tests/auto/qtextstream/tst_qtextstream.cpp
@@ -228,6 +228,7 @@ private slots:
void status_real_read();
void status_integer_read();
void status_word_read();
+ void status_write_error();
// use case tests
void useCase1();
@@ -4176,6 +4177,42 @@ void tst_QTextStream::status_word_read()
QCOMPARE(s.status(), QTextStream::ReadPastEnd);
}
+class FakeBuffer : public QBuffer
+{
+protected:
+ qint64 writeData(const char *c, qint64 i) { return m_lock ? 0 : QBuffer::writeData(c, i); }
+public:
+ FakeBuffer(bool locked = false) : m_lock(locked) {}
+ void setLocked(bool locked) { m_lock = locked; }
+private:
+ bool m_lock;
+};
+
+void tst_QTextStream::status_write_error()
+{
+ FakeBuffer fb(false);
+ QVERIFY(fb.open(QBuffer::ReadWrite));
+ QTextStream fs(&fb);
+ fs.setCodec(QTextCodec::codecForName("latin1"));
+ /* first write some initial content */
+ fs << "hello";
+ fs.flush();
+ QCOMPARE(fs.status(), QTextStream::Ok);
+ QCOMPARE(fb.data(), QByteArray("hello"));
+ /* then test that writing can cause an error */
+ fb.setLocked(true);
+ fs << "error";
+ fs.flush();
+ QCOMPARE(fs.status(), QTextStream::WriteFailed);
+ QCOMPARE(fb.data(), QByteArray("hello"));
+ /* finally test that writing after an error doesn't change the stream any more */
+ fb.setLocked(false);
+ fs << "can't do that";
+ fs.flush();
+ QCOMPARE(fs.status(), QTextStream::WriteFailed);
+ QCOMPARE(fb.data(), QByteArray("hello"));
+}
+
void tst_QTextStream::task180679_alignAccountingStyle()
{
{
diff --git a/tests/auto/qxmlstream/tst_qxmlstream.cpp b/tests/auto/qxmlstream/tst_qxmlstream.cpp
index 19e4b90..9e4f3ec 100644
--- a/tests/auto/qxmlstream/tst_qxmlstream.cpp
+++ b/tests/auto/qxmlstream/tst_qxmlstream.cpp
@@ -574,6 +574,7 @@ private slots:
void checkCommentIndentation() const;
void checkCommentIndentation_data() const;
void qtbug9196_crash() const;
+ void hasError() const;
private:
static QByteArray readFile(const QString &filename);
@@ -1560,5 +1561,86 @@ void tst_QXmlStream::qtbug9196_crash() const
}
}
+class FakeBuffer : public QBuffer
+{
+protected:
+ qint64 writeData(const char *c, qint64 i)
+ {
+ qint64 ai = qMin(m_capacity, i);
+ m_capacity -= ai;
+ return ai ? QBuffer::writeData(c, ai) : 0;
+ }
+public:
+ void setCapacity(int capacity) { m_capacity = capacity; }
+private:
+ qint64 m_capacity;
+};
+
+void tst_QXmlStream::hasError() const
+{
+ {
+ FakeBuffer fb;
+ QVERIFY(fb.open(QBuffer::ReadWrite));
+ fb.setCapacity(1000);
+ QXmlStreamWriter writer(&fb);
+ writer.writeStartDocument();
+ writer.writeEndDocument();
+ QVERIFY(!writer.hasError());
+ QCOMPARE(fb.data(), QByteArray("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"));
+ }
+
+ {
+ // Failure caused by write(QString)
+ FakeBuffer fb;
+ QVERIFY(fb.open(QBuffer::ReadWrite));
+ fb.setCapacity(strlen("<?xml version=\""));
+ QXmlStreamWriter writer(&fb);
+ writer.writeStartDocument();
+ QVERIFY(writer.hasError());
+ QCOMPARE(fb.data(), QByteArray("<?xml version=\""));
+ }
+
+ {
+ // Failure caused by write(char *)
+ FakeBuffer fb;
+ QVERIFY(fb.open(QBuffer::ReadWrite));
+ fb.setCapacity(strlen("<?xml version=\"1.0"));
+ QXmlStreamWriter writer(&fb);
+ writer.writeStartDocument();
+ QVERIFY(writer.hasError());
+ QCOMPARE(fb.data(), QByteArray("<?xml version=\"1.0"));
+ }
+
+ {
+ // Failure caused by write(QStringRef)
+ FakeBuffer fb;
+ QVERIFY(fb.open(QBuffer::ReadWrite));
+ fb.setCapacity(strlen("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test xmlns:"));
+ QXmlStreamWriter writer(&fb);
+ writer.writeStartDocument();
+ writer.writeStartElement("test");
+ writer.writeNamespace("http://foo.bar", "foo");
+ QVERIFY(writer.hasError());
+ QCOMPARE(fb.data(), QByteArray("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test xmlns:"));
+ }
+
+ {
+ // Refusal to write after 1st failure
+ FakeBuffer fb;
+ QVERIFY(fb.open(QBuffer::ReadWrite));
+ fb.setCapacity(10);
+ QXmlStreamWriter writer(&fb);
+ writer.writeStartDocument();
+ QVERIFY(writer.hasError());
+ QCOMPARE(fb.data(), QByteArray("<?xml vers"));
+ fb.setCapacity(1000);
+ writer.writeStartElement("test"); // literal & qstring
+ writer.writeNamespace("http://foo.bar", "foo"); // literal & qstringref
+ QVERIFY(writer.hasError());
+ QCOMPARE(fb.data(), QByteArray("<?xml vers"));
+ }
+
+}
+
#include "tst_qxmlstream.moc"
// vim: et:ts=4:sw=4:sts=4
diff --git a/tests/benchmarks/corelib/thread/qmutex/qmutex.pro b/tests/benchmarks/corelib/thread/qmutex/qmutex.pro
index eda2f11..8fda5fa 100644
--- a/tests/benchmarks/corelib/thread/qmutex/qmutex.pro
+++ b/tests/benchmarks/corelib/thread/qmutex/qmutex.pro
@@ -1,6 +1,6 @@
load(qttest_p4)
TEMPLATE = app
TARGET = tst_bench_qmutex
-
+QT -= gui
SOURCES += tst_qmutex.cpp
diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp
index fded508..b0c5702 100644
--- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp
+++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp
@@ -39,34 +39,93 @@
**
****************************************************************************/
-#include <qtest.h>
-#include <QtCore>
+#include <QtCore/QtCore>
+#include <QtTest/QtTest>
#include <math.h>
-//TESTED_FILES=
+#ifdef Q_OS_UNIX
+# include <pthread.h>
+# include <errno.h>
+typedef pthread_mutex_t NativeMutexType;
+void NativeMutexInitialize(NativeMutexType *mutex)
+{
+ pthread_mutex_init(mutex, NULL);
+}
+void NativeMutexDestroy(NativeMutexType *mutex)
+{
+ pthread_mutex_destroy(mutex);
+}
+void NativeMutexLock(NativeMutexType *mutex)
+{
+ pthread_mutex_lock(mutex);
+}
+void NativeMutexUnlock(NativeMutexType *mutex)
+{
+ pthread_mutex_unlock(mutex);
+}
+#elif defined(Q_OS_WIN)
+# define _WIN32_WINNT 0x0400
+# include <windows.h>
+typedef CRITICAL_SECTION NativeMutexType;
+void NativeMutexInitialize(NativeMutexType *mutex)
+{
+ InitializeCriticalSection(mutex);
+}
+void NativeMutexDestroy(NativeMutexType *mutex)
+{
+ DeleteCriticalSection(mutex);
+}
+void NativeMutexLock(NativeMutexType *mutex)
+{
+ EnterCriticalSection(mutex);
+}
+void NativeMutexUnlock(NativeMutexType *mutex)
+{
+ LeaveCriticalSection(mutex);
+}
+#endif
+//TESTED_FILES=
class tst_QMutex : public QObject
{
Q_OBJECT
+ int threadCount;
+
public:
- tst_QMutex();
- virtual ~tst_QMutex();
+ // barriers for the contended tests
+ static QSemaphore semaphore1, semaphore2, semaphore3, semaphore4;
+
+ tst_QMutex()
+ {
+ // at least 2 threads, even on single cpu/core machines
+ threadCount = qMax(2, QThread::idealThreadCount());
+ qDebug("thread count: %d", threadCount);
+ }
private slots:
void noThread_data();
void noThread();
-};
-tst_QMutex::tst_QMutex()
-{
-}
+ void uncontendedNative();
+ void uncontendedQMutex();
+ void uncontendedQMutexLocker();
-tst_QMutex::~tst_QMutex()
-{
-}
+ void contendedNative_data();
+ void contendedQMutex_data() { contendedNative_data(); }
+ void contendedQMutexLocker_data() { contendedNative_data(); }
+
+ void contendedNative();
+ void contendedQMutex();
+ void contendedQMutexLocker();
+};
+
+QSemaphore tst_QMutex::semaphore1;
+QSemaphore tst_QMutex::semaphore2;
+QSemaphore tst_QMutex::semaphore3;
+QSemaphore tst_QMutex::semaphore4;
void tst_QMutex::noThread_data()
{
@@ -127,5 +186,248 @@ void tst_QMutex::noThread()
QCOMPARE(int(count), N);
}
+void tst_QMutex::uncontendedNative()
+{
+ NativeMutexType mutex;
+ NativeMutexInitialize(&mutex);
+ QBENCHMARK {
+ NativeMutexLock(&mutex);
+ NativeMutexUnlock(&mutex);
+ }
+ NativeMutexDestroy(&mutex);
+}
+
+void tst_QMutex::uncontendedQMutex()
+{
+ QMutex mutex;
+ QBENCHMARK {
+ mutex.lock();
+ mutex.unlock();
+ }
+}
+
+void tst_QMutex::uncontendedQMutexLocker()
+{
+ QMutex mutex;
+ QBENCHMARK {
+ QMutexLocker locker(&mutex);
+ }
+}
+
+void tst_QMutex::contendedNative_data()
+{
+ QTest::addColumn<int>("iterations");
+ QTest::addColumn<int>("msleepDuration");
+ QTest::addColumn<bool>("use2mutexes");
+
+ QTest::newRow("baseline") << 0 << -1 << false;
+
+ QTest::newRow("no msleep, 1 mutex") << 1000 << -1 << false;
+ QTest::newRow("no msleep, 2 mutexes") << 1000 << -1 << true;
+ QTest::newRow("msleep(0), 1 mutex") << 1000 << 0 << false;
+ QTest::newRow("msleep(0), 2 mutexes") << 1000 << 0 << true;
+ QTest::newRow("msleep(1), 1 mutex") << 10 << 1 << false;
+ QTest::newRow("msleep(1), 2 mutexes") << 10 << 1 << true;
+ QTest::newRow("msleep(2), 1 mutex") << 10 << 2 << false;
+ QTest::newRow("msleep(2), 2 mutexes") << 10 << 2 << true;
+ QTest::newRow("msleep(10), 1 mutex") << 10 << 10 << false;
+ QTest::newRow("msleep(10), 2 mutexes") << 10 << 10 << true;
+}
+
+class NativeMutexThread : public QThread
+{
+ NativeMutexType *mutex1, *mutex2;
+ int iterations, msleepDuration;
+ bool use2mutexes;
+public:
+ bool done;
+ NativeMutexThread(NativeMutexType *mutex1, NativeMutexType *mutex2, int iterations, int msleepDuration, bool use2mutexes)
+ : mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
+ { }
+ void run() {
+ forever {
+ tst_QMutex::semaphore1.release();
+ tst_QMutex::semaphore2.acquire();
+ if (done)
+ break;
+ for (int i = 0; i < iterations; ++i) {
+ NativeMutexLock(mutex1);
+ if (use2mutexes)
+ NativeMutexLock(mutex2);
+ if (msleepDuration >= 0)
+ msleep(msleepDuration);
+ if (use2mutexes)
+ NativeMutexUnlock(mutex2);
+ NativeMutexUnlock(mutex1);
+
+ QThread::yieldCurrentThread();
+ }
+ tst_QMutex::semaphore3.release();
+ tst_QMutex::semaphore4.acquire();
+ }
+ }
+};
+
+void tst_QMutex::contendedNative()
+{
+ QFETCH(int, iterations);
+ QFETCH(int, msleepDuration);
+ QFETCH(bool, use2mutexes);
+
+ NativeMutexType mutex1, mutex2;
+ NativeMutexInitialize(&mutex1);
+ NativeMutexInitialize(&mutex2);
+
+ QVector<NativeMutexThread *> threads(threadCount);
+ for (int i = 0; i < threads.count(); ++i) {
+ threads[i] = new NativeMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
+ threads[i]->start();
+ }
+
+ QBENCHMARK {
+ semaphore1.acquire(threadCount);
+ semaphore2.release(threadCount);
+ semaphore3.acquire(threadCount);
+ semaphore4.release(threadCount);
+ }
+
+ for (int i = 0; i < threads.count(); ++i)
+ threads[i]->done = true;
+ semaphore1.acquire(threadCount);
+ semaphore2.release(threadCount);
+ for (int i = 0; i < threads.count(); ++i)
+ threads[i]->wait();
+ qDeleteAll(threads);
+
+ NativeMutexDestroy(&mutex1);
+ NativeMutexDestroy(&mutex2);
+}
+
+class QMutexThread : public QThread
+{
+ QMutex *mutex1, *mutex2;
+ int iterations, msleepDuration;
+ bool use2mutexes;
+public:
+ bool done;
+ QMutexThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes)
+ : mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
+ { }
+ void run() {
+ forever {
+ tst_QMutex::semaphore1.release();
+ tst_QMutex::semaphore2.acquire();
+ if (done)
+ break;
+ for (int i = 0; i < iterations; ++i) {
+ mutex1->lock();
+ if (use2mutexes)
+ mutex2->lock();
+ if (msleepDuration >= 0)
+ msleep(msleepDuration);
+ if (use2mutexes)
+ mutex2->unlock();
+ mutex1->unlock();
+
+ QThread::yieldCurrentThread();
+ }
+ tst_QMutex::semaphore3.release();
+ tst_QMutex::semaphore4.acquire();
+ }
+ }
+};
+
+void tst_QMutex::contendedQMutex()
+{
+ QFETCH(int, iterations);
+ QFETCH(int, msleepDuration);
+ QFETCH(bool, use2mutexes);
+
+ QMutex mutex1, mutex2;
+
+ QVector<QMutexThread *> threads(threadCount);
+ for (int i = 0; i < threads.count(); ++i) {
+ threads[i] = new QMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
+ threads[i]->start();
+ }
+
+ QBENCHMARK {
+ semaphore1.acquire(threadCount);
+ semaphore2.release(threadCount);
+ semaphore3.acquire(threadCount);
+ semaphore4.release(threadCount);
+ }
+
+ for (int i = 0; i < threads.count(); ++i)
+ threads[i]->done = true;
+ semaphore1.acquire(threadCount);
+ semaphore2.release(threadCount);
+ for (int i = 0; i < threads.count(); ++i)
+ threads[i]->wait();
+ qDeleteAll(threads);
+}
+
+class QMutexLockerThread : public QThread
+{
+ QMutex *mutex1, *mutex2;
+ int iterations, msleepDuration;
+ bool use2mutexes;
+public:
+ bool done;
+ QMutexLockerThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes)
+ : mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
+ { }
+ void run() {
+ forever {
+ tst_QMutex::semaphore1.release();
+ tst_QMutex::semaphore2.acquire();
+ if (done)
+ break;
+ for (int i = 0; i < iterations; ++i) {
+ {
+ QMutexLocker locker1(mutex1);
+ QMutexLocker locker2(use2mutexes ? mutex2 : 0);
+ if (msleepDuration >= 0)
+ msleep(msleepDuration);
+ }
+
+ QThread::yieldCurrentThread();
+ }
+ tst_QMutex::semaphore3.release();
+ tst_QMutex::semaphore4.acquire();
+ }
+ }
+};
+
+void tst_QMutex::contendedQMutexLocker()
+{
+ QFETCH(int, iterations);
+ QFETCH(int, msleepDuration);
+ QFETCH(bool, use2mutexes);
+
+ QMutex mutex1, mutex2;
+
+ QVector<QMutexLockerThread *> threads(threadCount);
+ for (int i = 0; i < threads.count(); ++i) {
+ threads[i] = new QMutexLockerThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
+ threads[i]->start();
+ }
+
+ QBENCHMARK {
+ semaphore1.acquire(threadCount);
+ semaphore2.release(threadCount);
+ semaphore3.acquire(threadCount);
+ semaphore4.release(threadCount);
+ }
+
+ for (int i = 0; i < threads.count(); ++i)
+ threads[i]->done = true;
+ semaphore1.acquire(threadCount);
+ semaphore2.release(threadCount);
+ for (int i = 0; i < threads.count(); ++i)
+ threads[i]->wait();
+ qDeleteAll(threads);
+}
+
QTEST_MAIN(tst_QMutex)
#include "tst_qmutex.moc"
diff --git a/tests/shared/filesystem.h b/tests/shared/filesystem.h
index 8274346..4775671 100644
--- a/tests/shared/filesystem.h
+++ b/tests/shared/filesystem.h
@@ -55,6 +55,9 @@
#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
#endif
#define REPARSE_MOUNTPOINT_HEADER_SIZE 8
+#ifndef FSCTL_SET_REPARSE_POINT
+#define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
+#endif
#endif
struct FileSystem