diff options
Diffstat (limited to 'src/corelib/thread')
34 files changed, 205 insertions, 167 deletions
diff --git a/src/corelib/thread/qatomic.cpp b/src/corelib/thread/qatomic.cpp index 1c83f23df0..11623f80dc 100644 --- a/src/corelib/thread/qatomic.cpp +++ b/src/corelib/thread/qatomic.cpp @@ -49,7 +49,7 @@ For atomic operations on pointers, see the QAtomicPointer class. - An \e atomic operation is a complex operation that completes without interruption. + 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. diff --git a/src/corelib/thread/qatomic.h b/src/corelib/thread/qatomic.h index 06cee4894e..1ccaecc135 100644 --- a/src/corelib/thread/qatomic.h +++ b/src/corelib/thread/qatomic.h @@ -46,8 +46,6 @@ #include <QtCore/qbasicatomic.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE @@ -220,6 +218,4 @@ inline void qAtomicDetach(T *&d) } QT_END_NAMESPACE -QT_END_HEADER - #endif // QATOMIC_H diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h index 70b69827c2..b5a402857c 100644 --- a/src/corelib/thread/qbasicatomic.h +++ b/src/corelib/thread/qbasicatomic.h @@ -44,7 +44,7 @@ #ifndef QBASICATOMIC_H #define QBASICATOMIC_H -#if defined(QT_MOC) || defined(QT_BUILD_QMAKE) || defined(QT_RCC) || defined(QT_UIC) || defined(QT_BOOTSTRAPPED) +#if defined(QT_BOOTSTRAPPED) # include <QtCore/qatomic_bootstrap.h> // Compiler dependent implementation @@ -101,15 +101,11 @@ // Only include if the implementation has been ported to QAtomicOps #ifndef QOLDBASICATOMIC_H -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE #if 0 // silence syncqt warnings QT_END_NAMESPACE -QT_END_HEADER - #pragma qt_no_master_include #pragma qt_sync_stop_processing #endif @@ -271,8 +267,6 @@ public: QT_END_NAMESPACE -QT_END_HEADER - #endif // QOLDBASICATOMIC_H #endif // QBASICATOMIC_H diff --git a/src/corelib/thread/qexception.cpp b/src/corelib/thread/qexception.cpp index 263f7d19fe..0c17399d33 100644 --- a/src/corelib/thread/qexception.cpp +++ b/src/corelib/thread/qexception.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE -/*! +/*! \class QException \inmodule QtCore \brief The QException class provides a base class for exceptions that can transferred across threads. @@ -91,7 +91,7 @@ QT_BEGIN_NAMESPACE \snippet code/src_corelib_thread_qexception.cpp 3 */ -/*! +/*! \class QUnhandledException \inmodule QtCore diff --git a/src/corelib/thread/qexception.h b/src/corelib/thread/qexception.h index fa944ce69d..accf0fc7b4 100644 --- a/src/corelib/thread/qexception.h +++ b/src/corelib/thread/qexception.h @@ -53,7 +53,6 @@ # include <exception> #endif -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -116,7 +115,6 @@ public: #endif // QT_NO_EXCEPTIONS QT_END_NAMESPACE -QT_END_HEADER #endif // QT_NO_QFUTURE diff --git a/src/corelib/thread/qfuture.h b/src/corelib/thread/qfuture.h index d9c4f1af77..8071e80d1b 100644 --- a/src/corelib/thread/qfuture.h +++ b/src/corelib/thread/qfuture.h @@ -49,7 +49,6 @@ #include <QtCore/qfutureinterface.h> #include <QtCore/qstring.h> -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -269,7 +268,6 @@ QFuture<void> qToVoidFuture(const QFuture<T> &future) } QT_END_NAMESPACE -QT_END_HEADER #endif // QT_NO_QFUTURE diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index 4ab28e81b2..421e683c4a 100644 --- a/src/corelib/thread/qfuture.qdoc +++ b/src/corelib/thread/qfuture.qdoc @@ -58,7 +58,7 @@ use the isResultReadyAt() function to determine if a result is ready or not. For QFuture objects that report more than one result, the resultCount() function returns the number of continuous results. This - means that it is always safe to iterate through the results from 0 to + means that it is always safe to iterate through the results from 0 to resultCount(). QFuture provides a \l{Java-style iterators}{Java-style iterator} diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp index f5590d95f8..0f7d04a7c5 100644 --- a/src/corelib/thread/qfutureinterface.cpp +++ b/src/corelib/thread/qfutureinterface.cpp @@ -288,7 +288,7 @@ void QFutureInterfaceBase::waitForResult(int resultIndex) return; lock.unlock(); - // To avoid deadlocks and reduce the number of threads used, try to + // To avoid deadlocks and reduce the number of threads used, try to // run the runnable in the current thread. QThreadPool::globalInstance()->d_func()->stealRunnable(d->runnable); diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h index 6ab1409f55..e0a59697a1 100644 --- a/src/corelib/thread/qfutureinterface.h +++ b/src/corelib/thread/qfutureinterface.h @@ -50,7 +50,6 @@ #include <QtCore/qexception.h> #include <QtCore/qresultstore.h> -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -235,7 +234,7 @@ inline void QFutureInterface<T>::reportResults(const QVector<T> &_results, int b this->reportResultsReady(resultCountBefore, store.count()); } else { const int insertIndex = store.addResults(beginIndex, &_results, count); - this->reportResultsReady(insertIndex, insertIndex + _results.count()); + this->reportResultsReady(insertIndex, insertIndex + _results.count()); } } @@ -310,8 +309,6 @@ public: }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QT_NO_QFUTURE #endif // QFUTUREINTERFACE_H diff --git a/src/corelib/thread/qfuturesynchronizer.h b/src/corelib/thread/qfuturesynchronizer.h index 60960f7711..39dbfc52a8 100644 --- a/src/corelib/thread/qfuturesynchronizer.h +++ b/src/corelib/thread/qfuturesynchronizer.h @@ -46,7 +46,6 @@ #ifndef QT_NO_QFUTURE -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -81,7 +80,7 @@ public: m_futures[i].cancel(); } } - + for (int i = 0; i < m_futures.count(); ++i) { m_futures[i].waitForFinished(); } @@ -113,8 +112,6 @@ protected: }; QT_END_NAMESPACE -QT_END_HEADER - #endif // QT_NO_QFUTURE #endif // QFUTURESYNCHRONIZER_H diff --git a/src/corelib/thread/qfuturewatcher.h b/src/corelib/thread/qfuturewatcher.h index d41b6139b6..c78ed7a83b 100644 --- a/src/corelib/thread/qfuturewatcher.h +++ b/src/corelib/thread/qfuturewatcher.h @@ -48,7 +48,6 @@ #include <QtCore/qobject.h> -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -215,8 +214,6 @@ Q_INLINE_TEMPLATE void QFutureWatcher<void>::setFuture(const QFuture<void> &_fut } QT_END_NAMESPACE -QT_END_HEADER - #endif // QT_NO_QFUTURE #endif // QFUTUREWATCHER_H diff --git a/src/corelib/thread/qgenericatomic.h b/src/corelib/thread/qgenericatomic.h index 90f0223ccf..a0a851eabb 100644 --- a/src/corelib/thread/qgenericatomic.h +++ b/src/corelib/thread/qgenericatomic.h @@ -44,14 +44,12 @@ #include <QtCore/qglobal.h> -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE #if 0 // silence syncqt warnings QT_END_NAMESPACE -QT_END_HEADER - +#pragma qt_sync_skip_header_check #pragma qt_sync_stop_processing #endif @@ -241,6 +239,4 @@ template <typename BaseClass> struct QGenericAtomicOps #undef always_inline QT_END_NAMESPACE -QT_END_HEADER - #endif // QGENERICATOMIC_H diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index 94bcdd1750..0bca0def22 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -46,8 +46,6 @@ #include <QtCore/qatomic.h> #include <new> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE @@ -211,6 +209,4 @@ typedef QMutex QBasicMutex; 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 index 1b8bcd6b3a..bec2d934c1 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -70,6 +70,8 @@ # define QT_LINUX_FUTEX #endif +struct timespec; + QT_BEGIN_NAMESPACE class QMutexData @@ -137,6 +139,13 @@ public: #endif //QT_LINUX_FUTEX +#ifdef Q_OS_UNIX +// helper functions for qmutex_unix.cpp and qwaitcondition_unix.cpp +// they are in qwaitcondition_unix.cpp actually +void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where); +void qt_abstime_for_timeout(struct timespec *ts, int timeout); +#endif + QT_END_NAMESPACE #endif // QMUTEX_P_H diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index ef030cb49a..2f8c2e1dc8 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -42,11 +42,14 @@ #include "qplatformdefs.h" #include "qmutex.h" #include "qstring.h" +#include "qelapsedtimer.h" #ifndef QT_NO_THREAD #include "qatomic.h" #include "qmutex_p.h" #include <errno.h> +#include <sys/time.h> +#include <time.h> #if defined(Q_OS_VXWORKS) && defined(wakeup) #undef wakeup @@ -64,7 +67,7 @@ QMutexPrivate::QMutexPrivate() : wakeup(false) { report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); - report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); + qt_initialize_pthread_cond(&cond, "QMutex"); } QMutexPrivate::~QMutexPrivate() @@ -81,12 +84,8 @@ bool QMutexPrivate::wait(int timeout) 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; + qt_abstime_for_timeout(&ti, timeout); errorCode = pthread_cond_timedwait(&cond, &mutex, &ti); } if (errorCode) { diff --git a/src/corelib/thread/qoldbasicatomic.h b/src/corelib/thread/qoldbasicatomic.h index 15785e2232..b755256ff7 100644 --- a/src/corelib/thread/qoldbasicatomic.h +++ b/src/corelib/thread/qoldbasicatomic.h @@ -44,16 +44,13 @@ #include <QtCore/qglobal.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE #if 0 // silence syncqt warnings QT_END_NAMESPACE -QT_END_HEADER - +#pragma qt_sync_skip_header_check #pragma qt_no_master_include #pragma qt_sync_stop_processing #endif @@ -142,6 +139,5 @@ public: #define Q_BASIC_ATOMIC_INITIALIZER(a) { (a) } QT_END_NAMESPACE -QT_END_HEADER #endif // QOLDBASICATOMIC_H diff --git a/src/corelib/thread/qreadwritelock.cpp b/src/corelib/thread/qreadwritelock.cpp index b6bb22b314..0de826fddf 100644 --- a/src/corelib/thread/qreadwritelock.cpp +++ b/src/corelib/thread/qreadwritelock.cpp @@ -93,7 +93,7 @@ QT_BEGIN_NAMESPACE \sa QReadLocker, QWriteLocker, QMutex, QSemaphore */ -/*! +/*! \enum QReadWriteLock::RecursionMode \since 4.4 diff --git a/src/corelib/thread/qreadwritelock.h b/src/corelib/thread/qreadwritelock.h index 8217d4eacd..6815878ec5 100644 --- a/src/corelib/thread/qreadwritelock.h +++ b/src/corelib/thread/qreadwritelock.h @@ -44,8 +44,6 @@ #include <QtCore/qglobal.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE @@ -231,6 +229,4 @@ private: QT_END_NAMESPACE -QT_END_HEADER - #endif // QREADWRITELOCK_H diff --git a/src/corelib/thread/qresultstore.cpp b/src/corelib/thread/qresultstore.cpp index 940fd45027..65c2437064 100644 --- a/src/corelib/thread/qresultstore.cpp +++ b/src/corelib/thread/qresultstore.cpp @@ -97,7 +97,7 @@ bool ResultIteratorBase::canIncrementVectorIndex() const return (m_vectorIndex + 1 < mapIterator.value().m_count); } -ResultStoreBase::ResultStoreBase() +ResultStoreBase::ResultStoreBase() : insertIndex(0), resultCount(0), m_filterMode(false), filteredResults(0) { } void ResultStoreBase::setFilterMode(bool enable) @@ -148,7 +148,7 @@ void ResultStoreBase::syncPendingResults() // check if we can insert any of the pending results: QMap<int, ResultItem>::iterator it = pendingResults.begin(); while (it != pendingResults.end()) { - int index = it.key(); + int index = it.key(); if (index != resultCount + filteredResults) break; @@ -165,7 +165,7 @@ int ResultStoreBase::addResult(int index, const void *result) return insertResultItem(index, resultItem); } -int ResultStoreBase::addResults(int index, const void *results, int vectorSize, int totalCount) +int ResultStoreBase::addResults(int index, const void *results, int vectorSize, int totalCount) { if (m_filterMode == false || vectorSize == totalCount) { ResultItem resultItem(results, vectorSize); @@ -218,7 +218,7 @@ ResultIteratorBase ResultStoreBase::resultAt(int index) const } const int vectorIndex = index - it.key(); - + if (vectorIndex >= it.value().count()) return ResultIteratorBase(m_results.end()); else if (it.value().isVector() == false && vectorIndex != 0) diff --git a/src/corelib/thread/qresultstore.h b/src/corelib/thread/qresultstore.h index 8c1787bc11..11ce23936d 100644 --- a/src/corelib/thread/qresultstore.h +++ b/src/corelib/thread/qresultstore.h @@ -49,7 +49,6 @@ #include <QtCore/qmap.h> #include <QtCore/qdebug.h> -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -149,7 +148,7 @@ protected: bool m_filterMode; QMap<int, ResultItem> pendingResults; int filteredResults; - + }; template <typename T> @@ -234,7 +233,6 @@ public: #endif //Q_QDOC QT_END_NAMESPACE -QT_END_HEADER #endif // QT_NO_QFUTURE diff --git a/src/corelib/thread/qrunnable.cpp b/src/corelib/thread/qrunnable.cpp index eed716af37..e271582b9b 100644 --- a/src/corelib/thread/qrunnable.cpp +++ b/src/corelib/thread/qrunnable.cpp @@ -57,7 +57,7 @@ change the auto-deletion flag. QThreadPool supports executing the same QRunnable more than once - by calling QThreadPool::tryStart(this) from within the run() function. + by calling QThreadPool::tryStart(this) from within the run() function. If autoDelete is enabled the QRunnable will be deleted when the last thread exits the run function. Calling QThreadPool::start() multiple times with the same QRunnable when autoDelete is enabled diff --git a/src/corelib/thread/qrunnable.h b/src/corelib/thread/qrunnable.h index ba03519872..a6cc095258 100644 --- a/src/corelib/thread/qrunnable.h +++ b/src/corelib/thread/qrunnable.h @@ -44,7 +44,6 @@ #include <QtCore/qglobal.h> -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -67,6 +66,5 @@ public: }; QT_END_NAMESPACE -QT_END_HEADER #endif diff --git a/src/corelib/thread/qsemaphore.h b/src/corelib/thread/qsemaphore.h index b47588ce62..40200151b0 100644 --- a/src/corelib/thread/qsemaphore.h +++ b/src/corelib/thread/qsemaphore.h @@ -44,8 +44,6 @@ #include <QtCore/qglobal.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE @@ -77,6 +75,4 @@ private: QT_END_NAMESPACE -QT_END_HEADER - #endif // QSEMAPHORE_H diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index bd8c6341c1..4d5bee3154 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -76,6 +76,7 @@ QThreadData::~QThreadData() // the problem... if (this->thread == QCoreApplicationPrivate::theMainThread) { QCoreApplicationPrivate::theMainThread = 0; + QThreadData::clearCurrentThreadData(); } QThread *t = thread; @@ -523,9 +524,9 @@ int QThread::exec() 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 + 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. @@ -592,6 +593,16 @@ void QThread::run() \sa Priority, priority(), start() */ +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->setPriority(priority); +} /*! \since 4.1 @@ -751,7 +762,7 @@ QThread::QThread(QThreadPrivate &dd, QObject *parent) QAbstractEventDispatcher *QThread::eventDispatcher() const { Q_D(const QThread); - return d->data->eventDispatcher; + return d->data->eventDispatcher.load(); } /*! @@ -766,7 +777,7 @@ QAbstractEventDispatcher *QThread::eventDispatcher() const void QThread::setEventDispatcher(QAbstractEventDispatcher *eventDispatcher) { Q_D(QThread); - if (d->data->eventDispatcher != 0) { + if (d->data->hasEventDispatcher()) { qWarning("QThread::setEventDispatcher: An event dispatcher has already been created for this thread"); } else { eventDispatcher->moveToThread(this); diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index c6c6167da7..19c0f82d86 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -46,8 +46,6 @@ #include <limits.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE @@ -164,6 +162,4 @@ private: 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 index 526633cafa..9d773b3c1c 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -142,6 +142,8 @@ public: QThreadPrivate(QThreadData *d = 0); ~QThreadPrivate(); + void setPriority(QThread::Priority prio); + mutable QMutex mutex; QAtomicInt quitLockRef; @@ -223,18 +225,27 @@ public: ~QThreadData(); static QThreadData *current(); + static void clearCurrentThreadData(); static QThreadData *get2(QThread *thread) { Q_ASSERT_X(thread != 0, "QThread", "internal error"); return thread->d_func()->data; } void ref(); void deref(); + inline bool hasEventDispatcher() const + { return eventDispatcher.load() != 0; } + + bool canWaitLocked() + { + QMutexLocker locker(&postEventList.mutex); + return canWait; + } QThread *thread; Qt::HANDLE threadId; bool quitNow; int loopLevel; - QAbstractEventDispatcher *eventDispatcher; + QAtomicPointer<QAbstractEventDispatcher> eventDispatcher; QStack<QEventLoop *> eventLoops; QPostEventList postEventList; bool canWait; diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 8abf1d06ef..f123e1813b 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -204,6 +204,11 @@ static void clear_thread_data() pthread_setspecific(current_thread_data_key, 0); } +void QThreadData::clearCurrentThreadData() +{ + clear_thread_data(); +} + QThreadData *QThreadData::current() { QThreadData *data = get_thread_data(); @@ -253,19 +258,19 @@ typedef void*(*QtThreadCallback)(void*); void QThreadPrivate::createEventDispatcher(QThreadData *data) { #if defined(Q_OS_BLACKBERRY) - data->eventDispatcher = new QEventDispatcherBlackberry; + data->eventDispatcher.storeRelease(new QEventDispatcherBlackberry); #else #if !defined(QT_NO_GLIB) if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB") && QEventDispatcherGlib::versionSupported()) - data->eventDispatcher = new QEventDispatcherGlib; + data->eventDispatcher.storeRelease(new QEventDispatcherGlib); else #endif - data->eventDispatcher = new QEventDispatcherUNIX; + data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); #endif - data->eventDispatcher->startingUp(); + data->eventDispatcher.load()->startingUp(); } #ifndef QT_NO_THREAD @@ -287,7 +292,7 @@ static void setCurrentThreadName(pthread_t threadId, const char *name) void *QThreadPrivate::start(void *arg) { -#if !defined(Q_OS_LINUX_ANDROID) +#if !defined(Q_OS_ANDROID) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); #endif pthread_cleanup_push(QThreadPrivate::finish, arg); @@ -295,22 +300,23 @@ 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)); - } - - data->threadId = (Qt::HANDLE)pthread_self(); - set_thread_data(data); - - data->ref(); { QMutexLocker locker(&thr->d_func()->mutex); + + // do we need to reset the thread priority? + if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) { + thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag)); + } + + data->threadId = (Qt::HANDLE)pthread_self(); + set_thread_data(data); + + data->ref(); data->quitNow = thr->d_func()->exited; } - if (data->eventDispatcher) // custom event dispatcher set? - data->eventDispatcher->startingUp(); + if (data->eventDispatcher.load()) // custom event dispatcher set? + data->eventDispatcher.load()->startingUp(); else createEventDispatcher(data); @@ -326,7 +332,7 @@ void *QThreadPrivate::start(void *arg) #endif emit thr->started(QThread::QPrivateSignal()); -#if !defined(Q_OS_LINUX_ANDROID) +#if !defined(Q_OS_ANDROID) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_testcancel(); #endif @@ -353,7 +359,7 @@ void QThreadPrivate::finish(void *arg) QThreadStorageData::finish((void **)data); locker.relock(); - QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; + QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.load(); if (eventDispatcher) { d->data->eventDispatcher = 0; locker.unlock(); @@ -415,6 +421,13 @@ int QThread::idealThreadCount() Q_DECL_NOTHROW // IRIX cores = (int)sysconf(_SC_NPROC_ONLN); #elif defined(Q_OS_INTEGRITY) +#if (__INTEGRITY_MAJOR_VERSION >= 10) + // Integrity V10+ does support multicore CPUs + Value processorCount; + if (GetProcessorCount(CurrentTask(), &processorCount) == 0) + cores = processorCount; + else +#endif // as of aug 2008 Integrity only supports one single core CPU cores = 1; #elif defined(Q_OS_VXWORKS) @@ -488,8 +501,20 @@ static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_pr #endif const int highestPriority = QThread::TimeCriticalPriority; - int prio_min = sched_get_priority_min(*sched_policy); - int prio_max = sched_get_priority_max(*sched_policy); + int prio_min; + int prio_max; +#if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM) + // for other scheduling policies than SCHED_RR or SCHED_FIFO + prio_min = SCHED_FIFO_LOW_PRI; + prio_max = SCHED_FIFO_HIGH_PRI; + + if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO)) +#endif + { + prio_min = sched_get_priority_min(*sched_policy); + prio_max = sched_get_priority_max(*sched_policy); + } + if (prio_min == -1 || prio_max == -1) return false; @@ -612,7 +637,7 @@ void QThread::start(Priority priority) void QThread::terminate() { -#if !defined(Q_OS_LINUX_ANDROID) +#if !defined(Q_OS_ANDROID) Q_D(QThread); QMutexLocker locker(&d->mutex); @@ -654,7 +679,7 @@ void QThread::setTerminationEnabled(bool enabled) "Current thread was not started with QThread."); Q_UNUSED(thr) -#if defined(Q_OS_LINUX_ANDROID) +#if defined(Q_OS_ANDROID) Q_UNUSED(enabled); #else pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL); @@ -663,16 +688,10 @@ void QThread::setTerminationEnabled(bool enabled) #endif } -void QThread::setPriority(Priority priority) +// Caller must lock the mutex +void QThreadPrivate::setPriority(QThread::Priority threadPriority) { - Q_D(QThread); - QMutexLocker locker(&d->mutex); - if (!d->running) { - qWarning("QThread::setPriority: Cannot set priority, thread is not running"); - return; - } - - d->priority = priority; + priority = threadPriority; // copied from start() with a few modifications: @@ -680,7 +699,7 @@ void QThread::setPriority(Priority priority) int sched_policy; sched_param param; - if (pthread_getschedparam(d->thread_id, &sched_policy, ¶m) != 0) { + if (pthread_getschedparam(thread_id, &sched_policy, ¶m) != 0) { // failed to get the scheduling policy, don't bother setting // the priority qWarning("QThread::setPriority: Cannot get scheduler parameters"); @@ -696,15 +715,15 @@ void QThread::setPriority(Priority priority) } param.sched_priority = prio; - int status = pthread_setschedparam(d->thread_id, sched_policy, ¶m); + int status = pthread_setschedparam(thread_id, sched_policy, ¶m); # 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, ¶m); + pthread_getschedparam(thread_id, &sched_policy, ¶m); param.sched_priority = sched_get_priority_min(sched_policy); - pthread_setschedparam(d->thread_id, sched_policy, ¶m); + pthread_setschedparam(thread_id, sched_policy, ¶m); } # else Q_UNUSED(status); diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 8614330d6f..a0fac8eff2 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -96,6 +96,11 @@ Q_DESTRUCTOR_FUNCTION(qt_free_tls) /* QThreadData */ +void QThreadData::clearCurrentThreadData() +{ + TlsSetValue(qt_current_thread_data_tls_index, 0); +} + QThreadData *QThreadData::current() { qt_create_tls(); @@ -301,8 +306,9 @@ void qt_set_thread_name(HANDLE threadId, LPCSTR threadName) void QThreadPrivate::createEventDispatcher(QThreadData *data) { - data->eventDispatcher = new QEventDispatcherWin32; - data->eventDispatcher->startingUp(); + QEventDispatcherWin32 *theEventDispatcher = new QEventDispatcherWin32; + data->eventDispatcher.storeRelease(theEventDispatcher); + theEventDispatcher->startingUp(); } #ifndef QT_NO_THREAD @@ -323,8 +329,8 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi data->quitNow = thr->d_func()->exited; } - if (data->eventDispatcher) // custom event dispatcher set? - data->eventDispatcher->startingUp(); + if (data->eventDispatcher.load()) // custom event dispatcher set? + data->eventDispatcher.load()->startingUp(); else createEventDispatcher(data); @@ -359,7 +365,7 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) QThreadStorageData::finish(tls_data); locker.relock(); - QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher; + QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.load(); if (eventDispatcher) { d->data->eventDispatcher = 0; locker.unlock(); @@ -582,55 +588,49 @@ void QThread::setTerminationEnabled(bool enabled) } } -void QThread::setPriority(Priority priority) +// Caller must hold the mutex +void QThreadPrivate::setPriority(QThread::Priority threadPriority) { - 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: + priority = threadPriority; + switch (priority) { + case QThread::IdlePriority: prio = THREAD_PRIORITY_IDLE; break; - case LowestPriority: + case QThread::LowestPriority: prio = THREAD_PRIORITY_LOWEST; break; - case LowPriority: + case QThread::LowPriority: prio = THREAD_PRIORITY_BELOW_NORMAL; break; - case NormalPriority: + case QThread::NormalPriority: prio = THREAD_PRIORITY_NORMAL; break; - case HighPriority: + case QThread::HighPriority: prio = THREAD_PRIORITY_ABOVE_NORMAL; break; - case HighestPriority: + case QThread::HighestPriority: prio = THREAD_PRIORITY_HIGHEST; break; - case TimeCriticalPriority: + case QThread::TimeCriticalPriority: prio = THREAD_PRIORITY_TIME_CRITICAL; break; - case InheritPriority: + case QThread::InheritPriority: default: qWarning("QThread::setPriority: Argument cannot be InheritPriority"); return; } - if (!SetThreadPriority(d->handle, prio)) { + if (!SetThreadPriority(handle, prio)) { qErrnoWarning("QThread::setPriority: Failed to set thread priority"); } } diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index 2b099706ff..1616fb9fab 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -133,7 +133,7 @@ void QThreadPoolThread::run() // wait for work, exiting after the expiry timeout is reached expired = !manager->runnableReady.wait(locker.mutex(), manager->expiryTimeout); ++manager->activeThreads; - + if (expired) --manager->waitingThreads; } @@ -223,7 +223,7 @@ void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority) int QThreadPoolPrivate::activeThreadCount() const { - // To improve scalability this function is called without holding + // To improve scalability this function is called without holding // the mutex lock -- keep it thread-safe. return (allThreads.count() - expiredThreads.count() @@ -301,7 +301,7 @@ bool QThreadPoolPrivate::waitForDone(int msecs) QElapsedTimer timer; timer.start(); int t; - while (!(queue.isEmpty() && activeThreads == 0) && + while (!(queue.isEmpty() && activeThreads == 0) && ((t = msecs - timer.elapsed()) > 0)) noActiveThreads.wait(locker.mutex(), t); } @@ -367,11 +367,11 @@ void QThreadPoolPrivate::stealRunnable(QRunnable *runnable) \snippet code/src_corelib_concurrent_qthreadpool.cpp 0 - QThreadPool deletes the QRunnable automatically by default. Use + QThreadPool deletes the QRunnable automatically by default. Use QRunnable::setAutoDelete() to change the auto-deletion flag. QThreadPool supports executing the same QRunnable more than once - by calling tryStart(this) from within QRunnable::run(). + by calling tryStart(this) from within QRunnable::run(). If autoDelete is enabled the QRunnable will be deleted when the last thread exits the run function. Calling start() multiple times with the same QRunnable when autoDelete is enabled @@ -595,8 +595,8 @@ void QThreadPool::releaseThread() } /*! - Waits up to \a msecs milliseconds for all threads to exit and removes all - threads from the thread pool. Returns true if all threads were removed; + Waits up to \a msecs milliseconds for all threads to exit and removes all + threads from the thread pool. Returns true if all threads were removed; otherwise it returns false. If \a msecs is -1 (the default), the timeout is ignored (waits for the last thread to exit). */ diff --git a/src/corelib/thread/qthreadpool.h b/src/corelib/thread/qthreadpool.h index bc572fc8e8..ffc16dedbe 100644 --- a/src/corelib/thread/qthreadpool.h +++ b/src/corelib/thread/qthreadpool.h @@ -49,7 +49,6 @@ #ifndef QT_NO_THREAD -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -87,7 +86,6 @@ public: }; QT_END_NAMESPACE -QT_END_HEADER #endif // QT_NO_THREAD diff --git a/src/corelib/thread/qthreadstorage.h b/src/corelib/thread/qthreadstorage.h index c98d181c1f..86285de84f 100644 --- a/src/corelib/thread/qthreadstorage.h +++ b/src/corelib/thread/qthreadstorage.h @@ -46,8 +46,6 @@ #ifndef QT_NO_THREAD -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE @@ -156,8 +154,6 @@ public: 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 index e8f51dad54..1468951373 100644 --- a/src/corelib/thread/qwaitcondition.h +++ b/src/corelib/thread/qwaitcondition.h @@ -46,8 +46,6 @@ #include <limits.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE @@ -99,6 +97,4 @@ public: QT_END_NAMESPACE -QT_END_HEADER - #endif // QWAITCONDITION_H diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp index ab4e7872fb..616a4bdfb8 100644 --- a/src/corelib/thread/qwaitcondition_unix.cpp +++ b/src/corelib/thread/qwaitcondition_unix.cpp @@ -45,22 +45,66 @@ #include "qreadwritelock.h" #include "qatomic.h" #include "qstring.h" +#include "qelapsedtimer.h" +#include "private/qcore_unix_p.h" #include "qmutex_p.h" #include "qreadwritelock_p.h" #include <errno.h> +#include <sys/time.h> +#include <time.h> #ifndef QT_NO_THREAD QT_BEGIN_NAMESPACE +#ifdef Q_OS_ANDROID +// Android lacks pthread_condattr_setclock, but it does have a nice function +// for relative waits. Use weakref so we can determine at runtime whether it is +// present. +static int local_cond_timedwait_relative(pthread_cond_t*, pthread_mutex_t *, const timespec *) +__attribute__((weakref("__pthread_cond_timedwait_relative"))); +#endif + 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))); } +void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where) +{ + pthread_condattr_t condattr; + + pthread_condattr_init(&condattr); +#if !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID) && (_POSIX_MONOTONIC_CLOCK-0 >= 0) + if (QElapsedTimer::clockType() == QElapsedTimer::MonotonicClock) + pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); +#endif + report_error(pthread_cond_init(cond, &condattr), where, "cv init"); + pthread_condattr_destroy(&condattr); +} + +void qt_abstime_for_timeout(timespec *ts, int timeout) +{ +#ifdef Q_OS_MAC + // on Mac, qt_gettime() (on qelapsedtimer_mac.cpp) returns ticks related to the Mach absolute time + // that doesn't work with pthread + // Mac also doesn't have clock_gettime + struct timeval tv; + gettimeofday(&tv, 0); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; +#else + *ts = qt_gettime(); +#endif + + ts->tv_sec += timeout / 1000; + ts->tv_nsec += timeout % 1000 * Q_UINT64_C(1000) * 1000; + normalizedTimespec(*ts); +} + class QWaitConditionPrivate { public: pthread_mutex_t mutex; @@ -68,20 +112,26 @@ public: int waiters; int wakeups; + int wait_relative(unsigned long time) + { + timespec ti; +#ifdef Q_OS_ANDROID + if (Q_LIKELY(local_cond_timedwait_relative)) { + ti.tv_sec = time / 1000; + ti.tv_nsec = time % 1000 * Q_UINT64_C(1000) * 1000; + return local_cond_timedwait_relative(&cond, &mutex, &ti); + } +#endif + qt_abstime_for_timeout(&ti, time); + return pthread_cond_timedwait(&cond, &mutex, &ti); + } + 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); + code = wait_relative(time); } else { code = pthread_cond_wait(&cond, &mutex); } @@ -114,7 +164,7 @@ 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"); + qt_initialize_pthread_cond(&d->cond, "QWaitCondition"); d->waiters = d->wakeups = 0; } diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri index 7247f2984e..13f0502b62 100644 --- a/src/corelib/thread/thread.pri +++ b/src/corelib/thread/thread.pri @@ -56,7 +56,7 @@ integrity:SOURCES += thread/qmutex_unix.cpp \ thread/qwaitcondition_unix.cpp unix: { - macx-* { + mac { SOURCES += thread/qmutex_mac.cpp } else:linux-*:!linux-lsb-* { SOURCES += thread/qmutex_linux.cpp |