From 65dac2b78c38803f418b331015c801247321dd1b Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 3 Mar 2011 13:56:11 +0200 Subject: Added a note to docs about killing processes in Symbian. Task-number: QT-4659 Reviewed-by: TrustMe --- src/corelib/io/qprocess.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index a44c1e1..5035b79 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -2082,6 +2082,9 @@ void QProcess::terminate() On Symbian, this function requires platform security capability \c PowerMgmt. If absent, the process will panic with KERN-EXEC 46. + \note Killing running processes from other processes will typically + cause a panic in Symbian due to platform security. + \sa {Symbian Platform Security Requirements} \sa terminate() */ -- cgit v0.12 From 25723504d1fc917671dbdeadf441c2ca12145297 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 3 Mar 2011 15:33:04 +0200 Subject: Fix QProcess::waitForFinished WaitForRequest handling in Symbian Waiting for both logonStatus and timerStatus after one has already completed normally could potentially return because some unrelated request completed in the meantime, swallowing the wrong signal. Task-number: QT-4659 Reviewed-by: Janne Koskinen --- src/corelib/io/qprocess_symbian.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/corelib/io/qprocess_symbian.cpp b/src/corelib/io/qprocess_symbian.cpp index d22d1ed..8a74c7b 100644 --- a/src/corelib/io/qprocess_symbian.cpp +++ b/src/corelib/io/qprocess_symbian.cpp @@ -961,16 +961,15 @@ bool QProcessPrivate::waitForFinished(int msecs) User::WaitForRequest(logonStatus, timerStatus); QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished() - Wait completed"); - if (timerStatus == KErrNone) + if (logonStatus != KRequestPending) { + timer.Cancel(); + User::WaitForRequest(timerStatus); + } else { timeoutOccurred = true; - - timer.Cancel(); + symbianProcess->LogonCancel(logonStatus); + User::WaitForRequest(logonStatus); + } timer.Close(); - - symbianProcess->LogonCancel(logonStatus); - - // Eat cancel request completion so that it won't mess up main thread scheduling later - User::WaitForRequest(logonStatus, timerStatus); } } else { QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished(), qt_rprocess_running returned false"); -- cgit v0.12 From c8aad7b59ede3e1c1655059ee9db2436c627aae2 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 4 Mar 2011 17:02:32 +0200 Subject: Don't leave from QNotifyChangeEvent::RunL() in QFileSystemWatcher Unhandled leave can panic the active scheduler, so simply eat the exception and output a warning, as not much else can be done. Task-number: QT-4660 Reviewed-by: Janne Koskinen --- src/corelib/io/qfilesystemwatcher_symbian.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qfilesystemwatcher_symbian.cpp b/src/corelib/io/qfilesystemwatcher_symbian.cpp index 29ec77a..8e8dfe5 100644 --- a/src/corelib/io/qfilesystemwatcher_symbian.cpp +++ b/src/corelib/io/qfilesystemwatcher_symbian.cpp @@ -95,7 +95,10 @@ void QNotifyChangeEvent::RunL() SetActive(); if (!failureCount) { - QT_TRYCATCH_LEAVING(engine->emitPathChanged(this)); + int err; + QT_TRYCATCH_ERROR(err, engine->emitPathChanged(this)); + if (err != KErrNone) + qWarning("QNotifyChangeEvent::RunL() - emitPathChanged threw exception (Converted error code: %d)", err); } } } -- cgit v0.12 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 From f5190b12af6dbeb3f98831276a0bd4e49467500a Mon Sep 17 00:00:00 2001 From: mread Date: Thu, 10 Mar 2011 09:55:25 +0000 Subject: Copying change to unix and Windows QThread implementation to Symbian During merge of SymbianLite branch, it was found that windows and unix QThread implementations had an identical change to locking on thread start. This change is now also applied to Symbian. Reviewed-by: iain --- src/corelib/thread/qthread_symbian.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 02d671b..40764b2 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -289,7 +289,10 @@ void *QThreadPrivate::start(void *arg) set_thread_data(data); - data->quitNow = false; + { + QMutexLocker locker(&thr->d_func()->mutex); + data->quitNow = thr->d_func()->exited; + } // ### TODO: allow the user to create a custom event dispatcher createEventDispatcher(data); -- cgit v0.12 From 9525ef8f3f8c2f28992457a626356cec86bd7279 Mon Sep 17 00:00:00 2001 From: mread Date: Wed, 9 Mar 2011 16:02:27 +0000 Subject: key to string translations for Symbian return and tab characters The Symbian port was not supplying string content for special characters that have a valid string representation. These appear to be return and tab characters. Now it does, for these. Task-number: QTBUG-17545 Reviewed-by: Shane Kearns --- src/gui/kernel/qkeymapper_s60.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qkeymapper_s60.cpp b/src/gui/kernel/qkeymapper_s60.cpp index bcf32a5..08cfae0 100644 --- a/src/gui/kernel/qkeymapper_s60.cpp +++ b/src/gui/kernel/qkeymapper_s60.cpp @@ -69,8 +69,17 @@ void QKeyMapperPrivate::clearMappings() QString QKeyMapperPrivate::translateKeyEvent(int keySym, Qt::KeyboardModifiers /* modifiers */) { - if (keySym >= Qt::Key_Escape) - return QString(); + if (keySym >= Qt::Key_Escape) { + switch (keySym) { + case Qt::Key_Tab: + return QString(QChar('\t')); + case Qt::Key_Return: // fall through + case Qt::Key_Enter: + return QString(QChar('\r')); + default: + return QString(); + } + } // Symbian doesn't actually use modifiers, but gives us the character code directly. -- cgit v0.12 From 498d14367250589e803d32155ffdd4c6fb56c764 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 10 Mar 2011 16:18:18 +0200 Subject: Strip echo suppression character "@" from commands in symbian-sbsv2 Symbian-sbsv2 toolchain cannot handle echo suppresion character "@" in recipes, so the character is stripped from all commands if it exists at the beginning of the command. Task-number: QTBUG-4767 Reviewed-by: Iain --- qmake/generators/symbian/symmake_sbsv2.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qmake/generators/symbian/symmake_sbsv2.cpp b/qmake/generators/symbian/symmake_sbsv2.cpp index f94a63f..6f53288 100644 --- a/qmake/generators/symbian/symmake_sbsv2.cpp +++ b/qmake/generators/symbian/symmake_sbsv2.cpp @@ -84,6 +84,12 @@ static void fixFlmCmd(QString *cmdLine, const QMap &commandsTo // separator, so replace it with "&&" command concatenator. cmdLine->replace("\n\t", "&&"); + // Strip output suppression, as sbsv2 can't handle it in FLMs. Cannot be done by simply + // adding "@" to commandsToReplace, as it'd get handled last due to alphabetical ordering, + // potentially masking other commands that need replacing. + if (cmdLine->contains("@")) + cmdLine->replace(QRegExp(cmdFind.arg("@")), cmdReplace.arg("")); + // Iterate command replacements in reverse alphabetical order of keys so // that keys which are starts of other longer keys are iterated after longer keys. QMapIterator cmdIter(commandsToReplace); -- cgit v0.12 From 59d0c47c82ed5628f0900918e0f6099ba6452e26 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 11 Mar 2011 10:41:27 +0000 Subject: fixing build error in qthread_symbian.cpp CI found that an include of qsystemerror_p.h was incorrect Reviewed-by: iain --- src/corelib/thread/qthread_symbian.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 40764b2..128124f 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -45,7 +45,7 @@ #include #include "qthreadstorage.h" #include "qthread_p.h" -#include "qsystemerror_p.h" +#include #include @@ -462,7 +462,7 @@ void QThread::start(Priority priority) d->data->symbian_thread_handle.SetPriority(symPriority); d->data->symbian_thread_handle.Resume(); } else { - qWarning("QThread::start: Thread creation error: %s", QSystemError(code, QSystemError::NativeError).toString()); + qWarning("QThread::start: Thread creation error: %s", qPrintable(QSystemError(code, QSystemError::NativeError).toString())); d->running = false; d->finished = false; -- cgit v0.12 From eed987453272d925a41d6e8249bdf3458609a58a Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 11 Mar 2011 12:24:47 +0000 Subject: fixing build issue in qwaitcondition_symbian.cpp include of qelapsedtimer was missing a .h Reviewed-by: Robert DeWolf --- src/corelib/thread/qwaitcondition_symbian.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/thread/qwaitcondition_symbian.cpp b/src/corelib/thread/qwaitcondition_symbian.cpp index 1e7172a..9967382 100644 --- a/src/corelib/thread/qwaitcondition_symbian.cpp +++ b/src/corelib/thread/qwaitcondition_symbian.cpp @@ -45,7 +45,7 @@ #include "qreadwritelock.h" #include "qatomic.h" #include "qstring.h" -#include "qelapsedtimer" +#include "qelapsedtimer.h" #include "qmutex_p.h" #include "qreadwritelock_p.h" -- cgit v0.12 From 8731cb8b852eaa638a64c8a6301ba577f2b735ac Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 15 Mar 2011 12:02:20 +0200 Subject: Removed broken "deploy.path" support from Symbian The undocumented special "deploy.path" variable hasn't been working in Symbian for several releases and doesn't really make much sense in Symbian in the first place. Also, apparently no-one has ever used it as there has been no bug reports, so might as well remove the check for it in Symbian. Task-number: QTBUG-14426 Reviewed-by: Janne Koskinen --- qmake/generators/symbian/initprojectdeploy_symbian.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qmake/generators/symbian/initprojectdeploy_symbian.cpp b/qmake/generators/symbian/initprojectdeploy_symbian.cpp index f9fae9d..f70c49d 100644 --- a/qmake/generators/symbian/initprojectdeploy_symbian.cpp +++ b/qmake/generators/symbian/initprojectdeploy_symbian.cpp @@ -169,9 +169,7 @@ void initProjectDeploySymbian(QMakeProject* project, QStringList& generatedDirs, QStringList& generatedFiles) { - QString targetPath = project->values("deploy.path").join(" "); - if (targetPath.isEmpty()) - targetPath = testPath; + QString targetPath = testPath; if (targetPath.endsWith("/") || targetPath.endsWith("\\")) targetPath = targetPath.mid(0, targetPath.size() - 1); -- cgit v0.12 From 82198dd1f7049cec89271b0ea82521752cc13c05 Mon Sep 17 00:00:00 2001 From: Guoqing Zhang Date: Wed, 16 Mar 2011 13:10:42 +0200 Subject: Add digit conversion in default format function Task-number: QTBUG-17993 Reviewed-by: Laszlo Agocs --- src/plugins/s60/3_2/3_2.pro | 1 + src/plugins/s60/5_0/5_0.pro | 1 + src/plugins/s60/src/qlocale_3_2.cpp | 2 ++ 3 files changed, 4 insertions(+) diff --git a/src/plugins/s60/3_2/3_2.pro b/src/plugins/s60/3_2/3_2.pro index 0524866..b104c05 100644 --- a/src/plugins/s60/3_2/3_2.pro +++ b/src/plugins/s60/3_2/3_2.pro @@ -16,6 +16,7 @@ contains(S60_VERSION, 3.1) { LIBS += -lDirectoryLocalizer } LIBS += -lefsrv + LIBS += -lnumberconversion INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE } diff --git a/src/plugins/s60/5_0/5_0.pro b/src/plugins/s60/5_0/5_0.pro index 00aea1b..b037215 100644 --- a/src/plugins/s60/5_0/5_0.pro +++ b/src/plugins/s60/5_0/5_0.pro @@ -16,6 +16,7 @@ contains(S60_VERSION, 3.1) { LIBS += -lDirectoryLocalizer } LIBS += -lefsrv + LIBS += -lnumberconversion INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE } diff --git a/src/plugins/s60/src/qlocale_3_2.cpp b/src/plugins/s60/src/qlocale_3_2.cpp index 8c0edd2..ab5d304 100644 --- a/src/plugins/s60/src/qlocale_3_2.cpp +++ b/src/plugins/s60/src/qlocale_3_2.cpp @@ -42,6 +42,7 @@ #include #include #include +#include EXPORT_C TPtrC defaultGetLongDateFormatSpec(TExtendedLocale& locale) { @@ -61,4 +62,5 @@ EXPORT_C TPtrC defaultGetTimeFormatSpec(TExtendedLocale& locale) EXPORT_C void defaultFormatL(TTime& time, TDes& des, const TDesC& format, const TLocale& locale) { time.FormatL(des, format, locale); + NumberConversion::ConvertDigits(des, locale.DigitType()); } -- cgit v0.12 From 5f99c63ab340da353497bfe4d74827b179d8a654 Mon Sep 17 00:00:00 2001 From: Guoqing Zhang Date: Wed, 16 Mar 2011 15:50:04 +0200 Subject: Fix build break Task-number: Reviewed-by: laszlo agocs --- src/plugins/s60/src/qlocale_3_2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/s60/src/qlocale_3_2.cpp b/src/plugins/s60/src/qlocale_3_2.cpp index ab5d304..ecbf46c 100644 --- a/src/plugins/s60/src/qlocale_3_2.cpp +++ b/src/plugins/s60/src/qlocale_3_2.cpp @@ -42,7 +42,7 @@ #include #include #include -#include +#include EXPORT_C TPtrC defaultGetLongDateFormatSpec(TExtendedLocale& locale) { -- cgit v0.12 From 1163032eda2dce89bd464d2a99f3cbbcf20cc232 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 16 Mar 2011 15:49:53 +0200 Subject: Fix emulator deployment for items with "!:" drive. "!:" drive is used to indicate need to prompt user to specify installation drive, which is obviously not happening when we do the build time emulator deployment, so default it to "c:" drive. Task-number: QTBUG-18134 Reviewed-by: Janne Koskinen --- qmake/generators/symbian/initprojectdeploy_symbian.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qmake/generators/symbian/initprojectdeploy_symbian.cpp b/qmake/generators/symbian/initprojectdeploy_symbian.cpp index f70c49d..8d04a42 100644 --- a/qmake/generators/symbian/initprojectdeploy_symbian.cpp +++ b/qmake/generators/symbian/initprojectdeploy_symbian.cpp @@ -223,7 +223,10 @@ void initProjectDeploySymbian(QMakeProject* project, } else { if (0 == platform.compare(QLatin1String(EMULATOR_DEPLOYMENT_PLATFORM))) { if (devicePathHasDriveLetter) { - devicePath = qt_epocRoot() + "epoc32/winscw/" + devicePath.remove(1, 1); + if (devicePath.startsWith("!")) + devicePath = qt_epocRoot() + "epoc32/winscw/c" + devicePath.remove(0, 2); + else + devicePath = qt_epocRoot() + "epoc32/winscw/" + devicePath.remove(1, 1); } else { devicePath = qt_epocRoot() + "epoc32/winscw/c" + devicePath; } -- cgit v0.12 From 130f8dce2f730811c3f1f0b4f45a3333c9a79600 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 16 Mar 2011 16:21:16 +0200 Subject: Fix mismatched $$translations handling after merge One use of $$translations prepends "$$_PRO_FILE_PWD_/" to it in symbian.conf, while another identical use doesn't. This discrepancy was caused by merge from 4.7. Reviewed-by: Janne Koskinen --- mkspecs/common/symbian/symbian.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index e3813a4..d9f6279 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -260,7 +260,7 @@ defineTest(matchSymbianLanguages) { HANDLED_LANGUAGES += $$strippedLanguage SYMBIAN_UNMAPPED_LANGUAGES += $$language SYMBIAN_MATCHED_LANGUAGES += $$language - SYMBIAN_MATCHED_TRANSLATIONS += $$translation + SYMBIAN_MATCHED_TRANSLATIONS += $$_PRO_FILE_PWD_/$$translation SYMBIAN_LANGUAGE_FALLBACK.$$language = $$strippedLanguage export(SYMBIAN_LANGUAGE_FALLBACK.$$language) } -- cgit v0.12 From 807b49a09210d4256d4e2f992468ce7f77e96c5d Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 17 Mar 2011 12:24:06 +0200 Subject: Add ".make.cache" to the files to be cleaned for symbian-abld. "make clean" will now delete any generated ".make.cache" files in symbian-abld builds. Task-number: QTBUG-15733 Reviewed-by: Janne Koskinen --- mkspecs/features/symbian/sis_targets.prf | 1 + 1 file changed, 1 insertion(+) diff --git a/mkspecs/features/symbian/sis_targets.prf b/mkspecs/features/symbian/sis_targets.prf index d6d6df0..9963b30 100644 --- a/mkspecs/features/symbian/sis_targets.prf +++ b/mkspecs/features/symbian/sis_targets.prf @@ -142,6 +142,7 @@ equals(GENERATE_SIS_TARGETS, true) { && echo QT_SIS_TARGET ?= $(QT_SIS_TARGET) >> $$make_cache_name QMAKE_EXTRA_TARGETS += store_build_target + QMAKE_CLEAN += $$make_cache_name } } else { sis_destdir = $$DESTDIR -- cgit v0.12 From a9cb2be8c14317001c0945da84f1a19e1d6ee6c6 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 18 Mar 2011 10:42:45 +0000 Subject: Making Symbian helper threads exit cleanly at app exit The idle detector thread and the adopted thread monitor thread could keep an app alive unnecessarily after main had exited, if the app's main thread was no longer set "process permanent". The idle detector thread now exits when the QCoreApplication is destroyed. The adopted thread monitor thread now exits when there are no more adopted threads to monitor. Task-number: QTBUG-18073 Reviewed-by: Shane Kearns --- src/corelib/kernel/qeventdispatcher_symbian.cpp | 50 ++++++++++++++++++++----- src/corelib/thread/qthread_symbian.cpp | 36 +++++++++++++----- 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 53796be..4c01bde 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -654,34 +655,54 @@ class QIdleDetectorThread { public: QIdleDetectorThread() - : m_state(STATE_RUN), m_stop(false) + : m_state(STATE_RUN), m_stop(false), m_running(false) { - qt_symbian_throwIfError(m_lock.CreateLocal(0)); + start(); + } + + ~QIdleDetectorThread() + { + stop(); + } + + void start() + { + QMutexLocker lock(&m_mutex); + if (m_running) + return; + m_stop = false; + m_state = STATE_RUN; TInt err = m_idleDetectorThread.Create(KNullDesC(), &idleDetectorThreadFunc, 1024, &User::Allocator(), this); if (err != KErrNone) - m_lock.Close(); - qt_symbian_throwIfError(err); + return; // Fail silently on error. Next kick will try again. Exception might stop the event being processed m_idleDetectorThread.SetPriority(EPriorityAbsoluteBackgroundNormal); m_idleDetectorThread.Resume(); + m_running = true; + // get a callback from QCoreApplication destruction to stop this thread + qAddPostRoutine(StopIdleDetectorThread); } - ~QIdleDetectorThread() + void stop() { + QMutexLocker lock(&m_mutex); + if (!m_running) + return; // close down the idle thread because if corelib is loaded temporarily, this would leak threads into the host process m_stop = true; - m_lock.Signal(); + m_kick.release(); m_idleDetectorThread.SetPriority(EPriorityNormal); TRequestStatus s; m_idleDetectorThread.Logon(s); User::WaitForRequest(s); m_idleDetectorThread.Close(); - m_lock.Close(); + m_running = false; } void kick() { + start(); m_state = STATE_KICKED; - m_lock.Signal(); + m_kick.release(); } bool hasRun() @@ -700,20 +721,29 @@ private: void IdleLoop() { while (!m_stop) { - m_lock.Wait(); + m_kick.acquire(); m_state = STATE_RUN; } } + static void StopIdleDetectorThread(); + private: enum IdleStates {STATE_KICKED, STATE_RUN} m_state; bool m_stop; + bool m_running; RThread m_idleDetectorThread; - RSemaphore m_lock; + QSemaphore m_kick; + QMutex m_mutex; }; Q_GLOBAL_STATIC(QIdleDetectorThread, idleDetectorThread); +void QIdleDetectorThread::StopIdleDetectorThread() +{ + idleDetectorThread()->stop(); +} + const int maxBusyTime = 2000; // maximum time we allow idle detector to be blocked before worrying, in milliseconds const int baseDelay = 1000; // minimum delay time used when backing off to allow idling, in microseconds #endif diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 128124f..75cb5eb 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -131,11 +131,7 @@ public: { data->symbian_thread_handle.LogonCancel(iStatus); } - void RunL() - { - data->deref(); - delete this; - } + void RunL(); private: QThreadData* data; }; @@ -177,6 +173,7 @@ public: for (int i=threadsToAdd.size()-1; i>=0; i--) { // Create an active object to monitor the thread new (ELeave) QCAdoptedThreadMonitor(threadsToAdd[i]); + count++; threadsToAdd.pop_back(); } start(); @@ -193,6 +190,8 @@ public: User::WaitForRequest(started); monitorThread.Close(); } + if (RThread().Id() == adoptedThreadAdder->monitorThread.Id()) + return; adoptedThreadAdder->threadsToAdd.push_back(thread); if (adoptedThreadAdder->stat) { adoptedThreadAdder->monitorThread.RequestComplete(adoptedThreadAdder->stat, KErrNone); @@ -204,15 +203,15 @@ public: CleanupStack::PushL(scheduler); CActiveScheduler::Install(scheduler); - adoptedThreadAdder = new(ELeave) QCAddAdoptedThread(); + adoptedThreadAdder = new(ELeave) QCAddAdoptedThread(); CleanupStack::PushL(adoptedThreadAdder); adoptedThreadAdder->ConstructL(); + QCAddAdoptedThread *adder = adoptedThreadAdder; RThread::Rendezvous(KErrNone); CActiveScheduler::Start(); - CleanupStack::PopAndDestroy(adoptedThreadAdder); - adoptedThreadAdder = 0; + CleanupStack::PopAndDestroy(adder); CleanupStack::PopAndDestroy(scheduler); } static int monitorThreadFunc(void *) @@ -224,18 +223,37 @@ public: delete cleanup; return ret; } + static void threadDied() + { + QMutexLocker adoptedThreadMonitorMutexlock(&adoptedThreadMonitorMutex); + if (adoptedThreadAdder) { + adoptedThreadAdder->count--; + if (adoptedThreadAdder->count <= 0 && adoptedThreadAdder->threadsToAdd.size() == 0) { + CActiveScheduler::Stop(); + adoptedThreadAdder = 0; + } + } + } private: QVector threadsToAdd; RThread monitorThread; static QMutex adoptedThreadMonitorMutex; - static QCAddAdoptedThread* adoptedThreadAdder; + static QCAddAdoptedThread *adoptedThreadAdder; + int count; TRequestStatus *stat; }; QMutex QCAddAdoptedThread::adoptedThreadMonitorMutex; QCAddAdoptedThread* QCAddAdoptedThread::adoptedThreadAdder = 0; +void QCAdoptedThreadMonitor::RunL() +{ + data->deref(); + QCAddAdoptedThread::threadDied(); + delete this; +} + void QAdoptedThread::init() { Q_D(QThread); -- cgit v0.12 From 89660713717dcbd6126d6a38f911b7a90dff7ba7 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Fri, 18 Mar 2011 16:04:20 +0200 Subject: QComboBox fix for QTBUG-16985 --- src/gui/widgets/qcombobox.cpp | 83 +++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index b5dda5a..0bfc03d 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -7,11 +7,11 @@ ** This file is part of the QtGui 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. +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -25,16 +25,16 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -116,7 +116,7 @@ QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewIt QPalette resolvedpalette = option.palette.resolve(QApplication::palette("QMenu")); QVariant value = index.data(Qt::ForegroundRole); - if (value.canConvert()) { + if (qVariantCanConvert(value)) { resolvedpalette.setBrush(QPalette::WindowText, qvariant_cast(value)); resolvedpalette.setBrush(QPalette::ButtonText, qvariant_cast(value)); resolvedpalette.setBrush(QPalette::Text, qvariant_cast(value)); @@ -152,7 +152,7 @@ QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewIt menuOption.icon = qvariant_cast(variant); break; } - if (index.data(Qt::BackgroundRole).canConvert()) { + if (qVariantCanConvert(index.data(Qt::BackgroundRole))) { menuOption.palette.setBrush(QPalette::All, QPalette::Background, qvariant_cast(index.data(Qt::BackgroundRole))); } @@ -369,7 +369,6 @@ void QComboBoxPrivateContainer::timerEvent(QTimerEvent *timerEvent) if (timerEvent->timerId() == adjustSizeTimer.timerId()) { adjustSizeTimer.stop(); if (combo->sizeAdjustPolicy() == QComboBox::AdjustToContents) { - combo->updateGeometry(); combo->adjustSize(); combo->update(); } @@ -1089,8 +1088,6 @@ void QComboBoxPrivate::updateViewContainerPaletteAndOpacity() container->setPalette(q->palette()); container->setWindowOpacity(1.0); } - if (lineEdit) - lineEdit->setPalette(q->palette()); } /*! @@ -1301,7 +1298,7 @@ QComboBox::~QComboBox() By default, this property has a value of 10. \note This property is ignored for non-editable comboboxes in styles that returns - true for QStyle::SH_ComboBox_Popup such as the Mac style or the Gtk+ Style. + false for QStyle::SH_ComboBox_Popup such as the Mac style or the Gtk+ Style. */ int QComboBox::maxVisibleItems() const { @@ -2011,18 +2008,11 @@ void QComboBox::setCurrentIndex(int index) void QComboBoxPrivate::setCurrentIndex(const QModelIndex &mi) { Q_Q(QComboBox); - - QModelIndex normalized; - if (mi.column() != modelColumn) - normalized = model->index(mi.row(), modelColumn, mi.parent()); - if (!normalized.isValid()) - normalized = mi; // Fallback to passed index. - - bool indexChanged = (normalized != currentIndex); + bool indexChanged = (mi != currentIndex); if (indexChanged) - currentIndex = QPersistentModelIndex(normalized); + currentIndex = QPersistentModelIndex(mi); if (lineEdit) { - QString newText = q->itemText(normalized.row()); + QString newText = q->itemText(currentIndex.row()); if (lineEdit->text() != newText) lineEdit->setText(newText); updateLineEditGeometry(); @@ -2358,7 +2348,9 @@ void QComboBox::showPopup() initStyleOption(&opt); QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxListBoxPopup, this)); - QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); + //QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); + QRect screen = qt_TRect2QRect(static_cast(S60->appUi())->ClientRect()); + QPoint below = mapToGlobal(listRect.bottomLeft()); int belowHeight = screen.bottom() - below.y(); QPoint above = mapToGlobal(listRect.topLeft()); @@ -2486,18 +2478,10 @@ void QComboBox::showPopup() listRect.setWidth(listRect.height()); //by default popup is centered on screen in landscape listRect.moveCenter(screen.center()); - if (staConTopRect.IsEmpty()) { - TRect cbaRect = TRect(); - AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, cbaRect); - AknLayoutUtils::TAknCbaLocation cbaLocation = AknLayoutUtils::CbaLocation(); - switch (cbaLocation) { - case AknLayoutUtils::EAknCbaLocationRight: - listRect.setRight(screen.right()); - break; - case AknLayoutUtils::EAknCbaLocationLeft: - listRect.setLeft(screen.left()); - break; - } + if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) { + // landscape without stacon, menu should be at the right + (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) : + listRect.setLeft(screen.left()); } } #endif @@ -2716,8 +2700,9 @@ void QComboBox::changeEvent(QEvent *e) initStyleOption(&opt); if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) { - const QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); - + //const QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); + QRect screen = qt_TRect2QRect(static_cast(S60->appUi())->ClientRect()); + QRect listRect(style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxListBoxPopup, this)); listRect.setHeight(qMin(screen.height(), screen.width())); @@ -2731,13 +2716,15 @@ void QComboBox::changeEvent(QEvent *e) listRect.setWidth(listRect.height()); //by default popup is centered on screen in landscape listRect.moveCenter(screen.center()); - if (staConTopRect.IsEmpty()) { + if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) { // landscape without stacon, menu should be at the right (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) : listRect.setLeft(screen.left()); } - d->container->setGeometry(listRect); + //d->container->setGeometry(listRect); } + + d->container->setGeometry(listRect); } } #endif @@ -2770,6 +2757,10 @@ void QComboBox::changeEvent(QEvent *e) void QComboBox::resizeEvent(QResizeEvent *) { Q_D(QComboBox); +#ifdef Q_WS_S60 + if (d->viewContainer() && d->viewContainer()->isVisible()) + showPopup(); +#endif d->updateLineEditGeometry(); } -- cgit v0.12 From e37d500cb1da388fbd53ae9e58548a59df29f598 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 18 Mar 2011 15:51:36 +0000 Subject: Moving Symbian CPU core detection to qthread_symbian.cpp This is resolving a merge issue where Symbian CPU core detection was added in one branch, but all the Symbian thread support was moved to a new file in another branch. Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_symbian.cpp | 21 +++++++++++++++++---- src/corelib/thread/qthread_unix.cpp | 26 -------------------------- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 75cb5eb..1474b36 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -48,7 +48,14 @@ #include #include +#include +#include +// You only find these enumerations on Symbian^3 onwards, so we need to provide our own +// to remain compatible with older releases. They won't be called by pre-Sym^3 SDKs. + +// HALData::ENumCpus +#define QT_HALData_ENumCpus 119 QT_BEGIN_NAMESPACE @@ -376,10 +383,16 @@ Qt::HANDLE QThread::currentThreadId() int QThread::idealThreadCount() { - int cores = -1; - - // ### TODO - Get the number of cores from HAL? when multicore architectures (SMP) are supported - cores = 1; + int cores = 1; + + if (QSysInfo::symbianVersion() >= QSysInfo::SV_SF_3) { + TInt inumcpus; + TInt err; + err = HAL::Get((HALData::TAttribute)QT_HALData_ENumCpus, inumcpus); + if (err == KErrNone) { + cores = qMax(inumcpus, 1); + } + } return cores; } diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index a1c6458..835378a 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -50,11 +50,6 @@ #include -#ifdef Q_OS_SYMBIAN -#include -#include -#endif - #include "qthreadstorage.h" #include "qthread_p.h" @@ -64,12 +59,6 @@ #include #include -// You only find these enumerations on Symbian^3 onwards, so we need to provide our own -// to remain compatible with older releases. They won't be called by pre-Sym^3 SDKs. - -// HALData::ENumCpus -#define QT_HALData_ENumCpus 119 - #ifdef Q_OS_BSD4 #include #endif @@ -378,21 +367,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) - if (QSysInfo::symbianVersion() >= QSysInfo::SV_SF_3) { - TInt inumcpus; - TInt err; - err = HAL::Get((HALData::TAttribute)QT_HALData_ENumCpus, inumcpus); - if (err != KErrNone) { - cores = 1; - } else if ( inumcpus <= 0 ) { - cores = 1; - } else { - cores = inumcpus; - } - } else { - cores = 1; - } #elif defined(Q_OS_VXWORKS) // VxWorks # if defined(QT_VXWORKS_HAS_CPUSET) -- cgit v0.12 From 7e26a493ecd1d77b1637a4c86b6f47fcce67a92c Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Tue, 22 Mar 2011 13:05:25 +0200 Subject: Revert "QComboBox fix for QTBUG-16985" The commit has to be reverted due to introduced build break for non-Symbian platforms. This reverts commit 89660713717dcbd6126d6a38f911b7a90dff7ba7. --- src/gui/widgets/qcombobox.cpp | 83 ++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 0bfc03d..b5dda5a 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -7,11 +7,11 @@ ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. +** 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 @@ -25,16 +25,16 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -116,7 +116,7 @@ QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewIt QPalette resolvedpalette = option.palette.resolve(QApplication::palette("QMenu")); QVariant value = index.data(Qt::ForegroundRole); - if (qVariantCanConvert(value)) { + if (value.canConvert()) { resolvedpalette.setBrush(QPalette::WindowText, qvariant_cast(value)); resolvedpalette.setBrush(QPalette::ButtonText, qvariant_cast(value)); resolvedpalette.setBrush(QPalette::Text, qvariant_cast(value)); @@ -152,7 +152,7 @@ QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewIt menuOption.icon = qvariant_cast(variant); break; } - if (qVariantCanConvert(index.data(Qt::BackgroundRole))) { + if (index.data(Qt::BackgroundRole).canConvert()) { menuOption.palette.setBrush(QPalette::All, QPalette::Background, qvariant_cast(index.data(Qt::BackgroundRole))); } @@ -369,6 +369,7 @@ void QComboBoxPrivateContainer::timerEvent(QTimerEvent *timerEvent) if (timerEvent->timerId() == adjustSizeTimer.timerId()) { adjustSizeTimer.stop(); if (combo->sizeAdjustPolicy() == QComboBox::AdjustToContents) { + combo->updateGeometry(); combo->adjustSize(); combo->update(); } @@ -1088,6 +1089,8 @@ void QComboBoxPrivate::updateViewContainerPaletteAndOpacity() container->setPalette(q->palette()); container->setWindowOpacity(1.0); } + if (lineEdit) + lineEdit->setPalette(q->palette()); } /*! @@ -1298,7 +1301,7 @@ QComboBox::~QComboBox() By default, this property has a value of 10. \note This property is ignored for non-editable comboboxes in styles that returns - false for QStyle::SH_ComboBox_Popup such as the Mac style or the Gtk+ Style. + true for QStyle::SH_ComboBox_Popup such as the Mac style or the Gtk+ Style. */ int QComboBox::maxVisibleItems() const { @@ -2008,11 +2011,18 @@ void QComboBox::setCurrentIndex(int index) void QComboBoxPrivate::setCurrentIndex(const QModelIndex &mi) { Q_Q(QComboBox); - bool indexChanged = (mi != currentIndex); + + QModelIndex normalized; + if (mi.column() != modelColumn) + normalized = model->index(mi.row(), modelColumn, mi.parent()); + if (!normalized.isValid()) + normalized = mi; // Fallback to passed index. + + bool indexChanged = (normalized != currentIndex); if (indexChanged) - currentIndex = QPersistentModelIndex(mi); + currentIndex = QPersistentModelIndex(normalized); if (lineEdit) { - QString newText = q->itemText(currentIndex.row()); + QString newText = q->itemText(normalized.row()); if (lineEdit->text() != newText) lineEdit->setText(newText); updateLineEditGeometry(); @@ -2348,9 +2358,7 @@ void QComboBox::showPopup() initStyleOption(&opt); QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxListBoxPopup, this)); - //QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); - QRect screen = qt_TRect2QRect(static_cast(S60->appUi())->ClientRect()); - + QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); QPoint below = mapToGlobal(listRect.bottomLeft()); int belowHeight = screen.bottom() - below.y(); QPoint above = mapToGlobal(listRect.topLeft()); @@ -2478,10 +2486,18 @@ void QComboBox::showPopup() listRect.setWidth(listRect.height()); //by default popup is centered on screen in landscape listRect.moveCenter(screen.center()); - if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) { - // landscape without stacon, menu should be at the right - (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) : - listRect.setLeft(screen.left()); + if (staConTopRect.IsEmpty()) { + TRect cbaRect = TRect(); + AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, cbaRect); + AknLayoutUtils::TAknCbaLocation cbaLocation = AknLayoutUtils::CbaLocation(); + switch (cbaLocation) { + case AknLayoutUtils::EAknCbaLocationRight: + listRect.setRight(screen.right()); + break; + case AknLayoutUtils::EAknCbaLocationLeft: + listRect.setLeft(screen.left()); + break; + } } } #endif @@ -2700,9 +2716,8 @@ void QComboBox::changeEvent(QEvent *e) initStyleOption(&opt); if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) { - //const QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); - QRect screen = qt_TRect2QRect(static_cast(S60->appUi())->ClientRect()); - + const QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); + QRect listRect(style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxListBoxPopup, this)); listRect.setHeight(qMin(screen.height(), screen.width())); @@ -2716,15 +2731,13 @@ void QComboBox::changeEvent(QEvent *e) listRect.setWidth(listRect.height()); //by default popup is centered on screen in landscape listRect.moveCenter(screen.center()); - if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) { + if (staConTopRect.IsEmpty()) { // landscape without stacon, menu should be at the right (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) : listRect.setLeft(screen.left()); } - //d->container->setGeometry(listRect); + d->container->setGeometry(listRect); } - - d->container->setGeometry(listRect); } } #endif @@ -2757,10 +2770,6 @@ void QComboBox::changeEvent(QEvent *e) void QComboBox::resizeEvent(QResizeEvent *) { Q_D(QComboBox); -#ifdef Q_WS_S60 - if (d->viewContainer() && d->viewContainer()->isVisible()) - showPopup(); -#endif d->updateLineEditGeometry(); } -- cgit v0.12 From e28d33a6924d14afc5851a9a3587891f8507ee16 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Tue, 22 Mar 2011 13:49:22 +0200 Subject: Fix for QTBUG-16985. QComboBox popup is resized/positioned correctly when device orientation changes. Task-number: QTBUG-16985 Reviewed-by: Sami Merila --- src/gui/widgets/qcombobox.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index b5dda5a..34e3672 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -2358,7 +2358,12 @@ void QComboBox::showPopup() initStyleOption(&opt); QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxListBoxPopup, this)); +#ifndef Q_WS_S60 QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); +#else + QRect screen = qt_TRect2QRect(static_cast(S60->appUi())->ClientRect()); +#endif + QPoint below = mapToGlobal(listRect.bottomLeft()); int belowHeight = screen.bottom() - below.y(); QPoint above = mapToGlobal(listRect.topLeft()); @@ -2486,18 +2491,10 @@ void QComboBox::showPopup() listRect.setWidth(listRect.height()); //by default popup is centered on screen in landscape listRect.moveCenter(screen.center()); - if (staConTopRect.IsEmpty()) { - TRect cbaRect = TRect(); - AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, cbaRect); - AknLayoutUtils::TAknCbaLocation cbaLocation = AknLayoutUtils::CbaLocation(); - switch (cbaLocation) { - case AknLayoutUtils::EAknCbaLocationRight: - listRect.setRight(screen.right()); - break; - case AknLayoutUtils::EAknCbaLocationLeft: - listRect.setLeft(screen.left()); - break; - } + if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) { + // landscape without stacon, menu should be at the right + (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) : + listRect.setLeft(screen.left()); } } #endif @@ -2716,7 +2713,7 @@ void QComboBox::changeEvent(QEvent *e) initStyleOption(&opt); if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) { - const QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); + QRect screen = qt_TRect2QRect(static_cast(S60->appUi())->ClientRect()); QRect listRect(style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxListBoxPopup, this)); @@ -2731,13 +2728,14 @@ void QComboBox::changeEvent(QEvent *e) listRect.setWidth(listRect.height()); //by default popup is centered on screen in landscape listRect.moveCenter(screen.center()); - if (staConTopRect.IsEmpty()) { + if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) { // landscape without stacon, menu should be at the right (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) : listRect.setLeft(screen.left()); } - d->container->setGeometry(listRect); } + + d->container->setGeometry(listRect); } } #endif @@ -2770,6 +2768,10 @@ void QComboBox::changeEvent(QEvent *e) void QComboBox::resizeEvent(QResizeEvent *) { Q_D(QComboBox); +#ifdef Q_WS_S60 + if (d->viewContainer() && d->viewContainer()->isVisible()) + showPopup(); +#endif d->updateLineEditGeometry(); } -- cgit v0.12 From 7cce8ce5af4087c662db657887b7971a2931e849 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 22 Mar 2011 16:27:23 +0200 Subject: Make createpackage and patch_capabilties scripts use tmp dir Temporary files created by these two scripts will now be created under a separate directory, contents of which is also added to cleanup. Task-number: QTBUG-11394 Reviewed-by: axis --- bin/createpackage.pl | 41 ++++++++++++++------------ bin/patch_capabilities.pl | 50 +++++++++++++++++++++++--------- mkspecs/common/symbian/symbian.conf | 2 +- mkspecs/features/symbian/sis_targets.prf | 21 ++++++++------ 4 files changed, 73 insertions(+), 41 deletions(-) diff --git a/bin/createpackage.pl b/bin/createpackage.pl index df91876..b7457e1 100755 --- a/bin/createpackage.pl +++ b/bin/createpackage.pl @@ -58,7 +58,7 @@ use File::Spec; use File::Path; # use CWD abs_bath, which is exported only on request use Cwd 'abs_path'; - +use File::Copy; sub Usage() { print <] = Specifies temporary directory to be used for package creation. + Defaults to 'createpackage_tmp' under same directory as templatepkg. Where parameters are as follows: templatepkg = Name of .pkg file template target = Either debug or release @@ -130,6 +132,7 @@ my $signed_sis_name = ""; my $onlyUnsigned = ""; my $convertGcce = ""; my $dontPatchCaps = ""; +my $tempPackageDir = ""; unless (GetOptions('i|install' => \$install, 'p|preprocess' => \$preprocessonly, @@ -139,7 +142,8 @@ unless (GetOptions('i|install' => \$install, 's|stub' => \$stub, 'n|sisname=s' => \$signed_sis_name, 'g|gcce-is-armv5' => \$convertGcce, - 'd|dont-patch' => \$dontPatchCaps,)) { + 'd|dont-patch' => \$dontPatchCaps, + 't|tmp-dir=s' => \$tempPackageDir,)) { Usage(); } @@ -190,18 +194,22 @@ $key = $ARGV[3] or $key = ""; my $passphrase; $passphrase = $ARGV[4] or $passphrase = ""; +if ($tempPackageDir eq "") { + my ($templateVolume, $templatePath, $templateFileName) = File::Spec->splitpath($templatepkg); + $tempPackageDir = File::Spec->catpath($templateVolume, $templatePath."createpackage_tmp", ""); +} + +mkpath($tempPackageDir); + # Generate output pkg basename (i.e. file name without extension) my $pkgoutputbasename = $templatepkg; -my $preservePkgOutput = ""; $pkgoutputbasename =~ s/_template/_$targetplatform/g; $pkgoutputbasename =~ s/_installer\.pkg/_installer___temp\.pkg/g; -if ($pkgoutputbasename eq $templatepkg) { - $preservePkgOutput = "1"; -} $pkgoutputbasename =~ s/\.pkg//g; # Store output file names to variables -my $pkgoutput = $pkgoutputbasename.".pkg"; +my ($dummy1, $dummy2, $pkgoutput) = File::Spec->splitpath($pkgoutputbasename.".pkg"); +$pkgoutput = $tempPackageDir."/".$pkgoutput; my $sisoutputbasename; if ($signed_sis_name eq "") { $sisoutputbasename = $pkgoutputbasename; @@ -300,9 +308,7 @@ unlink $unsigned_sis_name; if (!$onlyUnsigned) { unlink $signed_sis_name; } -if (!$preservePkgOutput) { - unlink $pkgoutput; -} +unlink $pkgoutput; # Preprocess PKG @@ -334,6 +340,11 @@ print OUTPUT $_; close OUTPUT; if ($preprocessonly) { + # Copy preprocessed file from tmp dir to pkg file dir + my ($templateVolume, $templatePath, $templateFileName) = File::Spec->splitpath($templatepkg); + my ($dummy1, $dummy2, $copyFileName) = File::Spec->splitpath($pkgoutput); + my $copyTarget = File::Spec->catpath($templateVolume, $templatePath, $copyFileName); + copy($pkgoutput, $copyTarget) or die "Preprocessed pkg file '$pkgoutput' cannot be copied."; exit; } @@ -354,7 +365,7 @@ if($stub) { system ("$patch_capabilities -c $pkgoutput") and print ("Warning: Package check for self-signing viability failed. Installing the package on a device will most likely fail!\n\n"); } else { print("Auto-patching self-signed package.\n"); - system ("$patch_capabilities $pkgoutput") and die ("ERROR: Automatic patching failed"); + system ("$patch_capabilities -t $tempPackageDir $pkgoutput") and die ("ERROR: Automatic patching failed"); } } @@ -377,9 +388,6 @@ if($stub) { print ("\nUnsigned package creation failed!\n"); } - if (!$preservePkgOutput) { - unlink $pkgoutput; - } print ("\n"); exit; } @@ -405,10 +413,7 @@ if($stub) { print ("\tAdditionally signed the SIS with certificate: $row->[0]!\n"); } - # remove temporary pkg and unsigned sis - if (!$preservePkgOutput) { - unlink $pkgoutput; - } + # remove temporary unsigned sis if (!$preserveUnsigned) { unlink $unsigned_sis_name; } diff --git a/bin/patch_capabilities.pl b/bin/patch_capabilities.pl index 91ab4b8..40b6a17 100755 --- a/bin/patch_capabilities.pl +++ b/bin/patch_capabilities.pl @@ -53,6 +53,7 @@ use File::Copy; use File::Spec; +use File::Path; sub Usage() { print("This script can be used to set capabilities of all binaries\n"); @@ -63,11 +64,13 @@ sub Usage() { print(" symbian-sbsv2 platform, 'target-platform' is REQUIRED. ***\n\n"); print(" *** NOTE2: When patching gcce binaries built with symbian-sbsv2 toolchain,\n"); print(" armv5 must be specified as platform.\n"); - print("\nUsage: patch_capabilities.pl [-c] pkg_filename [target-platform [capability list]]\n"); + print("\nUsage: patch_capabilities.pl [-c|-t tmp_path] pkg_filename [target-platform [capability list]]\n"); print("\nE.g. patch_capabilities.pl myapp_template.pkg release-armv5 \"All -TCB\"\n"); print("\nThe parameter -c can be used to just check if package is compatible with self-signing\n"); print("without actually doing any patching.\n"); print("Explicit capability list cannot be used with -c parameter.\n"); + print("\nThe parameter -t can be used to specify a dir under which the temporary files are created.\n"); + print("Defaults to 'patch_capabilities_tmp' under the path to pkg file.\n"); exit(); } @@ -101,6 +104,7 @@ if (@ARGV) my $pkgFileName = shift(@ARGV); my $justCheck = ""; my $msgPrefix = "Patching:"; + my $tempPatchPath = ""; if ($pkgFileName eq "-c") { $pkgFileName = shift(@ARGV); @@ -108,6 +112,18 @@ if (@ARGV) $msgPrefix = "Warning:"; } + if ($pkgFileName eq "-t") { + $tempPatchPath = shift(@ARGV); + $pkgFileName = shift(@ARGV); + } + + my ($pkgVolume, $pkgPath, $pkgPlainFileName) = File::Spec->splitpath($pkgFileName); + if ($tempPatchPath eq "") { + $tempPatchPath = File::Spec->catpath($pkgVolume, $pkgPath."patch_capabilities_tmp", ""); + } + + mkpath($tempPatchPath); + # These variables will only be set for template .pkg files. my $target; my $platform; @@ -165,8 +181,9 @@ if (@ARGV) # Start with no binaries listed. my @binaries = (); + my $binariesDelimeter = "///"; - my $tempPkgFileName = $pkgFileName."_@@TEMP@@"; + my $tempPkgFileName = $tempPatchPath."/__TEMP__".$pkgPlainFileName; if (!$justCheck) { unlink($tempPkgFileName); @@ -216,19 +233,23 @@ if (@ARGV) $sourcePath =~ s/\$\(TARGET\)/$target/gm; } + my ($dummy1, $dummy2, $binaryBaseName) = File::Spec->splitpath($sourcePath); + if ($justCheck) { - push (@binaries, $sourcePath); + push (@binaries, $binaryBaseName.$binariesDelimeter.$sourcePath); } else { - # Change the source file name (but only if not already patched) + # Copy original files over to patching dir + # Patching dir will be flat to make it cleanable with QMAKE_CLEAN, so path + # will be collapsed into the file name to avoid name collisions in the rare + # case where custom pkg rules are used to install files with same names from + # different directories (probably using platform checks to choose only one of them.) my $patchedSourcePath = $sourcePath; - if ($patchedSourcePath !~ m/_patched_caps/) - { - $newLine =~ s/(^.*)(\.dll|\.exe)(.*)(\.dll|\.exe)/$1_patched_caps$2$3$4/i; - $patchedSourcePath =~ s/(^.*)(\.dll|\.exe)/$1_patched_caps$2/i; + $patchedSourcePath =~ s/[\/\\:]/_/g; + $patchedSourcePath = "$tempPatchPath/$patchedSourcePath"; + $newLine =~ s/^.*(\.dll|\.exe)(.*)(\.dll|\.exe)/\"$patchedSourcePath$2$3/i; - copy($sourcePath, $patchedSourcePath) or die "$sourcePath cannot be copied for patching."; - } - push (@binaries, $patchedSourcePath); + copy($sourcePath, $patchedSourcePath) or die "$sourcePath cannot be copied for patching."; + push (@binaries, $binaryBaseName.$binariesDelimeter.$patchedSourcePath); } } } @@ -250,10 +271,13 @@ if (@ARGV) my $baseCommandToExecute = "${epocToolsDir}elftran -vid 0x0 -capability \"%s\" "; # Actually set the capabilities of the listed binaries. - foreach my $binaryPath(@binaries) + foreach my $binariesItem(@binaries) { + $binariesItem =~ m|^(.*)$binariesDelimeter(.*)$|; + my $binaryBaseName = $1; + my $binaryPath = $2; + # Create the command line for setting the capabilities. - my ($binaryVolume, $binaryDirs, $binaryBaseName) = File::Spec->splitpath($binaryPath); my $commandToExecute = $baseCommandToExecute; my $executeNeeded = ""; if (@capabilitiesSpecified) diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index d9f6279..74acc64 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -93,7 +93,7 @@ contains(QMAKE_HOST.os,Windows) { QMAKE_COPY = copy /y QMAKE_COPY_DIR = xcopy /s /q /y /i QMAKE_MOVE = move - QMAKE_DEL_FILE = del 2> NUL + QMAKE_DEL_FILE = del /q 2> NUL QMAKE_MKDIR = mkdir QMAKE_DEL_DIR = rmdir QMAKE_DEL_TREE = rmdir /s /q diff --git a/mkspecs/features/symbian/sis_targets.prf b/mkspecs/features/symbian/sis_targets.prf index 9963b30..d0fe881 100644 --- a/mkspecs/features/symbian/sis_targets.prf +++ b/mkspecs/features/symbian/sis_targets.prf @@ -26,6 +26,9 @@ equals(GENERATE_SIS_TARGETS, true) { qtPrepareTool(QMAKE_CREATEPACKAGE, createpackage) + CREATEPACKAGE_DIR = $$OBJECTS_DIR/createpackage_tmp + QMAKE_CLEAN += $$CREATEPACKAGE_DIR/* + symbian-abld|symbian-sbsv2 { symbian-sbsv2 { CONVERT_GCCE_PARAM = -g @@ -48,7 +51,7 @@ equals(GENERATE_SIS_TARGETS, true) { sis_target.depends += $${baseTarget}_template.pkg ok_sis_target.target = ok_sis - ok_sis_target.commands = $$QMAKE_CREATEPACKAGE $$CONVERT_GCCE_PARAM $(QT_SIS_OPTIONS) $${baseTarget}_template.pkg \ + ok_sis_target.commands = $$QMAKE_CREATEPACKAGE $$CONVERT_GCCE_PARAM -t $$CREATEPACKAGE_DIR $(QT_SIS_OPTIONS) $${baseTarget}_template.pkg \ $(QT_SIS_TARGET) $(QT_SIS_CERTIFICATE) $(QT_SIS_KEY) $(QT_SIS_PASSPHRASE) unsigned_sis_target.target = unsigned_sis @@ -65,7 +68,7 @@ equals(GENERATE_SIS_TARGETS, true) { unsigned_sis_target.depends += $${baseTarget}_template.pkg ok_unsigned_sis_target.target = ok_unsigned_sis - ok_unsigned_sis_target.commands = $$QMAKE_CREATEPACKAGE $$CONVERT_GCCE_PARAM $(QT_SIS_OPTIONS) -o $${baseTarget}_template.pkg $(QT_SIS_TARGET) + ok_unsigned_sis_target.commands = $$QMAKE_CREATEPACKAGE $$CONVERT_GCCE_PARAM -t $$CREATEPACKAGE_DIR $(QT_SIS_OPTIONS) -o $${baseTarget}_template.pkg $(QT_SIS_TARGET) target_sis_target.target = $${baseTarget}.sis target_sis_target.commands = $(MAKE) -f $(MAKEFILE) sis @@ -77,7 +80,7 @@ equals(GENERATE_SIS_TARGETS, true) { installer_sis_target.depends = $${baseTarget}_installer.pkg sis ok_installer_sis_target.target = ok_installer_sis - ok_installer_sis_target.commands = $$QMAKE_CREATEPACKAGE $(QT_SIS_OPTIONS) $${baseTarget}_installer.pkg - \ + ok_installer_sis_target.commands = $$QMAKE_CREATEPACKAGE -t $$CREATEPACKAGE_DIR $(QT_SIS_OPTIONS) $${baseTarget}_installer.pkg - \ $(QT_SIS_CERTIFICATE) $(QT_SIS_KEY) $(QT_SIS_PASSPHRASE) ok_installer_sis_target.depends = $${baseTarget}_installer.pkg @@ -86,7 +89,7 @@ equals(GENERATE_SIS_TARGETS, true) { unsigned_installer_sis_target.depends = $${baseTarget}_installer.pkg unsigned_sis ok_unsigned_installer_sis_target.target = ok_unsigned_installer_sis - ok_unsigned_installer_sis_target.commands = $$QMAKE_CREATEPACKAGE $(QT_SIS_OPTIONS) -o $${baseTarget}_installer.pkg + ok_unsigned_installer_sis_target.commands = $$QMAKE_CREATEPACKAGE -t $$CREATEPACKAGE_DIR $(QT_SIS_OPTIONS) -o $${baseTarget}_installer.pkg ok_unsigned_installer_sis_target.depends = $${baseTarget}_installer.pkg fail_sis_nocache_target.target = fail_sis_nocache @@ -106,7 +109,7 @@ equals(GENERATE_SIS_TARGETS, true) { stub_sis_target.depends += $${baseTarget}_stub.pkg ok_stub_sis_target.target = ok_stub_sis - ok_stub_sis_target.commands = $$QMAKE_CREATEPACKAGE -s $(QT_SIS_OPTIONS) $${baseTarget}_stub.pkg \ + ok_stub_sis_target.commands = $$QMAKE_CREATEPACKAGE -t $$CREATEPACKAGE_DIR -s $(QT_SIS_OPTIONS) $${baseTarget}_stub.pkg \ $(QT_SIS_TARGET) $(QT_SIS_CERTIFICATE) $(QT_SIS_KEY) $(QT_SIS_PASSPHRASE) QMAKE_EXTRA_TARGETS += sis_target \ @@ -150,12 +153,12 @@ equals(GENERATE_SIS_TARGETS, true) { !equals(TARGET, "$$baseTarget"):sis_destdir = $$sis_destdir/$$dirname(TARGET) sis_target.target = sis - sis_target.commands = $$QMAKE_CREATEPACKAGE $(QT_SIS_OPTIONS) $${baseTarget}_template.pkg \ + sis_target.commands = $$QMAKE_CREATEPACKAGE -t $$CREATEPACKAGE_DIR $(QT_SIS_OPTIONS) $${baseTarget}_template.pkg \ - $(QT_SIS_CERTIFICATE) $(QT_SIS_KEY) $(QT_SIS_PASSPHRASE) sis_target.depends = first $${baseTarget}_template.pkg unsigned_sis_target.target = unsigned_sis - unsigned_sis_target.commands = $$QMAKE_CREATEPACKAGE $(QT_SIS_OPTIONS) -o $${baseTarget}_template.pkg + unsigned_sis_target.commands = $$QMAKE_CREATEPACKAGE -t $$CREATEPACKAGE_DIR $(QT_SIS_OPTIONS) -o $${baseTarget}_template.pkg unsigned_sis_target.depends = first $${baseTarget}_template.pkg target_sis_target.target = $${sis_destdir}/$${baseTarget}.sis @@ -166,12 +169,12 @@ equals(GENERATE_SIS_TARGETS, true) { installer_sis_target.depends = $${baseTarget}_installer.pkg sis ok_installer_sis_target.target = ok_installer_sis - ok_installer_sis_target.commands = $$QMAKE_CREATEPACKAGE $(QT_SIS_OPTIONS) $${baseTarget}_installer.pkg - \ + ok_installer_sis_target.commands = $$QMAKE_CREATEPACKAGE -t $$CREATEPACKAGE_DIR $(QT_SIS_OPTIONS) $${baseTarget}_installer.pkg - \ $(QT_SIS_CERTIFICATE) $(QT_SIS_KEY) $(QT_SIS_PASSPHRASE) ok_installer_sis_target.depends = $${baseTarget}_installer.pkg unsigned_installer_sis_target.target = unsigned_installer_sis - unsigned_installer_sis_target.commands = $$QMAKE_CREATEPACKAGE $(QT_SIS_OPTIONS) -o $${baseTarget}_installer.pkg + unsigned_installer_sis_target.commands = $$QMAKE_CREATEPACKAGE -t $$CREATEPACKAGE_DIR $(QT_SIS_OPTIONS) -o $${baseTarget}_installer.pkg unsigned_installer_sis_target.depends = $${baseTarget}_installer.pkg unsigned_sis !isEmpty(sis_destdir):!equals(sis_destdir, "."):!equals(sis_destdir, "./") { -- cgit v0.12 From 5361bd692c74bdd160a08f43da54e5a0b8ae10cc Mon Sep 17 00:00:00 2001 From: Tomi Vihria Date: Mon, 28 Mar 2011 16:29:17 +0300 Subject: Fixed QFtp autotests not to crash in network time out situations QFtp autotests crashes, if tst_QFtp::binaryAscii test case fails with network time out. Then QFtp won't be deleted and its signal-slot connections won't be disconnected. In the beginning of the next test case QFtp pointer is set to 0, but during the case, a signal from the previous case comes and is tried to be handled using the already nulled pointer -> app crashes. Fix makes sure that QFtp pointer is always deleted properly after each test case. Task-number: QT-4614 Reviewed-by: Laszlo Agocs --- tests/auto/qftp/tst_qftp.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/tests/auto/qftp/tst_qftp.cpp b/tests/auto/qftp/tst_qftp.cpp index 1b4b503..64d49d8 100644 --- a/tests/auto/qftp/tst_qftp.cpp +++ b/tests/auto/qftp/tst_qftp.cpp @@ -262,6 +262,10 @@ void tst_QFtp::init() void tst_QFtp::cleanup() { + if (ftp) { + delete ftp; + ftp = 0; + } QFETCH_GLOBAL(bool, setProxy); if (setProxy) { QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); @@ -289,6 +293,7 @@ void tst_QFtp::connectToHost() QTestEventLoop::instance().enterLoop( 61 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -337,6 +342,7 @@ void tst_QFtp::connectToUnresponsiveHost() QVERIFY( it.value().success == 0 ); delete ftp; + ftp = 0; } void tst_QFtp::login_data() @@ -369,6 +375,7 @@ void tst_QFtp::login() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -415,6 +422,7 @@ void tst_QFtp::close() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -482,6 +490,7 @@ void tst_QFtp::list() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -542,6 +551,7 @@ void tst_QFtp::cd() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) { QFAIL( "Network operation timed out" ); } @@ -617,6 +627,7 @@ void tst_QFtp::get() QTestEventLoop::instance().enterLoop( 50 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -743,6 +754,7 @@ void tst_QFtp::put() break; } delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -775,6 +787,7 @@ void tst_QFtp::put() break; } delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -792,6 +805,7 @@ void tst_QFtp::put() QTestEventLoop::instance().enterLoop( timestep ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -860,6 +874,7 @@ void tst_QFtp::mkdir() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -884,6 +899,7 @@ void tst_QFtp::mkdir() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -903,6 +919,7 @@ void tst_QFtp::mkdir() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -942,6 +959,7 @@ void tst_QFtp::mkdir2() QVERIFY(commandFinishedSpy.at(3).at(1).toBool()); delete ftp; + ftp = 0; } void tst_QFtp::mkdir2Slot(int id, bool) @@ -1019,6 +1037,7 @@ void tst_QFtp::renameInit( const QString &host, const QString &user, const QStri QTestEventLoop::instance().enterLoop( 50 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1043,6 +1062,7 @@ void tst_QFtp::renameCleanup( const QString &host, const QString &user, const QS QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1087,6 +1107,7 @@ void tst_QFtp::rename() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1273,6 +1294,7 @@ void tst_QFtp::commandSequence() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1330,6 +1352,7 @@ void tst_QFtp::abort() break; } delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1367,6 +1390,7 @@ void tst_QFtp::abort() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1425,6 +1449,7 @@ void tst_QFtp::bytesAvailable() ftp->readAll(); QVERIFY( ftp->bytesAvailable() == 0 ); delete ftp; + ftp = 0; } void tst_QFtp::activeMode() @@ -1497,6 +1522,7 @@ void tst_QFtp::proxy() QTestEventLoop::instance().enterLoop( 50 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) { QFAIL( "Network operation timed out" ); } @@ -1531,6 +1557,8 @@ void tst_QFtp::binaryAscii() addCommand(QFtp::Close, ftp->close()); QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1551,6 +1579,8 @@ void tst_QFtp::binaryAscii() addCommand(QFtp::Close, ftp->close()); QTestEventLoop::instance().enterLoop( 30 ); + delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1573,6 +1603,7 @@ void tst_QFtp::binaryAscii() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1920,6 +1951,7 @@ bool tst_QFtp::fileExists( const QString &host, quint16 port, const QString &use inFileDirExistsFunction = TRUE; QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) { // ### make this test work qWarning("tst_QFtp::fileExists: Network operation timed out"); @@ -1970,6 +2002,7 @@ bool tst_QFtp::dirExists( const QString &host, quint16 port, const QString &user inFileDirExistsFunction = TRUE; QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) { // ### make this test work // QFAIL( "Network operation timed out" ); @@ -1996,8 +2029,11 @@ void tst_QFtp::doneSignal() ftp.close(); done_success = 0; - while ( ftp.hasPendingCommands() ) - QCoreApplication::instance()->processEvents(); + connect(&ftp, SIGNAL(done(bool)), &(QTestEventLoop::instance()), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(61); + if (QTestEventLoop::instance().timeout()) + QFAIL("Network operation timed out"); + QTest::qWait(200); QCOMPARE(spy.count(), 1); -- cgit v0.12