summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread
diff options
context:
space:
mode:
authormread <qt-info@nokia.com>2011-02-09 08:18:36 +0000
committermread <qt-info@nokia.com>2011-03-09 12:45:07 +0000
commit834ad29849ebef99d7e5c516cde26d550abff7cd (patch)
treec3da2435c2bb23948eaff22c93f7f70fcd2c9aea /src/corelib/thread
parentf351340d328a896829779794e8810f0d913161fb (diff)
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
Diffstat (limited to 'src/corelib/thread')
-rw-r--r--src/corelib/thread/qmutex_p.h13
-rw-r--r--src/corelib/thread/qmutex_symbian.cpp104
-rw-r--r--src/corelib/thread/qthread_symbian.cpp545
-rw-r--r--src/corelib/thread/qthread_unix.cpp145
-rw-r--r--src/corelib/thread/qwaitcondition_symbian.cpp210
-rw-r--r--src/corelib/thread/qwaitcondition_unix.cpp2
-rw-r--r--src/corelib/thread/thread.pri30
7 files changed, 891 insertions, 158 deletions
diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h
index 1a31c870ee..789d1f0f25 100644
--- a/src/corelib/thread/qmutex_p.h
+++ b/src/corelib/thread/qmutex_p.h
@@ -62,6 +62,11 @@
# include <mach/semaphore.h>
#endif
+#if defined(Q_OS_SYMBIAN)
+# include <e32std.h>
+#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 0000000000..e7487cd675
--- /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 <qdebug.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)
+{
+#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 0000000000..4a7a2049df
--- /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 <private/qcoreapplication_p.h>
+#if !defined(QT_NO_GLIB)
+# include "../kernel/qeventdispatcher_glib_p.h"
+#endif
+
+#include <private/qeventdispatcher_symbian_p.h>
+
+#include "qthreadstorage.h"
+
+#include "qthread_p.h"
+
+#include "qdebug.h"
+
+#include <sched.h>
+#include <errno.h>
+
+#ifdef Q_OS_BSD4
+#include <sys/sysctl.h>
+#endif
+#ifdef Q_OS_VXWORKS
+# if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
+# include <vxCpuLib.h>
+# include <cpuset.h>
+# define QT_VXWORKS_HAS_CPUSET
+# endif
+#endif
+
+#ifdef Q_OS_HPUX
+#include <sys/pstat.h>
+#endif
+
+#if defined(Q_OS_MAC)
+# ifdef qDebug
+# define old_qDebug qDebug
+# undef qDebug
+# endif
+#ifndef QT_NO_CORESERVICES
+# include <CoreServices/CoreServices.h>
+#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<QThreadData *>(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(&current_thread_data_key, destroy_current_thread_data);
+}
+
+static void destroy_current_thread_data_key()
+{
+ pthread_once(&current_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<QThreadData *>(Dll::Tls());
+}
+
+static void set_thread_data(QThreadData *data)
+{
+ qt_symbian_throwIfError(Dll::SetTls(data));
+// pthread_once(&current_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<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;
+}
+
+
+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<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));
+ }
+
+ // 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<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();
+}
+
+#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 0766447fd4..2f133152db 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 <private/qeventdispatcher_symbian_p.h>
-#else
#include <private/qeventdispatcher_unix_p.h>
-#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<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));
-#endif
}
static void set_thread_data(QThreadData *data)
{
-#ifdef 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);
}
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<QThread *>(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<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;
@@ -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 0000000000..83fa597ca3
--- /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 <errno.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;
+ 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 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 03f661d353..787d709831 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