summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread
diff options
context:
space:
mode:
authorThierry Bastian <thierry.bastian@nokia.com>2011-04-19 15:55:10 +0200
committerThierry Bastian <thierry.bastian@nokia.com>2011-04-19 15:55:10 +0200
commitf540574b44aa874af22ce8b15598b854f28517d7 (patch)
tree6e7b375107fdfeee54516ebc0cd52837a32035eb /src/corelib/thread
parent364ce5b7f5379499562b4f4f5a68da7ba068fe1e (diff)
parent8485052e3991aebf7c823b3e80fc06ccf9f08991 (diff)
Merge branch 'master-upstream'
Diffstat (limited to 'src/corelib/thread')
-rw-r--r--src/corelib/thread/qmutex_p.h8
-rw-r--r--src/corelib/thread/qmutex_symbian.cpp101
-rw-r--r--src/corelib/thread/qmutexpool.cpp22
-rw-r--r--src/corelib/thread/qmutexpool_p.h10
-rw-r--r--src/corelib/thread/qthread.cpp9
-rw-r--r--src/corelib/thread/qthread_p.h3
-rw-r--r--src/corelib/thread/qthread_symbian.cpp599
-rw-r--r--src/corelib/thread/qthread_unix.cpp178
-rw-r--r--src/corelib/thread/qthread_win.cpp15
-rw-r--r--src/corelib/thread/qwaitcondition_symbian.cpp196
-rw-r--r--src/corelib/thread/qwaitcondition_unix.cpp2
-rw-r--r--src/corelib/thread/thread.pri28
12 files changed, 974 insertions, 197 deletions
diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h
index 1a31c870ee..70860b149e 100644
--- a/src/corelib/thread/qmutex_p.h
+++ b/src/corelib/thread/qmutex_p.h
@@ -62,6 +62,10 @@
# include <mach/semaphore.h>
#endif
+#if defined(Q_OS_SYMBIAN)
+# include <e32std.h>
+#endif
+
QT_BEGIN_NAMESPACE
class QMutexPrivate : public QMutexData {
@@ -81,12 +85,14 @@ 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)
+ RSemaphore lock;
#endif
};
diff --git a/src/corelib/thread/qmutex_symbian.cpp b/src/corelib/thread/qmutex_symbian.cpp
new file mode 100644
index 0000000000..288c576d02
--- /dev/null
+++ b/src/corelib/thread/qmutex_symbian.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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"
+
+#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)
+{
+ int r = lock.CreateLocal(0);
+ if (r != KErrNone)
+ qWarning("QMutex: failed to create lock, error %d", r);
+ qt_symbian_throwIfError(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;
+ // 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);
+ contenders.deref();
+ return returnValue;
+}
+
+void QMutexPrivate::wakeUp()
+{
+ lock.Signal();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_THREAD
diff --git a/src/corelib/thread/qmutexpool.cpp b/src/corelib/thread/qmutexpool.cpp
index 13e29c328a..144fa35137 100644
--- a/src/corelib/thread/qmutexpool.cpp
+++ b/src/corelib/thread/qmutexpool.cpp
@@ -123,22 +123,20 @@ QMutexPool *QMutexPool::instance()
return globalMutexPool();
}
-/*!
+/*! \fn QMutexPool::get(void *address)
Returns a QMutex from the pool. QMutexPool uses the value \a address
to determine which mutex is returned from the pool.
*/
-QMutex *QMutexPool::get(const void *address)
-{
- Q_ASSERT_X(address != 0, "QMutexPool::get()", "'address' argument cannot be zero");
- int index = int((quintptr(address) >> (sizeof(address) >> 1)) % mutexes.count());
-
- if (!mutexes[index]) {
- // mutex not created, create one
- QMutex *newMutex = new QMutex(recursionMode);
- if (!mutexes[index].testAndSetOrdered(0, newMutex))
- delete newMutex;
- }
+/*! \internal
+ create the mutex for the given index
+ */
+QMutex *QMutexPool::createMutex(int index)
+{
+ // mutex not created, create one
+ QMutex *newMutex = new QMutex(recursionMode);
+ if (!mutexes[index].testAndSetOrdered(0, newMutex))
+ delete newMutex;
return mutexes[index];
}
diff --git a/src/corelib/thread/qmutexpool_p.h b/src/corelib/thread/qmutexpool_p.h
index 1a45ba927f..b2cd210d71 100644
--- a/src/corelib/thread/qmutexpool_p.h
+++ b/src/corelib/thread/qmutexpool_p.h
@@ -67,11 +67,19 @@ public:
explicit QMutexPool(QMutex::RecursionMode recursionMode = QMutex::NonRecursive, int size = 131);
~QMutexPool();
- QMutex *get(const void *address);
+ inline QMutex *get(const void *address) {
+ int index = uint(quintptr(address)) % mutexes.count();
+ QMutex *m = mutexes[index];
+ if (m)
+ return m;
+ else
+ return createMutex(index);
+ }
static QMutexPool *instance();
static QMutex *globalInstanceGet(const void *address);
private:
+ QMutex *createMutex(int index);
QVarLengthArray<QAtomicPointer<QMutex>, 131> mutexes;
QMutex::RecursionMode recursionMode;
};
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index 326f4948aa..aaa1e6dc36 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -77,8 +77,8 @@ QT_BEGIN_NAMESPACE
*/
QThreadData::QThreadData(int initialRefCount)
- : _ref(initialRefCount), thread(0),
- quitNow(false), loopLevel(0), eventDispatcher(0), canWait(true)
+ : _ref(initialRefCount), thread(0), threadId(0),
+ quitNow(false), loopLevel(0), eventDispatcher(0), canWait(true), isAdopted(false)
{
// fprintf(stderr, "QThreadData %p created\n", this);
}
@@ -149,9 +149,6 @@ QAdoptedThread::QAdoptedThread(QThreadData *data)
QAdoptedThread::~QAdoptedThread()
{
-#ifndef QT_NO_THREAD
- QThreadPrivate::finish(this);
-#endif
// fprintf(stderr, "~QAdoptedThread = %p\n", this);
}
@@ -409,7 +406,7 @@ QThread::~QThread()
wait();
locker.relock();
}
- if (d->running && !d->finished)
+ if (d->running && !d->finished && !d->data->isAdopted)
qWarning("QThread: Destroyed while thread is still running");
d->data->thread = 0;
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
index 36e07c0285..b43a456919 100644
--- a/src/corelib/thread/qthread_p.h
+++ b/src/corelib/thread/qthread_p.h
@@ -146,6 +146,7 @@ public:
#else
static void finish(void *);
#endif
+
#endif // Q_OS_UNIX
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
@@ -201,6 +202,7 @@ public:
void deref();
QThread *thread;
+ Qt::HANDLE threadId;
bool quitNow;
int loopLevel;
QAbstractEventDispatcher *eventDispatcher;
@@ -208,6 +210,7 @@ public:
QPostEventList postEventList;
bool canWait;
QVector<void *> tls;
+ bool isAdopted;
# ifdef Q_OS_SYMBIAN
RThread symbian_thread_handle;
diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp
new file mode 100644
index 0000000000..1474b3613a
--- /dev/null
+++ b/src/corelib/thread/qthread_symbian.cpp
@@ -0,0 +1,599 @@
+/****************************************************************************
+**
+** 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 <private/qcoreapplication_p.h>
+#include <private/qeventdispatcher_symbian_p.h>
+#include "qthreadstorage.h"
+#include "qthread_p.h"
+#include <private/qsystemerror_p.h>
+
+#include <sched.h>
+#include <hal.h>
+#include <hal_data.h>
+
+// 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
+
+#ifndef QT_NO_THREAD
+
+enum { ThreadPriorityResetFlag = 0x80000000 };
+
+// Utility functions for getting, setting and clearing thread specific data.
+static QThreadData *get_thread_data()
+{
+ return reinterpret_cast<QThreadData *>(Dll::Tls());
+}
+
+static void set_thread_data(QThreadData *data)
+{
+ qt_symbian_throwIfError(Dll::SetTls(data));
+}
+
+static void clear_thread_data()
+{
+ Dll::FreeTls();
+}
+
+
+static void init_symbian_thread_handle(RThread &thread)
+{
+ thread = RThread();
+ TThreadId threadId = thread.Id();
+ qt_symbian_throwIfError(thread.Open(threadId, EOwnerProcess));
+}
+
+QThreadData *QThreadData::current()
+{
+ QThreadData *data = get_thread_data();
+ if (!data) {
+ void *a;
+ if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, &a)) {
+ QThread *adopted = static_cast<QThread*>(a);
+ Q_ASSERT(adopted);
+ data = QThreadData::get2(adopted);
+ set_thread_data(data);
+ adopted->d_func()->running = true;
+ adopted->d_func()->finished = false;
+ static_cast<QAdoptedThread *>(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;
+}
+
+
+class QCAdoptedThreadMonitor : public CActive
+{
+public:
+ QCAdoptedThreadMonitor(QThread *thread)
+ : CActive(EPriorityStandard), data(QThreadData::get2(thread))
+ {
+ CActiveScheduler::Add(this);
+ data->symbian_thread_handle.Logon(iStatus);
+ SetActive();
+ }
+ ~QCAdoptedThreadMonitor()
+ {
+ Cancel();
+ }
+ void DoCancel()
+ {
+ data->symbian_thread_handle.LogonCancel(iStatus);
+ }
+ void RunL();
+private:
+ QThreadData* data;
+};
+
+class QCAddAdoptedThread : public CActive
+{
+public:
+ QCAddAdoptedThread()
+ : CActive(EPriorityStandard)
+ {
+ CActiveScheduler::Add(this);
+ }
+ void ConstructL()
+ {
+ User::LeaveIfError(monitorThread.Open(RThread().Id()));
+ start();
+ }
+ ~QCAddAdoptedThread()
+ {
+ Cancel();
+ monitorThread.Close();
+ }
+ void DoCancel()
+ {
+ User::RequestComplete(stat, KErrCancel);
+ }
+ void start()
+ {
+ iStatus = KRequestPending;
+ SetActive();
+ stat = &iStatus;
+ }
+ void RunL()
+ {
+ 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]);
+ count++;
+ threadsToAdd.pop_back();
+ }
+ start();
+ }
+ static void add(QThread *thread)
+ {
+ 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();
+ }
+ if (RThread().Id() == adoptedThreadAdder->monitorThread.Id())
+ return;
+ adoptedThreadAdder->threadsToAdd.push_back(thread);
+ if (adoptedThreadAdder->stat) {
+ adoptedThreadAdder->monitorThread.RequestComplete(adoptedThreadAdder->stat, KErrNone);
+ }
+ }
+ static void monitorThreadFuncL()
+ {
+ CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
+ CleanupStack::PushL(scheduler);
+ CActiveScheduler::Install(scheduler);
+
+ adoptedThreadAdder = new(ELeave) QCAddAdoptedThread();
+ CleanupStack::PushL(adoptedThreadAdder);
+ adoptedThreadAdder->ConstructL();
+ QCAddAdoptedThread *adder = adoptedThreadAdder;
+
+ RThread::Rendezvous(KErrNone);
+ CActiveScheduler::Start();
+
+ CleanupStack::PopAndDestroy(adder);
+ CleanupStack::PopAndDestroy(scheduler);
+ }
+ static int monitorThreadFunc(void *)
+ {
+ _LIT(KMonitorThreadName, "adoptedMonitorThread");
+ RThread::RenameMe(KMonitorThreadName());
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+ TRAPD(ret, monitorThreadFuncL());
+ 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<QThread*> threadsToAdd;
+ RThread monitorThread;
+ static QMutex adoptedThreadMonitorMutex;
+ 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);
+ d->thread_id = RThread().Id(); // type operator to TUint
+ init_symbian_thread_handle(d->data->symbian_thread_handle);
+ QCAddAdoptedThread::add(this);
+}
+
+/*
+ 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<QThread *>(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));
+ }
+
+ // 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);
+
+ {
+ QMutexLocker locker(&thr->d_func()->mutex);
+ data->quitNow = thr->d_func()->exited;
+ }
+
+ // ### 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<QThread *>(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();
+}
+
+int QThread::idealThreadCount()
+{
+ 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;
+}
+
+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:
+ symPriority = EPriorityMuchMore;
+ break;
+ case QThread::InheritPriority:
+ default:
+ symPriority = RThread().Priority();
+ 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 = 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 {
+ qWarning("QThread::start: Thread creation error: %s", qPrintable(QSystemError(code, QSystemError::NativeError).toString()));
+
+ 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 811a1932d6..044eb05913 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -48,16 +48,7 @@
# include "../kernel/qeventdispatcher_glib_p.h"
#endif
-#ifdef Q_OS_SYMBIAN
-#include <private/qeventdispatcher_symbian_p.h>
-#else
#include <private/qeventdispatcher_unix_p.h>
-#endif
-
-#ifdef Q_OS_SYMBIAN
-#include <hal.h>
-#include <hal_data.h>
-#endif
#include "qthreadstorage.h"
@@ -68,12 +59,6 @@
#include <sched.h>
#include <errno.h>
-// 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 <sys/sysctl.h>
#endif
@@ -148,7 +133,16 @@ static void destroy_current_thread_data(void *p)
// this destructor function, so we need to set it back to the
// right value...
pthread_setspecific(current_thread_data_key, p);
- reinterpret_cast<QThreadData *>(p)->deref();
+ QThreadData *data = static_cast<QThreadData *>(p);
+ if (data->isAdopted) {
+ QThread *thread = data->thread;
+ Q_ASSERT(thread);
+ QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
+ Q_ASSERT(!thread_p->finished);
+ thread_p->finish(thread);
+ }
+ data->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)
@@ -174,15 +168,10 @@ 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 HAVE_TLS
return currentThreadData;
-#elif defined Q_OS_SYMBIAN
- return reinterpret_cast<QThreadData *>(Dll::Tls());
#else
pthread_once(&current_thread_data_once, create_current_thread_data_key);
return reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key));
@@ -193,8 +182,6 @@ static void set_thread_data(QThreadData *data)
{
#ifdef HAVE_TLS
currentThreadData = data;
-#elif defined Q_OS_SYMBIAN
- qt_symbian_throwIfError(Dll::SetTls(data));
#endif
pthread_once(&current_thread_data_once, create_current_thread_data_key);
pthread_setspecific(current_thread_data_key, data);
@@ -204,27 +191,10 @@ static void clear_thread_data()
{
#ifdef HAVE_TLS
currentThreadData = 0;
-#elif defined 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();
@@ -251,6 +221,8 @@ QThreadData *QThreadData::current()
}
data->deref();
}
+ data->isAdopted = true;
+ data->threadId = (Qt::HANDLE)pthread_self();
if (!QCoreApplicationPrivate::theMainThread)
QCoreApplicationPrivate::theMainThread = data->thread;
}
@@ -262,9 +234,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
}
/*
@@ -292,11 +261,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();
}
@@ -304,11 +269,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<QThread *>(arg);
QThreadData *data = QThreadData::get2(thr);
@@ -318,23 +280,7 @@ 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
-
+ data->threadId = (Qt::HANDLE)pthread_self();
set_thread_data(data);
data->ref();
@@ -347,35 +293,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<QThread *>(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;
@@ -400,10 +332,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;
@@ -461,21 +389,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)
@@ -616,8 +529,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:
{
@@ -659,12 +571,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)
@@ -690,9 +596,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);
}
@@ -705,9 +609,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
}
}
@@ -719,7 +620,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",
@@ -727,26 +627,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)
@@ -763,18 +643,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;
}
@@ -786,25 +654,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/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp
index 44e8958d15..bdade1d24e 100644
--- a/src/corelib/thread/qthread_win.cpp
+++ b/src/corelib/thread/qthread_win.cpp
@@ -124,6 +124,8 @@ QThreadData *QThreadData::current()
}
threadData->deref();
}
+ threadData->isAdopted = true;
+ threadData->threadId = (Qt::HANDLE)GetCurrentThreadId();
if (!QCoreApplicationPrivate::theMainThread) {
QCoreApplicationPrivate::theMainThread = threadData->thread;
@@ -231,7 +233,17 @@ void qt_adopted_thread_watcher_function(void *)
} else {
// printf("(qt) - qt_adopted_thread_watcher_function... called\n");
const int qthreadIndex = handleIndex - 1;
- QThreadData::get2(qt_adopted_qthreads.at(qthreadIndex))->deref();
+
+ QThreadData *data = QThreadData::get2(qt_adopted_qthreads.at(qthreadIndex));
+ if (data->isAdopted) {
+ QThread *thread = data->thread;
+ Q_ASSERT(thread);
+ QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
+ Q_ASSERT(!thread_p->finished);
+ thread_p->finish(thread);
+ }
+ data->deref();
+
#if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600))
CloseHandle(qt_adopted_thread_handles.at(handleIndex));
#endif
@@ -295,6 +307,7 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi
qt_create_tls();
TlsSetValue(qt_current_thread_data_tls_index, data);
+ data->threadId = (Qt::HANDLE)GetCurrentThreadId();
QThread::setTerminationEnabled(false);
diff --git a/src/corelib/thread/qwaitcondition_symbian.cpp b/src/corelib/thread/qwaitcondition_symbian.cpp
new file mode 100644
index 0000000000..9967382735
--- /dev/null
+++ b/src/corelib/thread/qwaitcondition_symbian.cpp
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** 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.h"
+
+#include "qmutex_p.h"
+#include "qreadwritelock_p.h"
+
+#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;
+
+ QWaitConditionPrivate()
+ : waiters(0), wakeups(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 {
+ err = cond.Wait(mutex);
+ } 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
+ 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);
+ } 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->mutex.Signal();
+}
+
+void QWaitCondition::wakeAll()
+{
+ d->mutex.Wait();
+ d->wakeups = d->waiters;
+ d->cond.Broadcast();
+ d->mutex.Signal();
+}
+
+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 f06a158622..d0f23b5342 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 90583bbbbc..592ab1644b 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,14 +19,18 @@ 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:SOURCES += thread/qmutex_unix.cpp \
- thread/qthread_unix.cpp \
- thread/qwaitcondition_unix.cpp
+unix:!symbian: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 \