summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread
diff options
context:
space:
mode:
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