summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/corelib/thread
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/corelib/thread')
-rw-r--r--src/corelib/thread/qatomic.cpp1125
-rw-r--r--src/corelib/thread/qatomic.h227
-rw-r--r--src/corelib/thread/qbasicatomic.h230
-rw-r--r--src/corelib/thread/qmutex.cpp515
-rw-r--r--src/corelib/thread/qmutex.h248
-rw-r--r--src/corelib/thread/qmutex_p.h107
-rw-r--r--src/corelib/thread/qmutex_symbian.cpp101
-rw-r--r--src/corelib/thread/qmutex_unix.cpp209
-rw-r--r--src/corelib/thread/qmutex_win.cpp75
-rw-r--r--src/corelib/thread/qmutexpool.cpp156
-rw-r--r--src/corelib/thread/qmutexpool_p.h93
-rw-r--r--src/corelib/thread/qorderedmutexlocker_p.h121
-rw-r--r--src/corelib/thread/qreadwritelock.cpp581
-rw-r--r--src/corelib/thread/qreadwritelock.h239
-rw-r--r--src/corelib/thread/qreadwritelock_p.h87
-rw-r--r--src/corelib/thread/qsemaphore.cpp240
-rw-r--r--src/corelib/thread/qsemaphore.h83
-rw-r--r--src/corelib/thread/qthread.cpp772
-rw-r--r--src/corelib/thread/qthread.h166
-rw-r--r--src/corelib/thread/qthread_p.h237
-rw-r--r--src/corelib/thread/qthread_symbian.cpp609
-rw-r--r--src/corelib/thread/qthread_unix.cpp716
-rw-r--r--src/corelib/thread/qthread_win.cpp637
-rw-r--r--src/corelib/thread/qthreadstorage.cpp329
-rw-r--r--src/corelib/thread/qthreadstorage.h164
-rw-r--r--src/corelib/thread/qwaitcondition.h105
-rw-r--r--src/corelib/thread/qwaitcondition.qdoc173
-rw-r--r--src/corelib/thread/qwaitcondition_symbian.cpp196
-rw-r--r--src/corelib/thread/qwaitcondition_unix.cpp192
-rw-r--r--src/corelib/thread/qwaitcondition_win.cpp233
-rw-r--r--src/corelib/thread/thread.pri41
31 files changed, 9007 insertions, 0 deletions
diff --git a/src/corelib/thread/qatomic.cpp b/src/corelib/thread/qatomic.cpp
new file mode 100644
index 0000000000..dd8853b90e
--- /dev/null
+++ b/src/corelib/thread/qatomic.cpp
@@ -0,0 +1,1125 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+/*!
+ \class QAtomicInt
+ \brief The QAtomicInt class provides platform-independent atomic operations on integers.
+ \since 4.4
+
+ \ingroup thread
+
+ For atomic operations on pointers, see the QAtomicPointer class.
+
+ An \e atomic operation is a complex operation that completes without interruption.
+ The QAtomicInt class provides atomic reference counting, test-and-set, fetch-and-store,
+ and fetch-and-add for integers.
+
+ \section1 Non-atomic convenience operators
+
+ For convenience, QAtomicInt provides integer comparison, cast, and
+ assignment operators. Note that a combination of these operators
+ is \e not an atomic operation.
+
+ \section1 The Atomic API
+
+ \section2 Reference counting
+
+ The ref() and deref() functions provide an efficient reference
+ counting API. The return value of these functions are used to
+ indicate when the last reference has been released. These
+ functions allow you to implement your own implicitly shared
+ classes.
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qatomic.cpp 0
+
+ \section2 Memory ordering
+
+ QAtomicInt provides several implementations of the atomic
+ test-and-set, fetch-and-store, and fetch-and-add functions. Each
+ implementation defines a memory ordering semantic that describes
+ how memory accesses surrounding the atomic instruction are
+ executed by the processor. Since many modern architectures allow
+ out-of-order execution and memory ordering, using the correct
+ semantic is necessary to ensure that your application functions
+ properly on all processors.
+
+ \list
+
+ \o Relaxed - memory ordering is unspecified, leaving the compiler
+ and processor to freely reorder memory accesses.
+
+ \o Acquire - memory access following the atomic operation (in
+ program order) may not be re-ordered before the atomic operation.
+
+ \o Release - memory access before the atomic operation (in program
+ order) may not be re-ordered after the atomic operation.
+
+ \o Ordered - the same Acquire and Release semantics combined.
+
+ \endlist
+
+ \section2 Test-and-set
+
+ If the current value of the QAtomicInt is an expected value, the
+ test-and-set functions assign a new value to the QAtomicInt and
+ return true. If values are \a not the same, these functions do
+ nothing and return false. This operation equates to the following
+ code:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qatomic.cpp 1
+
+ There are 4 test-and-set functions: testAndSetRelaxed(),
+ testAndSetAcquire(), testAndSetRelease(), and
+ testAndSetOrdered(). See above for an explanation of the different
+ memory ordering semantics.
+
+ \section2 Fetch-and-store
+
+ The atomic fetch-and-store functions read the current value of the
+ QAtomicInt and then assign a new value, returning the original
+ value. This operation equates to the following code:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qatomic.cpp 2
+
+ There are 4 fetch-and-store functions: fetchAndStoreRelaxed(),
+ fetchAndStoreAcquire(), fetchAndStoreRelease(), and
+ fetchAndStoreOrdered(). See above for an explanation of the
+ different memory ordering semantics.
+
+ \section2 Fetch-and-add
+
+ The atomic fetch-and-add functions read the current value of the
+ QAtomicInt and then add the given value to the current value,
+ returning the original value. This operation equates to the
+ following code:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qatomic.cpp 3
+
+ There are 4 fetch-and-add functions: fetchAndAddRelaxed(),
+ fetchAndAddAcquire(), fetchAndAddRelease(), and
+ fetchAndAddOrdered(). See above for an explanation of the
+ different memory ordering semantics.
+
+ \section1 Feature Tests for the Atomic API
+
+ Providing a platform-independent atomic API that works on all
+ processors is challenging. The API provided by QAtomicInt is
+ guaranteed to work atomically on all processors. However, since
+ not all processors implement support for every operation provided
+ by QAtomicInt, it is necessary to expose information about the
+ processor.
+
+ You can check at compile time which features are supported on your
+ hardware using various macros. These will tell you if your
+ hardware always, sometimes, or does not support a particular
+ operation. The macros have the form
+ Q_ATOMIC_INT_\e{OPERATION}_IS_\e{HOW}_NATIVE. \e{OPERATION}
+ is one of REFERENCE_COUNTING, TEST_AND_SET,
+ FETCH_AND_STORE, or FETCH_AND_ADD, and \e{HOW} is one of
+ ALWAYS, SOMETIMES, or NOT. There will always be exactly one
+ defined macro per operation. For example, if
+ Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE is defined,
+ neither Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE nor
+ Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE will be defined.
+
+ An operation that completes in constant time is said to be
+ wait-free. Such operations are not implemented using locks or
+ loops of any kind. For atomic operations that are always
+ supported, and that are wait-free, Qt defines the
+ Q_ATOMIC_INT_\e{OPERATION}_IS_WAIT_FREE in addition to the
+ Q_ATOMIC_INT_\e{OPERATION}_IS_ALWAYS_NATIVE.
+
+ In cases where an atomic operation is only supported in newer
+ generations of the processor, QAtomicInt also provides a way to
+ check at runtime what your hardware supports with the
+ isReferenceCountingNative(), isTestAndSetNative(),
+ isFetchAndStoreNative(), and isFetchAndAddNative()
+ functions. Wait-free implementations can be detected using the
+ isReferenceCountingWaitFree(), isTestAndSetWaitFree(),
+ isFetchAndStoreWaitFree(), and isFetchAndAddWaitFree() functions.
+
+ Below is a complete list of all feature macros for QAtomicInt:
+
+ \list
+
+ \o Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
+ \o Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE
+ \o Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE
+ \o Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE
+
+ \o Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE
+ \o Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE
+ \o Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE
+ \o Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE
+
+ \o Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE
+ \o Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE
+ \o Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE
+ \o Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE
+
+ \o Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE
+ \o Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE
+ \o Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE
+ \o Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE
+
+ \endlist
+
+ \sa QAtomicPointer
+*/
+
+/*! \fn QAtomicInt::QAtomicInt(int value)
+
+ Constructs a QAtomicInt with the given \a value.
+*/
+
+/*! \fn QAtomicInt::QAtomicInt(const QAtomicInt &other)
+
+ Constructs a copy of \a other.
+*/
+
+/*! \fn QAtomicInt &QAtomicInt::operator=(int value)
+
+ Assigns the \a value to this QAtomicInt and returns a reference to
+ this QAtomicInt.
+*/
+
+/*! \fn QAtomicInt &QAtomicInt::operator=(const QAtomicInt &other)
+
+ Assigns \a other to this QAtomicInt and returns a reference to
+ this QAtomicInt.
+*/
+
+/*! \fn bool QAtomicInt::operator==(int value) const
+
+ Returns true if the \a value is equal to the value in this
+ QAtomicInt; otherwise returns false.
+*/
+
+/*! \fn bool QAtomicInt::operator!=(int value) const
+
+ Returns true if the value of this QAtomicInt is not equal to \a
+ value; otherwise returns false.
+*/
+
+/*! \fn bool QAtomicInt::operator!() const
+
+ Returns true is the value of this QAtomicInt is zero; otherwise
+ returns false.
+*/
+
+/*! \fn QAtomicInt::operator int() const
+
+ Returns the value stored by the QAtomicInt object as an integer.
+*/
+
+/*! \fn bool QAtomicInt::isReferenceCountingNative()
+
+ Returns true if reference counting is implemented using atomic
+ processor instructions, false otherwise.
+*/
+
+/*! \fn bool QAtomicInt::isReferenceCountingWaitFree()
+
+ Returns true if atomic reference counting is wait-free, false
+ otherwise.
+*/
+
+/*! \fn bool QAtomicInt::ref()
+ Atomically increments the value of this QAtomicInt. Returns true
+ if the new value is non-zero, false otherwise.
+
+ This function uses \e ordered \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before and after the atomic operation (in program order)
+ may not be re-ordered.
+
+ \sa deref()
+*/
+
+/*! \fn bool QAtomicInt::deref()
+ Atomically decrements the value of this QAtomicInt. Returns true
+ if the new value is non-zero, false otherwise.
+
+ This function uses \e ordered \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before and after the atomic operation (in program order)
+ may not be re-ordered.
+
+ \sa ref()
+*/
+
+/*! \fn bool QAtomicInt::isTestAndSetNative()
+
+ Returns true if test-and-set is implemented using atomic processor
+ instructions, false otherwise.
+*/
+
+/*! \fn bool QAtomicInt::isTestAndSetWaitFree()
+
+ Returns true if atomic test-and-set is wait-free, false otherwise.
+*/
+
+/*! \fn bool QAtomicInt::testAndSetRelaxed(int expectedValue, int newValue)
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInt is the \a expectedValue,
+ the test-and-set functions assign the \a newValue to this
+ QAtomicInt and return true. If the values are \e not the same,
+ this function does nothing and returns false.
+
+ This function uses \e relaxed \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, leaving the compiler and
+ processor to freely reorder memory accesses.
+*/
+
+/*! \fn bool QAtomicInt::testAndSetAcquire(int expectedValue, int newValue)
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInt is the \a expectedValue,
+ the test-and-set functions assign the \a newValue to this
+ QAtomicInt and return true. If the values are \e not the same,
+ this function does nothing and returns false.
+
+ This function uses \e acquire \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access following the atomic operation (in program order) may not
+ be re-ordered before the atomic operation.
+*/
+
+/*! \fn bool QAtomicInt::testAndSetRelease(int expectedValue, int newValue)
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInt is the \a expectedValue,
+ the test-and-set functions assign the \a newValue to this
+ QAtomicInt and return true. If the values are \e not the same,
+ this function does nothing and returns false.
+
+ This function uses \e release \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before the atomic operation (in program order) may not be
+ re-ordered after the atomic operation.
+*/
+
+/*! \fn bool QAtomicInt::testAndSetOrdered(int expectedValue, int newValue)
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInt is the \a expectedValue,
+ the test-and-set functions assign the \a newValue to this
+ QAtomicInt and return true. If the values are \e not the same,
+ this function does nothing and returns false.
+
+ This function uses \e ordered \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before and after the atomic operation (in program order)
+ may not be re-ordered.
+*/
+
+/*! \fn bool QAtomicInt::isFetchAndStoreNative()
+
+ Returns true if fetch-and-store is implemented using atomic
+ processor instructions, false otherwise.
+*/
+
+/*! \fn bool QAtomicInt::isFetchAndStoreWaitFree()
+
+ Returns true if atomic fetch-and-store is wait-free, false
+ otherwise.
+*/
+
+/*! \fn int QAtomicInt::fetchAndStoreRelaxed(int newValue)
+
+ Atomic fetch-and-store.
+
+ Reads the current value of this QAtomicInt and then assigns it the
+ \a newValue, returning the original value.
+
+ This function uses \e relaxed \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, leaving the compiler and
+ processor to freely reorder memory accesses.
+*/
+
+/*! \fn int QAtomicInt::fetchAndStoreAcquire(int newValue)
+
+ Atomic fetch-and-store.
+
+ Reads the current value of this QAtomicInt and then assigns it the
+ \a newValue, returning the original value.
+
+ This function uses \e acquire \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access following the atomic operation (in program order) may not
+ be re-ordered before the atomic operation.
+*/
+
+/*! \fn int QAtomicInt::fetchAndStoreRelease(int newValue)
+
+ Atomic fetch-and-store.
+
+ Reads the current value of this QAtomicInt and then assigns it the
+ \a newValue, returning the original value.
+
+ This function uses \e release \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before the atomic operation (in program order) may not be
+ re-ordered after the atomic operation.
+*/
+
+/*! \fn int QAtomicInt::fetchAndStoreOrdered(int newValue)
+
+ Atomic fetch-and-store.
+
+ Reads the current value of this QAtomicInt and then assigns it the
+ \a newValue, returning the original value.
+
+ This function uses \e ordered \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before and after the atomic operation (in program order)
+ may not be re-ordered.
+*/
+
+/*! \fn bool QAtomicInt::isFetchAndAddNative()
+
+ Returns true if fetch-and-add is implemented using atomic
+ processor instructions, false otherwise.
+*/
+
+/*! \fn bool QAtomicInt::isFetchAndAddWaitFree()
+
+ Returns true if atomic fetch-and-add is wait-free, false
+ otherwise.
+*/
+
+/*! \fn int QAtomicInt::fetchAndAddRelaxed(int valueToAdd)
+
+ Atomic fetch-and-add.
+
+ Reads the current value of this QAtomicInt and then adds
+ \a valueToAdd to the current value, returning the original value.
+
+ This function uses \e relaxed \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, leaving the compiler and
+ processor to freely reorder memory accesses.
+*/
+
+/*! \fn int QAtomicInt::fetchAndAddAcquire(int valueToAdd)
+
+ Atomic fetch-and-add.
+
+ Reads the current value of this QAtomicInt and then adds
+ \a valueToAdd to the current value, returning the original value.
+
+ This function uses \e acquire \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access following the atomic operation (in program order) may not
+ be re-ordered before the atomic operation.
+*/
+
+/*! \fn int QAtomicInt::fetchAndAddRelease(int valueToAdd)
+
+ Atomic fetch-and-add.
+
+ Reads the current value of this QAtomicInt and then adds
+ \a valueToAdd to the current value, returning the original value.
+
+ This function uses \e release \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before the atomic operation (in program order) may not be
+ re-ordered after the atomic operation.
+*/
+
+/*! \fn int QAtomicInt::fetchAndAddOrdered(int valueToAdd)
+
+ Atomic fetch-and-add.
+
+ Reads the current value of this QAtomicInt and then adds
+ \a valueToAdd to the current value, returning the original value.
+
+ This function uses \e ordered \l {QAtomicInt#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before and after the atomic operation (in program order)
+ may not be re-ordered.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined if and only if all generations of your
+ processor support atomic reference counting.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined when only certain generations of the
+ processor support atomic reference counting. Use the
+ QAtomicInt::isReferenceCountingNative() function to check what
+ your processor supports.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined when the hardware does not support atomic
+ reference counting.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE
+ \relates QAtomicInt
+
+ This macro is defined together with
+ Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE to indicate that
+ the reference counting is wait-free.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined if and only if your processor supports
+ atomic test-and-set on integers.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined when only certain generations of the
+ processor support atomic test-and-set on integers. Use the
+ QAtomicInt::isTestAndSetNative() function to check what your
+ processor supports.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined when the hardware does not support atomic
+ test-and-set on integers.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE
+ \relates QAtomicInt
+
+ This macro is defined together with
+ Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE to indicate that the
+ atomic test-and-set on integers is wait-free.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined if and only if your processor supports
+ atomic fetch-and-store on integers.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined when only certain generations of the
+ processor support atomic fetch-and-store on integers. Use the
+ QAtomicInt::isFetchAndStoreNative() function to check what your
+ processor supports.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined when the hardware does not support atomic
+ fetch-and-store on integers.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE
+ \relates QAtomicInt
+
+ This macro is defined together with
+ Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE to indicate that the
+ atomic fetch-and-store on integers is wait-free.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined if and only if your processor supports
+ atomic fetch-and-add on integers.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined when only certain generations of the
+ processor support atomic fetch-and-add on integers. Use the
+ QAtomicInt::isFetchAndAddNative() function to check what your
+ processor supports.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE
+ \relates QAtomicInt
+
+ This macro is defined when the hardware does not support atomic
+ fetch-and-add on integers.
+*/
+
+/*!
+ \macro Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE
+ \relates QAtomicInt
+
+ This macro is defined together with
+ Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE to indicate that the
+ atomic fetch-and-add on integers is wait-free.
+*/
+
+
+
+
+/*!
+ \class QAtomicPointer
+ \brief The QAtomicPointer class is a template class that provides platform-independent atomic operations on pointers.
+ \since 4.4
+
+ \ingroup thread
+
+ For atomic operations on integers, see the QAtomicInt class.
+
+ An \e atomic operation is a complex operation that completes without interruption.
+ The QAtomicPointer class provides atomic test-and-set, fetch-and-store, and fetch-and-add for pointers.
+
+ \section1 Non-atomic convenience operators
+
+ For convenience, QAtomicPointer provides pointer comparison, cast,
+ dereference, and assignment operators. Note that these operators
+ are \e not atomic.
+
+ \section1 The Atomic API
+
+ \section2 Memory ordering
+
+ QAtomicPointer provides several implementations of the atomic
+ test-and-set, fetch-and-store, and fetch-and-add functions. Each
+ implementation defines a memory ordering semantic that describes
+ how memory accesses surrounding the atomic instruction are
+ executed by the processor. Since many modern architectures allow
+ out-of-order execution and memory ordering, using the correct
+ semantic is necessary to ensure that your application functions
+ properly on all processors.
+
+ \list
+
+ \o Relaxed - memory ordering is unspecified, leaving the compiler
+ and processor to freely reorder memory accesses.
+
+ \o Acquire - memory access following the atomic operation (in
+ program order) may not be re-ordered before the atomic operation.
+
+ \o Release - memory access before the atomic operation (in program
+ order) may not be re-ordered after the atomic operation.
+
+ \o Ordered - the same Acquire and Release semantics combined.
+
+ \endlist
+
+ \section2 Test-and-set
+
+ If the current value of the QAtomicPointer is an expected value,
+ the test-and-set functions assign a new value to the
+ QAtomicPointer and return true. If values are \a not the same,
+ these functions do nothing and return false. This operation
+ equates to the following code:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qatomic.cpp 4
+
+ There are 4 test-and-set functions: testAndSetRelaxed(),
+ testAndSetAcquire(), testAndSetRelease(), and
+ testAndSetOrdered(). See above for an explanation of the different
+ memory ordering semantics.
+
+ \section2 Fetch-and-store
+
+ The atomic fetch-and-store functions read the current value of the
+ QAtomicPointer and then assign a new value, returning the original
+ value. This operation equates to the following code:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qatomic.cpp 5
+
+ There are 4 fetch-and-store functions: fetchAndStoreRelaxed(),
+ fetchAndStoreAcquire(), fetchAndStoreRelease(), and
+ fetchAndStoreOrdered(). See above for an explanation of the
+ different memory ordering semantics.
+
+ \section2 Fetch-and-add
+
+ The atomic fetch-and-add functions read the current value of the
+ QAtomicPointer and then add the given value to the current value,
+ returning the original value. This operation equates to the
+ following code:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qatomic.cpp 6
+
+ There are 4 fetch-and-add functions: fetchAndAddRelaxed(),
+ fetchAndAddAcquire(), fetchAndAddRelease(), and
+ fetchAndAddOrdered(). See above for an explanation of the
+ different memory ordering semantics.
+
+ \section1 Feature Tests for the Atomic API
+
+ Providing a platform-independent atomic API that works on all
+ processors is challenging. The API provided by QAtomicPointer is
+ guaranteed to work atomically on all processors. However, since
+ not all processors implement support for every operation provided
+ by QAtomicPointer, it is necessary to expose information about the
+ processor.
+
+ You can check at compile time which features are supported on your
+ hardware using various macros. These will tell you if your
+ hardware always, sometimes, or does not support a particular
+ operation. The macros have the form
+ Q_ATOMIC_POINTER_\e{OPERATION}_IS_\e{HOW}_NATIVE. \e{OPERATION} is
+ one of TEST_AND_SET, FETCH_AND_STORE, or FETCH_AND_ADD, and
+ \e{HOW} is one of ALWAYS, SOMETIMES, or NOT. There will always be
+ exactly one defined macro per operation. For example, if
+ Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE is defined, neither
+ Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE nor
+ Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE will be defined.
+
+ An operation that completes in constant time is said to be
+ wait-free. Such operations are not implemented using locks or
+ loops of any kind. For atomic operations that are always
+ supported, and that are wait-free, Qt defines the
+ Q_ATOMIC_POINTER_\e{OPERATION}_IS_WAIT_FREE in addition to the
+ Q_ATOMIC_POINTER_\e{OPERATION}_IS_ALWAYS_NATIVE.
+
+ In cases where an atomic operation is only supported in newer
+ generations of the processor, QAtomicPointer also provides a way
+ to check at runtime what your hardware supports with the
+ isTestAndSetNative(), isFetchAndStoreNative(), and
+ isFetchAndAddNative() functions. Wait-free implementations can be
+ detected using the isTestAndSetWaitFree(),
+ isFetchAndStoreWaitFree(), and isFetchAndAddWaitFree() functions.
+
+ Below is a complete list of all feature macros for QAtomicPointer:
+
+ \list
+
+ \o Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE
+ \o Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE
+ \o Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE
+ \o Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE
+
+ \o Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE
+ \o Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE
+ \o Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE
+ \o Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE
+
+ \o Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE
+ \o Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE
+ \o Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE
+ \o Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE
+
+ \endlist
+
+ \sa QAtomicInt
+*/
+
+/*! \fn QAtomicPointer::QAtomicPointer(T *value)
+
+ Constructs a QAtomicPointer with the given \a value.
+*/
+
+/*! \fn QAtomicPointer::QAtomicPointer(const QAtomicPointer<T> &other)
+
+ Constructs a copy of \a other.
+*/
+
+/*! \fn QAtomicPointer<T> &QAtomicPointer::operator=(T *value)
+
+ Assigns the \a value to this QAtomicPointer and returns a
+ reference to this QAtomicPointer.
+*/
+
+/*! \fn QAtomicPointer<T> &QAtomicPointer::operator=(const QAtomicPointer<T> &other)
+
+ Assigns \a other to this QAtomicPointer and returns a reference to
+ this QAtomicPointer.
+*/
+
+/*! \fn bool QAtomicPointer::operator==(T *value) const
+
+ Returns true if the \a value is equal to the value in this
+ QAtomicPointer; otherwise returns false.
+*/
+
+/*! \fn bool QAtomicPointer::operator!=(T *value) const
+
+ Returns true if the value of this QAtomicPointer is not equal to
+ \a value; otherwise returns false.
+*/
+
+/*! \fn bool QAtomicPointer::operator!() const
+
+ Returns true is the current value of this QAtomicPointer is zero;
+ otherwise returns false.
+*/
+
+/*! \fn QAtomicPointer::operator T *() const
+
+ Returns the current pointer value stored by this QAtomicPointer
+ object.
+*/
+
+/*! \fn T *QAtomicPointer::operator->() const
+
+*/
+
+/*! \fn bool QAtomicPointer::isTestAndSetNative()
+
+ Returns true if test-and-set is implemented using atomic processor
+ instructions, false otherwise.
+*/
+
+/*! \fn bool QAtomicPointer::isTestAndSetWaitFree()
+
+ Returns true if atomic test-and-set is wait-free, false otherwise.
+*/
+
+/*! \fn bool QAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue)
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicPointer is the \a expectedValue,
+ the test-and-set functions assign the \a newValue to this
+ QAtomicPointer and return true. If the values are \e not the same,
+ this function does nothing and returns false.
+
+ This function uses \e relaxed \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, leaving the compiler and
+ processor to freely reorder memory accesses.
+*/
+
+/*! \fn bool QAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue)
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicPointer is the \a expectedValue,
+ the test-and-set functions assign the \a newValue to this
+ QAtomicPointer and return true. If the values are \e not the same,
+ this function does nothing and returns false.
+
+ This function uses \e acquire \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access following the atomic operation (in program order) may not
+ be re-ordered before the atomic operation.
+*/
+
+/*! \fn bool QAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue)
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicPointer is the \a expectedValue,
+ the test-and-set functions assign the \a newValue to this
+ QAtomicPointer and return true. If the values are \e not the same,
+ this function does nothing and returns false.
+
+ This function uses \e release \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before the atomic operation (in program order) may not be
+ re-ordered after the atomic operation.
+*/
+
+/*! \fn bool QAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue)
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicPointer is the \a expectedValue,
+ the test-and-set functions assign the \a newValue to this
+ QAtomicPointer and return true. If the values are \e not the same,
+ this function does nothing and returns false.
+
+ This function uses \e ordered \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before and after the atomic operation (in program order)
+ may not be re-ordered.
+*/
+
+/*! \fn bool QAtomicPointer::isFetchAndStoreNative()
+
+ Returns true if fetch-and-store is implemented using atomic
+ processor instructions, false otherwise.
+*/
+
+/*! \fn bool QAtomicPointer::isFetchAndStoreWaitFree()
+
+ Returns true if atomic fetch-and-store is wait-free, false
+ otherwise.
+*/
+
+/*! \fn T *QAtomicPointer::fetchAndStoreRelaxed(T *newValue)
+
+ Atomic fetch-and-store.
+
+ Reads the current value of this QAtomicPointer and then assigns it the
+ \a newValue, returning the original value.
+
+ This function uses \e relaxed \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, leaving the compiler and
+ processor to freely reorder memory accesses.
+*/
+
+/*! \fn T *QAtomicPointer::fetchAndStoreAcquire(T *newValue)
+
+ Atomic fetch-and-store.
+
+ Reads the current value of this QAtomicPointer and then assigns it the
+ \a newValue, returning the original value.
+
+ This function uses \e acquire \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access following the atomic operation (in program order) may not
+ be re-ordered before the atomic operation.
+*/
+
+/*! \fn T *QAtomicPointer::fetchAndStoreRelease(T *newValue)
+
+ Atomic fetch-and-store.
+
+ Reads the current value of this QAtomicPointer and then assigns it the
+ \a newValue, returning the original value.
+
+ This function uses \e release \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before the atomic operation (in program order) may not be
+ re-ordered after the atomic operation.
+*/
+
+/*! \fn T *QAtomicPointer::fetchAndStoreOrdered(T *newValue)
+
+ Atomic fetch-and-store.
+
+ Reads the current value of this QAtomicPointer and then assigns it the
+ \a newValue, returning the original value.
+
+ This function uses \e ordered \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before and after the atomic operation (in program order)
+ may not be re-ordered.
+*/
+
+/*! \fn bool QAtomicPointer::isFetchAndAddNative()
+
+ Returns true if fetch-and-add is implemented using atomic
+ processor instructions, false otherwise.
+*/
+
+/*! \fn bool QAtomicPointer::isFetchAndAddWaitFree()
+
+ Returns true if atomic fetch-and-add is wait-free, false
+ otherwise.
+*/
+
+/*! \fn T *QAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd)
+
+ Atomic fetch-and-add.
+
+ Reads the current value of this QAtomicPointer and then adds
+ \a valueToAdd to the current value, returning the original value.
+
+ This function uses \e relaxed \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, leaving the compiler and
+ processor to freely reorder memory accesses.
+*/
+
+/*! \fn T *QAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd)
+
+ Atomic fetch-and-add.
+
+ Reads the current value of this QAtomicPointer and then adds
+ \a valueToAdd to the current value, returning the original value.
+
+ This function uses \e acquire \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access following the atomic operation (in program order) may not
+ be re-ordered before the atomic operation.
+*/
+
+/*! \fn T *QAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd)
+
+ Atomic fetch-and-add.
+
+ Reads the current value of this QAtomicPointer and then adds
+ \a valueToAdd to the current value, returning the original value.
+
+ This function uses \e release \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before the atomic operation (in program order) may not be
+ re-ordered after the atomic operation.
+*/
+
+/*! \fn T *QAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd)
+
+ Atomic fetch-and-add.
+
+ Reads the current value of this QAtomicPointer and then adds
+ \a valueToAdd to the current value, returning the original value.
+
+ This function uses \e ordered \l {QAtomicPointer#Memory
+ ordering}{memory ordering} semantics, which ensures that memory
+ access before and after the atomic operation (in program order)
+ may not be re-ordered.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE
+ \relates QAtomicPointer
+
+ This macro is defined if and only if your processor supports
+ atomic test-and-set on pointers.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE
+ \relates QAtomicPointer
+
+ This macro is defined when only certain generations of the
+ processor support atomic test-and-set on pointers. Use the
+ QAtomicPointer::isTestAndSetNative() function to check what your
+ processor supports.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE
+ \relates QAtomicPointer
+
+ This macro is defined when the hardware does not support atomic
+ test-and-set on pointers.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE
+ \relates QAtomicPointer
+
+ This macro is defined together with
+ Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE to indicate that
+ the atomic test-and-set on pointers is wait-free.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE
+ \relates QAtomicPointer
+
+ This macro is defined if and only if your processor supports
+ atomic fetch-and-store on pointers.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE
+ \relates QAtomicPointer
+
+ This macro is defined when only certain generations of the
+ processor support atomic fetch-and-store on pointers. Use the
+ QAtomicPointer::isFetchAndStoreNative() function to check what
+ your processor supports.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE
+ \relates QAtomicPointer
+
+ This macro is defined when the hardware does not support atomic
+ fetch-and-store on pointers.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE
+ \relates QAtomicPointer
+
+ This macro is defined together with
+ Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE to indicate that
+ the atomic fetch-and-store on pointers is wait-free.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE
+ \relates QAtomicPointer
+
+ This macro is defined if and only if your processor supports
+ atomic fetch-and-add on pointers.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE
+ \relates QAtomicPointer
+
+ This macro is defined when only certain generations of the
+ processor support atomic fetch-and-add on pointers. Use the
+ QAtomicPointer::isFetchAndAddNative() function to check what your
+ processor supports.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE
+ \relates QAtomicPointer
+
+ This macro is defined when the hardware does not support atomic
+ fetch-and-add on pointers.
+*/
+
+/*!
+ \macro Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE
+ \relates QAtomicPointer
+
+ This macro is defined together with
+ Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE to indicate that
+ the atomic fetch-and-add on pointers is wait-free.
+*/
diff --git a/src/corelib/thread/qatomic.h b/src/corelib/thread/qatomic.h
new file mode 100644
index 0000000000..94dc2e3b4e
--- /dev/null
+++ b/src/corelib/thread/qatomic.h
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QATOMIC_H
+#define QATOMIC_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qbasicatomic.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+// High-level atomic integer operations
+class Q_CORE_EXPORT QAtomicInt : public QBasicAtomicInt
+{
+public:
+ inline QAtomicInt(int value = 0)
+ {
+#ifdef QT_ARCH_PARISC
+ this->_q_lock[0] = this->_q_lock[1] = this->_q_lock[2] = this->_q_lock[3] = -1;
+#endif
+ _q_value = value;
+ }
+ inline QAtomicInt(const QAtomicInt &other)
+ {
+#ifdef QT_ARCH_PARISC
+ this->_q_lock[0] = this->_q_lock[1] = this->_q_lock[2] = this->_q_lock[3] = -1;
+#endif
+ _q_value = other._q_value;
+ }
+
+ inline QAtomicInt &operator=(int value)
+ {
+ (void) QBasicAtomicInt::operator=(value);
+ return *this;
+ }
+
+ inline QAtomicInt &operator=(const QAtomicInt &other)
+ {
+ (void) QBasicAtomicInt::operator=(other);
+ return *this;
+ }
+
+#ifdef qdoc
+ bool operator==(int value) const;
+ bool operator!=(int value) const;
+ bool operator!() const;
+ operator int() const;
+
+ static bool isReferenceCountingNative();
+ static bool isReferenceCountingWaitFree();
+
+ bool ref();
+ bool deref();
+
+ static bool isTestAndSetNative();
+ static bool isTestAndSetWaitFree();
+
+ bool testAndSetRelaxed(int expectedValue, int newValue);
+ bool testAndSetAcquire(int expectedValue, int newValue);
+ bool testAndSetRelease(int expectedValue, int newValue);
+ bool testAndSetOrdered(int expectedValue, int newValue);
+
+ static bool isFetchAndStoreNative();
+ static bool isFetchAndStoreWaitFree();
+
+ int fetchAndStoreRelaxed(int newValue);
+ int fetchAndStoreAcquire(int newValue);
+ int fetchAndStoreRelease(int newValue);
+ int fetchAndStoreOrdered(int newValue);
+
+ static bool isFetchAndAddNative();
+ static bool isFetchAndAddWaitFree();
+
+ int fetchAndAddRelaxed(int valueToAdd);
+ int fetchAndAddAcquire(int valueToAdd);
+ int fetchAndAddRelease(int valueToAdd);
+ int fetchAndAddOrdered(int valueToAdd);
+#endif
+};
+
+// High-level atomic pointer operations
+template <typename T>
+class QAtomicPointer : public QBasicAtomicPointer<T>
+{
+public:
+ inline QAtomicPointer(T *value = 0)
+ {
+#ifdef QT_ARCH_PARISC
+ this->_q_lock[0] = this->_q_lock[1] = this->_q_lock[2] = this->_q_lock[3] = -1;
+#endif
+ QBasicAtomicPointer<T>::_q_value = value;
+ }
+ inline QAtomicPointer(const QAtomicPointer<T> &other)
+ {
+#ifdef QT_ARCH_PARISC
+ this->_q_lock[0] = this->_q_lock[1] = this->_q_lock[2] = this->_q_lock[3] = -1;
+#endif
+ QBasicAtomicPointer<T>::_q_value = other._q_value;
+ }
+
+ inline QAtomicPointer<T> &operator=(T *value)
+ {
+ (void) QBasicAtomicPointer<T>::operator=(value);
+ return *this;
+ }
+
+ inline QAtomicPointer<T> &operator=(const QAtomicPointer<T> &other)
+ {
+ (void) QBasicAtomicPointer<T>::operator=(other);
+ return *this;
+ }
+
+#ifdef qdoc
+ bool operator==(T *value) const;
+ bool operator!=(T *value) const;
+ bool operator!() const;
+ operator T *() const;
+ T *operator->() const;
+
+ static bool isTestAndSetNative();
+ static bool isTestAndSetWaitFree();
+
+ bool testAndSetRelaxed(T *expectedValue, T *newValue);
+ bool testAndSetAcquire(T *expectedValue, T *newValue);
+ bool testAndSetRelease(T *expectedValue, T *newValue);
+ bool testAndSetOrdered(T *expectedValue, T *newValue);
+
+ static bool isFetchAndStoreNative();
+ static bool isFetchAndStoreWaitFree();
+
+ T *fetchAndStoreRelaxed(T *newValue);
+ T *fetchAndStoreAcquire(T *newValue);
+ T *fetchAndStoreRelease(T *newValue);
+ T *fetchAndStoreOrdered(T *newValue);
+
+ static bool isFetchAndAddNative();
+ static bool isFetchAndAddWaitFree();
+
+ T *fetchAndAddRelaxed(qptrdiff valueToAdd);
+ T *fetchAndAddAcquire(qptrdiff valueToAdd);
+ T *fetchAndAddRelease(qptrdiff valueToAdd);
+ T *fetchAndAddOrdered(qptrdiff valueToAdd);
+#endif
+};
+
+/*!
+ This is a helper for the assignment operators of implicitly
+ shared classes. Your assignment operator should look like this:
+
+ \snippet doc/src/snippets/code/src.corelib.thread.qatomic.h 0
+*/
+template <typename T>
+inline void qAtomicAssign(T *&d, T *x)
+{
+ if (d == x)
+ return;
+ x->ref.ref();
+ if (!d->ref.deref())
+ delete d;
+ d = x;
+}
+
+/*!
+ This is a helper for the detach method of implicitly shared
+ classes. Your private class needs a copy constructor which copies
+ the members and sets the refcount to 1. After that, your detach
+ function should look like this:
+
+ \snippet doc/src/snippets/code/src.corelib.thread.qatomic.h 1
+*/
+template <typename T>
+inline void qAtomicDetach(T *&d)
+{
+ if (d->ref == 1)
+ return;
+ T *x = d;
+ d = new T(*d);
+ if (!x->ref.deref())
+ delete x;
+}
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // QATOMIC_H
diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h
new file mode 100644
index 0000000000..72fd55ad7f
--- /dev/null
+++ b/src/corelib/thread/qbasicatomic.h
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBASICATOMIC_H
+#define QBASICATOMIC_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class Q_CORE_EXPORT QBasicAtomicInt
+{
+public:
+#ifdef QT_ARCH_PARISC
+ int _q_lock[4];
+#endif
+#if defined(QT_ARCH_WINDOWS) || defined(QT_ARCH_WINDOWSCE)
+ union { // needed for Q_BASIC_ATOMIC_INITIALIZER
+ volatile long _q_value;
+ };
+#else
+ volatile int _q_value;
+#endif
+
+ // Non-atomic API
+ inline bool operator==(int value) const
+ {
+ return _q_value == value;
+ }
+
+ inline bool operator!=(int value) const
+ {
+ return _q_value != value;
+ }
+
+ inline bool operator!() const
+ {
+ return _q_value == 0;
+ }
+
+ inline operator int() const
+ {
+ return _q_value;
+ }
+
+ inline QBasicAtomicInt &operator=(int value)
+ {
+#ifdef QT_ARCH_PARISC
+ this->_q_lock[0] = this->_q_lock[1] = this->_q_lock[2] = this->_q_lock[3] = -1;
+#endif
+ _q_value = value;
+ return *this;
+ }
+
+ // Atomic API, implemented in qatomic_XXX.h
+
+ static bool isReferenceCountingNative();
+ static bool isReferenceCountingWaitFree();
+
+ bool ref();
+ bool deref();
+
+ static bool isTestAndSetNative();
+ static bool isTestAndSetWaitFree();
+
+ bool testAndSetRelaxed(int expectedValue, int newValue);
+ bool testAndSetAcquire(int expectedValue, int newValue);
+ bool testAndSetRelease(int expectedValue, int newValue);
+ bool testAndSetOrdered(int expectedValue, int newValue);
+
+ static bool isFetchAndStoreNative();
+ static bool isFetchAndStoreWaitFree();
+
+ int fetchAndStoreRelaxed(int newValue);
+ int fetchAndStoreAcquire(int newValue);
+ int fetchAndStoreRelease(int newValue);
+ int fetchAndStoreOrdered(int newValue);
+
+ static bool isFetchAndAddNative();
+ static bool isFetchAndAddWaitFree();
+
+ int fetchAndAddRelaxed(int valueToAdd);
+ int fetchAndAddAcquire(int valueToAdd);
+ int fetchAndAddRelease(int valueToAdd);
+ int fetchAndAddOrdered(int valueToAdd);
+};
+
+template <typename T>
+class QBasicAtomicPointer
+{
+public:
+#ifdef QT_ARCH_PARISC
+ int _q_lock[4];
+#endif
+#if defined(QT_ARCH_WINDOWS) || defined(QT_ARCH_WINDOWSCE)
+ union {
+ T * volatile _q_value;
+# if !defined(Q_OS_WINCE) && !defined(__i386__) && !defined(_M_IX86)
+ qint64
+# else
+ long
+# endif
+ volatile _q_value_integral;
+ };
+#else
+ T * volatile _q_value;
+#endif
+
+ // Non-atomic API
+ inline bool operator==(T *value) const
+ {
+ return _q_value == value;
+ }
+
+ inline bool operator!=(T *value) const
+ {
+ return !operator==(value);
+ }
+
+ inline bool operator!() const
+ {
+ return operator==(0);
+ }
+
+ inline operator T *() const
+ {
+ return _q_value;
+ }
+
+ inline T *operator->() const
+ {
+ return _q_value;
+ }
+
+ inline QBasicAtomicPointer<T> &operator=(T *value)
+ {
+#ifdef QT_ARCH_PARISC
+ this->_q_lock[0] = this->_q_lock[1] = this->_q_lock[2] = this->_q_lock[3] = -1;
+#endif
+ _q_value = value;
+ return *this;
+ }
+
+ // Atomic API, implemented in qatomic_XXX.h
+
+ static bool isTestAndSetNative();
+ static bool isTestAndSetWaitFree();
+
+ bool testAndSetRelaxed(T *expectedValue, T *newValue);
+ bool testAndSetAcquire(T *expectedValue, T *newValue);
+ bool testAndSetRelease(T *expectedValue, T *newValue);
+ bool testAndSetOrdered(T *expectedValue, T *newValue);
+
+ static bool isFetchAndStoreNative();
+ static bool isFetchAndStoreWaitFree();
+
+ T *fetchAndStoreRelaxed(T *newValue);
+ T *fetchAndStoreAcquire(T *newValue);
+ T *fetchAndStoreRelease(T *newValue);
+ T *fetchAndStoreOrdered(T *newValue);
+
+ static bool isFetchAndAddNative();
+ static bool isFetchAndAddWaitFree();
+
+ T *fetchAndAddRelaxed(qptrdiff valueToAdd);
+ T *fetchAndAddAcquire(qptrdiff valueToAdd);
+ T *fetchAndAddRelease(qptrdiff valueToAdd);
+ T *fetchAndAddOrdered(qptrdiff valueToAdd);
+};
+
+#ifdef QT_ARCH_PARISC
+# define Q_BASIC_ATOMIC_INITIALIZER(a) {{-1,-1,-1,-1},(a)}
+#elif defined(QT_ARCH_WINDOWS) || defined(QT_ARCH_WINDOWSCE)
+# define Q_BASIC_ATOMIC_INITIALIZER(a) { {(a)} }
+#else
+# define Q_BASIC_ATOMIC_INITIALIZER(a) { (a) }
+#endif
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#if defined(QT_MOC) || defined(QT_BUILD_QMAKE) || defined(QT_RCC) || defined(QT_UIC) || defined(QT_BOOTSTRAPPED)
+# include <QtCore/qatomic_bootstrap.h>
+#else
+# include <QtCore/qatomic_arch.h>
+#endif
+
+#endif // QBASIC_ATOMIC
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
new file mode 100644
index 0000000000..001506cf7d
--- /dev/null
+++ b/src/corelib/thread/qmutex.cpp
@@ -0,0 +1,515 @@
+/****************************************************************************
+**
+** 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
+
+/*!
+ \class QMutex
+ \brief The QMutex class provides access serialization between threads.
+
+ \threadsafe
+
+ \ingroup thread
+
+ The purpose of a QMutex is to protect an object, data structure or
+ section of code so that only one thread can access it at a time
+ (this is similar to the Java \c synchronized keyword). It is
+ usually best to use a mutex with a QMutexLocker since this makes
+ it easy to ensure that locking and unlocking are performed
+ consistently.
+
+ For example, say there is a method that prints a message to the
+ user on two lines:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 0
+
+ If these two methods are called in succession, the following happens:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 1
+
+ If these two methods are called simultaneously from two threads then the
+ following sequence could result:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 2
+
+ If we add a mutex, we should get the result we want:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 3
+
+ Then only one thread can modify \c number at any given time and
+ the result is correct. This is a trivial example, of course, but
+ applies to any other case where things need to happen in a
+ particular sequence.
+
+ When you call lock() in a thread, other threads that try to call
+ lock() in the same place will block until the thread that got the
+ lock calls unlock(). A non-blocking alternative to lock() is
+ tryLock().
+
+ \sa QMutexLocker, QReadWriteLock, QSemaphore, QWaitCondition
+*/
+
+/*!
+ \enum QMutex::RecursionMode
+
+ \value Recursive In this mode, a thread can lock the same mutex
+ multiple times and the mutex won't be unlocked
+ until a corresponding number of unlock() calls
+ have been made.
+
+ \value NonRecursive In this mode, a thread may only lock a mutex
+ once.
+
+ \sa QMutex()
+*/
+
+/*!
+ Constructs a new mutex. The mutex is created in an unlocked state.
+
+ If \a mode is QMutex::Recursive, a thread can lock the same mutex
+ multiple times and the mutex won't be unlocked until a
+ corresponding number of unlock() calls have been made. The
+ default is QMutex::NonRecursive.
+
+ \sa lock(), unlock()
+*/
+QMutex::QMutex(RecursionMode mode)
+ : d(new QMutexPrivate(mode))
+{ }
+
+/*!
+ Destroys the mutex.
+
+ \warning Destroying a locked mutex may result in undefined behavior.
+*/
+QMutex::~QMutex()
+{ delete static_cast<QMutexPrivate *>(d); }
+
+/*!
+ Locks the mutex. If another thread has locked the mutex then this
+ call will block until that thread has unlocked it.
+
+ Calling this function multiple times on the same mutex from the
+ same thread is allowed if this mutex is a
+ \l{QMutex::Recursive}{recursive mutex}. If this mutex is a
+ \l{QMutex::NonRecursive}{non-recursive mutex}, this function will
+ \e dead-lock when the mutex is locked recursively.
+
+ \sa unlock()
+*/
+void QMutex::lock()
+{
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
+ Qt::HANDLE self;
+
+ if (d->recursive) {
+ self = QThread::currentThreadId();
+ if (d->owner == self) {
+ ++d->count;
+ Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter");
+ return;
+ }
+
+ bool isLocked = d->contenders.testAndSetAcquire(0, 1);
+ if (!isLocked) {
+ // didn't get the lock, wait for it
+ isLocked = d->wait();
+ Q_ASSERT_X(isLocked, "QMutex::lock",
+ "Internal error, infinite wait has timed out.");
+ }
+
+ d->owner = self;
+ ++d->count;
+ Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter");
+ return;
+ }
+
+ bool isLocked = d->contenders.testAndSetAcquire(0, 1);
+ if (!isLocked) {
+ lockInternal();
+ }
+}
+
+/*!
+ Attempts to lock the mutex. If the lock was obtained, this function
+ returns true. If another thread has locked the mutex, this
+ function returns false immediately.
+
+ If the lock was obtained, the mutex must be unlocked with unlock()
+ before another thread can successfully lock it.
+
+ Calling this function multiple times on the same mutex from the
+ same thread is allowed if this mutex is a
+ \l{QMutex::Recursive}{recursive mutex}. If this mutex is a
+ \l{QMutex::NonRecursive}{non-recursive mutex}, this function will
+ \e always return false when attempting to lock the mutex
+ recursively.
+
+ \sa lock(), unlock()
+*/
+bool QMutex::tryLock()
+{
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
+ Qt::HANDLE self;
+
+ if (d->recursive) {
+ self = QThread::currentThreadId();
+ if (d->owner == self) {
+ ++d->count;
+ Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
+ return true;
+ }
+
+ bool isLocked = d->contenders.testAndSetAcquire(0, 1);
+ if (!isLocked) {
+ // some other thread has the mutex locked, or we tried to
+ // recursively lock an non-recursive mutex
+ return isLocked;
+ }
+
+ d->owner = self;
+ ++d->count;
+ Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
+ return isLocked;
+ }
+
+ return d->contenders.testAndSetAcquire(0, 1);
+}
+
+/*! \overload
+
+ Attempts to lock the mutex. This function returns true if the lock
+ was obtained; otherwise it returns false. If another thread has
+ locked the mutex, this function will wait for at most \a timeout
+ milliseconds for the mutex to become available.
+
+ Note: Passing a negative number as the \a timeout is equivalent to
+ calling lock(), i.e. this function will wait forever until mutex
+ can be locked if \a timeout is negative.
+
+ If the lock was obtained, the mutex must be unlocked with unlock()
+ before another thread can successfully lock it.
+
+ Calling this function multiple times on the same mutex from the
+ same thread is allowed if this mutex is a
+ \l{QMutex::Recursive}{recursive mutex}. If this mutex is a
+ \l{QMutex::NonRecursive}{non-recursive mutex}, this function will
+ \e always return false when attempting to lock the mutex
+ recursively.
+
+ \sa lock(), unlock()
+*/
+bool QMutex::tryLock(int timeout)
+{
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
+ Qt::HANDLE self;
+
+ if (d->recursive) {
+ self = QThread::currentThreadId();
+ if (d->owner == self) {
+ ++d->count;
+ Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
+ return true;
+ }
+
+ bool isLocked = d->contenders.testAndSetAcquire(0, 1);
+ if (!isLocked) {
+ // didn't get the lock, wait for it
+ isLocked = d->wait(timeout);
+ if (!isLocked)
+ return false;
+ }
+
+ d->owner = self;
+ ++d->count;
+ Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
+ return true;
+ }
+
+ return (d->contenders.testAndSetAcquire(0, 1)
+ // didn't get the lock, wait for it
+ || d->wait(timeout));
+}
+
+
+/*!
+ Unlocks the mutex. Attempting to unlock a mutex in a different
+ thread to the one that locked it results in an error. Unlocking a
+ mutex that is not locked results in undefined behavior.
+
+ \sa lock()
+*/
+void QMutex::unlock()
+{
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
+ if (d->recursive) {
+ if (!--d->count) {
+ d->owner = 0;
+ if (!d->contenders.testAndSetRelease(1, 0))
+ d->wakeUp();
+ }
+ } else {
+ if (!d->contenders.testAndSetRelease(1, 0))
+ d->wakeUp();
+ }
+}
+
+/*!
+ \fn bool QMutex::locked()
+
+ Returns true if the mutex is locked by another thread; otherwise
+ returns false.
+
+ It is generally a bad idea to use this function, because code
+ that uses it has a race condition. Use tryLock() and unlock()
+ instead.
+
+ \oldcode
+ bool isLocked = mutex.locked();
+ \newcode
+ bool isLocked = true;
+ if (mutex.tryLock()) {
+ mutex.unlock();
+ isLocked = false;
+ }
+ \endcode
+*/
+
+/*!
+ \class QMutexLocker
+ \brief The QMutexLocker class is a convenience class that simplifies
+ locking and unlocking mutexes.
+
+ \threadsafe
+
+ \ingroup thread
+
+ Locking and unlocking a QMutex in complex functions and
+ statements or in exception handling code is error-prone and
+ difficult to debug. QMutexLocker can be used in such situations
+ to ensure that the state of the mutex is always well-defined.
+
+ QMutexLocker should be created within a function where a
+ QMutex needs to be locked. The mutex is locked when QMutexLocker
+ is created. You can unlock and relock the mutex with \c unlock()
+ and \c relock(). If locked, the mutex will be unlocked when the
+ QMutexLocker is destroyed.
+
+ For example, this complex function locks a QMutex upon entering
+ the function and unlocks the mutex at all the exit points:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 4
+
+ This example function will get more complicated as it is
+ developed, which increases the likelihood that errors will occur.
+
+ Using QMutexLocker greatly simplifies the code, and makes it more
+ readable:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 5
+
+ Now, the mutex will always be unlocked when the QMutexLocker
+ object is destroyed (when the function returns since \c locker is
+ an auto variable).
+
+ The same principle applies to code that throws and catches
+ exceptions. An exception that is not caught in the function that
+ has locked the mutex has no way of unlocking the mutex before the
+ exception is passed up the stack to the calling function.
+
+ QMutexLocker also provides a \c mutex() member function that returns
+ the mutex on which the QMutexLocker is operating. This is useful
+ for code that needs access to the mutex, such as
+ QWaitCondition::wait(). For example:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 6
+
+ \sa QReadLocker, QWriteLocker, QMutex
+*/
+
+/*!
+ \fn QMutexLocker::QMutexLocker(QMutex *mutex)
+
+ Constructs a QMutexLocker and locks \a mutex. The mutex will be
+ unlocked when the QMutexLocker is destroyed. If \a mutex is zero,
+ QMutexLocker does nothing.
+
+ \sa QMutex::lock()
+*/
+
+/*!
+ \fn QMutexLocker::~QMutexLocker()
+
+ Destroys the QMutexLocker and unlocks the mutex that was locked
+ in the constructor.
+
+ \sa QMutex::unlock()
+*/
+
+/*!
+ \fn QMutex *QMutexLocker::mutex() const
+
+ Returns a pointer to the mutex that was locked in the
+ constructor.
+*/
+
+/*!
+ \fn void QMutexLocker::unlock()
+
+ Unlocks this mutex locker. You can use \c relock() to lock
+ it again. It does not need to be locked when destroyed.
+
+ \sa relock()
+*/
+
+/*!
+ \fn void QMutexLocker::relock()
+
+ Relocks an unlocked mutex locker.
+
+ \sa unlock()
+*/
+
+/*!
+ \fn QMutex::QMutex(bool recursive)
+
+ Use the constructor that takes a RecursionMode parameter instead.
+*/
+
+/*!
+ \internal helper for lockInline()
+ */
+void QMutex::lockInternal()
+{
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
+
+ if (QThread::idealThreadCount() == 1) {
+ // don't spin on single cpu machines
+ bool isLocked = d->wait();
+ Q_ASSERT_X(isLocked, "QMutex::lock",
+ "Internal error, infinite wait has timed out.");
+ Q_UNUSED(isLocked);
+ return;
+ }
+
+ QElapsedTimer elapsedTimer;
+ elapsedTimer.start();
+ do {
+ qint64 spinTime = elapsedTimer.nsecsElapsed();
+ if (spinTime > d->maximumSpinTime) {
+ // didn't get the lock, wait for it, since we're not going to gain anything by spinning more
+ elapsedTimer.start();
+ bool isLocked = d->wait();
+ Q_ASSERT_X(isLocked, "QMutex::lock",
+ "Internal error, infinite wait has timed out.");
+ Q_UNUSED(isLocked);
+
+ qint64 maximumSpinTime = d->maximumSpinTime;
+ qint64 averageWaitTime = d->averageWaitTime;
+ qint64 actualWaitTime = elapsedTimer.nsecsElapsed();
+ if (actualWaitTime < (QMutexPrivate::MaximumSpinTimeThreshold * 3 / 2)) {
+ // measure the wait times
+ averageWaitTime = d->averageWaitTime = qMin((averageWaitTime + actualWaitTime) / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold));
+ }
+
+ // adjust the spin count when spinning does not benefit contention performance
+ if ((spinTime + actualWaitTime) - qint64(QMutexPrivate::MaximumSpinTimeThreshold) >= qint64(QMutexPrivate::MaximumSpinTimeThreshold)) {
+ // long waits, stop spinning
+ d->maximumSpinTime = 0;
+ } else {
+ // allow spinning if wait times decrease, but never spin more than the average wait time (otherwise we may perform worse)
+ d->maximumSpinTime = qBound(qint64(averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold));
+ }
+ return;
+ }
+ // be a good citizen... yielding lets something else run if there is something to run, but may also relieve memory pressure if not
+ QThread::yieldCurrentThread();
+ } while (d->contenders != 0 || !d->contenders.testAndSetAcquire(0, 1));
+
+ // spinning is working, do not change the spin time (unless we are using much less time than allowed to spin)
+ qint64 maximumSpinTime = d->maximumSpinTime;
+ qint64 spinTime = elapsedTimer.nsecsElapsed();
+ if (spinTime < maximumSpinTime / 2) {
+ // we are using much less time than we need, adjust the limit
+ d->maximumSpinTime = qBound(qint64(d->averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold));
+ }
+}
+
+/*!
+ \internal
+*/
+void QMutex::unlockInternal()
+{
+ static_cast<QMutexPrivate *>(d)->wakeUp();
+}
+
+/*!
+ \fn QMutex::lockInline()
+ \internal
+ inline version of QMutex::lock()
+*/
+
+/*!
+ \fn QMutex::unlockInline()
+ \internal
+ inline version of QMutex::unlock()
+*/
+
+/*!
+ \fn QMutex::tryLockInline()
+ \internal
+ inline version of QMutex::tryLock()
+*/
+
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_THREAD
diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h
new file mode 100644
index 0000000000..5f75195b4e
--- /dev/null
+++ b/src/corelib/thread/qmutex.h
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QMUTEX_H
+#define QMUTEX_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qatomic.h>
+#include <new>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_THREAD
+
+class QAtomicInt;
+class QMutexData;
+
+class Q_CORE_EXPORT QMutex
+{
+ friend class QWaitCondition;
+ friend class QWaitConditionPrivate;
+
+public:
+ enum RecursionMode { NonRecursive, Recursive };
+
+ explicit QMutex(RecursionMode mode = NonRecursive);
+ ~QMutex();
+
+ void lock(); //### Qt5: make inline;
+ inline void lockInline();
+ bool tryLock(); //### Qt5: make inline;
+ bool tryLock(int timeout);
+ inline bool tryLockInline();
+ void unlock(); //### Qt5: make inline;
+ inline void unlockInline();
+
+#if defined(QT3_SUPPORT)
+ inline QT3_SUPPORT bool locked()
+ {
+ if (!tryLock())
+ return true;
+ unlock();
+ return false;
+ }
+ inline QT3_SUPPORT_CONSTRUCTOR QMutex(bool recursive)
+ {
+ new (this) QMutex(recursive ? Recursive : NonRecursive);
+ }
+#endif
+
+private:
+ void lockInternal();
+ void unlockInternal();
+ Q_DISABLE_COPY(QMutex)
+
+ QMutexData *d;
+};
+
+class Q_CORE_EXPORT QMutexLocker
+{
+public:
+ inline explicit QMutexLocker(QMutex *m)
+ {
+ Q_ASSERT_X((reinterpret_cast<quintptr>(m) & quintptr(1u)) == quintptr(0),
+ "QMutexLocker", "QMutex pointer is misaligned");
+ if (m) {
+ m->lockInline();
+ val = reinterpret_cast<quintptr>(m) | quintptr(1u);
+ } else {
+ val = 0;
+ }
+ }
+ inline ~QMutexLocker() { unlock(); }
+
+ inline void unlock()
+ {
+ if ((val & quintptr(1u)) == quintptr(1u)) {
+ val &= ~quintptr(1u);
+ mutex()->unlockInline();
+ }
+ }
+
+ inline void relock()
+ {
+ if (val) {
+ if ((val & quintptr(1u)) == quintptr(0u)) {
+ mutex()->lockInline();
+ val |= quintptr(1u);
+ }
+ }
+ }
+
+#if defined(Q_CC_MSVC)
+#pragma warning( push )
+#pragma warning( disable : 4312 ) // ignoring the warning from /Wp64
+#endif
+
+ inline QMutex *mutex() const
+ {
+ return reinterpret_cast<QMutex *>(val & ~quintptr(1u));
+ }
+
+#if defined(Q_CC_MSVC)
+#pragma warning( pop )
+#endif
+
+private:
+ Q_DISABLE_COPY(QMutexLocker)
+
+ quintptr val;
+};
+
+class QMutexData
+{
+ public:
+ QAtomicInt contenders;
+ const uint recursive : 1;
+ uint reserved : 31;
+ protected:
+ QMutexData(QMutex::RecursionMode mode);
+ ~QMutexData();
+};
+
+#ifdef QT_NO_DEBUG
+inline void QMutex::unlockInline()
+{
+ if (d->recursive) {
+ unlock();
+ } else if (!d->contenders.testAndSetRelease(1, 0)) {
+ unlockInternal();
+ }
+}
+
+inline bool QMutex::tryLockInline()
+{
+ if (d->recursive) {
+ return tryLock();
+ } else {
+ return d->contenders.testAndSetAcquire(0, 1);
+ }
+}
+
+inline void QMutex::lockInline()
+{
+ if (d->recursive) {
+ lock();
+ } else if(!tryLockInline()) {
+ lockInternal();
+ }
+}
+#else // QT_NO_DEBUG
+//in debug we do not use inline calls in order to allow debugging tools
+// to hook the mutex locking functions.
+inline void QMutex::unlockInline() { unlock(); }
+inline bool QMutex::tryLockInline() { return tryLock(); }
+inline void QMutex::lockInline() { lock(); }
+#endif // QT_NO_DEBUG
+
+
+#else // QT_NO_THREAD
+
+
+class Q_CORE_EXPORT QMutex
+{
+public:
+ enum RecursionMode { NonRecursive, Recursive };
+
+ inline explicit QMutex(RecursionMode mode = NonRecursive) { Q_UNUSED(mode); }
+ inline ~QMutex() {}
+
+ static inline void lock() {}
+ static inline void lockInline() {}
+ static inline bool tryLock(int timeout = 0) { Q_UNUSED(timeout); return true; }
+ static inline bool tryLockInline() { return true; }
+ static inline void unlock() {}
+ static inline void unlockInline() {}
+
+#if defined(QT3_SUPPORT)
+ static inline QT3_SUPPORT bool locked() { return false; }
+#endif
+
+private:
+ Q_DISABLE_COPY(QMutex)
+};
+
+class Q_CORE_EXPORT QMutexLocker
+{
+public:
+ inline explicit QMutexLocker(QMutex *) {}
+ inline ~QMutexLocker() {}
+
+ static inline void unlock() {}
+ static void relock() {}
+ static inline QMutex *mutex() { return 0; }
+
+private:
+ Q_DISABLE_COPY(QMutexLocker)
+};
+
+#endif // QT_NO_THREAD
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMUTEX_H
diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h
new file mode 100644
index 0000000000..70860b149e
--- /dev/null
+++ b/src/corelib/thread/qmutex_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QMUTEX_P_H
+#define QMUTEX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qmutex.cpp, qmutex_unix.cpp, and qmutex_win.cpp. This header
+// file may change from version to version without notice, or even be
+// removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qnamespace.h>
+#include <QtCore/qmutex.h>
+
+#if defined(Q_OS_MAC)
+# include <mach/semaphore.h>
+#endif
+
+#if defined(Q_OS_SYMBIAN)
+# include <e32std.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QMutexPrivate : public QMutexData {
+public:
+ QMutexPrivate(QMutex::RecursionMode mode);
+ ~QMutexPrivate();
+
+ bool wait(int timeout = -1);
+ void wakeUp();
+
+ // 1ms = 1000000ns
+ enum { MaximumSpinTimeThreshold = 1000000 };
+ volatile qint64 maximumSpinTime;
+ volatile qint64 averageWaitTime;
+ Qt::HANDLE owner;
+ uint count;
+
+#if defined(Q_OS_MAC)
+ semaphore_t mach_semaphore;
+#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
+};
+
+inline QMutexData::QMutexData(QMutex::RecursionMode mode)
+ : recursive(mode == QMutex::Recursive)
+{}
+
+inline QMutexData::~QMutexData() {}
+
+QT_END_NAMESPACE
+
+#endif // QMUTEX_P_H
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/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp
new file mode 100644
index 0000000000..11e20604e2
--- /dev/null
+++ b/src/corelib/thread/qmutex_unix.cpp
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** 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 "qstring.h"
+
+#ifndef QT_NO_THREAD
+#include "qatomic.h"
+#include "qmutex_p.h"
+
+#include <errno.h>
+
+#if defined(Q_OS_VXWORKS) && defined(wakeup)
+#undef wakeup
+#endif
+
+#if defined(Q_OS_MAC)
+# include <mach/mach.h>
+# include <mach/task.h>
+#elif defined(Q_OS_LINUX)
+# include <linux/futex.h>
+# include <sys/syscall.h>
+# include <unistd.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(Q_OS_MAC) && !defined(Q_OS_LINUX)
+static void report_error(int code, const char *where, const char *what)
+{
+ if (code != 0)
+ qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code)));
+}
+#endif
+
+
+QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
+ : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0)
+{
+#if defined(Q_OS_MAC)
+ kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0);
+ if (r != KERN_SUCCESS)
+ qWarning("QMutex: failed to create semaphore, error %d", r);
+#elif !defined(Q_OS_LINUX)
+ wakeup = false;
+ report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init");
+ report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init");
+#endif
+}
+
+QMutexPrivate::~QMutexPrivate()
+{
+#if defined(Q_OS_MAC)
+ kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore);
+ if (r != KERN_SUCCESS)
+ qWarning("QMutex: failed to destroy semaphore, error %d", r);
+#elif !defined(Q_OS_LINUX)
+ report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy");
+ report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy");
+#endif
+}
+
+#if defined(Q_OS_MAC)
+
+bool QMutexPrivate::wait(int timeout)
+{
+ if (contenders.fetchAndAddAcquire(1) == 0) {
+ // lock acquired without waiting
+ return true;
+ }
+ bool returnValue;
+ if (timeout < 0) {
+ returnValue = semaphore_wait(mach_semaphore) == KERN_SUCCESS;
+ } else {
+ mach_timespec_t ts;
+ ts.tv_nsec = ((timeout % 1000) * 1000) * 1000;
+ ts.tv_sec = (timeout / 1000);
+ kern_return_t r = semaphore_timedwait(mach_semaphore, ts);
+ returnValue = r == KERN_SUCCESS;
+ }
+ contenders.deref();
+ return returnValue;
+}
+
+void QMutexPrivate::wakeUp()
+{
+ semaphore_signal(mach_semaphore);
+}
+
+#elif defined(Q_OS_LINUX)
+
+static inline int _q_futex(volatile int *addr, int op, int val, const struct timespec *timeout, int *addr2, int val2)
+{
+ return syscall(SYS_futex, addr, op, val, timeout, addr2, val2);
+}
+
+bool QMutexPrivate::wait(int timeout)
+{
+ while (contenders.fetchAndStoreAcquire(2) > 0) {
+ struct timespec ts, *pts = 0;
+ if (timeout >= 0) {
+ ts.tv_nsec = ((timeout % 1000) * 1000) * 1000;
+ ts.tv_sec = (timeout / 1000);
+ pts = &ts;
+ }
+ int r = _q_futex(&contenders._q_value, FUTEX_WAIT, 2, pts, 0, 0);
+ if (r != 0 && errno == ETIMEDOUT)
+ return false;
+ }
+ return true;
+}
+
+void QMutexPrivate::wakeUp()
+{
+ (void) contenders.fetchAndStoreRelease(0);
+ (void) _q_futex(&contenders._q_value, FUTEX_WAKE, 1, 0, 0, 0);
+}
+
+#else // !Q_OS_MAC && !Q_OS_LINUX
+
+bool QMutexPrivate::wait(int timeout)
+{
+ if (contenders.fetchAndAddAcquire(1) == 0) {
+ // lock acquired without waiting
+ return true;
+ }
+ report_error(pthread_mutex_lock(&mutex), "QMutex::lock", "mutex lock");
+ int errorCode = 0;
+ while (!wakeup) {
+ if (timeout < 0) {
+ errorCode = pthread_cond_wait(&cond, &mutex);
+ } else {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+
+ timespec ti;
+ ti.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000;
+ ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000);
+ ti.tv_nsec %= 1000000000;
+
+ errorCode = pthread_cond_timedwait(&cond, &mutex, &ti);
+ }
+ if (errorCode) {
+ if (errorCode == ETIMEDOUT) {
+ if (wakeup)
+ errorCode = 0;
+ break;
+ }
+ report_error(errorCode, "QMutex::lock()", "cv wait");
+ }
+ }
+ wakeup = false;
+ report_error(pthread_mutex_unlock(&mutex), "QMutex::lock", "mutex unlock");
+ contenders.deref();
+ return errorCode == 0;
+}
+
+void QMutexPrivate::wakeUp()
+{
+ report_error(pthread_mutex_lock(&mutex), "QMutex::unlock", "mutex lock");
+ wakeup = true;
+ report_error(pthread_cond_signal(&cond), "QMutex::unlock", "cv signal");
+ report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock");
+}
+
+#endif // !Q_OS_MAC && !Q_OS_LINUX
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_THREAD
diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp
new file mode 100644
index 0000000000..3a535c16ab
--- /dev/null
+++ b/src/corelib/thread/qmutex_win.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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 <qt_windows.h>
+
+#include "qmutex.h"
+#include <qatomic.h>
+#include "qmutex_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
+ : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0)
+{
+ event = CreateEvent(0, FALSE, FALSE, 0);
+ if (!event)
+ qWarning("QMutexPrivate::QMutexPrivate: Cannot create event");
+}
+
+QMutexPrivate::~QMutexPrivate()
+{ CloseHandle(event); }
+
+bool QMutexPrivate::wait(int timeout)
+{
+ if (contenders.fetchAndAddAcquire(1) == 0) {
+ // lock acquired without waiting
+ return true;
+ }
+ bool returnValue = (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0);
+ contenders.deref();
+ return returnValue;
+}
+
+void QMutexPrivate::wakeUp()
+{ SetEvent(event); }
+
+QT_END_NAMESPACE
diff --git a/src/corelib/thread/qmutexpool.cpp b/src/corelib/thread/qmutexpool.cpp
new file mode 100644
index 0000000000..144fa35137
--- /dev/null
+++ b/src/corelib/thread/qmutexpool.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** 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 "qatomic.h"
+#include "qmutexpool_p.h"
+
+#ifndef QT_NO_THREAD
+
+QT_BEGIN_NAMESPACE
+
+// qt_global_mutexpool is here for backwards compatibility only,
+// use QMutexpool::instance() in new clode.
+Q_CORE_EXPORT QMutexPool *qt_global_mutexpool = 0;
+Q_GLOBAL_STATIC_WITH_ARGS(QMutexPool, globalMutexPool, (QMutex::Recursive))
+
+/*!
+ \class QMutexPool
+ \brief The QMutexPool class provides a pool of QMutex objects.
+
+ \internal
+
+ \ingroup thread
+
+ QMutexPool is a convenience class that provides access to a fixed
+ number of QMutex objects.
+
+ Typical use of a QMutexPool is in situations where it is not
+ possible or feasible to use one QMutex for every protected object.
+ The mutex pool will return a mutex based on the address of the
+ object that needs protection.
+
+ For example, consider this simple class:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qmutexpool.cpp 0
+
+ Adding a QMutex member to the Number class does not make sense,
+ because it is so small. However, in order to ensure that access to
+ each Number is protected, you need to use a mutex. In this case, a
+ QMutexPool would be ideal.
+
+ Code to calculate the square of a number would then look something
+ like this:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qmutexpool.cpp 1
+
+ This function will safely calculate the square of a number, since
+ it uses a mutex from a QMutexPool. The mutex is locked and
+ unlocked automatically by the QMutexLocker class. See the
+ QMutexLocker documentation for more details.
+*/
+
+/*!
+ Constructs a QMutexPool, reserving space for \a size QMutexes. All
+ mutexes in the pool are created with \a recursionMode. By default,
+ all mutexes are non-recursive.
+
+ The QMutexes are created when needed, and deleted when the
+ QMutexPool is destructed.
+*/
+QMutexPool::QMutexPool(QMutex::RecursionMode recursionMode, int size)
+ : mutexes(size), recursionMode(recursionMode)
+{
+ for (int index = 0; index < mutexes.count(); ++index) {
+ mutexes[index] = 0;
+ }
+}
+
+/*!
+ Destructs a QMutexPool. All QMutexes that were created by the pool
+ are deleted.
+*/
+QMutexPool::~QMutexPool()
+{
+ for (int index = 0; index < mutexes.count(); ++index) {
+ delete mutexes[index];
+ mutexes[index] = 0;
+ }
+}
+
+/*!
+ Returns the global QMutexPool instance.
+*/
+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.
+*/
+
+/*! \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];
+}
+
+/*!
+ Returns a QMutex from the global mutex pool.
+*/
+QMutex *QMutexPool::globalInstanceGet(const void *address)
+{
+ QMutexPool * const globalInstance = globalMutexPool();
+ if (globalInstance == 0)
+ return 0;
+ return globalInstance->get(address);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_THREAD
diff --git a/src/corelib/thread/qmutexpool_p.h b/src/corelib/thread/qmutexpool_p.h
new file mode 100644
index 0000000000..b2cd210d71
--- /dev/null
+++ b/src/corelib/thread/qmutexpool_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QMUTEXPOOL_P_H
+#define QMUTEXPOOL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of QSettings. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qatomic.h"
+#include "QtCore/qmutex.h"
+#include "QtCore/qvarlengtharray.h"
+
+#ifndef QT_NO_THREAD
+
+QT_BEGIN_NAMESPACE
+
+class Q_CORE_EXPORT QMutexPool
+{
+public:
+ explicit QMutexPool(QMutex::RecursionMode recursionMode = QMutex::NonRecursive, int size = 131);
+ ~QMutexPool();
+
+ 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;
+};
+
+extern Q_CORE_EXPORT QMutexPool *qt_global_mutexpool;
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_THREAD
+
+#endif // QMUTEXPOOL_P_H
diff --git a/src/corelib/thread/qorderedmutexlocker_p.h b/src/corelib/thread/qorderedmutexlocker_p.h
new file mode 100644
index 0000000000..ddabfb7977
--- /dev/null
+++ b/src/corelib/thread/qorderedmutexlocker_p.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QORDEREDMUTEXLOCKER_P_H
+#define QORDEREDMUTEXLOCKER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+#include <QtCore/qmutex.h>
+
+/*
+ Locks 2 mutexes in a defined order, avoiding a recursive lock if
+ we're trying to lock the same mutex twice.
+*/
+class QOrderedMutexLocker
+{
+public:
+ QOrderedMutexLocker(QMutex *m1, QMutex *m2)
+ : mtx1((m1 == m2) ? m1 : (m1 < m2 ? m1 : m2)),
+ mtx2((m1 == m2) ? 0 : (m1 < m2 ? m2 : m1)),
+ locked(false)
+ {
+ relock();
+ }
+ ~QOrderedMutexLocker()
+ {
+ unlock();
+ }
+
+ void relock()
+ {
+ if (!locked) {
+ if (mtx1) mtx1->lockInline();
+ if (mtx2) mtx2->lockInline();
+ locked = true;
+ }
+ }
+
+ void unlock()
+ {
+ if (locked) {
+ if (mtx1) mtx1->unlockInline();
+ if (mtx2) mtx2->unlockInline();
+ locked = false;
+ }
+ }
+
+ static bool relock(QMutex *mtx1, QMutex *mtx2)
+ {
+ // mtx1 is already locked, mtx2 not... do we need to unlock and relock?
+ if (mtx1 == mtx2)
+ return false;
+ if (mtx1 < mtx2) {
+ mtx2->lockInline();
+ return true;
+ }
+ if (!mtx2->tryLockInline()) {
+ mtx1->unlock();
+ mtx2->lock();
+ mtx1->lock();
+ }
+ return true;
+ }
+
+private:
+ QMutex *mtx1, *mtx2;
+ bool locked;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/thread/qreadwritelock.cpp b/src/corelib/thread/qreadwritelock.cpp
new file mode 100644
index 0000000000..aabd26e07b
--- /dev/null
+++ b/src/corelib/thread/qreadwritelock.cpp
@@ -0,0 +1,581 @@
+/****************************************************************************
+**
+** 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 "qreadwritelock.h"
+
+#ifndef QT_NO_THREAD
+#include "qmutex.h"
+#include "qthread.h"
+#include "qwaitcondition.h"
+
+#include "qreadwritelock_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*! \class QReadWriteLock
+ \brief The QReadWriteLock class provides read-write locking.
+
+ \threadsafe
+
+ \ingroup thread
+
+ A read-write lock is a synchronization tool for protecting
+ resources that can be accessed for reading and writing. This type
+ of lock is useful if you want to allow multiple threads to have
+ simultaneous read-only access, but as soon as one thread wants to
+ write to the resource, all other threads must be blocked until
+ the writing is complete.
+
+ In many cases, QReadWriteLock is a direct competitor to QMutex.
+ QReadWriteLock is a good choice if there are many concurrent
+ reads and writing occurs infrequently.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qreadwritelock.cpp 0
+
+ To ensure that writers aren't blocked forever by readers, readers
+ attempting to obtain a lock will not succeed if there is a blocked
+ writer waiting for access, even if the lock is currently only
+ accessed by other readers. Also, if the lock is accessed by a
+ writer and another writer comes in, that writer will have
+ priority over any readers that might also be waiting.
+
+ Like QMutex, a QReadWriteLock can be recursively locked by the
+ same thread when constructed in
+ \l{QReadWriteLock::RecursionMode}. In such cases,
+ unlock() must be called the same number of times lockForWrite() or
+ lockForRead() was called. Note that the lock type cannot be
+ changed when trying to lock recursively, i.e. it is not possible
+ to lock for reading in a thread that already has locked for
+ writing (and vice versa).
+
+ \sa QReadLocker, QWriteLocker, QMutex, QSemaphore
+*/
+
+/*!
+ \enum QReadWriteLock::RecursionMode
+ \since 4.4
+
+ \value Recursive In this mode, a thread can lock the same
+ QReadWriteLock multiple times and the mutex won't be unlocked
+ until a corresponding number of unlock() calls have been made.
+
+ \value NonRecursive In this mode, a thread may only lock a
+ QReadWriteLock once.
+
+ \sa QReadWriteLock()
+*/
+
+/*!
+ Constructs a QReadWriteLock object in NonRecursive mode.
+
+ \sa lockForRead(), lockForWrite()
+*/
+QReadWriteLock::QReadWriteLock()
+ :d(new QReadWriteLockPrivate(NonRecursive))
+{ }
+
+/*!
+ \since 4.4
+
+ Constructs a QReadWriteLock object in the given \a recursionMode.
+
+ \sa lockForRead(), lockForWrite(), RecursionMode
+*/
+QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
+ : d(new QReadWriteLockPrivate(recursionMode))
+{ }
+
+/*!
+ Destroys the QReadWriteLock object.
+
+ \warning Destroying a read-write lock that is in use may result
+ in undefined behavior.
+*/
+QReadWriteLock::~QReadWriteLock()
+{
+ delete d;
+}
+
+/*!
+ Locks the lock for reading. This function will block the current
+ thread if any thread (including the current) has locked for
+ writing.
+
+ \sa unlock() lockForWrite() tryLockForRead()
+*/
+void QReadWriteLock::lockForRead()
+{
+ QMutexLocker lock(&d->mutex);
+
+ Qt::HANDLE self = 0;
+ if (d->recursive) {
+ self = QThread::currentThreadId();
+
+ QHash<Qt::HANDLE, int>::iterator it = d->currentReaders.find(self);
+ if (it != d->currentReaders.end()) {
+ ++it.value();
+ ++d->accessCount;
+ Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::lockForRead()",
+ "Overflow in lock counter");
+ return;
+ }
+ }
+
+ while (d->accessCount < 0 || d->waitingWriters) {
+ ++d->waitingReaders;
+ d->readerWait.wait(&d->mutex);
+ --d->waitingReaders;
+ }
+ if (d->recursive)
+ d->currentReaders.insert(self, 1);
+
+ ++d->accessCount;
+ Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::lockForRead()", "Overflow in lock counter");
+}
+
+/*!
+ Attempts to lock for reading. If the lock was obtained, this
+ function returns true, otherwise it returns false instead of
+ waiting for the lock to become available, i.e. it does not block.
+
+ The lock attempt will fail if another thread has locked for
+ writing.
+
+ If the lock was obtained, the lock must be unlocked with unlock()
+ before another thread can successfully lock it.
+
+ \sa unlock() lockForRead()
+*/
+bool QReadWriteLock::tryLockForRead()
+{
+ QMutexLocker lock(&d->mutex);
+
+ Qt::HANDLE self = 0;
+ if (d->recursive) {
+ self = QThread::currentThreadId();
+
+ QHash<Qt::HANDLE, int>::iterator it = d->currentReaders.find(self);
+ if (it != d->currentReaders.end()) {
+ ++it.value();
+ ++d->accessCount;
+ Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()",
+ "Overflow in lock counter");
+ return true;
+ }
+ }
+
+ if (d->accessCount < 0)
+ return false;
+ if (d->recursive)
+ d->currentReaders.insert(self, 1);
+
+ ++d->accessCount;
+ Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()", "Overflow in lock counter");
+
+ return true;
+}
+
+/*! \overload
+
+ Attempts to lock for reading. This function returns true if the
+ lock was obtained; otherwise it returns false. If another thread
+ has locked for writing, this function will wait for at most \a
+ timeout milliseconds for the lock to become available.
+
+ Note: Passing a negative number as the \a timeout is equivalent to
+ calling lockForRead(), i.e. this function will wait forever until
+ lock can be locked for reading when \a timeout is negative.
+
+ If the lock was obtained, the lock must be unlocked with unlock()
+ before another thread can successfully lock it.
+
+ \sa unlock() lockForRead()
+*/
+bool QReadWriteLock::tryLockForRead(int timeout)
+{
+ QMutexLocker lock(&d->mutex);
+
+ Qt::HANDLE self = 0;
+ if (d->recursive) {
+ self = QThread::currentThreadId();
+
+ QHash<Qt::HANDLE, int>::iterator it = d->currentReaders.find(self);
+ if (it != d->currentReaders.end()) {
+ ++it.value();
+ ++d->accessCount;
+ Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()",
+ "Overflow in lock counter");
+ return true;
+ }
+ }
+
+ while (d->accessCount < 0 || d->waitingWriters) {
+ ++d->waitingReaders;
+ bool success = d->readerWait.wait(&d->mutex, timeout < 0 ? ULONG_MAX : ulong(timeout));
+ --d->waitingReaders;
+ if (!success)
+ return false;
+ }
+ if (d->recursive)
+ d->currentReaders.insert(self, 1);
+
+ ++d->accessCount;
+ Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()", "Overflow in lock counter");
+
+ return true;
+}
+
+/*!
+ Locks the lock for writing. This function will block the current
+ thread if another thread has locked for reading or writing.
+
+ \sa unlock() lockForRead() tryLockForWrite()
+*/
+void QReadWriteLock::lockForWrite()
+{
+ QMutexLocker lock(&d->mutex);
+
+ Qt::HANDLE self = 0;
+ if (d->recursive) {
+ self = QThread::currentThreadId();
+
+ if (d->currentWriter == self) {
+ --d->accessCount;
+ Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::lockForWrite()",
+ "Overflow in lock counter");
+ return;
+ }
+ }
+
+ while (d->accessCount != 0) {
+ ++d->waitingWriters;
+ d->writerWait.wait(&d->mutex);
+ --d->waitingWriters;
+ }
+ if (d->recursive)
+ d->currentWriter = self;
+
+ --d->accessCount;
+ Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::lockForWrite()", "Overflow in lock counter");
+}
+
+/*!
+ Attempts to lock for writing. If the lock was obtained, this
+ function returns true; otherwise, it returns false immediately.
+
+ The lock attempt will fail if another thread has locked for
+ reading or writing.
+
+ If the lock was obtained, the lock must be unlocked with unlock()
+ before another thread can successfully lock it.
+
+ \sa unlock() lockForWrite()
+*/
+bool QReadWriteLock::tryLockForWrite()
+{
+ QMutexLocker lock(&d->mutex);
+
+ Qt::HANDLE self = 0;
+ if (d->recursive) {
+ self = QThread::currentThreadId();
+
+ if (d->currentWriter == self) {
+ --d->accessCount;
+ Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::lockForWrite()",
+ "Overflow in lock counter");
+ return true;
+ }
+ }
+
+ if (d->accessCount != 0)
+ return false;
+ if (d->recursive)
+ d->currentWriter = self;
+
+ --d->accessCount;
+ Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::tryLockForWrite()",
+ "Overflow in lock counter");
+
+ return true;
+}
+
+/*! \overload
+
+ Attempts to lock for writing. This function returns true if the
+ lock was obtained; otherwise it returns false. If another thread
+ has locked for reading or writing, this function will wait for at
+ most \a timeout milliseconds for the lock to become available.
+
+ Note: Passing a negative number as the \a timeout is equivalent to
+ calling lockForWrite(), i.e. this function will wait forever until
+ lock can be locked for writing when \a timeout is negative.
+
+ If the lock was obtained, the lock must be unlocked with unlock()
+ before another thread can successfully lock it.
+
+ \sa unlock() lockForWrite()
+*/
+bool QReadWriteLock::tryLockForWrite(int timeout)
+{
+ QMutexLocker lock(&d->mutex);
+
+ Qt::HANDLE self = 0;
+ if (d->recursive) {
+ self = QThread::currentThreadId();
+
+ if (d->currentWriter == self) {
+ --d->accessCount;
+ Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::lockForWrite()",
+ "Overflow in lock counter");
+ return true;
+ }
+ }
+
+ while (d->accessCount != 0) {
+ ++d->waitingWriters;
+ bool success = d->writerWait.wait(&d->mutex, timeout < 0 ? ULONG_MAX : ulong(timeout));
+ --d->waitingWriters;
+
+ if (!success)
+ return false;
+ }
+ if (d->recursive)
+ d->currentWriter = self;
+
+ --d->accessCount;
+ Q_ASSERT_X(d->accessCount < 0, "QReadWriteLock::tryLockForWrite()",
+ "Overflow in lock counter");
+
+ return true;
+}
+
+/*!
+ Unlocks the lock.
+
+ Attempting to unlock a lock that is not locked is an error, and will result
+ in program termination.
+
+ \sa lockForRead() lockForWrite() tryLockForRead() tryLockForWrite()
+*/
+void QReadWriteLock::unlock()
+{
+ QMutexLocker lock(&d->mutex);
+
+ Q_ASSERT_X(d->accessCount != 0, "QReadWriteLock::unlock()", "Cannot unlock an unlocked lock");
+
+ bool unlocked = false;
+ if (d->accessCount > 0) {
+ // releasing a read lock
+ if (d->recursive) {
+ Qt::HANDLE self = QThread::currentThreadId();
+ QHash<Qt::HANDLE, int>::iterator it = d->currentReaders.find(self);
+ if (it != d->currentReaders.end()) {
+ if (--it.value() <= 0)
+ d->currentReaders.erase(it);
+ }
+ }
+
+ unlocked = --d->accessCount == 0;
+ } else if (d->accessCount < 0 && ++d->accessCount == 0) {
+ // released a write lock
+ unlocked = true;
+ d->currentWriter = 0;
+ }
+
+ if (unlocked) {
+ if (d->waitingWriters) {
+ d->writerWait.wakeOne();
+ } else if (d->waitingReaders) {
+ d->readerWait.wakeAll();
+ }
+ }
+}
+
+/*!
+ \class QReadLocker
+ \brief The QReadLocker class is a convenience class that
+ simplifies locking and unlocking read-write locks for read access.
+
+ \threadsafe
+
+ \ingroup thread
+
+ The purpose of QReadLocker (and QWriteLocker) is to simplify
+ QReadWriteLock locking and unlocking. Locking and unlocking
+ statements or in exception handling code is error-prone and
+ difficult to debug. QReadLocker can be used in such situations
+ to ensure that the state of the lock is always well-defined.
+
+ Here's an example that uses QReadLocker to lock and unlock a
+ read-write lock for reading:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qreadwritelock.cpp 1
+
+ It is equivalent to the following code:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qreadwritelock.cpp 2
+
+ The QMutexLocker documentation shows examples where the use of a
+ locker object greatly simplifies programming.
+
+ \sa QWriteLocker, QReadWriteLock
+*/
+
+/*!
+ \fn QReadLocker::QReadLocker(QReadWriteLock *lock)
+
+ Constructs a QReadLocker and locks \a lock for reading. The lock
+ will be unlocked when the QReadLocker is destroyed. If \c lock is
+ zero, QReadLocker does nothing.
+
+ \sa QReadWriteLock::lockForRead()
+*/
+
+/*!
+ \fn QReadLocker::~QReadLocker()
+
+ Destroys the QReadLocker and unlocks the lock that was passed to
+ the constructor.
+
+ \sa QReadWriteLock::unlock()
+*/
+
+/*!
+ \fn void QReadLocker::unlock()
+
+ Unlocks the lock associated with this locker.
+
+ \sa QReadWriteLock::unlock()
+*/
+
+/*!
+ \fn void QReadLocker::relock()
+
+ Relocks an unlocked lock.
+
+ \sa unlock()
+*/
+
+/*!
+ \fn QReadWriteLock *QReadLocker::readWriteLock() const
+
+ Returns a pointer to the read-write lock that was passed
+ to the constructor.
+*/
+
+/*!
+ \class QWriteLocker
+ \brief The QWriteLocker class is a convenience class that
+ simplifies locking and unlocking read-write locks for write access.
+
+ \threadsafe
+
+ \ingroup thread
+
+ The purpose of QWriteLocker (and QReadLocker is to simplify
+ QReadWriteLock locking and unlocking. Locking and unlocking
+ statements or in exception handling code is error-prone and
+ difficult to debug. QWriteLocker can be used in such situations
+ to ensure that the state of the lock is always well-defined.
+
+ Here's an example that uses QWriteLocker to lock and unlock a
+ read-write lock for writing:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qreadwritelock.cpp 3
+
+ It is equivalent to the following code:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qreadwritelock.cpp 4
+
+ The QMutexLocker documentation shows examples where the use of a
+ locker object greatly simplifies programming.
+
+ \sa QReadLocker, QReadWriteLock
+*/
+
+/*!
+ \fn QWriteLocker::QWriteLocker(QReadWriteLock *lock)
+
+ Constructs a QWriteLocker and locks \a lock for writing. The lock
+ will be unlocked when the QWriteLocker is destroyed. If \c lock is
+ zero, QWriteLocker does nothing.
+
+ \sa QReadWriteLock::lockForWrite()
+*/
+
+/*!
+ \fn QWriteLocker::~QWriteLocker()
+
+ Destroys the QWriteLocker and unlocks the lock that was passed to
+ the constructor.
+
+ \sa QReadWriteLock::unlock()
+*/
+
+/*!
+ \fn void QWriteLocker::unlock()
+
+ Unlocks the lock associated with this locker.
+
+ \sa QReadWriteLock::unlock()
+*/
+
+/*!
+ \fn void QWriteLocker::relock()
+
+ Relocks an unlocked lock.
+
+ \sa unlock()
+*/
+
+/*!
+ \fn QReadWriteLock *QWriteLocker::readWriteLock() const
+
+ Returns a pointer to the read-write lock that was passed
+ to the constructor.
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_THREAD
diff --git a/src/corelib/thread/qreadwritelock.h b/src/corelib/thread/qreadwritelock.h
new file mode 100644
index 0000000000..e4fd18e0e3
--- /dev/null
+++ b/src/corelib/thread/qreadwritelock.h
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QREADWRITELOCK_H
+#define QREADWRITELOCK_H
+
+#include <QtCore/qglobal.h>
+#include <limits.h> // ### Qt 5: remove
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_THREAD
+
+struct QReadWriteLockPrivate;
+
+class Q_CORE_EXPORT QReadWriteLock
+{
+public:
+ enum RecursionMode { NonRecursive, Recursive };
+
+ QReadWriteLock(); // ### Qt 5: merge with below
+ QReadWriteLock(RecursionMode recursionMode);
+ ~QReadWriteLock();
+
+ void lockForRead();
+ bool tryLockForRead();
+ bool tryLockForRead(int timeout);
+
+ void lockForWrite();
+ bool tryLockForWrite();
+ bool tryLockForWrite(int timeout);
+
+ void unlock();
+
+private:
+ Q_DISABLE_COPY(QReadWriteLock)
+ QReadWriteLockPrivate *d;
+
+ friend class QWaitCondition;
+};
+
+#if defined(Q_CC_MSVC)
+#pragma warning( push )
+#pragma warning( disable : 4312 ) // ignoring the warning from /Wp64
+#endif
+
+class Q_CORE_EXPORT QReadLocker
+{
+public:
+ inline QReadLocker(QReadWriteLock *readWriteLock);
+
+ inline ~QReadLocker()
+ { unlock(); }
+
+ inline void unlock()
+ {
+ if (q_val) {
+ if ((q_val & quintptr(1u)) == quintptr(1u)) {
+ q_val &= ~quintptr(1u);
+ readWriteLock()->unlock();
+ }
+ }
+ }
+
+ inline void relock()
+ {
+ if (q_val) {
+ if ((q_val & quintptr(1u)) == quintptr(0u)) {
+ readWriteLock()->lockForRead();
+ q_val |= quintptr(1u);
+ }
+ }
+ }
+
+ inline QReadWriteLock *readWriteLock() const
+ { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
+
+private:
+ Q_DISABLE_COPY(QReadLocker)
+ quintptr q_val;
+};
+
+inline QReadLocker::QReadLocker(QReadWriteLock *areadWriteLock)
+ : q_val(reinterpret_cast<quintptr>(areadWriteLock))
+{
+ Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
+ "QReadLocker", "QReadWriteLock pointer is misaligned");
+ relock();
+}
+
+class Q_CORE_EXPORT QWriteLocker
+{
+public:
+ inline QWriteLocker(QReadWriteLock *readWriteLock);
+
+ inline ~QWriteLocker()
+ { unlock(); }
+
+ inline void unlock()
+ {
+ if (q_val) {
+ if ((q_val & quintptr(1u)) == quintptr(1u)) {
+ q_val &= ~quintptr(1u);
+ readWriteLock()->unlock();
+ }
+ }
+ }
+
+ inline void relock()
+ {
+ if (q_val) {
+ if ((q_val & quintptr(1u)) == quintptr(0u)) {
+ readWriteLock()->lockForWrite();
+ q_val |= quintptr(1u);
+ }
+ }
+ }
+
+ inline QReadWriteLock *readWriteLock() const
+ { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
+
+
+private:
+ Q_DISABLE_COPY(QWriteLocker)
+ quintptr q_val;
+};
+
+inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
+ : q_val(reinterpret_cast<quintptr>(areadWriteLock))
+{
+ Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
+ "QWriteLocker", "QReadWriteLock pointer is misaligned");
+ relock();
+}
+
+#if defined(Q_CC_MSVC)
+#pragma warning( pop )
+#endif
+
+#else // QT_NO_THREAD
+
+class Q_CORE_EXPORT QReadWriteLock
+{
+public:
+ enum RecursionMode { NonRecursive, Recursive };
+ inline explicit QReadWriteLock(RecursionMode = NonRecursive) { }
+ inline ~QReadWriteLock() { }
+
+ static inline void lockForRead() { }
+ static inline bool tryLockForRead() { return true; }
+ static inline bool tryLockForRead(int timeout) { Q_UNUSED(timeout); return true; }
+
+ static inline void lockForWrite() { }
+ static inline bool tryLockForWrite() { return true; }
+ static inline bool tryLockForWrite(int timeout) { Q_UNUSED(timeout); return true; }
+
+ static inline void unlock() { }
+
+private:
+ Q_DISABLE_COPY(QReadWriteLock)
+};
+
+class Q_CORE_EXPORT QReadLocker
+{
+public:
+ inline QReadLocker(QReadWriteLock *) { }
+ inline ~QReadLocker() { }
+
+ static inline void unlock() { }
+ static inline void relock() { }
+ static inline QReadWriteLock *readWriteLock() { return 0; }
+
+private:
+ Q_DISABLE_COPY(QReadLocker)
+};
+
+class Q_CORE_EXPORT QWriteLocker
+{
+public:
+ inline explicit QWriteLocker(QReadWriteLock *) { }
+ inline ~QWriteLocker() { }
+
+ static inline void unlock() { }
+ static inline void relock() { }
+ static inline QReadWriteLock *readWriteLock() { return 0; }
+
+private:
+ Q_DISABLE_COPY(QWriteLocker)
+};
+
+#endif // QT_NO_THREAD
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QREADWRITELOCK_H
diff --git a/src/corelib/thread/qreadwritelock_p.h b/src/corelib/thread/qreadwritelock_p.h
new file mode 100644
index 0000000000..26f26d78a4
--- /dev/null
+++ b/src/corelib/thread/qreadwritelock_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QREADWRITELOCK_P_H
+#define QREADWRITELOCK_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the implementation. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qhash.h>
+
+#ifndef QT_NO_THREAD
+
+QT_BEGIN_NAMESPACE
+
+struct QReadWriteLockPrivate
+{
+ QReadWriteLockPrivate(QReadWriteLock::RecursionMode recursionMode)
+ : accessCount(0), waitingReaders(0), waitingWriters(0),
+ recursive(recursionMode == QReadWriteLock::Recursive), currentWriter(0)
+ { }
+
+ QMutex mutex;
+ QWaitCondition readerWait;
+ QWaitCondition writerWait;
+
+ int accessCount;
+ int waitingReaders;
+ int waitingWriters;
+
+ bool recursive;
+ Qt::HANDLE currentWriter;
+ QHash<Qt::HANDLE, int> currentReaders;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_THREAD
+
+#endif // QREADWRITELOCK_P_H
diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp
new file mode 100644
index 0000000000..ba6fa6ef9b
--- /dev/null
+++ b/src/corelib/thread/qsemaphore.cpp
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** 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 "qsemaphore.h"
+
+#ifndef QT_NO_THREAD
+#include "qmutex.h"
+#include "qwaitcondition.h"
+#include "qelapsedtimer.h"
+#include "qdatetime.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSemaphore
+ \brief The QSemaphore class provides a general counting semaphore.
+
+ \threadsafe
+
+ \ingroup thread
+
+ A semaphore is a generalization of a mutex. While a mutex can
+ only be locked once, it's possible to acquire a semaphore
+ multiple times. Semaphores are typically used to protect a
+ certain number of identical resources.
+
+ Semaphores support two fundamental operations, acquire() and
+ release():
+
+ \list
+ \o acquire(\e{n}) tries to acquire \e n resources. If there aren't
+ that many resources available, the call will block until this
+ is the case.
+ \o release(\e{n}) releases \e n resources.
+ \endlist
+
+ There's also a tryAcquire() function that returns immediately if
+ it cannot acquire the resources, and an available() function that
+ returns the number of available resources at any time.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qsemaphore.cpp 0
+
+ A typical application of semaphores is for controlling access to
+ a circular buffer shared by a producer thread and a consumer
+ thread. The \l{threads/semaphores}{Semaphores} example shows how
+ to use QSemaphore to solve that problem.
+
+ A non-computing example of a semaphore would be dining at a
+ restaurant. A semaphore is initialized with the number of chairs
+ in the restaurant. As people arrive, they want a seat. As seats
+ are filled, available() is decremented. As people leave, the
+ available() is incremented, allowing more people to enter. If a
+ party of 10 people want to be seated, but there are only 9 seats,
+ those 10 people will wait, but a party of 4 people would be
+ seated (taking the available seats to 5, making the party of 10
+ people wait longer).
+
+ \sa QMutex, QWaitCondition, QThread, {Semaphores Example}
+*/
+
+class QSemaphorePrivate {
+public:
+ inline QSemaphorePrivate(int n) : avail(n) { }
+
+ QMutex mutex;
+ QWaitCondition cond;
+
+ int avail;
+};
+
+/*!
+ Creates a new semaphore and initializes the number of resources
+ it guards to \a n (by default, 0).
+
+ \sa release(), available()
+*/
+QSemaphore::QSemaphore(int n)
+{
+ Q_ASSERT_X(n >= 0, "QSemaphore", "parameter 'n' must be non-negative");
+ d = new QSemaphorePrivate(n);
+}
+
+/*!
+ Destroys the semaphore.
+
+ \warning Destroying a semaphore that is in use may result in
+ undefined behavior.
+*/
+QSemaphore::~QSemaphore()
+{ delete d; }
+
+/*!
+ Tries to acquire \c n resources guarded by the semaphore. If \a n
+ > available(), this call will block until enough resources are
+ available.
+
+ \sa release(), available(), tryAcquire()
+*/
+void QSemaphore::acquire(int n)
+{
+ Q_ASSERT_X(n >= 0, "QSemaphore::acquire", "parameter 'n' must be non-negative");
+ QMutexLocker locker(&d->mutex);
+ while (n > d->avail)
+ d->cond.wait(locker.mutex());
+ d->avail -= n;
+}
+
+/*!
+ Releases \a n resources guarded by the semaphore.
+
+ This function can be used to "create" resources as well. For
+ example:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qsemaphore.cpp 1
+
+ \sa acquire(), available()
+*/
+void QSemaphore::release(int n)
+{
+ Q_ASSERT_X(n >= 0, "QSemaphore::release", "parameter 'n' must be non-negative");
+ QMutexLocker locker(&d->mutex);
+ d->avail += n;
+ d->cond.wakeAll();
+}
+
+/*!
+ Returns the number of resources currently available to the
+ semaphore. This number can never be negative.
+
+ \sa acquire(), release()
+*/
+int QSemaphore::available() const
+{
+ QMutexLocker locker(&d->mutex);
+ return d->avail;
+}
+
+/*!
+ Tries to acquire \c n resources guarded by the semaphore and
+ returns true on success. If available() < \a n, this call
+ immediately returns false without acquiring any resources.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qsemaphore.cpp 2
+
+ \sa acquire()
+*/
+bool QSemaphore::tryAcquire(int n)
+{
+ Q_ASSERT_X(n >= 0, "QSemaphore::tryAcquire", "parameter 'n' must be non-negative");
+ QMutexLocker locker(&d->mutex);
+ if (n > d->avail)
+ return false;
+ d->avail -= n;
+ return true;
+}
+
+/*!
+ Tries to acquire \c n resources guarded by the semaphore and
+ returns true on success. If available() < \a n, this call will
+ wait for at most \a timeout milliseconds for resources to become
+ available.
+
+ Note: Passing a negative number as the \a timeout is equivalent to
+ calling acquire(), i.e. this function will wait forever for
+ resources to become available if \a timeout is negative.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qsemaphore.cpp 3
+
+ \sa acquire()
+*/
+bool QSemaphore::tryAcquire(int n, int timeout)
+{
+ Q_ASSERT_X(n >= 0, "QSemaphore::tryAcquire", "parameter 'n' must be non-negative");
+ QMutexLocker locker(&d->mutex);
+ if (timeout < 0) {
+ while (n > d->avail)
+ d->cond.wait(locker.mutex());
+ } else {
+ QElapsedTimer timer;
+ timer.start();
+ while (n > d->avail) {
+ const qint64 elapsed = timer.elapsed();
+ if (timeout - elapsed <= 0
+ || !d->cond.wait(locker.mutex(), timeout - elapsed))
+ return false;
+ }
+ }
+ d->avail -= n;
+ return true;
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_THREAD
diff --git a/src/corelib/thread/qsemaphore.h b/src/corelib/thread/qsemaphore.h
new file mode 100644
index 0000000000..e820175528
--- /dev/null
+++ b/src/corelib/thread/qsemaphore.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QSEMAPHORE_H
+#define QSEMAPHORE_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_THREAD
+
+class QSemaphorePrivate;
+
+class Q_CORE_EXPORT QSemaphore
+{
+public:
+ explicit QSemaphore(int n = 0);
+ ~QSemaphore();
+
+ void acquire(int n = 1);
+ bool tryAcquire(int n = 1);
+ bool tryAcquire(int n, int timeout);
+
+ void release(int n = 1);
+
+ int available() const;
+
+private:
+ Q_DISABLE_COPY(QSemaphore)
+
+ QSemaphorePrivate *d;
+};
+
+#endif // QT_NO_THREAD
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSEMAPHORE_H
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
new file mode 100644
index 0000000000..aaa1e6dc36
--- /dev/null
+++ b/src/corelib/thread/qthread.cpp
@@ -0,0 +1,772 @@
+/****************************************************************************
+**
+** 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 "qthreadstorage.h"
+#include "qmutex.h"
+#include "qmutexpool_p.h"
+#include "qreadwritelock.h"
+#include "qabstracteventdispatcher.h"
+
+#include <qeventloop.h>
+#include <qhash.h>
+
+#include "qthread_p.h"
+#include "private/qcoreapplication_p.h"
+
+/*
+#ifdef Q_OS_WIN32
+# include "qt_windows.h"
+#else
+# include <unistd.h>
+# include <netinet/in.h>
+# include <sys/utsname.h>
+# include <sys/socket.h>
+*/
+/*
+# elif defined(Q_OS_HPUX)
+# include <sys/pstat.h>
+# elif defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_MAC)
+# include <sys/sysctl.h>
+# endif
+#endif
+*/
+
+QT_BEGIN_NAMESPACE
+
+/*
+ QThreadData
+*/
+
+QThreadData::QThreadData(int initialRefCount)
+ : _ref(initialRefCount), thread(0), threadId(0),
+ quitNow(false), loopLevel(0), eventDispatcher(0), canWait(true), isAdopted(false)
+{
+ // fprintf(stderr, "QThreadData %p created\n", this);
+}
+
+QThreadData::~QThreadData()
+{
+ Q_ASSERT(_ref == 0);
+
+ // In the odd case that Qt is running on a secondary thread, the main
+ // thread instance will have been dereffed asunder because of the deref in
+ // QThreadData::current() and the deref in the pthread_destroy. To avoid
+ // crashing during QCoreApplicationData's global static cleanup we need to
+ // safeguard the main thread here.. This fix is a bit crude, but it solves
+ // the problem...
+ if (this->thread == QCoreApplicationPrivate::theMainThread) {
+ QCoreApplicationPrivate::theMainThread = 0;
+ }
+
+ QThread *t = thread;
+ thread = 0;
+ delete t;
+
+ for (int i = 0; i < postEventList.size(); ++i) {
+ const QPostEvent &pe = postEventList.at(i);
+ if (pe.event) {
+ --pe.receiver->d_func()->postedEvents;
+ pe.event->posted = false;
+ delete pe.event;
+ }
+ }
+
+ // fprintf(stderr, "QThreadData %p destroyed\n", this);
+}
+
+void QThreadData::ref()
+{
+#ifndef QT_NO_THREAD
+ (void) _ref.ref();
+ Q_ASSERT(_ref != 0);
+#endif
+}
+
+void QThreadData::deref()
+{
+#ifndef QT_NO_THREAD
+ if (!_ref.deref())
+ delete this;
+#endif
+}
+
+/*
+ QAdoptedThread
+*/
+
+QAdoptedThread::QAdoptedThread(QThreadData *data)
+ : QThread(*new QThreadPrivate(data))
+{
+ // thread should be running and not finished for the lifetime
+ // of the application (even if QCoreApplication goes away)
+#ifndef QT_NO_THREAD
+ d_func()->running = true;
+ d_func()->finished = false;
+ init();
+#endif
+
+ // fprintf(stderr, "new QAdoptedThread = %p\n", this);
+}
+
+QAdoptedThread::~QAdoptedThread()
+{
+ // fprintf(stderr, "~QAdoptedThread = %p\n", this);
+}
+
+QThread *QAdoptedThread::createThreadForAdoption()
+{
+ QScopedPointer<QThread> t(new QAdoptedThread(0));
+ t->moveToThread(t.data());
+ return t.take();
+}
+
+void QAdoptedThread::run()
+{
+ // this function should never be called
+ qFatal("QAdoptedThread::run(): Internal error, this implementation should never be called.");
+}
+#ifndef QT_NO_THREAD
+/*
+ QThreadPrivate
+*/
+
+QThreadPrivate::QThreadPrivate(QThreadData *d)
+ : QObjectPrivate(), running(false), finished(false), terminated(false),
+ isInFinish(false), exited(false), returnCode(-1),
+ stackSize(0), priority(QThread::InheritPriority), data(d)
+{
+#if defined (Q_OS_UNIX)
+ thread_id = 0;
+#elif defined (Q_WS_WIN)
+ handle = 0;
+ id = 0;
+ waiters = 0;
+#endif
+#if defined (Q_WS_WIN) || defined (Q_OS_SYMBIAN)
+ terminationEnabled = true;
+ terminatePending = false;
+#endif
+
+ if (!data)
+ data = new QThreadData;
+}
+
+QThreadPrivate::~QThreadPrivate()
+{
+ data->deref();
+}
+
+/*!
+ \class QThread
+ \brief The QThread class provides platform-independent threads.
+
+ \ingroup thread
+
+ A QThread represents a separate thread of control within the
+ program; it shares data with all the other threads within the
+ process but executes independently in the way that a separate
+ program does on a multitasking operating system. Instead of
+ starting in \c main(), QThreads begin executing in run(). By
+ default, run() starts the event loop by calling exec() (see
+ below). To create your own threads, subclass QThread and
+ reimplement run(). For example:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qthread.cpp 0
+
+ This will create a QTcpSocket in the thread and then execute the
+ thread's event loop. Use the start() method to begin execution.
+ Execution ends when you return from run(), just as an application
+ does when it leaves main(). QThread will notifiy you via a signal
+ when the thread is started(), finished(), and terminated(), or
+ you can use isFinished() and isRunning() to query the state of
+ the thread. Use wait() to block until the thread has finished
+ execution.
+
+ Each thread gets its own stack from the operating system. The
+ operating system also determines the default size of the stack.
+ You can use setStackSize() to set a custom stack size.
+
+ Each QThread can have its own event loop. You can start the event
+ loop by calling exec(); you can stop it by calling exit() or
+ quit(). Having an event loop in a thread makes it possible to
+ connect signals from other threads to slots in this thread, using
+ a mechanism called \l{Qt::QueuedConnection}{queued
+ connections}. It also makes it possible to use classes that
+ require the event loop, such as QTimer and QTcpSocket, in the
+ thread. Note, however, that it is not possible to use any widget
+ classes in the thread.
+
+ In extreme cases, you may want to forcibly terminate() an
+ executing thread. However, doing so is dangerous and discouraged.
+ Please read the documentation for terminate() and
+ setTerminationEnabled() for detailed information.
+
+ The static functions currentThreadId() and currentThread() return
+ identifiers for the currently executing thread. The former
+ returns a platform specific ID for the thread; the latter returns
+ a QThread pointer.
+
+ QThread also provides platform independent sleep functions in
+ varying resolutions. Use sleep() for full second resolution,
+ msleep() for millisecond resolution, and usleep() for microsecond
+ resolution.
+
+ \sa {Thread Support in Qt}, QThreadStorage, QMutex, QSemaphore, QWaitCondition,
+ {Mandelbrot Example}, {Semaphores Example}, {Wait Conditions Example}
+*/
+
+/*!
+ \fn Qt::HANDLE QThread::currentThreadId()
+
+ Returns the thread handle of the currently executing thread.
+
+ \warning The handle returned by this function is used for internal
+ purposes and should not be used in any application code.
+
+ \warning On Windows, the returned value is a pseudo-handle for the
+ current thread. It can't be used for numerical comparison. i.e.,
+ this function returns the DWORD (Windows-Thread ID) returned by
+ the Win32 function getCurrentThreadId(), not the HANDLE
+ (Windows-Thread HANDLE) returned by the Win32 function
+ getCurrentThread().
+*/
+
+/*!
+ \fn int QThread::idealThreadCount()
+
+ Returns the ideal number of threads that can be run on the system. This is done querying
+ the number of processor cores, both real and logical, in the system. This function returns -1
+ if the number of processor cores could not be detected.
+*/
+
+/*!
+ \fn void QThread::yieldCurrentThread()
+
+ Yields execution of the current thread to another runnable thread,
+ if any. Note that the operating system decides to which thread to
+ switch.
+*/
+
+/*!
+ \fn void QThread::start(Priority priority)
+
+ Begins execution of the thread by calling run(), which should be
+ reimplemented in a QThread subclass to contain your code. The
+ operating system will schedule the thread according to the \a
+ priority parameter. If the thread is already running, this
+ function does nothing.
+
+ The effect of the \a priority parameter is dependent on the
+ operating system's scheduling policy. In particular, the \a priority
+ will be ignored on systems that do not support thread priorities
+ (such as on Linux, see http://linux.die.net/man/2/sched_setscheduler
+ for more details).
+
+ \sa run(), terminate()
+*/
+
+/*!
+ \fn void QThread::started()
+
+ This signal is emitted when the thread starts executing.
+
+ \sa finished(), terminated()
+*/
+
+/*!
+ \fn void QThread::finished()
+
+ This signal is emitted when the thread has finished executing.
+
+ \sa started(), terminated()
+*/
+
+/*!
+ \fn void QThread::terminated()
+
+ This signal is emitted when the thread is terminated.
+
+ \sa started(), finished()
+*/
+
+/*!
+ \enum QThread::Priority
+
+ This enum type indicates how the operating system should schedule
+ newly created threads.
+
+ \value IdlePriority scheduled only when no other threads are
+ running.
+
+ \value LowestPriority scheduled less often than LowPriority.
+ \value LowPriority scheduled less often than NormalPriority.
+
+ \value NormalPriority the default priority of the operating
+ system.
+
+ \value HighPriority scheduled more often than NormalPriority.
+ \value HighestPriority scheduled more often than HighPriority.
+
+ \value TimeCriticalPriority scheduled as often as possible.
+
+ \value InheritPriority use the same priority as the creating
+ thread. This is the default.
+*/
+
+/*!
+ Returns a pointer to a QThread which represents the currently
+ executing thread.
+*/
+QThread *QThread::currentThread()
+{
+ QThreadData *data = QThreadData::current();
+ Q_ASSERT(data != 0);
+ return data->thread;
+}
+
+/*!
+ Constructs a new thread with the given \a parent. The thread does
+ not begin executing until start() is called.
+
+ \sa start()
+*/
+QThread::QThread(QObject *parent)
+ : QObject(*(new QThreadPrivate), parent)
+{
+ Q_D(QThread);
+ // fprintf(stderr, "QThreadData %p created for thread %p\n", d->data, this);
+ d->data->thread = this;
+}
+
+/*! \internal
+ */
+QThread::QThread(QThreadPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+ Q_D(QThread);
+ // fprintf(stderr, "QThreadData %p taken from private data for thread %p\n", d->data, this);
+ d->data->thread = this;
+}
+
+/*!
+ Destroys the thread.
+
+ Note that deleting a QThread object will not stop the execution
+ of the thread it represents. Deleting a running QThread (i.e.
+ isFinished() returns false) will probably result in a program
+ crash. You can wait() on a thread to make sure that it has
+ finished.
+*/
+QThread::~QThread()
+{
+ Q_D(QThread);
+ {
+ QMutexLocker locker(&d->mutex);
+ if (d->isInFinish) {
+ locker.unlock();
+ wait();
+ locker.relock();
+ }
+ if (d->running && !d->finished && !d->data->isAdopted)
+ qWarning("QThread: Destroyed while thread is still running");
+
+ d->data->thread = 0;
+ }
+}
+
+/*!
+ Returns true if the thread is finished; otherwise returns false.
+
+ \sa isRunning()
+*/
+bool QThread::isFinished() const
+{
+ Q_D(const QThread);
+ QMutexLocker locker(&d->mutex);
+ return d->finished;
+}
+
+/*!
+ Returns true if the thread is running; otherwise returns false.
+
+ \sa isFinished()
+*/
+bool QThread::isRunning() const
+{
+ Q_D(const QThread);
+ QMutexLocker locker(&d->mutex);
+ return d->running;
+}
+
+/*!
+ Sets the maximum stack size for the thread to \a stackSize. If \a
+ stackSize is greater than zero, the maximum stack size is set to
+ \a stackSize bytes, otherwise the maximum stack size is
+ automatically determined by the operating system.
+
+ \warning Most operating systems place minimum and maximum limits
+ on thread stack sizes. The thread will fail to start if the stack
+ size is outside these limits.
+
+ \sa stackSize()
+*/
+void QThread::setStackSize(uint stackSize)
+{
+ Q_D(QThread);
+ QMutexLocker locker(&d->mutex);
+ Q_ASSERT_X(!d->running, "QThread::setStackSize",
+ "cannot change stack size while the thread is running");
+ d->stackSize = stackSize;
+}
+
+/*!
+ Returns the maximum stack size for the thread (if set with
+ setStackSize()); otherwise returns zero.
+
+ \sa setStackSize()
+*/
+uint QThread::stackSize() const
+{
+ Q_D(const QThread);
+ QMutexLocker locker(&d->mutex);
+ return d->stackSize;
+}
+
+/*!
+ Enters the event loop and waits until exit() is called, returning the value
+ that was passed to exit(). The value returned is 0 if exit() is called via
+ quit().
+
+ It is necessary to call this function to start event handling.
+
+ \sa quit(), exit()
+*/
+int QThread::exec()
+{
+ Q_D(QThread);
+ QMutexLocker locker(&d->mutex);
+ d->data->quitNow = false;
+ if (d->exited) {
+ d->exited = false;
+ return d->returnCode;
+ }
+ locker.unlock();
+
+ QEventLoop eventLoop;
+ int returnCode = eventLoop.exec();
+
+ locker.relock();
+ d->exited = false;
+ d->returnCode = -1;
+ return returnCode;
+}
+
+/*!
+ Tells the thread's event loop to exit with a return code.
+
+ After calling this function, the thread leaves the event loop and
+ returns from the call to QEventLoop::exec(). The
+ QEventLoop::exec() function returns \a returnCode.
+
+ By convention, a \a returnCode of 0 means success, any non-zero value
+ indicates an error.
+
+ Note that unlike the C library function of the same name, this
+ function \e does return to the caller -- it is event processing
+ that stops.
+
+ No QEventLoops will be started anymore in this thread until
+ QThread::exec() has been called again. If the eventloop in QThread::exec()
+ is not running then the next call to QThread::exec() will also return
+ immediately.
+
+ \sa quit() QEventLoop
+*/
+void QThread::exit(int returnCode)
+{
+ Q_D(QThread);
+ QMutexLocker locker(&d->mutex);
+ d->exited = true;
+ d->returnCode = returnCode;
+ d->data->quitNow = true;
+ for (int i = 0; i < d->data->eventLoops.size(); ++i) {
+ QEventLoop *eventLoop = d->data->eventLoops.at(i);
+ eventLoop->exit(returnCode);
+ }
+}
+
+/*!
+ Tells the thread's event loop to exit with return code 0 (success).
+ Equivalent to calling QThread::exit(0).
+
+ This function does nothing if the thread does not have an event
+ loop.
+
+ \sa exit() QEventLoop
+*/
+void QThread::quit()
+{ exit(); }
+
+/*!
+ The starting point for the thread. After calling start(), the
+ newly created thread calls this function. The default
+ implementation simply calls exec().
+
+ You can reimplemented this function to do other useful
+ work. Returning from this method will end the execution of the
+ thread.
+
+ \sa start() wait()
+*/
+void QThread::run()
+{
+ (void) exec();
+}
+
+/*! \internal
+ Initializes the QThread system.
+*/
+#if defined (Q_OS_WIN)
+void qt_create_tls();
+#endif
+
+void QThread::initialize()
+{
+ if (qt_global_mutexpool)
+ return;
+ qt_global_mutexpool = QMutexPool::instance();
+
+#if defined (Q_OS_WIN)
+ qt_create_tls();
+#endif
+}
+
+
+/*! \internal
+ Cleans up the QThread system.
+*/
+void QThread::cleanup()
+{
+ qt_global_mutexpool = 0;
+}
+
+/*!
+ \fn bool QThread::finished() const
+
+ Use isFinished() instead.
+*/
+
+/*!
+ \fn bool QThread::running() const
+
+ Use isRunning() instead.
+*/
+
+/*! \fn void QThread::setPriority(Priority priority)
+ \since 4.1
+
+ This function sets the \a priority for a running thread. If the
+ thread is not running, this function does nothing and returns
+ immediately. Use start() to start a thread with a specific
+ priority.
+
+ The \a priority argument can be any value in the \c
+ QThread::Priority enum except for \c InheritPriorty.
+
+ The effect of the \a priority parameter is dependent on the
+ operating system's scheduling policy. In particular, the \a priority
+ will be ignored on systems that do not support thread priorities
+ (such as on Linux, see http://linux.die.net/man/2/sched_setscheduler
+ for more details).
+
+ \sa Priority priority() start()
+*/
+
+/*!
+ \since 4.1
+
+ Returns the priority for a running thread. If the thread is not
+ running, this function returns \c InheritPriority.
+
+ \sa Priority setPriority() start()
+*/
+QThread::Priority QThread::priority() const
+{
+ Q_D(const QThread);
+ QMutexLocker locker(&d->mutex);
+
+ // mask off the high bits that are used for flags
+ return Priority(d->priority & 0xffff);
+}
+
+/*!
+ \fn void QThread::sleep(unsigned long secs)
+
+ Forces the current thread to sleep for \a secs seconds.
+
+ \sa msleep(), usleep()
+*/
+
+/*!
+ \fn void QThread::msleep(unsigned long msecs)
+
+ Causes the current thread to sleep for \a msecs milliseconds.
+
+ \sa sleep(), usleep()
+*/
+
+/*!
+ \fn void QThread::usleep(unsigned long usecs)
+
+ Causes the current thread to sleep for \a usecs microseconds.
+
+ \sa sleep(), msleep()
+*/
+
+/*!
+ \fn void QThread::terminate()
+
+ Terminates the execution of the thread. The thread may or may not
+ be terminated immediately, depending on the operating systems
+ scheduling policies. Use QThread::wait() after terminate() for
+ synchronous termination.
+
+ When the thread is terminated, all threads waiting for the thread
+ to finish will be woken up.
+
+ \warning This function is dangerous and its use is discouraged.
+ The thread can be terminated at any point in its code path.
+ Threads can be terminated while modifying data. There is no
+ chance for the thread to clean up after itself, unlock any held
+ mutexes, etc. In short, use this function only if absolutely
+ necessary.
+
+ Termination can be explicitly enabled or disabled by calling
+ QThread::setTerminationEnabled(). Calling this function while
+ termination is disabled results in the termination being
+ deferred, until termination is re-enabled. See the documentation
+ of QThread::setTerminationEnabled() for more information.
+
+ \sa setTerminationEnabled()
+*/
+
+/*!
+ \fn bool QThread::wait(unsigned long time)
+
+ Blocks the thread until either of these conditions is met:
+
+ \list
+ \o The thread associated with this QThread object has finished
+ execution (i.e. when it returns from \l{run()}). This function
+ will return true if the thread has finished. It also returns
+ true if the thread has not been started yet.
+ \o \a time milliseconds has elapsed. If \a time is ULONG_MAX (the
+ default), then the wait will never timeout (the thread must
+ return from \l{run()}). This function will return false if the
+ wait timed out.
+ \endlist
+
+ This provides similar functionality to the POSIX \c
+ pthread_join() function.
+
+ \sa sleep(), terminate()
+*/
+
+/*!
+ \fn void QThread::setTerminationEnabled(bool enabled)
+
+ Enables or disables termination of the current thread based on the
+ \a enabled parameter. The thread must have been started by
+ QThread.
+
+ When \a enabled is false, termination is disabled. Future calls
+ to QThread::terminate() will return immediately without effect.
+ Instead, the termination is deferred until termination is enabled.
+
+ When \a enabled is true, termination is enabled. Future calls to
+ QThread::terminate() will terminate the thread normally. If
+ termination has been deferred (i.e. QThread::terminate() was
+ called with termination disabled), this function will terminate
+ the calling thread \e immediately. Note that this function will
+ not return in this case.
+
+ \sa terminate()
+*/
+
+#else // QT_NO_THREAD
+
+QThread::QThread(QObject *parent)
+ : QObject(*(new QThreadPrivate), (QObject*)0){
+ Q_D(QThread);
+ d->data->thread = this;
+}
+
+QThread *QThread::currentThread()
+{
+ return QThreadData::current()->thread;
+}
+
+QThreadData* QThreadData::current()
+{
+ static QThreadData *data = 0; // reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key));
+ if (!data) {
+ QScopedPointer<QThreadData> newdata(new QThreadData);
+ newdata->thread = new QAdoptedThread(newdata.data());
+ data = newdata.take();
+ data->deref();
+ }
+ return data;
+}
+
+/*! \internal
+ */
+QThread::QThread(QThreadPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+ Q_D(QThread);
+ // fprintf(stderr, "QThreadData %p taken from private data for thread %p\n", d->data, this);
+ d->data->thread = this;
+}
+
+#endif // QT_NO_THREAD
+
+QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h
new file mode 100644
index 0000000000..014a0062fe
--- /dev/null
+++ b/src/corelib/thread/qthread.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTHREAD_H
+#define QTHREAD_H
+
+#include <QtCore/qobject.h>
+
+#include <limits.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class QThreadData;
+class QThreadPrivate;
+
+#ifndef QT_NO_THREAD
+class Q_CORE_EXPORT QThread : public QObject
+{
+public:
+ static Qt::HANDLE currentThreadId();
+ static QThread *currentThread();
+ static int idealThreadCount();
+ static void yieldCurrentThread();
+
+ explicit QThread(QObject *parent = 0);
+ ~QThread();
+
+ enum Priority {
+ IdlePriority,
+
+ LowestPriority,
+ LowPriority,
+ NormalPriority,
+ HighPriority,
+ HighestPriority,
+
+ TimeCriticalPriority,
+
+ InheritPriority
+ };
+
+ void setPriority(Priority priority);
+ Priority priority() const;
+
+ bool isFinished() const;
+ bool isRunning() const;
+
+ void setStackSize(uint stackSize);
+ uint stackSize() const;
+
+ void exit(int retcode = 0);
+
+public Q_SLOTS:
+ void start(Priority = InheritPriority);
+ void terminate();
+ void quit();
+
+public:
+ // default argument causes thread to block indefinately
+ bool wait(unsigned long time = ULONG_MAX);
+
+Q_SIGNALS:
+ void started();
+ void finished();
+ void terminated();
+
+protected:
+ virtual void run();
+ int exec();
+
+ static void setTerminationEnabled(bool enabled = true);
+
+ static void sleep(unsigned long);
+ static void msleep(unsigned long);
+ static void usleep(unsigned long);
+
+#ifdef QT3_SUPPORT
+public:
+ inline QT3_SUPPORT bool finished() const { return isFinished(); }
+ inline QT3_SUPPORT bool running() const { return isRunning(); }
+#endif
+
+protected:
+ QThread(QThreadPrivate &dd, QObject *parent = 0);
+
+private:
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QThread)
+
+ static void initialize();
+ static void cleanup();
+
+ friend class QCoreApplication;
+ friend class QThreadData;
+};
+
+#else // QT_NO_THREAD
+
+class Q_CORE_EXPORT QThread : public QObject
+{
+public:
+ static Qt::HANDLE currentThreadId() { return Qt::HANDLE(currentThread()); }
+ static QThread* currentThread();
+
+protected:
+ QThread(QThreadPrivate &dd, QObject *parent = 0);
+
+private:
+ explicit QThread(QObject *parent = 0);
+ static QThread *instance;
+
+ friend class QCoreApplication;
+ friend class QThreadData;
+ friend class QAdoptedThread;
+ Q_DECLARE_PRIVATE(QThread)
+};
+
+#endif // QT_NO_THREAD
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTHREAD_H
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
new file mode 100644
index 0000000000..b43a456919
--- /dev/null
+++ b/src/corelib/thread/qthread_p.h
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTHREAD_P_H
+#define QTHREAD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+//
+
+#include "qplatformdefs.h"
+#include "QtCore/qthread.h"
+#include "QtCore/qmutex.h"
+#include "QtCore/qstack.h"
+#include "QtCore/qwaitcondition.h"
+#include "QtCore/qmap.h"
+#include "private/qobject_p.h"
+
+#ifdef Q_OS_SYMBIAN
+#include <e32base.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractEventDispatcher;
+class QEventLoop;
+
+class QPostEvent
+{
+public:
+ QObject *receiver;
+ QEvent *event;
+ int priority;
+ inline QPostEvent()
+ : receiver(0), event(0), priority(0)
+ { }
+ inline QPostEvent(QObject *r, QEvent *e, int p)
+ : receiver(r), event(e), priority(p)
+ { }
+};
+inline bool operator<(int priority, const QPostEvent &pe)
+{
+ return pe.priority < priority;
+}
+inline bool operator<(const QPostEvent &pe, int priority)
+{
+ return priority < pe.priority;
+}
+
+class QPostEventList : public QList<QPostEvent>
+{
+public:
+ // recursion == recursion count for sendPostedEvents()
+ int recursion;
+
+ // sendOffset == the current event to start sending
+ int startOffset;
+ // insertionOffset == set by sendPostedEvents to tell postEvent() where to start insertions
+ int insertionOffset;
+
+ QMutex mutex;
+
+ inline QPostEventList()
+ : QList<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0)
+ { }
+};
+
+#ifndef QT_NO_THREAD
+
+class QThreadPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QThread)
+
+public:
+ QThreadPrivate(QThreadData *d = 0);
+ ~QThreadPrivate();
+
+ mutable QMutex mutex;
+
+ bool running;
+ bool finished;
+ bool terminated;
+ bool isInFinish; //when in QThreadPrivate::finish
+
+ bool exited;
+ int returnCode;
+
+ uint stackSize;
+ QThread::Priority priority;
+
+ static QThread *threadForId(int id);
+
+#ifdef Q_OS_UNIX
+ pthread_t thread_id;
+ QWaitCondition thread_done;
+
+ static void *start(void *arg);
+#if defined(Q_OS_SYMBIAN)
+ static void finish(void *arg, bool lockAnyway=true, bool closeNativeHandle=true);
+#else
+ static void finish(void *);
+#endif
+
+#endif // Q_OS_UNIX
+
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+ HANDLE handle;
+ unsigned int id;
+ int waiters;
+
+ static unsigned int __stdcall start(void *);
+ static void finish(void *, bool lockAnyway=true);
+#endif // Q_OS_WIN32
+
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN)
+ bool terminationEnabled, terminatePending;
+# endif
+ QThreadData *data;
+
+ static void createEventDispatcher(QThreadData *data);
+};
+
+#else // QT_NO_THREAD
+
+class QThreadPrivate : public QObjectPrivate
+{
+public:
+ QThreadPrivate(QThreadData *d = 0) : data(d ? d : new QThreadData) {}
+ ~QThreadPrivate() { delete data; }
+
+ QThreadData *data;
+
+ static void setCurrentThread(QThread*) {}
+ static QThread *threadForId(int) { return QThread::currentThread(); }
+ static void createEventDispatcher(QThreadData *data);
+
+ Q_DECLARE_PUBLIC(QThread)
+};
+
+#endif // QT_NO_THREAD
+
+class QThreadData
+{
+ QAtomicInt _ref;
+
+public:
+ QThreadData(int initialRefCount = 1);
+ ~QThreadData();
+
+ static QThreadData *current();
+ static QThreadData *get2(QThread *thread)
+ { Q_ASSERT_X(thread != 0, "QThread", "internal error"); return thread->d_func()->data; }
+
+
+ void ref();
+ void deref();
+
+ QThread *thread;
+ Qt::HANDLE threadId;
+ bool quitNow;
+ int loopLevel;
+ QAbstractEventDispatcher *eventDispatcher;
+ QStack<QEventLoop *> eventLoops;
+ QPostEventList postEventList;
+ bool canWait;
+ QVector<void *> tls;
+ bool isAdopted;
+
+# ifdef Q_OS_SYMBIAN
+ RThread symbian_thread_handle;
+# endif
+};
+
+// thread wrapper for the main() thread
+class QAdoptedThread : public QThread
+{
+ Q_DECLARE_PRIVATE(QThread)
+
+public:
+ QAdoptedThread(QThreadData *data = 0);
+ ~QAdoptedThread();
+ void init();
+
+ static QThread *createThreadForAdoption();
+private:
+ void run();
+};
+
+QT_END_NAMESPACE
+
+#endif // QTHREAD_P_H
diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp
new file mode 100644
index 0000000000..5d8b5cbf0d
--- /dev/null
+++ b/src/corelib/thread/qthread_symbian.cpp
@@ -0,0 +1,609 @@
+/****************************************************************************
+**
+** 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();
+ }
+ data->isAdopted = true;
+ data->threadId = QThread::currentThreadId();
+ 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()
+{
+ 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();
+ 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);
+
+ data->threadId = QThread::currentThreadId();
+ 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
new file mode 100644
index 0000000000..044eb05913
--- /dev/null
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -0,0 +1,716 @@
+/****************************************************************************
+**
+** 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_unix_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 };
+
+#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL))
+#define HAVE_TLS
+#endif
+#if defined(Q_CC_XLC) || defined (Q_CC_SUN)
+#define HAVE_TLS
+#endif
+
+#ifdef HAVE_TLS
+static __thread QThreadData *currentThreadData = 0;
+#endif
+
+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)
+{
+#if defined(Q_OS_VXWORKS)
+ // Calling setspecific(..., 0) sets the value to 0 for ALL threads.
+ // The 'set to 1' workaround adds a bit of an overhead though,
+ // since this function is called twice now.
+ if (p == (void *)1)
+ return;
+#endif
+ // 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);
+ 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)
+ pthread_setspecific(current_thread_data_key,
+#if defined(Q_OS_VXWORKS)
+ (void *)1);
+#else
+ 0);
+#endif
+}
+
+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.
+static QThreadData *get_thread_data()
+{
+#ifdef HAVE_TLS
+ return currentThreadData;
+#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 HAVE_TLS
+ currentThreadData = 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 HAVE_TLS
+ currentThreadData = 0;
+#endif
+ pthread_setspecific(current_thread_data_key, 0);
+}
+
+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();
+ }
+ data->isAdopted = true;
+ data->threadId = (Qt::HANDLE)pthread_self();
+ if (!QCoreApplicationPrivate::theMainThread)
+ QCoreApplicationPrivate::theMainThread = data->thread;
+ }
+ return data;
+}
+
+
+void QAdoptedThread::init()
+{
+ Q_D(QThread);
+ d->thread_id = pthread_self();
+}
+
+/*
+ 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)
+{
+#if !defined(QT_NO_GLIB)
+ if (qgetenv("QT_NO_GLIB").isEmpty()
+ && qgetenv("QT_NO_THREADED_GLIB").isEmpty()
+ && QEventDispatcherGlib::versionSupported())
+ data->eventDispatcher = new QEventDispatcherGlib;
+ else
+#endif
+ data->eventDispatcher = new QEventDispatcherUNIX;
+ data->eventDispatcher->startingUp();
+}
+
+#ifndef QT_NO_THREAD
+
+void *QThreadPrivate::start(void *arg)
+{
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ pthread_cleanup_push(QThreadPrivate::finish, 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));
+ }
+
+ data->threadId = (Qt::HANDLE)pthread_self();
+ set_thread_data(data);
+
+ data->ref();
+ {
+ 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();
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
+ thr->run();
+
+ pthread_cleanup_pop(1);
+
+ return 0;
+}
+
+void QThreadPrivate::finish(void *arg)
+{
+ QThread *thr = reinterpret_cast<QThread *>(arg);
+ QThreadPrivate *d = thr->d_func();
+
+ QMutexLocker locker(&d->mutex);
+
+ 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;
+ d->running = false;
+ d->finished = true;
+
+ d->isInFinish = false;
+ d->thread_done.wakeAll();
+}
+
+
+
+
+/**************************************************************************
+ ** QThread
+ *************************************************************************/
+
+Qt::HANDLE QThread::currentThreadId()
+{
+ // requires a C cast here otherwise we run into trouble on AIX
+ return (Qt::HANDLE)pthread_self();
+}
+
+#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;
+
+#if defined(Q_OS_MAC) && !defined(Q_WS_QPA)
+ // Mac OS X
+ cores = MPProcessorsScheduled();
+#elif defined(Q_OS_HPUX)
+ // HP-UX
+ struct pst_dynamic psd;
+ if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
+ perror("pstat_getdynamic");
+ cores = -1;
+ } else {
+ cores = (int)psd.psd_proc_cnt;
+ }
+#elif defined(Q_OS_BSD4)
+ // FreeBSD, OpenBSD, NetBSD, BSD/OS
+ size_t len = sizeof(cores);
+ int mib[2];
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
+ perror("sysctl");
+ cores = -1;
+ }
+#elif defined(Q_OS_IRIX)
+ // IRIX
+ cores = (int)sysconf(_SC_NPROC_ONLN);
+#elif defined(Q_OS_INTEGRITY)
+ // as of aug 2008 Integrity only supports one single core CPU
+ cores = 1;
+#elif defined(Q_OS_VXWORKS)
+ // VxWorks
+# if defined(QT_VXWORKS_HAS_CPUSET)
+ cpuset_t cpus = vxCpuEnabledGet();
+ cores = 0;
+
+ // 128 cores should be enough for everyone ;)
+ for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
+ if (CPUSET_ISSET(cpus, i)) {
+ CPUSET_CLR(cpus, i);
+ cores++;
+ }
+ }
+# else
+ // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
+ cores = 1;
+# endif
+#else
+ // the rest: Linux, Solaris, AIX, Tru64
+ cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
+#endif
+
+ return cores;
+}
+
+void QThread::yieldCurrentThread()
+{
+ sched_yield();
+}
+
+/* \internal
+ helper function to do thread sleeps, since usleep()/nanosleep()
+ aren't reliable enough (in terms of behavior and availability)
+*/
+static void thread_sleep(struct timespec *ti)
+{
+ pthread_mutex_t mtx;
+ pthread_cond_t cnd;
+
+ pthread_mutex_init(&mtx, 0);
+ pthread_cond_init(&cnd, 0);
+
+ pthread_mutex_lock(&mtx);
+ (void) pthread_cond_timedwait(&cnd, &mtx, ti);
+ pthread_mutex_unlock(&mtx);
+
+ pthread_cond_destroy(&cnd);
+ pthread_mutex_destroy(&mtx);
+}
+
+void QThread::sleep(unsigned long secs)
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ struct timespec ti;
+ ti.tv_sec = tv.tv_sec + secs;
+ ti.tv_nsec = (tv.tv_usec * 1000);
+ thread_sleep(&ti);
+}
+
+void QThread::msleep(unsigned long msecs)
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ struct timespec ti;
+
+ ti.tv_nsec = (tv.tv_usec + (msecs % 1000) * 1000) * 1000;
+ ti.tv_sec = tv.tv_sec + (msecs / 1000) + (ti.tv_nsec / 1000000000);
+ ti.tv_nsec %= 1000000000;
+ thread_sleep(&ti);
+}
+
+void QThread::usleep(unsigned long usecs)
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ struct timespec ti;
+
+ ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000;
+ ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000);
+ ti.tv_nsec %= 1000000000;
+ thread_sleep(&ti);
+}
+
+#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
+// Does some magic and calculate the Unix scheduler priorities
+// sched_policy is IN/OUT: it must be set to a valid policy before calling this function
+// sched_priority is OUT only
+static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
+{
+#ifdef SCHED_IDLE
+ if (priority == QThread::IdlePriority) {
+ *sched_policy = SCHED_IDLE;
+ *sched_priority = 0;
+ return true;
+ }
+ const int lowestPriority = QThread::LowestPriority;
+#else
+ const int lowestPriority = QThread::IdlePriority;
+#endif
+ const int highestPriority = QThread::TimeCriticalPriority;
+
+ int prio_min = sched_get_priority_min(*sched_policy);
+ int prio_max = sched_get_priority_max(*sched_policy);
+ if (prio_min == -1 || prio_max == -1)
+ return false;
+
+ int prio;
+ // crudely scale our priority enum values to the prio_min/prio_max
+ prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
+ prio = qMax(prio_min, qMin(prio_max, prio));
+
+ *sched_priority = prio;
+ return true;
+}
+#endif
+
+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;
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ d->priority = priority;
+
+#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
+ switch (priority) {
+ case InheritPriority:
+ {
+ pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
+ break;
+ }
+
+ default:
+ {
+ int sched_policy;
+ if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
+ // failed to get the scheduling policy, don't bother
+ // setting the priority
+ qWarning("QThread::start: Cannot determine default scheduler policy");
+ break;
+ }
+
+ int prio;
+ if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
+ // failed to get the scheduling parameters, don't
+ // bother setting the priority
+ qWarning("QThread::start: Cannot determine scheduler priority range");
+ break;
+ }
+
+ sched_param sp;
+ sp.sched_priority = prio;
+
+ if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
+ || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
+ || pthread_attr_setschedparam(&attr, &sp) != 0) {
+ // could not set scheduling hints, fallback to inheriting them
+ // we'll try again from inside the thread
+ pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
+ d->priority = Priority(priority | ThreadPriorityResetFlag);
+ }
+ break;
+ }
+ }
+#endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
+
+
+ if (d->stackSize > 0) {
+#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
+ int code = pthread_attr_setstacksize(&attr, d->stackSize);
+#else
+ int code = ENOSYS; // stack size not supported, automatically fail
+#endif // _POSIX_THREAD_ATTR_STACKSIZE
+
+ if (code) {
+ qWarning("QThread::start: Thread stack size error: %s",
+ qPrintable(qt_error_string(code)));
+
+ // we failed to set the stacksize, and as the documentation states,
+ // the thread will fail to run...
+ d->running = false;
+ d->finished = false;
+ return;
+ }
+ }
+
+ int code =
+ pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
+ if (code == EPERM) {
+ // caller does not have permission to set the scheduling
+ // parameters/policy
+ pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
+ code =
+ pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
+ }
+
+ pthread_attr_destroy(&attr);
+
+ if (code) {
+ qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code)));
+
+ d->running = false;
+ d->finished = false;
+ d->thread_id = 0;
+ }
+}
+
+void QThread::terminate()
+{
+ Q_D(QThread);
+ QMutexLocker locker(&d->mutex);
+
+ if (!d->thread_id)
+ return;
+
+ int code = pthread_cancel(d->thread_id);
+ if (code) {
+ qWarning("QThread::start: Thread termination error: %s",
+ qPrintable(qt_error_string((code))));
+ } else {
+ d->terminated = true;
+ }
+}
+
+bool QThread::wait(unsigned long time)
+{
+ Q_D(QThread);
+ QMutexLocker locker(&d->mutex);
+
+ if (d->thread_id == pthread_self()) {
+ qWarning("QThread::wait: Thread tried to wait on itself");
+ return false;
+ }
+
+ if (d->finished || !d->running)
+ return true;
+
+ while (d->running) {
+ 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.");
+
+ Q_UNUSED(thr)
+ pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
+ if (enabled)
+ pthread_testcancel();
+}
+
+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:
+
+#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
+ int sched_policy;
+ sched_param param;
+
+ if (pthread_getschedparam(d->thread_id, &sched_policy, &param) != 0) {
+ // failed to get the scheduling policy, don't bother setting
+ // the priority
+ qWarning("QThread::setPriority: Cannot get scheduler parameters");
+ return;
+ }
+
+ int prio;
+ if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
+ // failed to get the scheduling parameters, don't
+ // bother setting the priority
+ qWarning("QThread::setPriority: Cannot determine scheduler priority range");
+ return;
+ }
+
+ param.sched_priority = prio;
+ int status = pthread_setschedparam(d->thread_id, sched_policy, &param);
+
+# ifdef SCHED_IDLE
+ // were we trying to set to idle priority and failed?
+ if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
+ // reset to lowest priority possible
+ pthread_getschedparam(d->thread_id, &sched_policy, &param);
+ param.sched_priority = sched_get_priority_min(sched_policy);
+ pthread_setschedparam(d->thread_id, sched_policy, &param);
+ }
+# else
+ Q_UNUSED(status);
+# endif // SCHED_IDLE
+#endif
+}
+
+#endif // QT_NO_THREAD
+
+QT_END_NAMESPACE
+
diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp
new file mode 100644
index 0000000000..bab6cf85de
--- /dev/null
+++ b/src/corelib/thread/qthread_win.cpp
@@ -0,0 +1,637 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+//#define WINVER 0x0500
+#if _WIN32_WINNT < 0x0400
+#define _WIN32_WINNT 0x0400
+#endif
+
+
+#include "qthread.h"
+#include "qthread_p.h"
+#include "qthreadstorage.h"
+#include "qmutex.h"
+
+#include <qcoreapplication.h>
+#include <qpointer.h>
+
+#include <private/qcoreapplication_p.h>
+#include <private/qeventdispatcher_win_p.h>
+
+#include <qt_windows.h>
+
+
+#ifndef Q_OS_WINCE
+#ifndef _MT
+#define _MT
+#endif
+#include <process.h>
+#else
+#include "qfunctions_wince.h"
+#endif
+
+#ifndef QT_NO_THREAD
+QT_BEGIN_NAMESPACE
+
+void qt_watch_adopted_thread(const HANDLE adoptedThreadHandle, QThread *qthread);
+void qt_adopted_thread_watcher_function(void *);
+
+static DWORD qt_current_thread_data_tls_index = TLS_OUT_OF_INDEXES;
+void qt_create_tls()
+{
+ if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES)
+ return;
+ static QMutex mutex;
+ QMutexLocker locker(&mutex);
+ qt_current_thread_data_tls_index = TlsAlloc();
+}
+
+static void qt_free_tls()
+{
+ if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES) {
+ TlsFree(qt_current_thread_data_tls_index);
+ qt_current_thread_data_tls_index = TLS_OUT_OF_INDEXES;
+ }
+}
+Q_DESTRUCTOR_FUNCTION(qt_free_tls)
+
+/*
+ QThreadData
+*/
+QThreadData *QThreadData::current()
+{
+ qt_create_tls();
+ QThreadData *threadData = reinterpret_cast<QThreadData *>(TlsGetValue(qt_current_thread_data_tls_index));
+ if (!threadData) {
+ QThread *adopted = 0;
+ if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, (void **) &adopted)) {
+ Q_ASSERT(adopted);
+ threadData = QThreadData::get2(adopted);
+ TlsSetValue(qt_current_thread_data_tls_index, threadData);
+ adopted->d_func()->running = true;
+ adopted->d_func()->finished = false;
+ static_cast<QAdoptedThread *>(adopted)->init();
+ } else {
+ threadData = new QThreadData;
+ // This needs to be called prior to new AdoptedThread() to
+ // avoid recursion.
+ TlsSetValue(qt_current_thread_data_tls_index, threadData);
+ QT_TRY {
+ threadData->thread = new QAdoptedThread(threadData);
+ } QT_CATCH(...) {
+ TlsSetValue(qt_current_thread_data_tls_index, 0);
+ threadData->deref();
+ threadData = 0;
+ QT_RETHROW;
+ }
+ threadData->deref();
+ }
+ threadData->isAdopted = true;
+ threadData->threadId = (Qt::HANDLE)GetCurrentThreadId();
+
+ if (!QCoreApplicationPrivate::theMainThread) {
+ QCoreApplicationPrivate::theMainThread = threadData->thread;
+ } else {
+ HANDLE realHandle = INVALID_HANDLE_VALUE;
+#if !defined(Q_OS_WINCE) || (defined(_WIN32_WCE) && (_WIN32_WCE>=0x600))
+ DuplicateHandle(GetCurrentProcess(),
+ GetCurrentThread(),
+ GetCurrentProcess(),
+ &realHandle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+#else
+ realHandle = (HANDLE)GetCurrentThreadId();
+#endif
+ qt_watch_adopted_thread(realHandle, threadData->thread);
+ }
+ }
+ return threadData;
+}
+
+void QAdoptedThread::init()
+{
+ d_func()->handle = GetCurrentThread();
+ d_func()->id = GetCurrentThreadId();
+}
+
+static QVector<HANDLE> qt_adopted_thread_handles;
+static QVector<QThread *> qt_adopted_qthreads;
+static QMutex qt_adopted_thread_watcher_mutex;
+static HANDLE qt_adopted_thread_watcher_handle = 0;
+static HANDLE qt_adopted_thread_wakeup = 0;
+
+/*! \internal
+ Adds an adopted thread to the list of threads that Qt watches to make sure
+ the thread data is properly cleaned up. This function starts the watcher
+ thread if necessary.
+*/
+void qt_watch_adopted_thread(const HANDLE adoptedThreadHandle, QThread *qthread)
+{
+ QMutexLocker lock(&qt_adopted_thread_watcher_mutex);
+ qt_adopted_thread_handles.append(adoptedThreadHandle);
+ qt_adopted_qthreads.append(qthread);
+
+ // Start watcher thread if it is not already running.
+ if (qt_adopted_thread_watcher_handle == 0) {
+ if (qt_adopted_thread_wakeup == 0) {
+ qt_adopted_thread_wakeup = CreateEvent(0, false, false, 0);
+ qt_adopted_thread_handles.prepend(qt_adopted_thread_wakeup);
+ }
+
+ qt_adopted_thread_watcher_handle =
+ (HANDLE)_beginthread(qt_adopted_thread_watcher_function, 0, NULL);
+ } else {
+ SetEvent(qt_adopted_thread_wakeup);
+ }
+}
+
+/*! \internal
+ This function loops and waits for native adopted threads to finish.
+ When this happens it derefs the QThreadData for the adopted thread
+ to make sure it gets cleaned up properly.
+*/
+void qt_adopted_thread_watcher_function(void *)
+{
+ forever {
+ qt_adopted_thread_watcher_mutex.lock();
+
+ if (qt_adopted_thread_handles.count() == 1) {
+ qt_adopted_thread_watcher_handle = 0;
+ qt_adopted_thread_watcher_mutex.unlock();
+ break;
+ }
+
+ QVector<HANDLE> handlesCopy = qt_adopted_thread_handles;
+ qt_adopted_thread_watcher_mutex.unlock();
+
+ DWORD ret = WAIT_TIMEOUT;
+ int loops = (handlesCopy.count() / MAXIMUM_WAIT_OBJECTS) + 1, offset, count;
+ if (loops == 1) {
+ // no need to loop, no timeout
+ offset = 0;
+ count = handlesCopy.count();
+ ret = WaitForMultipleObjects(handlesCopy.count(), handlesCopy.constData(), false, INFINITE);
+ } else {
+ int loop = 0;
+ do {
+ offset = loop * MAXIMUM_WAIT_OBJECTS;
+ count = qMin(handlesCopy.count() - offset, MAXIMUM_WAIT_OBJECTS);
+ ret = WaitForMultipleObjects(count, handlesCopy.constData() + offset, false, 100);
+ loop = (loop + 1) % loops;
+ } while (ret == WAIT_TIMEOUT);
+ }
+
+ if (ret == WAIT_FAILED || !(ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + uint(count))) {
+ qWarning("QThread internal error while waiting for adopted threads: %d", int(GetLastError()));
+ continue;
+ }
+
+ const int handleIndex = offset + ret - WAIT_OBJECT_0;
+ if (handleIndex == 0){
+ // New handle to watch was added.
+ continue;
+ } else {
+// printf("(qt) - qt_adopted_thread_watcher_function... called\n");
+ const int qthreadIndex = handleIndex - 1;
+
+ 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
+ QMutexLocker lock(&qt_adopted_thread_watcher_mutex);
+ qt_adopted_thread_handles.remove(handleIndex);
+ qt_adopted_qthreads.remove(qthreadIndex);
+ }
+ }
+}
+
+#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE)
+
+#ifndef Q_OS_WIN64
+# define ULONG_PTR DWORD
+#endif
+
+typedef struct tagTHREADNAME_INFO
+{
+ DWORD dwType; // must be 0x1000
+ LPCSTR szName; // pointer to name (in user addr space)
+ HANDLE dwThreadID; // thread ID (-1=caller thread)
+ DWORD dwFlags; // reserved for future use, must be zero
+} THREADNAME_INFO;
+
+void qt_set_thread_name(HANDLE threadId, LPCSTR threadName)
+{
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = threadName;
+ info.dwThreadID = threadId;
+ info.dwFlags = 0;
+
+ __try
+ {
+ RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR*)&info);
+ }
+ __except (EXCEPTION_CONTINUE_EXECUTION)
+ {
+ }
+}
+#endif // !QT_NO_DEBUG && Q_CC_MSVC && !Q_OS_WINCE
+
+/**************************************************************************
+ ** QThreadPrivate
+ *************************************************************************/
+
+#endif // QT_NO_THREAD
+
+void QThreadPrivate::createEventDispatcher(QThreadData *data)
+{
+ data->eventDispatcher = new QEventDispatcherWin32;
+ data->eventDispatcher->startingUp();
+}
+
+#ifndef QT_NO_THREAD
+
+unsigned int __stdcall QThreadPrivate::start(void *arg)
+{
+ QThread *thr = reinterpret_cast<QThread *>(arg);
+ QThreadData *data = QThreadData::get2(thr);
+
+ qt_create_tls();
+ TlsSetValue(qt_current_thread_data_tls_index, data);
+ data->threadId = (Qt::HANDLE)GetCurrentThreadId();
+
+ QThread::setTerminationEnabled(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);
+
+#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINCE)
+ // sets the name of the current thread.
+ QByteArray objectName = thr->objectName().toLocal8Bit();
+ qt_set_thread_name((HANDLE)-1,
+ objectName.isEmpty() ?
+ thr->metaObject()->className() : objectName.constData());
+#endif
+
+ emit thr->started();
+ QThread::setTerminationEnabled(true);
+ thr->run();
+
+ finish(arg);
+ return 0;
+}
+
+void QThreadPrivate::finish(void *arg, bool lockAnyway)
+{
+ 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 **tls_data = reinterpret_cast<void **>(&d->data->tls);
+ locker.unlock();
+ if (terminated)
+ emit thr->terminated();
+ emit thr->finished();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QThreadStorageData::finish(tls_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->running = false;
+ d->finished = true;
+ d->isInFinish = false;
+
+ if (!d->waiters) {
+ CloseHandle(d->handle);
+ d->handle = 0;
+ }
+
+ d->id = 0;
+
+}
+
+/**************************************************************************
+ ** QThread
+ *************************************************************************/
+
+Qt::HANDLE QThread::currentThreadId()
+{
+ return (Qt::HANDLE)GetCurrentThreadId();
+}
+
+int QThread::idealThreadCount()
+{
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ return sysinfo.dwNumberOfProcessors;
+}
+
+void QThread::yieldCurrentThread()
+{
+#ifndef Q_OS_WINCE
+ SwitchToThread();
+#else
+ ::Sleep(0);
+#endif
+}
+
+void QThread::sleep(unsigned long secs)
+{
+ ::Sleep(secs * 1000);
+}
+
+void QThread::msleep(unsigned long msecs)
+{
+ ::Sleep(msecs);
+}
+
+void QThread::usleep(unsigned long usecs)
+{
+ ::Sleep((usecs / 1000) + 1);
+}
+
+
+void QThread::start(Priority priority)
+{
+ Q_D(QThread);
+ QMutexLocker locker(&d->mutex);
+
+ if (d->isInFinish) {
+ locker.unlock();
+ wait();
+ locker.relock();
+ }
+
+ if (d->running)
+ return;
+
+ d->running = true;
+ d->finished = false;
+ d->terminated = false;
+ d->exited = false;
+ d->returnCode = 0;
+
+ /*
+ NOTE: we create the thread in the suspended state, set the
+ priority and then resume the thread.
+
+ since threads are created with normal priority by default, we
+ could get into a case where a thread (with priority less than
+ NormalPriority) tries to create a new thread (also with priority
+ less than NormalPriority), but the newly created thread preempts
+ its 'parent' and runs at normal priority.
+ */
+ d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
+ this, CREATE_SUSPENDED, &(d->id));
+
+ if (!d->handle) {
+ qErrnoWarning(errno, "QThread::start: Failed to create thread");
+ d->running = false;
+ d->finished = true;
+ return;
+ }
+
+ int prio;
+ d->priority = priority;
+ switch (d->priority) {
+ case IdlePriority:
+ prio = THREAD_PRIORITY_IDLE;
+ break;
+
+ case LowestPriority:
+ prio = THREAD_PRIORITY_LOWEST;
+ break;
+
+ case LowPriority:
+ prio = THREAD_PRIORITY_BELOW_NORMAL;
+ break;
+
+ case NormalPriority:
+ prio = THREAD_PRIORITY_NORMAL;
+ break;
+
+ case HighPriority:
+ prio = THREAD_PRIORITY_ABOVE_NORMAL;
+ break;
+
+ case HighestPriority:
+ prio = THREAD_PRIORITY_HIGHEST;
+ break;
+
+ case TimeCriticalPriority:
+ prio = THREAD_PRIORITY_TIME_CRITICAL;
+ break;
+
+ case InheritPriority:
+ default:
+ prio = GetThreadPriority(GetCurrentThread());
+ break;
+ }
+
+ if (!SetThreadPriority(d->handle, prio)) {
+ qErrnoWarning("QThread::start: Failed to set thread priority");
+ }
+
+ if (ResumeThread(d->handle) == (DWORD) -1) {
+ qErrnoWarning("QThread::start: Failed to resume new thread");
+ }
+}
+
+void QThread::terminate()
+{
+ Q_D(QThread);
+ QMutexLocker locker(&d->mutex);
+ if (!d->running)
+ return;
+ if (!d->terminationEnabled) {
+ d->terminatePending = true;
+ return;
+ }
+ TerminateThread(d->handle, 0);
+ d->terminated = true;
+ QThreadPrivate::finish(this, false);
+}
+
+bool QThread::wait(unsigned long time)
+{
+ Q_D(QThread);
+ QMutexLocker locker(&d->mutex);
+
+ if (d->id == GetCurrentThreadId()) {
+ qWarning("QThread::wait: Thread tried to wait on itself");
+ return false;
+ }
+ if (d->finished || !d->running)
+ return true;
+
+ ++d->waiters;
+ locker.mutex()->unlock();
+
+ bool ret = false;
+ switch (WaitForSingleObject(d->handle, time)) {
+ case WAIT_OBJECT_0:
+ ret = true;
+ break;
+ case WAIT_FAILED:
+ qErrnoWarning("QThread::wait: Thread wait failure");
+ break;
+ case WAIT_ABANDONED:
+ case WAIT_TIMEOUT:
+ default:
+ break;
+ }
+
+ locker.mutex()->lock();
+ --d->waiters;
+
+ if (ret && !d->finished) {
+ // thread was terminated by someone else
+ d->terminated = true;
+ QThreadPrivate::finish(this, false);
+ }
+
+ if (d->finished && !d->waiters) {
+ CloseHandle(d->handle);
+ d->handle = 0;
+ }
+
+ return ret;
+}
+
+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;
+ QThreadPrivate::finish(thr, false);
+ locker.unlock(); // don't leave the mutex locked!
+ _endthreadex(0);
+ }
+}
+
+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;
+ }
+
+ // copied from start() with a few modifications:
+
+ int prio;
+ d->priority = priority;
+ switch (d->priority) {
+ case IdlePriority:
+ prio = THREAD_PRIORITY_IDLE;
+ break;
+
+ case LowestPriority:
+ prio = THREAD_PRIORITY_LOWEST;
+ break;
+
+ case LowPriority:
+ prio = THREAD_PRIORITY_BELOW_NORMAL;
+ break;
+
+ case NormalPriority:
+ prio = THREAD_PRIORITY_NORMAL;
+ break;
+
+ case HighPriority:
+ prio = THREAD_PRIORITY_ABOVE_NORMAL;
+ break;
+
+ case HighestPriority:
+ prio = THREAD_PRIORITY_HIGHEST;
+ break;
+
+ case TimeCriticalPriority:
+ prio = THREAD_PRIORITY_TIME_CRITICAL;
+ break;
+
+ case InheritPriority:
+ default:
+ qWarning("QThread::setPriority: Argument cannot be InheritPriority");
+ return;
+ }
+
+ if (!SetThreadPriority(d->handle, prio)) {
+ qErrnoWarning("QThread::setPriority: Failed to set thread priority");
+ }
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_THREAD
diff --git a/src/corelib/thread/qthreadstorage.cpp b/src/corelib/thread/qthreadstorage.cpp
new file mode 100644
index 0000000000..2b353333ee
--- /dev/null
+++ b/src/corelib/thread/qthreadstorage.cpp
@@ -0,0 +1,329 @@
+/****************************************************************************
+**
+** 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 "qthreadstorage.h"
+
+#ifndef QT_NO_THREAD
+#include "qthread.h"
+#include "qthread_p.h"
+#include "qmutex.h"
+
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+
+// #define THREADSTORAGE_DEBUG
+#ifdef THREADSTORAGE_DEBUG
+# define DEBUG_MSG qtsDebug
+
+# include <stdio.h>
+# include <stdarg.h>
+void qtsDebug(const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+
+ fprintf(stderr, "QThreadStorage: ");
+ vfprintf(stderr, fmt, va);
+ fprintf(stderr, "\n");
+
+ va_end(va);
+}
+#else
+# define DEBUG_MSG if(false)qDebug
+#endif
+
+Q_GLOBAL_STATIC(QMutex, mutex)
+typedef QVector<void (*)(void *)> DestructorMap;
+Q_GLOBAL_STATIC(DestructorMap, destructors)
+
+QThreadStorageData::QThreadStorageData(void (*func)(void *))
+{
+ QMutexLocker locker(mutex());
+ DestructorMap *destr = destructors();
+ if (!destr) {
+ /*
+ the destructors vector has already been destroyed, yet a new
+ QThreadStorage is being allocated. this can only happen during global
+ destruction, at which point we assume that there is only one thread.
+ in order to keep QThreadStorage working, we need somewhere to store
+ the data, best place we have in this situation is at the tail of the
+ current thread's tls vector. the destructor is ignored, since we have
+ no where to store it, and no way to actually call it.
+ */
+ QThreadData *data = QThreadData::current();
+ id = data->tls.count();
+ DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p cannot be stored", id, func);
+ return;
+ }
+ for (id = 0; id < destr->count(); id++) {
+ if (destr->at(id) == 0)
+ break;
+ }
+ if (id == destr->count()) {
+ destr->append(func);
+ } else {
+ (*destr)[id] = func;
+ }
+ DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p", id, func);
+}
+
+QThreadStorageData::~QThreadStorageData()
+{
+ DEBUG_MSG("QThreadStorageData: Released id %d", id);
+ QMutexLocker locker(mutex());
+ if (destructors())
+ (*destructors())[id] = 0;
+}
+
+void **QThreadStorageData::get() const
+{
+ QThreadData *data = QThreadData::current();
+ if (!data) {
+ qWarning("QThreadStorage::get: QThreadStorage can only be used with threads started with QThread");
+ return 0;
+ }
+ QVector<void *> &tls = data->tls;
+ if (tls.size() <= id)
+ tls.resize(id + 1);
+ void **v = &tls[id];
+
+ DEBUG_MSG("QThreadStorageData: Returning storage %d, data %p, for thread %p",
+ id,
+ *v,
+ data->thread);
+
+ return *v ? v : 0;
+}
+
+void **QThreadStorageData::set(void *p)
+{
+ QThreadData *data = QThreadData::current();
+ if (!data) {
+ qWarning("QThreadStorage::set: QThreadStorage can only be used with threads started with QThread");
+ return 0;
+ }
+ QVector<void *> &tls = data->tls;
+ if (tls.size() <= id)
+ tls.resize(id + 1);
+
+ void *&value = tls[id];
+ // delete any previous data
+ if (value != 0) {
+ DEBUG_MSG("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p",
+ id,
+ value,
+ data->thread);
+
+ QMutexLocker locker(mutex());
+ DestructorMap *destr = destructors();
+ void (*destructor)(void *) = destr ? destr->value(id) : 0;
+ locker.unlock();
+
+ void *q = value;
+ value = 0;
+
+ if (destructor)
+ destructor(q);
+ }
+
+ // store new data
+ value = p;
+ DEBUG_MSG("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread, p);
+ return &value;
+}
+
+void QThreadStorageData::finish(void **p)
+{
+ QVector<void *> *tls = reinterpret_cast<QVector<void *> *>(p);
+ if (!tls || tls->isEmpty() || !mutex())
+ return; // nothing to do
+
+ DEBUG_MSG("QThreadStorageData: Destroying storage for thread %p", QThread::currentThread());
+ while (!tls->isEmpty()) {
+ void *&value = tls->last();
+ void *q = value;
+ value = 0;
+ int i = tls->size() - 1;
+ tls->resize(i);
+
+ if (!q) {
+ // data already deleted
+ continue;
+ }
+
+ QMutexLocker locker(mutex());
+ void (*destructor)(void *) = destructors()->value(i);
+ locker.unlock();
+
+ if (!destructor) {
+ if (QThread::currentThread())
+ qWarning("QThreadStorage: Thread %p exited after QThreadStorage %d destroyed",
+ QThread::currentThread(), i);
+ continue;
+ }
+ destructor(q); //crash here might mean the thread exited after qthreadstorage was destroyed
+
+ if (tls->size() > i) {
+ //re reset the tls in case it has been recreated by its own destructor.
+ (*tls)[i] = 0;
+ }
+ }
+ tls->clear();
+}
+
+/*!
+ \class QThreadStorage
+ \brief The QThreadStorage class provides per-thread data storage.
+
+ \threadsafe
+
+ \ingroup thread
+
+ QThreadStorage is a template class that provides per-thread data
+ storage.
+
+ The setLocalData() function stores a single thread-specific value
+ for the calling thread. The data can be accessed later using
+ localData().
+
+ The hasLocalData() function allows the programmer to determine if
+ data has previously been set using the setLocalData() function.
+ This is also useful for lazy initializiation.
+
+ If T is a pointer type, QThreadStorage takes ownership of the data
+ (which must be created on the heap with \c new) and deletes it when
+ the thread exits, either normally or via termination.
+
+ For example, the following code uses QThreadStorage to store a
+ single cache for each thread that calls the cacheObject() and
+ removeFromCache() functions. The cache is automatically
+ deleted when the calling thread exits.
+
+ \snippet doc/src/snippets/threads/threads.cpp 7
+ \snippet doc/src/snippets/threads/threads.cpp 8
+ \snippet doc/src/snippets/threads/threads.cpp 9
+
+ \section1 Caveats
+
+ \list
+
+ \o The QThreadStorage destructor does not delete per-thread data.
+ QThreadStorage only deletes per-thread data when the thread exits
+ or when setLocalData() is called multiple times.
+
+ \o QThreadStorage can be used to store data for the \c main()
+ thread. QThreadStorage deletes all data set for the \c main()
+ thread when QApplication is destroyed, regardless of whether or
+ not the \c main() thread has actually finished.
+
+ \endlist
+
+ \sa QThread
+*/
+
+/*!
+ \fn QThreadStorage::QThreadStorage()
+
+ Constructs a new per-thread data storage object.
+*/
+
+/*!
+ \fn QThreadStorage::~QThreadStorage()
+
+ Destroys the per-thread data storage object.
+
+ Note: The per-thread data stored is not deleted. Any data left
+ in QThreadStorage is leaked. Make sure that all threads using
+ QThreadStorage have exited before deleting the QThreadStorage.
+
+ \sa hasLocalData()
+*/
+
+/*!
+ \fn bool QThreadStorage::hasLocalData() const
+
+ If T is a pointer type, returns true if the calling thread has
+ non-zero data available.
+
+ If T is a value type, returns whether the data has already been
+ constructed by calling setLocalData or localData.
+
+ \sa localData()
+*/
+
+/*!
+ \fn T &QThreadStorage::localData()
+
+ Returns a reference to the data that was set by the calling
+ thread.
+
+ If no data has been set, this will create a default constructed
+ instance of type T.
+
+ \sa hasLocalData()
+*/
+
+/*!
+ \fn const T QThreadStorage::localData() const
+ \overload
+
+ Returns a copy of the data that was set by the calling thread.
+
+ \sa hasLocalData()
+*/
+
+/*!
+ \fn void QThreadStorage::setLocalData(T data)
+
+ Sets the local data for the calling thread to \a data. It can be
+ accessed later using the localData() functions.
+
+ If T is a pointer type, QThreadStorage takes ownership of the data
+ and deletes it automatically either when the thread exits (either
+ normally or via termination) or when setLocalData() is called again.
+
+ \sa localData(), hasLocalData()
+*/
+
+#endif // QT_NO_THREAD
+
+QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthreadstorage.h b/src/corelib/thread/qthreadstorage.h
new file mode 100644
index 0000000000..e1cafb65cb
--- /dev/null
+++ b/src/corelib/thread/qthreadstorage.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTHREADSTORAGE_H
+#define QTHREADSTORAGE_H
+
+#include <QtCore/qglobal.h>
+
+#ifndef QT_NO_THREAD
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+class Q_CORE_EXPORT QThreadStorageData
+{
+public:
+ explicit QThreadStorageData(void (*func)(void *));
+ ~QThreadStorageData();
+
+ void** get() const;
+ void** set(void* p);
+
+ static void finish(void**);
+ int id;
+};
+
+#if !defined(QT_MOC_CPP)
+// MOC_SKIP_BEGIN
+
+// pointer specialization
+template <typename T>
+inline
+T *&qThreadStorage_localData(QThreadStorageData &d, T **)
+{
+ void **v = d.get();
+ if (!v) v = d.set(0);
+ return *(reinterpret_cast<T**>(v));
+}
+
+template <typename T>
+inline
+T *qThreadStorage_localData_const(const QThreadStorageData &d, T **)
+{
+ void **v = d.get();
+ return v ? *(reinterpret_cast<T**>(v)) : 0;
+}
+
+template <typename T>
+inline
+void qThreadStorage_setLocalData(QThreadStorageData &d, T **t)
+{ (void) d.set(*t); }
+
+template <typename T>
+inline
+void qThreadStorage_deleteData(void *d, T **)
+{ delete static_cast<T *>(d); }
+
+// value-based specialization
+template <typename T>
+inline
+T &qThreadStorage_localData(QThreadStorageData &d, T *)
+{
+ void **v = d.get();
+ if (!v) v = d.set(new T());
+ return *(reinterpret_cast<T*>(*v));
+}
+
+template <typename T>
+inline
+T qThreadStorage_localData_const(const QThreadStorageData &d, T *)
+{
+ void **v = d.get();
+ return v ? *(reinterpret_cast<T*>(*v)) : T();
+}
+
+template <typename T>
+inline
+void qThreadStorage_setLocalData(QThreadStorageData &d, T *t)
+{ (void) d.set(new T(*t)); }
+
+template <typename T>
+inline
+void qThreadStorage_deleteData(void *d, T *)
+{ delete static_cast<T *>(d); }
+
+
+// MOC_SKIP_END
+#endif
+
+template <class T>
+class QThreadStorage
+{
+private:
+ QThreadStorageData d;
+
+ Q_DISABLE_COPY(QThreadStorage)
+
+ static inline void deleteData(void *x)
+ { qThreadStorage_deleteData(x, reinterpret_cast<T*>(0)); }
+
+public:
+ inline QThreadStorage() : d(deleteData) { }
+ inline ~QThreadStorage() { }
+
+ inline bool hasLocalData() const
+ { return d.get() != 0; }
+
+ inline T& localData()
+ { return qThreadStorage_localData(d, reinterpret_cast<T*>(0)); }
+ inline T localData() const
+ { return qThreadStorage_localData_const(d, reinterpret_cast<T*>(0)); }
+
+ inline void setLocalData(T t)
+ { qThreadStorage_setLocalData(d, &t); }
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_THREAD
+
+#endif // QTHREADSTORAGE_H
diff --git a/src/corelib/thread/qwaitcondition.h b/src/corelib/thread/qwaitcondition.h
new file mode 100644
index 0000000000..c49f36d256
--- /dev/null
+++ b/src/corelib/thread/qwaitcondition.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QWAITCONDITION_H
+#define QWAITCONDITION_H
+
+#include <QtCore/qglobal.h>
+
+#include <limits.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Core)
+
+#ifndef QT_NO_THREAD
+
+class QWaitConditionPrivate;
+class QMutex;
+class QReadWriteLock;
+
+class Q_CORE_EXPORT QWaitCondition
+{
+public:
+ QWaitCondition();
+ ~QWaitCondition();
+
+ bool wait(QMutex *mutex, unsigned long time = ULONG_MAX);
+ bool wait(QReadWriteLock *readWriteLock, unsigned long time = ULONG_MAX);
+
+ void wakeOne();
+ void wakeAll();
+
+private:
+ Q_DISABLE_COPY(QWaitCondition)
+
+ QWaitConditionPrivate * d;
+};
+
+#else
+
+class QMutex;
+class Q_CORE_EXPORT QWaitCondition
+{
+public:
+ QWaitCondition() {}
+ ~QWaitCondition() {}
+
+ bool wait(QMutex *mutex, unsigned long time = ULONG_MAX)
+ {
+ Q_UNUSED(mutex);
+ Q_UNUSED(time);
+ return true;
+ }
+
+ void wakeOne() {}
+ void wakeAll() {}
+};
+
+#endif // QT_NO_THREAD
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QWAITCONDITION_H
diff --git a/src/corelib/thread/qwaitcondition.qdoc b/src/corelib/thread/qwaitcondition.qdoc
new file mode 100644
index 0000000000..8138763f55
--- /dev/null
+++ b/src/corelib/thread/qwaitcondition.qdoc
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** 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 documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QWaitCondition
+ \brief The QWaitCondition class provides a condition variable for
+ synchronizing threads.
+
+ \threadsafe
+
+ \ingroup thread
+
+ QWaitCondition allows a thread to tell other threads that some
+ sort of condition has been met. One or many threads can block
+ waiting for a QWaitCondition to set a condition with wakeOne() or
+ wakeAll(). Use wakeOne() to wake one randomly selected condition or
+ wakeAll() to wake them all.
+
+ For example, let's suppose that we have three tasks that should
+ be performed whenever the user presses a key. Each task could be
+ split into a thread, each of which would have a
+ \l{QThread::run()}{run()} body like this:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qwaitcondition_unix.cpp 0
+
+ Here, the \c keyPressed variable is a global variable of type
+ QWaitCondition.
+
+ A fourth thread would read key presses and wake the other three
+ threads up every time it receives one, like this:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qwaitcondition_unix.cpp 1
+
+ The order in which the three threads are woken up is undefined.
+ Also, if some of the threads are still in \c do_something() when
+ the key is pressed, they won't be woken up (since they're not
+ waiting on the condition variable) and so the task will not be
+ performed for that key press. This issue can be solved using a
+ counter and a QMutex to guard it. For example, here's the new
+ code for the worker threads:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qwaitcondition_unix.cpp 2
+
+ Here's the code for the fourth thread:
+
+ \snippet doc/src/snippets/code/src_corelib_thread_qwaitcondition_unix.cpp 3
+
+ The mutex is necessary because the results of two threads
+ attempting to change the value of the same variable
+ simultaneously are unpredictable.
+
+ Wait conditions are a powerful thread synchronization primitive.
+ The \l{threads/waitconditions}{Wait Conditions} example shows how
+ to use QWaitCondition as an alternative to QSemaphore for
+ controlling access to a circular buffer shared by a producer
+ thread and a consumer thread.
+
+ \sa QMutex, QSemaphore, QThread, {Wait Conditions Example}
+*/
+
+/*!
+ \fn QWaitCondition::QWaitCondition()
+
+ Constructs a new wait condition object.
+*/
+
+/*!
+ \fn QWaitCondition::~QWaitCondition()
+
+ Destroys the wait condition object.
+*/
+
+/*!
+ \fn void QWaitCondition::wakeOne()
+
+ Wakes one thread waiting on the wait condition. The thread that
+ is woken up depends on the operating system's scheduling
+ policies, and cannot be controlled or predicted.
+
+ If you want to wake up a specific thread, the solution is
+ typically to use different wait conditions and have different
+ threads wait on different conditions.
+
+ \sa wakeAll()
+*/
+
+/*!
+ \fn void QWaitCondition::wakeAll()
+
+ Wakes all threads waiting on the wait condition. The order in
+ which the threads are woken up depends on the operating system's
+ scheduling policies and cannot be controlled or predicted.
+
+ \sa wakeOne()
+*/
+
+/*!
+ \fn bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
+
+ Releases the locked \a mutex and waits on the wait condition. The
+ \a mutex must be initially locked by the calling thread. If \a
+ mutex is not in a locked state, this function returns
+ immediately. If \a mutex is a recursive mutex, this function
+ returns immediately. The \a mutex will be unlocked, and the
+ calling thread will block until either of these conditions is met:
+
+ \list
+ \o Another thread signals it using wakeOne() or wakeAll(). This
+ function will return true in this case.
+ \o \a time milliseconds has elapsed. If \a time is \c ULONG_MAX
+ (the default), then the wait will never timeout (the event
+ must be signalled). This function will return false if the
+ wait timed out.
+ \endlist
+
+ The mutex will be returned to the same locked state. This
+ function is provided to allow the atomic transition from the
+ locked state to the wait state.
+
+ \sa wakeOne(), wakeAll()
+*/
+
+/*!
+ \fn bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
+ \since 4.4
+
+ Releases the locked \a readWriteLock and waits on the wait
+ condition. The \a readWriteLock must be initially locked by the
+ calling thread. If \a readWriteLock is not in a locked state, this
+ function returns immediately. The \a readWriteLock must not be
+ locked recursively, otherwise this function will not release the
+ lock properly. The \a readWriteLock will be unlocked, and the
+ calling thread will block until either of these conditions is met:
+
+ \list
+ \o Another thread signals it using wakeOne() or wakeAll(). This
+ function will return true in this case.
+ \o \a time milliseconds has elapsed. If \a time is \c ULONG_MAX
+ (the default), then the wait will never timeout (the event
+ must be signalled). This function will return false if the
+ wait timed out.
+ \endlist
+
+ The \a readWriteLock will be returned to the same locked
+ state. This function is provided to allow the atomic transition
+ from the locked state to the wait state.
+
+ \sa wakeOne(), wakeAll()
+*/
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
new file mode 100644
index 0000000000..d0f23b5342
--- /dev/null
+++ b/src/corelib/thread/qwaitcondition_unix.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** 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 "qmutex_p.h"
+#include "qreadwritelock_p.h"
+
+#include <errno.h>
+
+#ifndef QT_NO_THREAD
+
+QT_BEGIN_NAMESPACE
+
+static void report_error(int code, const char *where, const char *what)
+{
+ if (code != 0)
+ qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code)));
+}
+
+class QWaitConditionPrivate {
+public:
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int waiters;
+ int wakeups;
+
+ bool wait(unsigned long time)
+ {
+ int code;
+ forever {
+ if (time != ULONG_MAX) {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+
+ timespec ti;
+ ti.tv_nsec = (tv.tv_usec + (time % 1000) * 1000) * 1000;
+ ti.tv_sec = tv.tv_sec + (time / 1000) + (ti.tv_nsec / 1000000000);
+ ti.tv_nsec %= 1000000000;
+
+ code = pthread_cond_timedwait(&cond, &mutex, &ti);
+ } else {
+ code = pthread_cond_wait(&cond, &mutex);
+ }
+ if (code == 0 && wakeups == 0) {
+ // many vendors warn of spurios wakeups from
+ // pthread_cond_wait(), especially after signal delivery,
+ // even though POSIX doesn't allow for it... sigh
+ continue;
+ }
+ break;
+ }
+
+ Q_ASSERT_X(waiters > 0, "QWaitCondition::wait", "internal error (waiters)");
+ --waiters;
+ if (code == 0) {
+ Q_ASSERT_X(wakeups > 0, "QWaitCondition::wait", "internal error (wakeups)");
+ --wakeups;
+ }
+ report_error(pthread_mutex_unlock(&mutex), "QWaitCondition::wait()", "mutex unlock");
+
+ if (code && code != ETIMEDOUT)
+ report_error(code, "QWaitCondition::wait()", "cv wait");
+
+ return (code == 0);
+ }
+};
+
+
+QWaitCondition::QWaitCondition()
+{
+ d = new QWaitConditionPrivate;
+ report_error(pthread_mutex_init(&d->mutex, NULL), "QWaitCondition", "mutex init");
+ report_error(pthread_cond_init(&d->cond, NULL), "QWaitCondition", "cv init");
+ d->waiters = d->wakeups = 0;
+}
+
+
+QWaitCondition::~QWaitCondition()
+{
+ report_error(pthread_cond_destroy(&d->cond), "QWaitCondition", "cv destroy");
+ report_error(pthread_mutex_destroy(&d->mutex), "QWaitCondition", "mutex destroy");
+ delete d;
+}
+
+void QWaitCondition::wakeOne()
+{
+ report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeOne()", "mutex lock");
+ d->wakeups = qMin(d->wakeups + 1, d->waiters);
+ report_error(pthread_cond_signal(&d->cond), "QWaitCondition::wakeOne()", "cv signal");
+ report_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeOne()", "mutex unlock");
+}
+
+void QWaitCondition::wakeAll()
+{
+ report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeAll()", "mutex lock");
+ d->wakeups = d->waiters;
+ report_error(pthread_cond_broadcast(&d->cond), "QWaitCondition::wakeAll()", "cv broadcast");
+ report_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeAll()", "mutex unlock");
+}
+
+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;
+ }
+
+ report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
+ ++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;
+ }
+
+ report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
+ ++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_win.cpp b/src/corelib/thread/qwaitcondition_win.cpp
new file mode 100644
index 0000000000..ee1c7ba01f
--- /dev/null
+++ b/src/corelib/thread/qwaitcondition_win.cpp
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** 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 "qwaitcondition.h"
+#include "qnamespace.h"
+#include "qmutex.h"
+#include "qreadwritelock.h"
+#include "qlist.h"
+#include "qalgorithms.h"
+#include "qt_windows.h"
+
+#ifndef QT_NO_THREAD
+
+#define Q_MUTEX_T void*
+#include <private/qmutex_p.h>
+#include <private/qreadwritelock_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//***********************************************************************
+// QWaitConditionPrivate
+// **********************************************************************
+
+class QWaitConditionEvent
+{
+public:
+ inline QWaitConditionEvent() : priority(0), wokenUp(false)
+ {
+ event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ }
+ inline ~QWaitConditionEvent() { CloseHandle(event); }
+ int priority;
+ bool wokenUp;
+ HANDLE event;
+};
+
+typedef QList<QWaitConditionEvent *> EventQueue;
+
+class QWaitConditionPrivate
+{
+public:
+ QMutex mtx;
+ EventQueue queue;
+ EventQueue freeQueue;
+
+ QWaitConditionEvent *pre();
+ bool wait(QWaitConditionEvent *wce, unsigned long time);
+ void post(QWaitConditionEvent *wce, bool ret);
+};
+
+QWaitConditionEvent *QWaitConditionPrivate::pre()
+{
+ mtx.lock();
+ QWaitConditionEvent *wce =
+ freeQueue.isEmpty() ? new QWaitConditionEvent : freeQueue.takeFirst();
+ wce->priority = GetThreadPriority(GetCurrentThread());
+ wce->wokenUp = false;
+
+ // insert 'wce' into the queue (sorted by priority)
+ int index = 0;
+ for (; index < queue.size(); ++index) {
+ QWaitConditionEvent *current = queue.at(index);
+ if (current->priority < wce->priority)
+ break;
+ }
+ queue.insert(index, wce);
+ mtx.unlock();
+
+ return wce;
+}
+
+bool QWaitConditionPrivate::wait(QWaitConditionEvent *wce, unsigned long time)
+{
+ // wait for the event
+ bool ret = false;
+ switch (WaitForSingleObject(wce->event, time)) {
+ default: break;
+
+ case WAIT_OBJECT_0:
+ ret = true;
+ break;
+ }
+ return ret;
+}
+
+void QWaitConditionPrivate::post(QWaitConditionEvent *wce, bool ret)
+{
+ mtx.lock();
+
+ // remove 'wce' from the queue
+ queue.removeAll(wce);
+ ResetEvent(wce->event);
+ freeQueue.append(wce);
+
+ // wakeups delivered after the timeout should be forwarded to the next waiter
+ if (!ret && wce->wokenUp && !queue.isEmpty()) {
+ QWaitConditionEvent *other = queue.first();
+ SetEvent(other->event);
+ other->wokenUp = true;
+ }
+
+ mtx.unlock();
+}
+
+//***********************************************************************
+// QWaitCondition implementation
+//***********************************************************************
+
+QWaitCondition::QWaitCondition()
+{
+ d = new QWaitConditionPrivate;
+}
+
+QWaitCondition::~QWaitCondition()
+{
+ if (!d->queue.isEmpty()) {
+ qWarning("QWaitCondition: Destroyed while threads are still waiting");
+ qDeleteAll(d->queue);
+ }
+
+ qDeleteAll(d->freeQueue);
+ delete d;
+}
+
+bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
+{
+ if (!mutex)
+ return false;
+ if (mutex->d->recursive) {
+ qWarning("QWaitCondition::wait: Cannot wait on recursive mutexes");
+ return false;
+ }
+
+ QWaitConditionEvent *wce = d->pre();
+ mutex->unlock();
+
+ bool returnValue = d->wait(wce, time);
+
+ mutex->lock();
+ d->post(wce, returnValue);
+
+ 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;
+ }
+
+ QWaitConditionEvent *wce = d->pre();
+ int previousAccessCount = readWriteLock->d->accessCount;
+ readWriteLock->unlock();
+
+ bool returnValue = d->wait(wce, time);
+
+ if (previousAccessCount < 0)
+ readWriteLock->lockForWrite();
+ else
+ readWriteLock->lockForRead();
+ d->post(wce, returnValue);
+
+ return returnValue;
+}
+
+void QWaitCondition::wakeOne()
+{
+ // wake up the first waiting thread in the queue
+ QMutexLocker locker(&d->mtx);
+ for (int i = 0; i < d->queue.size(); ++i) {
+ QWaitConditionEvent *current = d->queue.at(i);
+ if (current->wokenUp)
+ continue;
+ SetEvent(current->event);
+ current->wokenUp = true;
+ break;
+ }
+}
+
+void QWaitCondition::wakeAll()
+{
+ // wake up the all threads in the queue
+ QMutexLocker locker(&d->mtx);
+ for (int i = 0; i < d->queue.size(); ++i) {
+ QWaitConditionEvent *current = d->queue.at(i);
+ SetEvent(current->event);
+ current->wokenUp = true;
+ }
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_THREAD
diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri
new file mode 100644
index 0000000000..592ab1644b
--- /dev/null
+++ b/src/corelib/thread/thread.pri
@@ -0,0 +1,41 @@
+# Qt core thread module
+
+# public headers
+HEADERS += thread/qmutex.h \
+ thread/qreadwritelock.h \
+ thread/qsemaphore.h \
+ thread/qthread.h \
+ thread/qthreadstorage.h \
+ thread/qwaitcondition.h \
+ thread/qatomic.h
+
+# private headers
+HEADERS += thread/qmutex_p.h \
+ thread/qmutexpool_p.h \
+ thread/qorderedmutexlocker_p.h \
+ thread/qreadwritelock_p.h \
+ thread/qthread_p.h
+
+SOURCES += thread/qatomic.cpp \
+ thread/qmutex.cpp \
+ thread/qreadwritelock.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
+
+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
+
+integrity:SOURCES += thread/qmutex_unix.cpp \
+ thread/qthread_unix.cpp \
+ thread/qwaitcondition_unix.cpp