From f351340d328a896829779794e8810f0d913161fb Mon Sep 17 00:00:00 2001 From: mread Date: Tue, 8 Feb 2011 14:05:37 +0000 Subject: Starting a benchmark test for QWaitCondition This new test is added in anticipation of a native implementation of QWaitCondition for Symbian. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- .../thread/qwaitcondition/qwaitcondition.pro | 5 + .../thread/qwaitcondition/tst_qwaitcondition.cpp | 197 +++++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 tests/benchmarks/corelib/thread/qwaitcondition/qwaitcondition.pro create mode 100644 tests/benchmarks/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp diff --git a/tests/benchmarks/corelib/thread/qwaitcondition/qwaitcondition.pro b/tests/benchmarks/corelib/thread/qwaitcondition/qwaitcondition.pro new file mode 100644 index 0000000..bc7bd58 --- /dev/null +++ b/tests/benchmarks/corelib/thread/qwaitcondition/qwaitcondition.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_bench_qwaitcondition +QT -= gui +SOURCES += tst_qwaitcondition.cpp diff --git a/tests/benchmarks/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp b/tests/benchmarks/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp new file mode 100644 index 0000000..ae5b48e --- /dev/null +++ b/tests/benchmarks/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include + + +class tst_QWaitCondition : public QObject +{ + Q_OBJECT + +public: + tst_QWaitCondition() + { + } + +private slots: + void oscillate_data(); + void oscillate(); + + void thrash_data(); + void thrash(); + +public: + static QWaitCondition local, remote; +}; + +QWaitCondition tst_QWaitCondition::local; +QWaitCondition tst_QWaitCondition::remote; + +class OscillateThread : public QThread +{ +public: + bool m_done; + bool m_useMutex; + unsigned long m_timeout; + bool m_wakeOne; + int count; + + OscillateThread(bool useMutex, unsigned long timeout, bool wakeOne) + : m_done(false), m_useMutex(useMutex), m_timeout(timeout), m_wakeOne(wakeOne) + {} + void run() + { + QMutex mtx; + QReadWriteLock rwl; + count = 0; + + forever { + if (m_done) + break; + if (m_wakeOne) + tst_QWaitCondition::local.wakeOne(); + else + tst_QWaitCondition::local.wakeAll(); + if (m_useMutex) { + mtx.lock(); + tst_QWaitCondition::remote.wait(&mtx, m_timeout); + mtx.unlock(); + } else { + rwl.lockForWrite(); + tst_QWaitCondition::remote.wait(&rwl, m_timeout); + rwl.unlock(); + } + count++; + } + } +}; + +void tst_QWaitCondition::oscillate_data() +{ + QTest::addColumn("useMutex"); + QTest::addColumn("timeout"); + QTest::addColumn("wakeOne"); + + QTest::newRow("mutex, timeout, one") << true << 1000ul << true; + QTest::newRow("readWriteLock, timeout, one") << false << 1000ul << true; + QTest::newRow("mutex, timeout, all") << true << 1000ul << false; + QTest::newRow("readWriteLock, timeout, all") << false << 1000ul << false; + QTest::newRow("mutex, forever, one") << true << ULONG_MAX << true; + QTest::newRow("readWriteLock, forever, one") << false << ULONG_MAX << true; + QTest::newRow("mutex, forever, all") << true << ULONG_MAX << false; + QTest::newRow("readWriteLock, forever, all") << false << ULONG_MAX << false; +} + +void tst_QWaitCondition::oscillate() +{ + QMutex mtx; + QReadWriteLock rwl; + + QFETCH(bool, useMutex); + QFETCH(unsigned long, timeout); + QFETCH(bool, wakeOne); + + OscillateThread thrd(useMutex, timeout, wakeOne); + thrd.start(); + + QBENCHMARK { + if (useMutex) + mtx.lock(); + else + rwl.lockForWrite(); + if (wakeOne) + remote.wakeOne(); + else + remote.wakeAll(); + if (useMutex) { + local.wait(&mtx, timeout); + mtx.unlock(); + } else { + local.wait(&rwl, timeout); + rwl.unlock(); + } + } + + thrd.m_done = true; + remote.wakeAll(); + thrd.wait(); + + QCOMPARE(0, 0); +} + +void tst_QWaitCondition::thrash_data() +{ + oscillate_data(); +} + +void tst_QWaitCondition::thrash() +{ + QMutex mtx; + mtx.lock(); + + QFETCH(bool, useMutex); + QFETCH(unsigned long, timeout); + QFETCH(bool, wakeOne); + + OscillateThread thrd(useMutex, timeout, wakeOne); + thrd.start(); + local.wait(&mtx, 1000ul); + mtx.unlock(); + + QBENCHMARK { + if (wakeOne) + remote.wakeOne(); + else + remote.wakeAll(); + } + + thrd.m_done = true; + remote.wakeAll(); + thrd.wait(); + + QCOMPARE(0, 0); +} + +QTEST_MAIN(tst_QWaitCondition) +#include "tst_qwaitcondition.moc" -- cgit v0.12 From 834ad29849ebef99d7e5c516cde26d550abff7cd Mon Sep 17 00:00:00 2001 From: mread Date: Wed, 9 Feb 2011 08:18:36 +0000 Subject: Symbian native implementation of corelib/thread QThread, QWaitCondition and QMutex have new Symbian native implementations. These new implementations are split out into new _symbian files. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qmutex_p.h | 13 +- src/corelib/thread/qmutex_symbian.cpp | 104 +++++ src/corelib/thread/qthread_symbian.cpp | 545 ++++++++++++++++++++++++++ src/corelib/thread/qthread_unix.cpp | 145 +------ src/corelib/thread/qwaitcondition_symbian.cpp | 210 ++++++++++ src/corelib/thread/qwaitcondition_unix.cpp | 2 - src/corelib/thread/thread.pri | 30 +- 7 files changed, 891 insertions(+), 158 deletions(-) create mode 100644 src/corelib/thread/qmutex_symbian.cpp create mode 100644 src/corelib/thread/qthread_symbian.cpp create mode 100644 src/corelib/thread/qwaitcondition_symbian.cpp diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 1a31c87..789d1f0 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -62,6 +62,11 @@ # include #endif +#if defined(Q_OS_SYMBIAN) +# include +#undef QT_SYMBIAN_USE_RFASTLOCK +#endif + QT_BEGIN_NAMESPACE class QMutexPrivate : public QMutexData { @@ -81,12 +86,18 @@ public: #if defined(Q_OS_MAC) semaphore_t mach_semaphore; -#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_SYMBIAN) volatile bool wakeup; pthread_mutex_t mutex; pthread_cond_t cond; #elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE) HANDLE event; +#elif defined(Q_OS_SYMBIAN) +# ifdef QT_SYMBIAN_USE_RFASTLOCK + RFastLock lock; +# else + RSemaphore lock; +# endif #endif }; diff --git a/src/corelib/thread/qmutex_symbian.cpp b/src/corelib/thread/qmutex_symbian.cpp new file mode 100644 index 0000000..e7487cd --- /dev/null +++ b/src/corelib/thread/qmutex_symbian.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qmutex.h" +#include + +#ifndef QT_NO_THREAD +#include "qatomic.h" +#include "qelapsedtimer.h" +#include "qthread.h" +#include "qmutex_p.h" + +QT_BEGIN_NAMESPACE + + +QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) + : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) +{ +#ifdef QT_SYMBIAN_USE_RFASTLOCK + int r = lock.CreateLocal(); +#else + int r = lock.CreateLocal(0); +#endif + if (r != KErrNone) + qWarning("QMutex: failed to create lock, error %d", r); +} + +QMutexPrivate::~QMutexPrivate() +{ + lock.Close(); +} + +bool QMutexPrivate::wait(int timeout) +{ + if (contenders.fetchAndAddAcquire(1) == 0) { + // lock acquired without waiting + return true; + } + int r = KErrTimedOut; + if (timeout < 0) { + lock.Wait(); + r = KErrNone; + } else { + // Symbian lock waits are specified in microseconds. + // The wait is therefore chunked. + // KErrNone indicates success, KErrGeneral and KErrArgument are real fails, anything else is a timeout + do { + int waitTime = qMin(KMaxTInt / 1000, timeout); + timeout -= waitTime; + r = lock.Wait(waitTime * 1000); + } while (r != KErrNone && r != KErrGeneral && r != KErrArgument && timeout > 0); + } + bool returnValue = (r == KErrNone); + contenders.deref(); + return returnValue; +} + +void QMutexPrivate::wakeUp() +{ + lock.Signal(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_THREAD diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp new file mode 100644 index 0000000..4a7a204 --- /dev/null +++ b/src/corelib/thread/qthread_symbian.cpp @@ -0,0 +1,545 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qthread.h" + +#include "qplatformdefs.h" + +#include +#if !defined(QT_NO_GLIB) +# include "../kernel/qeventdispatcher_glib_p.h" +#endif + +#include + +#include "qthreadstorage.h" + +#include "qthread_p.h" + +#include "qdebug.h" + +#include +#include + +#ifdef Q_OS_BSD4 +#include +#endif +#ifdef Q_OS_VXWORKS +# if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6)) +# include +# include +# define QT_VXWORKS_HAS_CPUSET +# endif +#endif + +#ifdef Q_OS_HPUX +#include +#endif + +#if defined(Q_OS_MAC) +# ifdef qDebug +# define old_qDebug qDebug +# undef qDebug +# endif +#ifndef QT_NO_CORESERVICES +# include +#endif //QT_NO_CORESERVICES + +# ifdef old_qDebug +# undef qDebug +# define qDebug QT_NO_QDEBUG_MACRO +# undef old_qDebug +# endif +#endif + +#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE) +// from linux/sched.h +# define SCHED_IDLE 5 +#endif + +#if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0) +#define QT_HAS_THREAD_PRIORITY_SCHEDULING +#endif + + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_THREAD + +enum { ThreadPriorityResetFlag = 0x80000000 }; + +static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT; +static pthread_key_t current_thread_data_key; + +static void destroy_current_thread_data(void *p) +{ + // POSIX says the value in our key is set to zero before calling + // this destructor function, so we need to set it back to the + // right value... + pthread_setspecific(current_thread_data_key, p); + reinterpret_cast(p)->deref(); + // ... but we must reset it to zero before returning so we aren't + // called again (POSIX allows implementations to call destructor + // functions repeatedly until all values are zero) + pthread_setspecific(current_thread_data_key, 0); +} + +static void create_current_thread_data_key() +{ + pthread_key_create(¤t_thread_data_key, destroy_current_thread_data); +} + +static void destroy_current_thread_data_key() +{ + pthread_once(¤t_thread_data_once, create_current_thread_data_key); + pthread_key_delete(current_thread_data_key); +} +Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key) + + +// Utility functions for getting, setting and clearing thread specific data. +// In Symbian, TLS access is significantly faster than pthread_getspecific. +// However Symbian does not have the thread destruction cleanup functionality +// that pthread has, so pthread_setspecific is also used. +static QThreadData *get_thread_data() +{ + return reinterpret_cast(Dll::Tls()); +} + +static void set_thread_data(QThreadData *data) +{ + qt_symbian_throwIfError(Dll::SetTls(data)); +// pthread_once(¤t_thread_data_once, create_current_thread_data_key); +// pthread_setspecific(current_thread_data_key, data); +} + +static void clear_thread_data() +{ + Dll::FreeTls(); +// pthread_setspecific(current_thread_data_key, 0); +} + + +static void init_symbian_thread_handle(RThread &thread) +{ + thread = RThread(); + TThreadId threadId = thread.Id(); + thread.Open(threadId); + + // Make thread handle accessible process wide + RThread originalCloser = thread; + thread.Duplicate(thread, EOwnerProcess); + originalCloser.Close(); +} + +QThreadData *QThreadData::current() +{ + QThreadData *data = get_thread_data(); + if (!data) { + void *a; + if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, &a)) { + QThread *adopted = static_cast(a); + Q_ASSERT(adopted); + data = QThreadData::get2(adopted); + set_thread_data(data); + adopted->d_func()->running = true; + adopted->d_func()->finished = false; + static_cast(adopted)->init(); + } else { + data = new QThreadData; + QT_TRY { + set_thread_data(data); + data->thread = new QAdoptedThread(data); + } QT_CATCH(...) { + clear_thread_data(); + data->deref(); + data = 0; + QT_RETHROW; + } + data->deref(); + } + if (!QCoreApplicationPrivate::theMainThread) + QCoreApplicationPrivate::theMainThread = data->thread; + } + return data; +} + + +void QAdoptedThread::init() +{ + Q_D(QThread); + d->thread_id = RThread().Id(); // type operator to TUint + init_symbian_thread_handle(d->data->symbian_thread_handle); +} + +/* + QThreadPrivate +*/ + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +typedef void*(*QtThreadCallback)(void*); + +#if defined(Q_C_CALLBACKS) +} +#endif + +#endif // QT_NO_THREAD + +void QThreadPrivate::createEventDispatcher(QThreadData *data) +{ + data->eventDispatcher = new QEventDispatcherSymbian; + data->eventDispatcher->startingUp(); +} + +#ifndef QT_NO_THREAD + +void *QThreadPrivate::start(void *arg) +{ + QThread *thr = reinterpret_cast(arg); + QThreadData *data = QThreadData::get2(thr); + + // do we need to reset the thread priority? + if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) { + thr->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag)); + } + + // Because Symbian Open C does not provide a way to convert between + // RThread and pthread_t, we must delay initialization of the RThread + // handle when creating a thread, until we are running in the new thread. + // Here, we pick up the current thread and assign that to the handle. + init_symbian_thread_handle(data->symbian_thread_handle); + + // On symbian, threads other than the main thread are non critical by default + // This means a worker thread can crash without crashing the application - to + // use this feature, we would need to use RThread::Logon in the main thread + // to catch abnormal thread exit and emit the finished signal. + // For the sake of cross platform consistency, we set the thread as process critical + // - advanced users who want the symbian behaviour can change the critical + // attribute of the thread again once the app gains control in run() + User::SetCritical(User::EProcessCritical); + + set_thread_data(data); + + data->ref(); + data->quitNow = false; + + // ### TODO: allow the user to create a custom event dispatcher + createEventDispatcher(data); + + emit thr->started(); + thr->run(); + + QThreadPrivate::finish(arg); + + return 0; +} + +void QThreadPrivate::finish(void *arg, bool lockAnyway, bool closeNativeHandle) +{ + QThread *thr = reinterpret_cast(arg); + QThreadPrivate *d = thr->d_func(); + + QMutexLocker locker(lockAnyway ? &d->mutex : 0); + + d->isInFinish = true; + d->priority = QThread::InheritPriority; + bool terminated = d->terminated; + void *data = &d->data->tls; + locker.unlock(); + if (terminated) + emit thr->terminated(); + emit thr->finished(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QThreadStorageData::finish((void **)data); + locker.relock(); + d->terminated = false; + + QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; + if (eventDispatcher) { + d->data->eventDispatcher = 0; + locker.unlock(); + eventDispatcher->closingDown(); + delete eventDispatcher; + locker.relock(); + } + + d->thread_id = 0; + if (closeNativeHandle) + d->data->symbian_thread_handle.Close(); + d->running = false; + d->finished = true; + + d->isInFinish = false; + d->thread_done.wakeAll(); +} + + + + +/************************************************************************** + ** QThread + *************************************************************************/ + +Qt::HANDLE QThread::currentThreadId() +{ + return (Qt::HANDLE) (TUint) RThread().Id(); +} + +#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN) +// LSB doesn't define _SC_NPROCESSORS_ONLN. +# define _SC_NPROCESSORS_ONLN 84 +#endif + +int QThread::idealThreadCount() +{ + int cores = -1; + + // ### TODO - Get the number of cores from HAL? when multicore architectures (SMP) are supported + cores = 1; + + return cores; +} + +void QThread::yieldCurrentThread() +{ + sched_yield(); +} + +/* \internal + helper function to do thread sleeps +*/ +static void thread_sleep(unsigned long remaining, unsigned long scale) +{ + // maximum Symbian wait is 2^31 microseconds + unsigned long maxWait = KMaxTInt / scale; + do { + unsigned long waitTime = qMin(maxWait, remaining); + remaining -= waitTime; + User::AfterHighRes(waitTime * scale); + } while (remaining); +} + +void QThread::sleep(unsigned long secs) +{ + thread_sleep(secs, 1000000ul); +} + +void QThread::msleep(unsigned long msecs) +{ + thread_sleep(msecs, 1000ul); +} + +void QThread::usleep(unsigned long usecs) +{ + thread_sleep(usecs, 1ul); +} + +TThreadPriority calculateSymbianPriority(QThread::Priority priority) + { + // Both Qt & Symbian use limited enums; this matches the mapping previously done through conversion to Posix granularity + TThreadPriority symPriority; + switch (priority) + { + case QThread::IdlePriority: + symPriority = EPriorityMuchLess; + break; + case QThread::LowestPriority: + case QThread::LowPriority: + symPriority = EPriorityLess; + break; + case QThread::NormalPriority: + symPriority = EPriorityNormal; + break; + case QThread::HighPriority: + symPriority = EPriorityMore; + break; + case QThread::HighestPriority: + case QThread::TimeCriticalPriority: + default: + symPriority = EPriorityMuchMore; + break; + } + return symPriority; + } + +void QThread::start(Priority priority) +{ + Q_D(QThread); + QMutexLocker locker(&d->mutex); + + if (d->isInFinish) + d->thread_done.wait(locker.mutex()); + + if (d->running) + return; + + d->running = true; + d->finished = false; + d->terminated = false; + d->returnCode = 0; + d->exited = false; + + d->priority = priority; + + if (d->stackSize == 0) + // The default stack size on Symbian is very small, making even basic + // operations like file I/O fail, so we increase it by default. + d->stackSize = 0x14000; // Maximum stack size on Symbian. + + int code = 0; + if (d->data->symbian_thread_handle.Create(KNullDesC, (TThreadFunction) QThreadPrivate::start, d->stackSize, NULL, this) == KErrNone) + { + d->thread_id = d->data->symbian_thread_handle.Id(); + TThreadPriority symPriority = calculateSymbianPriority(priority); + d->data->symbian_thread_handle.SetPriority(symPriority); + d->data->symbian_thread_handle.Resume(); + } + else + code = ENOMEM; // probably the problem + + if (code) { + qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code))); + + d->running = false; + d->finished = false; + d->thread_id = 0; + d->data->symbian_thread_handle.Close(); + } +} + +void QThread::terminate() +{ + Q_D(QThread); + QMutexLocker locker(&d->mutex); + + if (!d->thread_id) + return; + + if (!d->running) + return; + if (!d->terminationEnabled) { + d->terminatePending = true; + return; + } + + d->terminated = true; + // "false, false" meaning: + // 1. lockAnyway = false. Don't lock the mutex because it's already locked + // (see above). + // 2. closeNativeSymbianHandle = false. We don't want to close the thread handle, + // because we need it here to terminate the thread. + QThreadPrivate::finish(this, false, false); + d->data->symbian_thread_handle.Terminate(KErrNone); + d->data->symbian_thread_handle.Close(); +} + +bool QThread::wait(unsigned long time) +{ + Q_D(QThread); + QMutexLocker locker(&d->mutex); + + if (d->thread_id == (TUint) RThread().Id()) { + qWarning("QThread::wait: Thread tried to wait on itself"); + return false; + } + + if (d->finished || !d->running) + return true; + + while (d->running) { + // Check if thread still exists. Needed because kernel will kill it without notification + // before global statics are deleted at application exit. + if (d->data->symbian_thread_handle.Handle() + && d->data->symbian_thread_handle.ExitType() != EExitPending) { + // Cannot call finish here as wait is typically called from another thread. + // It won't be necessary anyway, as we should never get here under normal operations; + // all QThreads are EProcessCritical and therefore cannot normally exit + // undetected (i.e. panic) as long as all thread control is via QThread. + return true; + } + if (!d->thread_done.wait(locker.mutex(), time)) + return false; + } + return true; +} + +void QThread::setTerminationEnabled(bool enabled) +{ + QThread *thr = currentThread(); + Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()", + "Current thread was not started with QThread."); + QThreadPrivate *d = thr->d_func(); + QMutexLocker locker(&d->mutex); + d->terminationEnabled = enabled; + if (enabled && d->terminatePending) { + d->terminated = true; + // "false" meaning: + // - lockAnyway = false. Don't lock the mutex because it's already locked + // (see above). + QThreadPrivate::finish(thr, false); + locker.unlock(); // don't leave the mutex locked! + User::Exit(0); // may be some other cleanup required? what if AS or cleanup stack? + } +} + +void QThread::setPriority(Priority priority) +{ + Q_D(QThread); + QMutexLocker locker(&d->mutex); + if (!d->running) { + qWarning("QThread::setPriority: Cannot set priority, thread is not running"); + return; + } + + d->priority = priority; + + // copied from start() with a few modifications: + TThreadPriority symPriority = calculateSymbianPriority(priority); + d->data->symbian_thread_handle.SetPriority(symPriority); +} + +#endif // QT_NO_THREAD + +QT_END_NAMESPACE + diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 0766447..2f13315 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -48,11 +48,7 @@ # include "../kernel/qeventdispatcher_glib_p.h" #endif -#ifdef Q_OS_SYMBIAN -#include -#else #include -#endif #include "qthreadstorage.h" @@ -152,51 +148,23 @@ Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key) // Utility functions for getting, setting and clearing thread specific data. -// In Symbian, TLS access is significantly faster than pthread_getspecific. -// However Symbian does not have the thread destruction cleanup functionality -// that pthread has, so pthread_setspecific is also used. static QThreadData *get_thread_data() { -#ifdef Q_OS_SYMBIAN - return reinterpret_cast(Dll::Tls()); -#else pthread_once(¤t_thread_data_once, create_current_thread_data_key); return reinterpret_cast(pthread_getspecific(current_thread_data_key)); -#endif } static void set_thread_data(QThreadData *data) { -#ifdef Q_OS_SYMBIAN - qt_symbian_throwIfError(Dll::SetTls(data)); -#endif pthread_once(¤t_thread_data_once, create_current_thread_data_key); pthread_setspecific(current_thread_data_key, data); } static void clear_thread_data() { -#ifdef Q_OS_SYMBIAN - Dll::FreeTls(); -#endif pthread_setspecific(current_thread_data_key, 0); } - -#ifdef Q_OS_SYMBIAN -static void init_symbian_thread_handle(RThread &thread) -{ - thread = RThread(); - TThreadId threadId = thread.Id(); - thread.Open(threadId); - - // Make thread handle accessible process wide - RThread originalCloser = thread; - thread.Duplicate(thread, EOwnerProcess); - originalCloser.Close(); -} -#endif - QThreadData *QThreadData::current() { QThreadData *data = get_thread_data(); @@ -234,9 +202,6 @@ void QAdoptedThread::init() { Q_D(QThread); d->thread_id = pthread_self(); -#ifdef Q_OS_SYMBIAN - init_symbian_thread_handle(d->data->symbian_thread_handle); -#endif } /* @@ -264,11 +229,7 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) data->eventDispatcher = new QEventDispatcherGlib; else #endif -#ifdef Q_OS_SYMBIAN - data->eventDispatcher = new QEventDispatcherSymbian; -#else - data->eventDispatcher = new QEventDispatcherUNIX; -#endif + data->eventDispatcher = new QEventDispatcherUNIX; data->eventDispatcher->startingUp(); } @@ -276,11 +237,8 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) void *QThreadPrivate::start(void *arg) { - // Symbian Open C supports neither thread cancellation nor cleanup_push. -#ifndef Q_OS_SYMBIAN pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_cleanup_push(QThreadPrivate::finish, arg); -#endif QThread *thr = reinterpret_cast(arg); QThreadData *data = QThreadData::get2(thr); @@ -290,23 +248,6 @@ void *QThreadPrivate::start(void *arg) thr->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag)); } -#ifdef Q_OS_SYMBIAN - // Because Symbian Open C does not provide a way to convert between - // RThread and pthread_t, we must delay initialization of the RThread - // handle when creating a thread, until we are running in the new thread. - // Here, we pick up the current thread and assign that to the handle. - init_symbian_thread_handle(data->symbian_thread_handle); - - // On symbian, threads other than the main thread are non critical by default - // This means a worker thread can crash without crashing the application - to - // use this feature, we would need to use RThread::Logon in the main thread - // to catch abnormal thread exit and emit the finished signal. - // For the sake of cross platform consistency, we set the thread as process critical - // - advanced users who want the symbian behaviour can change the critical - // attribute of the thread again once the app gains control in run() - User::SetCritical(User::EProcessCritical); -#endif - set_thread_data(data); data->ref(); @@ -316,35 +257,21 @@ void *QThreadPrivate::start(void *arg) createEventDispatcher(data); emit thr->started(); -#ifndef Q_OS_SYMBIAN pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_testcancel(); -#endif thr->run(); -#ifdef Q_OS_SYMBIAN - QThreadPrivate::finish(arg); -#else pthread_cleanup_pop(1); -#endif return 0; } -#ifdef Q_OS_SYMBIAN -void QThreadPrivate::finish(void *arg, bool lockAnyway, bool closeNativeHandle) -#else void QThreadPrivate::finish(void *arg) -#endif { QThread *thr = reinterpret_cast(arg); QThreadPrivate *d = thr->d_func(); -#ifdef Q_OS_SYMBIAN - QMutexLocker locker(lockAnyway ? &d->mutex : 0); -#else QMutexLocker locker(&d->mutex); -#endif d->isInFinish = true; d->priority = QThread::InheritPriority; @@ -369,10 +296,6 @@ void QThreadPrivate::finish(void *arg) } d->thread_id = 0; -#ifdef Q_OS_SYMBIAN - if (closeNativeHandle) - d->data->symbian_thread_handle.Close(); -#endif d->running = false; d->finished = true; @@ -430,9 +353,6 @@ int QThread::idealThreadCount() #elif defined(Q_OS_INTEGRITY) // as of aug 2008 Integrity only supports one single core CPU cores = 1; -#elif defined(Q_OS_SYMBIAN) - // ### TODO - Get the number of cores from HAL? when multicore architectures (SMP) are supported - cores = 1; #elif defined(Q_OS_VXWORKS) // VxWorks # if defined(QT_VXWORKS_HAS_CPUSET) @@ -573,8 +493,7 @@ void QThread::start(Priority priority) d->priority = priority; -#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING) && !defined(Q_OS_SYMBIAN) -// ### Need to implement thread sheduling and priorities for symbian os. Implementation removed for now +#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING) switch (priority) { case InheritPriority: { @@ -616,12 +535,6 @@ void QThread::start(Priority priority) } #endif // QT_HAS_THREAD_PRIORITY_SCHEDULING -#ifdef Q_OS_SYMBIAN - if (d->stackSize == 0) - // The default stack size on Symbian is very small, making even basic - // operations like file I/O fail, so we increase it by default. - d->stackSize = 0x14000; // Maximum stack size on Symbian. -#endif if (d->stackSize > 0) { #if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0) @@ -647,9 +560,7 @@ void QThread::start(Priority priority) if (code == EPERM) { // caller does not have permission to set the scheduling // parameters/policy -#ifndef Q_OS_SYMBIAN pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); -#endif code = pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this); } @@ -662,9 +573,6 @@ void QThread::start(Priority priority) d->running = false; d->finished = false; d->thread_id = 0; -#ifdef Q_OS_SYMBIAN - d->data->symbian_thread_handle.Close(); -#endif } } @@ -676,7 +584,6 @@ void QThread::terminate() if (!d->thread_id) return; -#ifndef Q_OS_SYMBIAN int code = pthread_cancel(d->thread_id); if (code) { qWarning("QThread::start: Thread termination error: %s", @@ -684,26 +591,6 @@ void QThread::terminate() } else { d->terminated = true; } -#else - if (!d->running) - return; - if (!d->terminationEnabled) { - d->terminatePending = true; - return; - } - - d->terminated = true; - // "false, false" meaning: - // 1. lockAnyway = false. Don't lock the mutex because it's already locked - // (see above). - // 2. closeNativeSymbianHandle = false. We don't want to close the thread handle, - // because we need it here to terminate the thread. - QThreadPrivate::finish(this, false, false); - d->data->symbian_thread_handle.Terminate(KErrNone); - d->data->symbian_thread_handle.Close(); -#endif - - } bool QThread::wait(unsigned long time) @@ -720,18 +607,6 @@ bool QThread::wait(unsigned long time) return true; while (d->running) { -#ifdef Q_OS_SYMBIAN - // Check if thread still exists. Needed because kernel will kill it without notification - // before global statics are deleted at application exit. - if (d->data->symbian_thread_handle.Handle() - && d->data->symbian_thread_handle.ExitType() != EExitPending) { - // Cannot call finish here as wait is typically called from another thread. - // It won't be necessary anyway, as we should never get here under normal operations; - // all QThreads are EProcessCritical and therefore cannot normally exit - // undetected (i.e. panic) as long as all thread control is via QThread. - return true; - } -#endif if (!d->thread_done.wait(locker.mutex(), time)) return false; } @@ -743,25 +618,11 @@ void QThread::setTerminationEnabled(bool enabled) QThread *thr = currentThread(); Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()", "Current thread was not started with QThread."); -#ifndef Q_OS_SYMBIAN + Q_UNUSED(thr) pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL); if (enabled) pthread_testcancel(); -#else - QThreadPrivate *d = thr->d_func(); - QMutexLocker locker(&d->mutex); - d->terminationEnabled = enabled; - if (enabled && d->terminatePending) { - d->terminated = true; - // "false" meaning: - // - lockAnyway = false. Don't lock the mutex because it's already locked - // (see above). - QThreadPrivate::finish(thr, false); - locker.unlock(); // don't leave the mutex locked! - pthread_exit(NULL); - } -#endif } void QThread::setPriority(Priority priority) diff --git a/src/corelib/thread/qwaitcondition_symbian.cpp b/src/corelib/thread/qwaitcondition_symbian.cpp new file mode 100644 index 0000000..83fa597 --- /dev/null +++ b/src/corelib/thread/qwaitcondition_symbian.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qwaitcondition.h" +#include "qmutex.h" +#include "qreadwritelock.h" +#include "qatomic.h" +#include "qstring.h" +#include "qelapsedtimer" +#include "qdebug.h" + +#include "qmutex_p.h" +#include "qreadwritelock_p.h" + +#include + +#ifndef QT_NO_THREAD + +QT_BEGIN_NAMESPACE + +static void report_error(int err, const char *where, const char *what) +{ + if (err != KErrNone) + qWarning("%s: %s failure: %d", where, what, err); +} + +class QWaitConditionPrivate { +public: + RMutex mutex; + RCondVar cond; + int waiters; + int wakeups; + int count; + + QWaitConditionPrivate() + : waiters(0), wakeups(0), count(0) + { + qt_symbian_throwIfError(mutex.CreateLocal()); + int err = cond.CreateLocal(); + if (err != KErrNone) { + mutex.Close(); + qt_symbian_throwIfError(err); + } + } + + ~QWaitConditionPrivate() + { + cond.Close(); + mutex.Close(); + } + + bool wait(unsigned long time) + { + TInt err = KErrNone; + if (time == ULONG_MAX) { + // untimed wait, loop because RCondVar::Wait may return before the condition is triggered + do { + // qDebug() << "about to wait forever"; + err = cond.Wait(mutex); + // qDebug() << "cond.Wait(mutex) returned"; + } while (err == KErrNone && wakeups == 0); + } else { + unsigned long maxWait = KMaxTInt / 1000; + QElapsedTimer waitTimer; + do { + waitTimer.start(); + unsigned long waitTime = qMin(maxWait, time); + // wait at least 1ms, as 0 means no wait + // qDebug() << "about to wait " << qMax(1ul, waitTime) * 1000; + err = cond.TimedWait(mutex, qMax(1ul, waitTime) * 1000); + // RCondVar::TimedWait may return before the condition is triggered, update the timeout with actual wait time + time -= qMin((unsigned long)waitTimer.elapsed(), waitTime); + // qDebug() << "err=" << err << " time=" << time << " wakeups=" << wakeups; + } while ((err == KErrNone && wakeups == 0) || (err == KErrTimedOut && time > 0)); + } + + Q_ASSERT_X(waiters > 0, "QWaitCondition::wait", "internal error (waiters)"); + --waiters; + if (err == KErrNone) { + Q_ASSERT_X(wakeups > 0, "QWaitCondition::wait", "internal error (wakeups)"); + --wakeups; + } + + mutex.Signal(); + + if (err && err != KErrTimedOut) + report_error(err, "QWaitCondition::wait()", "cv wait"); + return err == KErrNone; + } +}; + +QWaitCondition::QWaitCondition() +{ + d = new QWaitConditionPrivate; +} + +QWaitCondition::~QWaitCondition() +{ + delete d; +} + +void QWaitCondition::wakeOne() +{ + d->mutex.Wait(); + d->wakeups = qMin(d->wakeups + 1, d->waiters); + d->cond.Signal(); + d->count++; + d->mutex.Signal(); + if ((d->count%1000) == 999) + User::After(1); +} + +void QWaitCondition::wakeAll() +{ + d->mutex.Wait(); + d->wakeups = d->waiters; + d->cond.Broadcast(); + d->count++; + d->mutex.Signal(); + if ((d->count%1000) == 999) + User::After(1); +} + +bool QWaitCondition::wait(QMutex *mutex, unsigned long time) +{ + if (! mutex) + return false; + if (mutex->d->recursive) { + qWarning("QWaitCondition: cannot wait on recursive mutexes"); + return false; + } + + d->mutex.Wait(); + ++d->waiters; + mutex->unlock(); + + bool returnValue = d->wait(time); + + mutex->lock(); + + return returnValue; +} + +bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time) +{ + if (!readWriteLock || readWriteLock->d->accessCount == 0) + return false; + if (readWriteLock->d->accessCount < -1) { + qWarning("QWaitCondition: cannot wait on QReadWriteLocks with recursive lockForWrite()"); + return false; + } + + d->mutex.Wait(); + ++d->waiters; + + int previousAccessCount = readWriteLock->d->accessCount; + readWriteLock->unlock(); + + bool returnValue = d->wait(time); + + if (previousAccessCount < 0) + readWriteLock->lockForWrite(); + else + readWriteLock->lockForRead(); + + return returnValue; +} + +QT_END_NAMESPACE + +#endif // QT_NO_THREAD diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp index f06a158..d0f23b5 100644 --- a/src/corelib/thread/qwaitcondition_unix.cpp +++ b/src/corelib/thread/qwaitcondition_unix.cpp @@ -61,8 +61,6 @@ static void report_error(int code, const char *where, const char *what) qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code))); } - - class QWaitConditionPrivate { public: pthread_mutex_t mutex; diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri index 03f661d..787d709 100644 --- a/src/corelib/thread/thread.pri +++ b/src/corelib/thread/thread.pri @@ -4,11 +4,11 @@ HEADERS += thread/qmutex.h \ thread/qreadwritelock.h \ thread/qsemaphore.h \ - thread/qthread.h \ - thread/qthreadstorage.h \ - thread/qwaitcondition.h \ - thread/qatomic.h - + thread/qthread.h \ + thread/qthreadstorage.h \ + thread/qwaitcondition.h \ + thread/qatomic.h + # private headers HEADERS += thread/qmutex_p.h \ thread/qmutexpool_p.h \ @@ -19,15 +19,19 @@ HEADERS += thread/qmutex_p.h \ SOURCES += thread/qatomic.cpp \ thread/qmutex.cpp \ thread/qreadwritelock.cpp \ - thread/qmutexpool.cpp \ - thread/qsemaphore.cpp \ - thread/qthread.cpp \ - thread/qthreadstorage.cpp + thread/qmutexpool.cpp \ + thread/qsemaphore.cpp \ + thread/qthread.cpp \ + thread/qthreadstorage.cpp + +unix:!symbian:SOURCES += thread/qmutex_unix.cpp \ + thread/qthread_unix.cpp \ + thread/qwaitcondition_unix.cpp -unix:SOURCES += thread/qmutex_unix.cpp \ - thread/qthread_unix.cpp \ - thread/qwaitcondition_unix.cpp +symbian:SOURCES += thread/qmutex_symbian.cpp \ + thread/qthread_symbian.cpp \ + thread/qwaitcondition_symbian.cpp win32:SOURCES += thread/qmutex_win.cpp \ thread/qthread_win.cpp \ - thread/qwaitcondition_win.cpp + thread/qwaitcondition_win.cpp -- cgit v0.12 From a8f22772c120b1560ec28eea6695fc1cde47a328 Mon Sep 17 00:00:00 2001 From: mread Date: Mon, 14 Feb 2011 11:41:29 +0000 Subject: Native adopted thread lifetime monitoring Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_symbian.cpp | 105 ++++++++++----------------------- 1 file changed, 30 insertions(+), 75 deletions(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 4a7a204..d1e2eaa 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -59,46 +59,6 @@ #include #include -#ifdef Q_OS_BSD4 -#include -#endif -#ifdef Q_OS_VXWORKS -# if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6)) -# include -# include -# define QT_VXWORKS_HAS_CPUSET -# endif -#endif - -#ifdef Q_OS_HPUX -#include -#endif - -#if defined(Q_OS_MAC) -# ifdef qDebug -# define old_qDebug qDebug -# undef qDebug -# endif -#ifndef QT_NO_CORESERVICES -# include -#endif //QT_NO_CORESERVICES - -# ifdef old_qDebug -# undef qDebug -# define qDebug QT_NO_QDEBUG_MACRO -# undef old_qDebug -# endif -#endif - -#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE) -// from linux/sched.h -# define SCHED_IDLE 5 -#endif - -#if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0) -#define QT_HAS_THREAD_PRIORITY_SCHEDULING -#endif - QT_BEGIN_NAMESPACE @@ -106,39 +66,7 @@ QT_BEGIN_NAMESPACE enum { ThreadPriorityResetFlag = 0x80000000 }; -static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT; -static pthread_key_t current_thread_data_key; - -static void destroy_current_thread_data(void *p) -{ - // POSIX says the value in our key is set to zero before calling - // this destructor function, so we need to set it back to the - // right value... - pthread_setspecific(current_thread_data_key, p); - reinterpret_cast(p)->deref(); - // ... but we must reset it to zero before returning so we aren't - // called again (POSIX allows implementations to call destructor - // functions repeatedly until all values are zero) - pthread_setspecific(current_thread_data_key, 0); -} - -static void create_current_thread_data_key() -{ - pthread_key_create(¤t_thread_data_key, destroy_current_thread_data); -} - -static void destroy_current_thread_data_key() -{ - pthread_once(¤t_thread_data_once, create_current_thread_data_key); - pthread_key_delete(current_thread_data_key); -} -Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key) - - // Utility functions for getting, setting and clearing thread specific data. -// In Symbian, TLS access is significantly faster than pthread_getspecific. -// However Symbian does not have the thread destruction cleanup functionality -// that pthread has, so pthread_setspecific is also used. static QThreadData *get_thread_data() { return reinterpret_cast(Dll::Tls()); @@ -147,14 +75,11 @@ static QThreadData *get_thread_data() static void set_thread_data(QThreadData *data) { qt_symbian_throwIfError(Dll::SetTls(data)); -// pthread_once(¤t_thread_data_once, create_current_thread_data_key); -// pthread_setspecific(current_thread_data_key, data); } static void clear_thread_data() { Dll::FreeTls(); -// pthread_setspecific(current_thread_data_key, 0); } @@ -202,12 +127,42 @@ QThreadData *QThreadData::current() return data; } +class AdoptedThreadLifetimeMonitor : public QThread + { +public: + QMutex mutex; + QThreadData* adoptedData; + AdoptedThreadLifetimeMonitor(QThreadData* pData) + : adoptedData(pData) + { + mutex.lock(); + } + void run() + { + mutex.unlock(); + TRequestStatus wait = KRequestPending; + adoptedData->symbian_thread_handle.Logon(wait); + User::WaitForRequest(wait); + deleteLater(); + adoptedData->deref(); + } + }; + +void createAdoptedThreadLifetimeMonitor(QThreadData* data) + { + AdoptedThreadLifetimeMonitor* monitor = new AdoptedThreadLifetimeMonitor(data); + monitor->start(); + monitor->mutex.lock(); + monitor->mutex.unlock(); + data->deref(); + } void QAdoptedThread::init() { Q_D(QThread); d->thread_id = RThread().Id(); // type operator to TUint init_symbian_thread_handle(d->data->symbian_thread_handle); + createAdoptedThreadLifetimeMonitor(d->data); } /* -- cgit v0.12 From 5ab8d2ac9e07ee7cb9ad442a651b9bdb2acc1d87 Mon Sep 17 00:00:00 2001 From: mread Date: Mon, 14 Feb 2011 15:38:23 +0000 Subject: Fixed thread priority code The thread priority setting code was not dealing with the inherit case correctly. Now that it is, the wait condition delay hack has been removed. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_symbian.cpp | 19 ++++--------------- src/corelib/thread/qwaitcondition_symbian.cpp | 14 +------------- 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index d1e2eaa..b68453c 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -40,20 +40,11 @@ ****************************************************************************/ #include "qthread.h" - #include "qplatformdefs.h" - #include -#if !defined(QT_NO_GLIB) -# include "../kernel/qeventdispatcher_glib_p.h" -#endif - #include - #include "qthreadstorage.h" - #include "qthread_p.h" - #include "qdebug.h" #include @@ -281,11 +272,6 @@ Qt::HANDLE QThread::currentThreadId() return (Qt::HANDLE) (TUint) RThread().Id(); } -#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN) -// LSB doesn't define _SC_NPROCESSORS_ONLN. -# define _SC_NPROCESSORS_ONLN 84 -#endif - int QThread::idealThreadCount() { int cores = -1; @@ -351,9 +337,12 @@ TThreadPriority calculateSymbianPriority(QThread::Priority priority) break; case QThread::HighestPriority: case QThread::TimeCriticalPriority: - default: symPriority = EPriorityMuchMore; break; + case QThread::InheritPriority: + default: + symPriority = RThread().Priority(); + break; } return symPriority; } diff --git a/src/corelib/thread/qwaitcondition_symbian.cpp b/src/corelib/thread/qwaitcondition_symbian.cpp index 83fa597..114811e 100644 --- a/src/corelib/thread/qwaitcondition_symbian.cpp +++ b/src/corelib/thread/qwaitcondition_symbian.cpp @@ -46,7 +46,6 @@ #include "qatomic.h" #include "qstring.h" #include "qelapsedtimer" -#include "qdebug.h" #include "qmutex_p.h" #include "qreadwritelock_p.h" @@ -69,10 +68,9 @@ public: RCondVar cond; int waiters; int wakeups; - int count; QWaitConditionPrivate() - : waiters(0), wakeups(0), count(0) + : waiters(0), wakeups(0) { qt_symbian_throwIfError(mutex.CreateLocal()); int err = cond.CreateLocal(); @@ -94,9 +92,7 @@ public: if (time == ULONG_MAX) { // untimed wait, loop because RCondVar::Wait may return before the condition is triggered do { - // qDebug() << "about to wait forever"; err = cond.Wait(mutex); - // qDebug() << "cond.Wait(mutex) returned"; } while (err == KErrNone && wakeups == 0); } else { unsigned long maxWait = KMaxTInt / 1000; @@ -105,11 +101,9 @@ public: waitTimer.start(); unsigned long waitTime = qMin(maxWait, time); // wait at least 1ms, as 0 means no wait - // qDebug() << "about to wait " << qMax(1ul, waitTime) * 1000; err = cond.TimedWait(mutex, qMax(1ul, waitTime) * 1000); // RCondVar::TimedWait may return before the condition is triggered, update the timeout with actual wait time time -= qMin((unsigned long)waitTimer.elapsed(), waitTime); - // qDebug() << "err=" << err << " time=" << time << " wakeups=" << wakeups; } while ((err == KErrNone && wakeups == 0) || (err == KErrTimedOut && time > 0)); } @@ -143,10 +137,7 @@ void QWaitCondition::wakeOne() d->mutex.Wait(); d->wakeups = qMin(d->wakeups + 1, d->waiters); d->cond.Signal(); - d->count++; d->mutex.Signal(); - if ((d->count%1000) == 999) - User::After(1); } void QWaitCondition::wakeAll() @@ -154,10 +145,7 @@ void QWaitCondition::wakeAll() d->mutex.Wait(); d->wakeups = d->waiters; d->cond.Broadcast(); - d->count++; d->mutex.Signal(); - if ((d->count%1000) == 999) - User::After(1); } bool QWaitCondition::wait(QMutex *mutex, unsigned long time) -- cgit v0.12 From f3d22a9094dfcb9a8c7bd51b1872b05b7cf47139 Mon Sep 17 00:00:00 2001 From: mread Date: Tue, 15 Feb 2011 12:51:41 +0000 Subject: Removed unnecessary ref() on QThreadData Symbian's QThreadPrivate::start had a ref() on QThreadData which was causing it to never be deleted. This made sense in Unix, where there was always a deref in the thread cleanup. But this does not happen in Symbian. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_symbian.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index b68453c..25027dd 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -207,7 +207,6 @@ void *QThreadPrivate::start(void *arg) set_thread_data(data); - data->ref(); data->quitNow = false; // ### TODO: allow the user to create a custom event dispatcher -- cgit v0.12 From 68517f9f7e96fa7c654898732f0ca9bd63d10723 Mon Sep 17 00:00:00 2001 From: mread Date: Tue, 15 Feb 2011 15:26:42 +0000 Subject: Attempt to have one thread for all adopted thread monitoring Compiles, not tested yet. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_symbian.cpp | 150 ++++++++++++++++++++++++++++----- 1 file changed, 127 insertions(+), 23 deletions(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 25027dd..811d7da 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -118,34 +118,138 @@ QThreadData *QThreadData::current() return data; } -class AdoptedThreadLifetimeMonitor : public QThread +QMutex adoptedThreadMonitorMutex; +class QCAddAdoptedThread; +QCAddAdoptedThread* adoptedThreadAdder = 0; +QWaitCondition adoptedThreadAcceptWait; + +class QCAdoptedThreadMonitor : public CActive +{ +public: + QCAdoptedThreadMonitor(QThreadData *data) + : CActive(EPriorityStandard), adoptedData(data) { + CActiveScheduler::Add(this); + adoptedData->symbian_thread_handle.Logon(iStatus); + } + ~QCAdoptedThreadMonitor(); + void DoCancel() + { + adoptedData->symbian_thread_handle.LogonCancel(iStatus); + } + void RunL() + { + adoptedData->deref(); + delete this; + } +private: + QThreadData *adoptedData; +}; + +class QCAddAdoptedThread : public CActive +{ public: - QMutex mutex; - QThreadData* adoptedData; - AdoptedThreadLifetimeMonitor(QThreadData* pData) - : adoptedData(pData) - { - mutex.lock(); - } - void run() + QCAddAdoptedThread() + : CActive(EPriorityStandard), count(0), dataToAdd(0) + { + CActiveScheduler::Add(this); + start(); + } + ~QCAddAdoptedThread() + { + Cancel(); + } + void RunL() + { + if (iStatus.Int() != KErrNone) + return; + + // Create an active object to monitor the thread + new (ELeave) QCAdoptedThreadMonitor(dataToAdd); + count++; + dataToAdd = 0; + start(); + + adoptedThreadAcceptWait.wakeAll(); + } + void add(QThreadData* data) + { + dataToAdd = data; + TRequestStatus *stat = &iStatus; + User::RequestComplete(stat, KErrNone); + } + void start() + { + iStatus = KRequestPending; + SetActive(); + } + void DoCancel() + { + TRequestStatus *stat = &iStatus; + User::RequestComplete(stat, KErrCancel); + } + void adoptedTheadClosed() + { + QMutexLocker adoptedThreadMonitorMutexlock(&adoptedThreadMonitorMutex); + count--; + if (!count) { - mutex.unlock(); - TRequestStatus wait = KRequestPending; - adoptedData->symbian_thread_handle.Logon(wait); - User::WaitForRequest(wait); - deleteLater(); - adoptedData->deref(); + adoptedThreadAdder = 0; + CActiveScheduler::Stop(); } - }; + } +private: + int count; + QThreadData* dataToAdd; +}; + +QCAdoptedThreadMonitor::~QCAdoptedThreadMonitor() +{ + Cancel(); + adoptedThreadAdder->adoptedTheadClosed(); +} -void createAdoptedThreadLifetimeMonitor(QThreadData* data) +void monitorThreadFuncL() +{ + CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); + CleanupStack::PushL(scheduler); + CActiveScheduler::Install(scheduler); + + adoptedThreadAdder = new(ELeave) QCAddAdoptedThread(); + RThread::Rendezvous(KErrNone); + CActiveScheduler::Start(); + + CleanupStack::PopAndDestroy(scheduler); +} + +int monitorThreadFunc(void *) +{ + _LIT(KMonitorThreadName, "adoptedMonitorThread"); + RThread::RenameMe(KMonitorThreadName()); + CTrapCleanup* cleanup = CTrapCleanup::New(); + TRAPD(ret, monitorThreadFuncL()); + delete cleanup; + return ret; +} + +void monitorThreadLifetime(QThreadData* data) { - AdoptedThreadLifetimeMonitor* monitor = new AdoptedThreadLifetimeMonitor(data); - monitor->start(); - monitor->mutex.lock(); - monitor->mutex.unlock(); - data->deref(); + QMutexLocker adoptedThreadMonitorMutexlock(&adoptedThreadMonitorMutex); + if (!adoptedThreadAdder) + { + RThread monitorThread; + qt_symbian_throwIfError(monitorThread.Create(KNullDesC(), &monitorThreadFunc, 1024, &User::Allocator(), 0)); + TRequestStatus started; + monitorThread.Rendezvous(started); + monitorThread.Resume(); + User::WaitForRequest(started); + monitorThread.Close(); + } + adoptedThreadAdder->add(data); + QMutex waitLock; + waitLock.lock(); + adoptedThreadAcceptWait.wait(&waitLock); + waitLock.unlock(); } void QAdoptedThread::init() @@ -153,7 +257,7 @@ void QAdoptedThread::init() Q_D(QThread); d->thread_id = RThread().Id(); // type operator to TUint init_symbian_thread_handle(d->data->symbian_thread_handle); - createAdoptedThreadLifetimeMonitor(d->data); + monitorThreadLifetime(d->data); } /* -- cgit v0.12 From 586ba876034f46be1fe1c916f84f51392e60f3ef Mon Sep 17 00:00:00 2001 From: mread Date: Wed, 16 Feb 2011 14:17:36 +0000 Subject: Using a single monitor thread to monitor all adopted threads This reduces the number of extra threads required when native threads are adopted. In practice, the main thread is native and the montitor thread itself, so the monitor thread always ends up monitoring both. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_symbian.cpp | 162 ++++++++++++++++----------------- 1 file changed, 76 insertions(+), 86 deletions(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 811d7da..bb1a4a7 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -118,146 +118,136 @@ QThreadData *QThreadData::current() return data; } -QMutex adoptedThreadMonitorMutex; -class QCAddAdoptedThread; -QCAddAdoptedThread* adoptedThreadAdder = 0; -QWaitCondition adoptedThreadAcceptWait; class QCAdoptedThreadMonitor : public CActive { public: - QCAdoptedThreadMonitor(QThreadData *data) - : CActive(EPriorityStandard), adoptedData(data) + QCAdoptedThreadMonitor(QThread *thread) + : CActive(EPriorityStandard), data(QThreadData::get2(thread)) { CActiveScheduler::Add(this); - adoptedData->symbian_thread_handle.Logon(iStatus); + data->symbian_thread_handle.Logon(iStatus); + SetActive(); + } + ~QCAdoptedThreadMonitor() + { + Cancel(); } - ~QCAdoptedThreadMonitor(); void DoCancel() { - adoptedData->symbian_thread_handle.LogonCancel(iStatus); + data->symbian_thread_handle.LogonCancel(iStatus); } void RunL() { - adoptedData->deref(); + data->deref(); delete this; } private: - QThreadData *adoptedData; + QThreadData* data; }; class QCAddAdoptedThread : public CActive { public: QCAddAdoptedThread() - : CActive(EPriorityStandard), count(0), dataToAdd(0) + : CActive(EPriorityStandard) { CActiveScheduler::Add(this); + } + void ConstructL() + { + User::LeaveIfError(monitorThread.Open(RThread().Id())); start(); } ~QCAddAdoptedThread() { Cancel(); + monitorThread.Close(); } - void RunL() - { - if (iStatus.Int() != KErrNone) - return; - - // Create an active object to monitor the thread - new (ELeave) QCAdoptedThreadMonitor(dataToAdd); - count++; - dataToAdd = 0; - start(); - - adoptedThreadAcceptWait.wakeAll(); - } - void add(QThreadData* data) + void DoCancel() { - dataToAdd = data; TRequestStatus *stat = &iStatus; - User::RequestComplete(stat, KErrNone); + User::RequestComplete(stat, KErrCancel); } void start() { iStatus = KRequestPending; SetActive(); } - void DoCancel() + void RunL() { - TRequestStatus *stat = &iStatus; - User::RequestComplete(stat, KErrCancel); + if (iStatus.Int() != KErrNone) + return; + + QMutexLocker adoptedThreadMonitorMutexlock(&adoptedThreadMonitorMutex); + for (int i=threadsToAdd.size()-1; i>=0; i--) { + // Create an active object to monitor the thread + new (ELeave) QCAdoptedThreadMonitor(threadsToAdd[i]); + threadsToAdd.pop_back(); + } + start(); } - void adoptedTheadClosed() + static void add(QThread* thread) { QMutexLocker adoptedThreadMonitorMutexlock(&adoptedThreadMonitorMutex); - count--; - if (!count) - { - adoptedThreadAdder = 0; - CActiveScheduler::Stop(); + if (!adoptedThreadAdder) { + RThread monitorThread; + qt_symbian_throwIfError(monitorThread.Create(KNullDesC(), &monitorThreadFunc, 1024, &User::Allocator(), 0)); + TRequestStatus started; + monitorThread.Rendezvous(started); + monitorThread.Resume(); + User::WaitForRequest(started); + monitorThread.Close(); + } + adoptedThreadAdder->threadsToAdd.push_back(thread); + if (adoptedThreadAdder->IsActive()) { + TRequestStatus *stat = &adoptedThreadAdder->iStatus; + adoptedThreadAdder->monitorThread.RequestComplete(stat, KErrNone); } } -private: - int count; - QThreadData* dataToAdd; -}; - -QCAdoptedThreadMonitor::~QCAdoptedThreadMonitor() -{ - Cancel(); - adoptedThreadAdder->adoptedTheadClosed(); -} - -void monitorThreadFuncL() -{ - CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); - CleanupStack::PushL(scheduler); - CActiveScheduler::Install(scheduler); - - adoptedThreadAdder = new(ELeave) QCAddAdoptedThread(); - RThread::Rendezvous(KErrNone); - CActiveScheduler::Start(); + static void monitorThreadFuncL() + { + CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); + CleanupStack::PushL(scheduler); + CActiveScheduler::Install(scheduler); - CleanupStack::PopAndDestroy(scheduler); -} + adoptedThreadAdder = new(ELeave) QCAddAdoptedThread(); + CleanupStack::PushL(adoptedThreadAdder); + adoptedThreadAdder->ConstructL(); -int monitorThreadFunc(void *) -{ - _LIT(KMonitorThreadName, "adoptedMonitorThread"); - RThread::RenameMe(KMonitorThreadName()); - CTrapCleanup* cleanup = CTrapCleanup::New(); - TRAPD(ret, monitorThreadFuncL()); - delete cleanup; - return ret; -} + RThread::Rendezvous(KErrNone); + CActiveScheduler::Start(); -void monitorThreadLifetime(QThreadData* data) - { - QMutexLocker adoptedThreadMonitorMutexlock(&adoptedThreadMonitorMutex); - if (!adoptedThreadAdder) - { - RThread monitorThread; - qt_symbian_throwIfError(monitorThread.Create(KNullDesC(), &monitorThreadFunc, 1024, &User::Allocator(), 0)); - TRequestStatus started; - monitorThread.Rendezvous(started); - monitorThread.Resume(); - User::WaitForRequest(started); - monitorThread.Close(); + CleanupStack::PopAndDestroy(adoptedThreadAdder); + adoptedThreadAdder = 0; + CleanupStack::PopAndDestroy(scheduler); } - adoptedThreadAdder->add(data); - QMutex waitLock; - waitLock.lock(); - adoptedThreadAcceptWait.wait(&waitLock); - waitLock.unlock(); + static int monitorThreadFunc(void *) + { + _LIT(KMonitorThreadName, "adoptedMonitorThread"); + RThread::RenameMe(KMonitorThreadName()); + CTrapCleanup* cleanup = CTrapCleanup::New(); + TRAPD(ret, monitorThreadFuncL()); + delete cleanup; + return ret; } +private: + QVector threadsToAdd; + RThread monitorThread; + static QMutex adoptedThreadMonitorMutex; + static QCAddAdoptedThread* adoptedThreadAdder; +}; + +QMutex QCAddAdoptedThread::adoptedThreadMonitorMutex; +QCAddAdoptedThread* QCAddAdoptedThread::adoptedThreadAdder = 0; + void QAdoptedThread::init() { Q_D(QThread); d->thread_id = RThread().Id(); // type operator to TUint init_symbian_thread_handle(d->data->symbian_thread_handle); - monitorThreadLifetime(d->data); + QCAddAdoptedThread::add(this); } /* -- cgit v0.12 From 7b3d400cafe71cd9d290cc3f485ca67741cdcb33 Mon Sep 17 00:00:00 2001 From: mread Date: Wed, 16 Feb 2011 14:20:27 +0000 Subject: Extra debug info for failures in tst_qSemaphore tryAcquireWithTimeout() There was one non-repeatable failure of tryAcquireWithTimeout() on Symbian. Added extra debug info to try to find out why, if it ever happens again. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- tests/auto/qsemaphore/tst_qsemaphore.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/auto/qsemaphore/tst_qsemaphore.cpp b/tests/auto/qsemaphore/tst_qsemaphore.cpp index ba2175a..9fc6de1 100644 --- a/tests/auto/qsemaphore/tst_qsemaphore.cpp +++ b/tests/auto/qsemaphore/tst_qsemaphore.cpp @@ -244,6 +244,8 @@ void tst_QSemaphore::tryAcquireWithTimeout() QSemaphore semaphore; QTime time; +#define QVERIFYGE(a,b) {int e = a; if (a= " << #b << "=" << b; QVERIFY(e>=b);} +#define QVERIFYLE(a,b) {int e = a; if (b= timeout); + QVERIFYGE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 1); semaphore.release(); QCOMPARE(semaphore.available(), 2); time.start(); QVERIFY(!semaphore.tryAcquire(3, timeout)); - QVERIFY(time.elapsed() >= timeout); + QVERIFYGE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 2); semaphore.release(10); QCOMPARE(semaphore.available(), 12); time.start(); QVERIFY(!semaphore.tryAcquire(100, timeout)); - QVERIFY(time.elapsed() >= timeout); + QVERIFYGE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 12); semaphore.release(10); QCOMPARE(semaphore.available(), 22); time.start(); QVERIFY(!semaphore.tryAcquire(100, timeout)); - QVERIFY(time.elapsed() >= timeout); + QVERIFYGE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 22); time.start(); QVERIFY(semaphore.tryAcquire(1, timeout)); - QVERIFY(time.elapsed() <= timeout); + QVERIFYLE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 21); time.start(); QVERIFY(semaphore.tryAcquire(1, timeout)); - QVERIFY(time.elapsed() <= timeout); + QVERIFYLE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 20); time.start(); QVERIFY(semaphore.tryAcquire(10, timeout)); - QVERIFY(time.elapsed() <= timeout); + QVERIFYLE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 10); time.start(); QVERIFY(semaphore.tryAcquire(10, timeout)); - QVERIFY(time.elapsed() <= timeout); + QVERIFYLE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 0); // should not be able to acquire more time.start(); QVERIFY(!semaphore.tryAcquire(1, timeout)); - QVERIFY(time.elapsed() >= timeout); + QVERIFYGE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 0); time.start(); QVERIFY(!semaphore.tryAcquire(1, timeout)); - QVERIFY(time.elapsed() >= timeout); + QVERIFYGE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 0); time.start(); QVERIFY(!semaphore.tryAcquire(10, timeout)); - QVERIFY(time.elapsed() >= timeout); + QVERIFYGE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 0); time.start(); QVERIFY(!semaphore.tryAcquire(10, timeout)); - QVERIFY(time.elapsed() >= timeout); + QVERIFYGE(time.elapsed(), timeout); QCOMPARE(semaphore.available(), 0); } -- cgit v0.12 From 6f46333d84c6bbf538dfd06d96b726cd4c3438c1 Mon Sep 17 00:00:00 2001 From: mread Date: Wed, 16 Feb 2011 15:06:37 +0000 Subject: tst_qthread now using RThread for Symbian native thread testing It was using pthreads, but RThreads are the true native threads for Symbian, so switched to that. The test was passing with pthreads before this change, and is passing with RThreads after. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- tests/auto/qthread/tst_qthread.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp index 19c6c16..1629b91 100644 --- a/tests/auto/qthread/tst_qthread.cpp +++ b/tests/auto/qthread/tst_qthread.cpp @@ -662,7 +662,9 @@ void tst_QThread::usleep() typedef void (*FunctionPointer)(void *); void noop(void*) { } -#ifdef Q_OS_UNIX +#ifdef Q_OS_SYMBIAN +typedef RThread ThreadHandle; +#elif defined Q_OS_UNIX typedef pthread_t ThreadHandle; #elif defined Q_OS_WIN typedef HANDLE ThreadHandle; @@ -693,6 +695,7 @@ public: protected: static void *runUnix(void *data); static unsigned WIN_FIX_STDCALL runWin(void *data); + static int runSymbian(void *data); FunctionPointer functionPointer; void *data; @@ -702,7 +705,10 @@ void NativeThreadWrapper::start(FunctionPointer functionPointer, void *data) { this->functionPointer = functionPointer; this->data = data; -#ifdef Q_OS_UNIX +#ifdef Q_OS_SYMBIAN + qt_symbian_throwIfError(nativeThreadHandle.Create(KNullDesC(), NativeThreadWrapper::runSymbian, 1024, &User::Allocator(), this)); + nativeThreadHandle.Resume(); +#elif defined Q_OS_UNIX const int state = pthread_create(&nativeThreadHandle, 0, NativeThreadWrapper::runUnix, this); Q_UNUSED(state); #elif defined(Q_OS_WINCE) @@ -722,7 +728,12 @@ void NativeThreadWrapper::startAndWait(FunctionPointer functionPointer, void *da void NativeThreadWrapper::join() { -#ifdef Q_OS_UNIX +#ifdef Q_OS_SYMBIAN + TRequestStatus stat; + nativeThreadHandle.Logon(stat); + User::WaitForRequest(stat); + nativeThreadHandle.Close(); +#elif defined Q_OS_UNIX pthread_join(nativeThreadHandle, 0); #elif defined Q_OS_WIN WaitForSingleObject(nativeThreadHandle, INFINITE); @@ -762,6 +773,12 @@ unsigned WIN_FIX_STDCALL NativeThreadWrapper::runWin(void *data) return 0; } +int NativeThreadWrapper::runSymbian(void *data) +{ + runUnix(data); + return 0; +} + void NativeThreadWrapper::stop() { QMutexLocker lock(&mutex); -- cgit v0.12 From 3d84f558a80b0c224b6c36808fd8f1fee8ace752 Mon Sep 17 00:00:00 2001 From: mread Date: Wed, 16 Feb 2011 15:19:33 +0000 Subject: Trigger for using RFastLock __SYMBIAN_KERNEL_HYBRID_HEAP__ is not directly related to RFastLock's timed wait functions, but it was added at about the right time so is effective. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qmutex_p.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 789d1f0..c213c80 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -64,7 +64,11 @@ #if defined(Q_OS_SYMBIAN) # include -#undef QT_SYMBIAN_USE_RFASTLOCK +# ifdef __SYMBIAN_KERNEL_HYBRID_HEAP__ +# define QT_SYMBIAN_USE_RFASTLOCK +# else +# undef QT_SYMBIAN_USE_RFASTLOCK +# endif #endif QT_BEGIN_NAMESPACE -- cgit v0.12 From a84dcc30b096915dc71d8c9696696731dee45c48 Mon Sep 17 00:00:00 2001 From: mread Date: Thu, 17 Feb 2011 11:05:36 +0000 Subject: QMutex symbian review changes Improved documentation Added a trywait(0) test and fixed the bug it found Symbian implementation throws on construction fail Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qmutex_p.h | 3 ++ src/corelib/thread/qmutex_symbian.cpp | 4 +- tests/auto/qmutex/tst_qmutex.cpp | 69 +++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index c213c80..2588228 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -98,8 +98,11 @@ public: HANDLE event; #elif defined(Q_OS_SYMBIAN) # ifdef QT_SYMBIAN_USE_RFASTLOCK + // RFastLock is a fast semaphone which only calls into the kernel side if there is contention RFastLock lock; # else + // RSemaphore is used on Symbian OS versions that do not have a timed RFastLock wait. + // There is no timed wait on RMutex itself, so RSemaphore has to be used instead. RSemaphore lock; # endif #endif diff --git a/src/corelib/thread/qmutex_symbian.cpp b/src/corelib/thread/qmutex_symbian.cpp index e7487cd..09c59af 100644 --- a/src/corelib/thread/qmutex_symbian.cpp +++ b/src/corelib/thread/qmutex_symbian.cpp @@ -62,6 +62,7 @@ QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) #endif if (r != KErrNone) qWarning("QMutex: failed to create lock, error %d", r); + qt_symbian_throwIfError(r); } QMutexPrivate::~QMutexPrivate() @@ -86,7 +87,8 @@ bool QMutexPrivate::wait(int timeout) do { int waitTime = qMin(KMaxTInt / 1000, timeout); timeout -= waitTime; - r = lock.Wait(waitTime * 1000); + // Symbian undocumented feature - 0us means no timeout! Use a minimum of 1 + r = lock.Wait(qMax(1, waitTime * 1000)); } while (r != KErrNone && r != KErrGeneral && r != KErrArgument && timeout > 0); } bool returnValue = (r == KErrNone); diff --git a/tests/auto/qmutex/tst_qmutex.cpp b/tests/auto/qmutex/tst_qmutex.cpp index ea983cb..a8c4b37 100644 --- a/tests/auto/qmutex/tst_qmutex.cpp +++ b/tests/auto/qmutex/tst_qmutex.cpp @@ -129,27 +129,57 @@ void tst_QMutex::tryLock() testsTurn.release(); threadsTurn.acquire(); + QVERIFY(!normalMutex.tryLock(0)); + testsTurn.release(); + + threadsTurn.acquire(); + timer.start(); + QVERIFY(normalMutex.tryLock(0)); + QVERIFY(timer.elapsed() < 1000); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + QVERIFY(!normalMutex.tryLock(0)); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + normalMutex.unlock(); + testsTurn.release(); + + threadsTurn.acquire(); } }; Thread thread; thread.start(); + // thread can't acquire lock + testsTurn.acquire(); + normalMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + threadsTurn.release(); + + // thread can acquire lock + testsTurn.acquire(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + normalMutex.unlock(); + threadsTurn.release(); + + // thread can't acquire lock, timeout = 1000 testsTurn.acquire(); normalMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); threadsTurn.release(); + // thread can acquire lock, timeout = 1000 testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); threadsTurn.release(); + // thread can't acquire lock, timeout = 0 testsTurn.acquire(); normalMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); threadsTurn.release(); + // thread can acquire lock, timeout = 0 testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); @@ -190,6 +220,7 @@ void tst_QMutex::tryLock() timer.start(); QVERIFY(!recursiveMutex.tryLock(1000)); QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!recursiveMutex.tryLock(0)); testsTurn.release(); threadsTurn.acquire(); @@ -206,12 +237,47 @@ void tst_QMutex::tryLock() testsTurn.release(); threadsTurn.acquire(); + QVERIFY(!recursiveMutex.tryLock(0)); + QVERIFY(!recursiveMutex.tryLock(0)); + testsTurn.release(); + + threadsTurn.acquire(); + timer.start(); + QVERIFY(recursiveMutex.tryLock(0)); + QVERIFY(timer.elapsed() < 1000); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + QVERIFY(recursiveMutex.tryLock(0)); + QVERIFY(lockCount.testAndSetRelaxed(1, 2)); + QVERIFY(lockCount.testAndSetRelaxed(2, 1)); + recursiveMutex.unlock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + recursiveMutex.unlock(); + testsTurn.release(); + + threadsTurn.acquire(); } }; Thread thread; thread.start(); + // thread can't acquire lock + testsTurn.acquire(); + recursiveMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(0, 1)); + recursiveMutex.lock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 2)); + threadsTurn.release(); + + // thread can acquire lock + testsTurn.acquire(); + QVERIFY(lockCount.testAndSetRelaxed(2, 1)); + recursiveMutex.unlock(); + QVERIFY(lockCount.testAndSetRelaxed(1, 0)); + recursiveMutex.unlock(); + threadsTurn.release(); + + // thread can't acquire lock, timeout = 1000 testsTurn.acquire(); recursiveMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); @@ -219,6 +285,7 @@ void tst_QMutex::tryLock() QVERIFY(lockCount.testAndSetRelaxed(1, 2)); threadsTurn.release(); + // thread can acquire lock, timeout = 1000 testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); @@ -226,6 +293,7 @@ void tst_QMutex::tryLock() recursiveMutex.unlock(); threadsTurn.release(); + // thread can't acquire lock, timeout = 0 testsTurn.acquire(); recursiveMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); @@ -233,6 +301,7 @@ void tst_QMutex::tryLock() QVERIFY(lockCount.testAndSetRelaxed(1, 2)); threadsTurn.release(); + // thread can acquire lock, timeout = 0 testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); -- cgit v0.12 From 04510ff7b065b27f2a80f2cbf42cb097c98923b0 Mon Sep 17 00:00:00 2001 From: mread Date: Thu, 17 Feb 2011 11:43:54 +0000 Subject: Improving init_symbian_thread_handle From review comments on QThread_Symbian.cpp. init_symbian_thread_handle now opens the thread with process wide ownership directly, rather than going through an intermediate Duplicate. Retested QTBUG-13612 test case, which originally caused that function to be written. tst_qthread passes. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_symbian.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index bb1a4a7..4bbf5e3 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -78,12 +78,7 @@ static void init_symbian_thread_handle(RThread &thread) { thread = RThread(); TThreadId threadId = thread.Id(); - thread.Open(threadId); - - // Make thread handle accessible process wide - RThread originalCloser = thread; - thread.Duplicate(thread, EOwnerProcess); - originalCloser.Close(); + qt_symbian_throwIfError(thread.Open(threadId, EOwnerProcess)); } QThreadData *QThreadData::current() -- cgit v0.12 From c5a462519a8bce0faa31ce41414022749e3ad2f5 Mon Sep 17 00:00:00 2001 From: mread Date: Thu, 17 Feb 2011 13:07:51 +0000 Subject: Symbian adopted thread monitor review fixes The adopted thread monitor could cause a stray event panic if multiple threads where added quickly. A new autotest was written to force the fault (successfully). A fix was then added. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_symbian.cpp | 8 +++---- tests/auto/qthread/tst_qthread.cpp | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 4bbf5e3..096cd6d 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -161,13 +161,13 @@ public: } void DoCancel() { - TRequestStatus *stat = &iStatus; User::RequestComplete(stat, KErrCancel); } void start() { iStatus = KRequestPending; SetActive(); + stat = &iStatus; } void RunL() { @@ -195,9 +195,8 @@ public: monitorThread.Close(); } adoptedThreadAdder->threadsToAdd.push_back(thread); - if (adoptedThreadAdder->IsActive()) { - TRequestStatus *stat = &adoptedThreadAdder->iStatus; - adoptedThreadAdder->monitorThread.RequestComplete(stat, KErrNone); + if (adoptedThreadAdder->stat) { + adoptedThreadAdder->monitorThread.RequestComplete(adoptedThreadAdder->stat, KErrNone); } } static void monitorThreadFuncL() @@ -232,6 +231,7 @@ private: RThread monitorThread; static QMutex adoptedThreadMonitorMutex; static QCAddAdoptedThread* adoptedThreadAdder; + TRequestStatus *stat; }; QMutex QCAddAdoptedThread::adoptedThreadMonitorMutex; diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp index 1629b91..ee498cc 100644 --- a/tests/auto/qthread/tst_qthread.cpp +++ b/tests/auto/qthread/tst_qthread.cpp @@ -104,6 +104,7 @@ private slots: void adoptedThreadExec(); void adoptedThreadFinished(); void adoptMultipleThreads(); + void adoptMultipleThreadsOverlap(); void QTBUG13810_exitAndStart(); void QTBUG15378_exitAndExec(); @@ -947,6 +948,49 @@ void tst_QThread::adoptMultipleThreads() QCOMPARE(int(recorder.activationCount), numThreads); } +void tst_QThread::adoptMultipleThreadsOverlap() +{ +#if defined(Q_OS_WIN) + // Windows CE is not capable of handling that many threads. On the emulator it is dead with 26 threads already. +# if defined(Q_OS_WINCE) + const int numThreads = 20; +# else + // need to test lots of threads, so that we exceed MAXIMUM_WAIT_OBJECTS in qt_adopted_thread_watcher() + const int numThreads = 200; +# endif +#elif defined(Q_OS_SYMBIAN) + // stress the monitoring thread's add function + const int numThreads = 100; +#else + const int numThreads = 5; +#endif + QVector nativeThreads; + + SignalRecorder recorder; + + for (int i = 0; i < numThreads; ++i) { + nativeThreads.append(new NativeThreadWrapper()); + nativeThreads.at(i)->setWaitForStop(); + nativeThreads.at(i)->mutex.lock(); + nativeThreads.at(i)->start(); + } + for (int i = 0; i < numThreads; ++i) { + nativeThreads.at(i)->startCondition.wait(&nativeThreads.at(i)->mutex); + QObject::connect(nativeThreads.at(i)->qthread, SIGNAL(finished()), &recorder, SLOT(slot())); + nativeThreads.at(i)->mutex.unlock(); + } + + QObject::connect(nativeThreads.at(numThreads - 1)->qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + for (int i = 0; i < numThreads; ++i) { + nativeThreads.at(i)->stop(); + nativeThreads.at(i)->join(); + } + + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(int(recorder.activationCount), numThreads); +} void tst_QThread::stressTest() { #if defined(Q_OS_WINCE) -- cgit v0.12 From 3a9ed967f793abe5049c91217f47d63c9457c1db Mon Sep 17 00:00:00 2001 From: mread Date: Thu, 17 Feb 2011 13:45:38 +0000 Subject: further review fixes for qthread_symbian.cpp Removed a call to get the symbian thread handle when we already had it. Improved error reporting on failure. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_symbian.cpp | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 096cd6d..ce93f9f 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -46,6 +46,7 @@ #include "qthreadstorage.h" #include "qthread_p.h" #include "qdebug.h" +#include "qsystemerror_p.h" #include #include @@ -279,12 +280,6 @@ void *QThreadPrivate::start(void *arg) thr->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag)); } - // Because Symbian Open C does not provide a way to convert between - // RThread and pthread_t, we must delay initialization of the RThread - // handle when creating a thread, until we are running in the new thread. - // Here, we pick up the current thread and assign that to the handle. - init_symbian_thread_handle(data->symbian_thread_handle); - // On symbian, threads other than the main thread are non critical by default // This means a worker thread can crash without crashing the application - to // use this feature, we would need to use RThread::Logon in the main thread @@ -459,19 +454,14 @@ void QThread::start(Priority priority) // operations like file I/O fail, so we increase it by default. d->stackSize = 0x14000; // Maximum stack size on Symbian. - int code = 0; - if (d->data->symbian_thread_handle.Create(KNullDesC, (TThreadFunction) QThreadPrivate::start, d->stackSize, NULL, this) == KErrNone) - { + int code = d->data->symbian_thread_handle.Create(KNullDesC, (TThreadFunction) QThreadPrivate::start, d->stackSize, NULL, this); + if (code == KErrNone) { d->thread_id = d->data->symbian_thread_handle.Id(); TThreadPriority symPriority = calculateSymbianPriority(priority); d->data->symbian_thread_handle.SetPriority(symPriority); d->data->symbian_thread_handle.Resume(); - } - else - code = ENOMEM; // probably the problem - - if (code) { - qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code))); + } else { + qWarning("QThread::start: Thread creation error: %s", QSystemError(code, QSystemError::NativeError).toString()); d->running = false; d->finished = false; -- cgit v0.12 From 563c766ced47c1bfb25976e5a8b8668ed9ab0c53 Mon Sep 17 00:00:00 2001 From: mread Date: Thu, 17 Feb 2011 15:05:57 +0000 Subject: making the QWaitCondition benchmark more reliable The benchmark sometimes hung because wait conditions were sometimes signalled before being waited for. This change adds a real condition to control the interactions. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- .../thread/qwaitcondition/tst_qwaitcondition.cpp | 29 ++++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/benchmarks/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp b/tests/benchmarks/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp index ae5b48e..1bfc637 100644 --- a/tests/benchmarks/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp +++ b/tests/benchmarks/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp @@ -63,10 +63,13 @@ private slots: public: static QWaitCondition local, remote; + enum Turn {LocalTurn, RemoteTurn}; + static Turn turn; }; QWaitCondition tst_QWaitCondition::local; QWaitCondition tst_QWaitCondition::remote; +tst_QWaitCondition::Turn tst_QWaitCondition::turn = tst_QWaitCondition::LocalTurn; class OscillateThread : public QThread { @@ -89,19 +92,22 @@ public: forever { if (m_done) break; - if (m_wakeOne) - tst_QWaitCondition::local.wakeOne(); - else - tst_QWaitCondition::local.wakeAll(); if (m_useMutex) { mtx.lock(); - tst_QWaitCondition::remote.wait(&mtx, m_timeout); + while (tst_QWaitCondition::turn == tst_QWaitCondition::LocalTurn) + tst_QWaitCondition::remote.wait(&mtx, m_timeout); mtx.unlock(); } else { rwl.lockForWrite(); - tst_QWaitCondition::remote.wait(&rwl, m_timeout); + while (tst_QWaitCondition::turn == tst_QWaitCondition::LocalTurn) + tst_QWaitCondition::remote.wait(&rwl, m_timeout); rwl.unlock(); } + tst_QWaitCondition::turn = tst_QWaitCondition::LocalTurn; + if (m_wakeOne) + tst_QWaitCondition::local.wakeOne(); + else + tst_QWaitCondition::local.wakeAll(); count++; } } @@ -132,6 +138,7 @@ void tst_QWaitCondition::oscillate() QFETCH(unsigned long, timeout); QFETCH(bool, wakeOne); + turn = LocalTurn; OscillateThread thrd(useMutex, timeout, wakeOne); thrd.start(); @@ -140,15 +147,18 @@ void tst_QWaitCondition::oscillate() mtx.lock(); else rwl.lockForWrite(); + turn = RemoteTurn; if (wakeOne) remote.wakeOne(); else remote.wakeAll(); if (useMutex) { - local.wait(&mtx, timeout); + while (turn == RemoteTurn) + local.wait(&mtx, timeout); mtx.unlock(); } else { - local.wait(&rwl, timeout); + while (turn == RemoteTurn) + local.wait(&rwl, timeout); rwl.unlock(); } } @@ -174,12 +184,14 @@ void tst_QWaitCondition::thrash() QFETCH(unsigned long, timeout); QFETCH(bool, wakeOne); + turn = LocalTurn; OscillateThread thrd(useMutex, timeout, wakeOne); thrd.start(); local.wait(&mtx, 1000ul); mtx.unlock(); QBENCHMARK { + turn = RemoteTurn; if (wakeOne) remote.wakeOne(); else @@ -187,6 +199,7 @@ void tst_QWaitCondition::thrash() } thrd.m_done = true; + turn = RemoteTurn; remote.wakeAll(); thrd.wait(); -- cgit v0.12 From c5c7ce758c991e760015fa60194a154e2ecbc622 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 18 Feb 2011 10:25:57 +0000 Subject: Making RFastLock work for QMutex It needed an initial lock to make it behave like a semaphore. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qmutex_symbian.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/thread/qmutex_symbian.cpp b/src/corelib/thread/qmutex_symbian.cpp index 09c59af..c5671f5 100644 --- a/src/corelib/thread/qmutex_symbian.cpp +++ b/src/corelib/thread/qmutex_symbian.cpp @@ -57,6 +57,8 @@ QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) { #ifdef QT_SYMBIAN_USE_RFASTLOCK int r = lock.CreateLocal(); + if (r == KErrNone) + lock.Wait(); #else int r = lock.CreateLocal(0); #endif -- cgit v0.12 From 830a08f6612346f90a321fa32de10e1e4a79d94f Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 18 Feb 2011 11:19:36 +0000 Subject: Removing RFastLock use Benchmarks showed no benefit from RFastLock vs RSemaphore. Since RSemaphore works on all target platforms, and RFastLock does not, there is no benefit in using RFastLock. So to simplify the code, it is removed. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qmutex_p.h | 12 ------------ src/corelib/thread/qmutex_symbian.cpp | 8 +------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 2588228..70860b1 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -64,11 +64,6 @@ #if defined(Q_OS_SYMBIAN) # include -# ifdef __SYMBIAN_KERNEL_HYBRID_HEAP__ -# define QT_SYMBIAN_USE_RFASTLOCK -# else -# undef QT_SYMBIAN_USE_RFASTLOCK -# endif #endif QT_BEGIN_NAMESPACE @@ -97,14 +92,7 @@ public: #elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE) HANDLE event; #elif defined(Q_OS_SYMBIAN) -# ifdef QT_SYMBIAN_USE_RFASTLOCK - // RFastLock is a fast semaphone which only calls into the kernel side if there is contention - RFastLock lock; -# else - // RSemaphore is used on Symbian OS versions that do not have a timed RFastLock wait. - // There is no timed wait on RMutex itself, so RSemaphore has to be used instead. RSemaphore lock; -# endif #endif }; diff --git a/src/corelib/thread/qmutex_symbian.cpp b/src/corelib/thread/qmutex_symbian.cpp index c5671f5..f5ff57c 100644 --- a/src/corelib/thread/qmutex_symbian.cpp +++ b/src/corelib/thread/qmutex_symbian.cpp @@ -55,13 +55,7 @@ QT_BEGIN_NAMESPACE QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) { -#ifdef QT_SYMBIAN_USE_RFASTLOCK - int r = lock.CreateLocal(); - if (r == KErrNone) - lock.Wait(); -#else - int r = lock.CreateLocal(0); -#endif + int r = lock.CreateLocal(0); if (r != KErrNone) qWarning("QMutex: failed to create lock, error %d", r); qt_symbian_throwIfError(r); -- cgit v0.12 From b6c60b0c9778f51af8c80f853d840ba25910c6f4 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 18 Feb 2011 15:48:32 +0000 Subject: removed some memory leaks from tst_qthread This now deletes nativeThread objects Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- tests/auto/qthread/tst_qthread.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp index ee498cc..38a0525 100644 --- a/tests/auto/qthread/tst_qthread.cpp +++ b/tests/auto/qthread/tst_qthread.cpp @@ -941,6 +941,7 @@ void tst_QThread::adoptMultipleThreads() for (int i = 0; i < numThreads; ++i) { nativeThreads.at(i)->stop(); nativeThreads.at(i)->join(); + delete nativeThreads.at(i); } QTestEventLoop::instance().enterLoop(5); @@ -985,6 +986,7 @@ void tst_QThread::adoptMultipleThreadsOverlap() for (int i = 0; i < numThreads; ++i) { nativeThreads.at(i)->stop(); nativeThreads.at(i)->join(); + delete nativeThreads.at(i); } QTestEventLoop::instance().enterLoop(5); -- cgit v0.12 From b63fa9907a3299f6b9ce158b153941be2b666cc9 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 18 Feb 2011 16:37:11 +0000 Subject: Fix threadstorage test The test was not calling the destructor in the test class because the global static was defined before the destructor was declared. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- tests/auto/qthreadstorage/tst_qthreadstorage.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp index a62bfee..2391c81 100644 --- a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp +++ b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp @@ -385,19 +385,18 @@ void tst_QThreadStorage::QTBUG14579_leakInDestructor() QCOMPARE(int(SPointer::count), c); } - -class QTBUG14579_reset; -Q_GLOBAL_STATIC(QThreadStorage, QTBUG14579_resetTls) - class QTBUG14579_reset { public: SPointer member; - ~QTBUG14579_reset() { - //Quite stupid, but WTF::ThreadSpecific::destroy does it. - QTBUG14579_resetTls()->setLocalData(this); - } + ~QTBUG14579_reset(); }; +Q_GLOBAL_STATIC(QThreadStorage, QTBUG14579_resetTls) + +QTBUG14579_reset::~QTBUG14579_reset() { + //Quite stupid, but WTF::ThreadSpecific::destroy does it. + QTBUG14579_resetTls()->setLocalData(this); +} void tst_QThreadStorage::QTBUG14579_resetInDestructor() { -- cgit v0.12 From ef4b63c5d9424f82c17ebe614873e4205af0deb9 Mon Sep 17 00:00:00 2001 From: mread Date: Thu, 3 Mar 2011 16:19:05 +0000 Subject: removing unused headers qdebug.h was only temporarily needed for debugging. errno.h is not needed for Symbian code. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- src/corelib/thread/qmutex_symbian.cpp | 1 - src/corelib/thread/qthread_symbian.cpp | 4 +--- src/corelib/thread/qwaitcondition_symbian.cpp | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/corelib/thread/qmutex_symbian.cpp b/src/corelib/thread/qmutex_symbian.cpp index f5ff57c..288c576 100644 --- a/src/corelib/thread/qmutex_symbian.cpp +++ b/src/corelib/thread/qmutex_symbian.cpp @@ -41,7 +41,6 @@ #include "qplatformdefs.h" #include "qmutex.h" -#include #ifndef QT_NO_THREAD #include "qatomic.h" diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index ce93f9f..02d671b 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -45,11 +45,9 @@ #include #include "qthreadstorage.h" #include "qthread_p.h" -#include "qdebug.h" #include "qsystemerror_p.h" #include -#include QT_BEGIN_NAMESPACE @@ -183,7 +181,7 @@ public: } start(); } - static void add(QThread* thread) + static void add(QThread *thread) { QMutexLocker adoptedThreadMonitorMutexlock(&adoptedThreadMonitorMutex); if (!adoptedThreadAdder) { diff --git a/src/corelib/thread/qwaitcondition_symbian.cpp b/src/corelib/thread/qwaitcondition_symbian.cpp index 114811e..1e7172a 100644 --- a/src/corelib/thread/qwaitcondition_symbian.cpp +++ b/src/corelib/thread/qwaitcondition_symbian.cpp @@ -50,8 +50,6 @@ #include "qmutex_p.h" #include "qreadwritelock_p.h" -#include - #ifndef QT_NO_THREAD QT_BEGIN_NAMESPACE -- cgit v0.12 From ad9213b694902d0698911ed1212efca984ee8ab3 Mon Sep 17 00:00:00 2001 From: mread Date: Tue, 8 Mar 2011 11:06:47 +0000 Subject: Using Symbian native mutex type in tst_bench_qmutex The QMutex benchmark contains benchmarks for the native mutex type. It was using pthread_mutex_t on Symbian, which isn't the true native mutex type and so isn't really representative of true native performance. Now it uses RMutex. Task-number: QTBUG-13990 Reviewed-by: Shane Kearns --- .../benchmarks/corelib/thread/qmutex/tst_qmutex.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index b0c5702..468096d 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -44,7 +44,26 @@ #include -#ifdef Q_OS_UNIX +#ifdef Q_OS_SYMBIAN +# include +typedef RMutex NativeMutexType; +void NativeMutexInitialize(NativeMutexType *mutex) +{ + mutex->CreateLocal(); +} +void NativeMutexDestroy(NativeMutexType *mutex) +{ + mutex->Close(); +} +void NativeMutexLock(NativeMutexType *mutex) +{ + mutex->Wait(); +} +void NativeMutexUnlock(NativeMutexType *mutex) +{ + mutex->Signal(); +} +#elif defined(Q_OS_UNIX) # include # include typedef pthread_mutex_t NativeMutexType; -- cgit v0.12