/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** 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. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** ** $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 "QtCore/qcoreapplication.h" #include "private/qobject_p.h" 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) { } }; Q_DECLARE_TYPEINFO(QPostEvent, Q_MOVABLE_TYPE); inline bool operator<(int priority, const QPostEvent &pe) { return pe.priority < priority; } inline bool operator<(const QPostEvent &pe, int priority) { return priority < pe.priority; } // This class holds the list of posted events. // The list has to be kept sorted by priority class QPostEventList : public QVector { 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() : QVector(), recursion(0), startOffset(0), insertionOffset(0) { } void addEvent(const QPostEvent &ev) { int priority = ev.priority; if (isEmpty() || last().priority >= priority || begin() + insertionOffset >= end()) { // optimization: we can simply append if the last event in // the queue has higher or equal priority append(ev); } else { // insert event in descending priority order, using upper // bound for a given priority (to ensure proper ordering // of events with the same priority) QPostEventList::iterator at = qUpperBound(begin() + insertionOffset, end(), priority); insert(at, ev); } } private: //hides because they do not keep that list sorted. addEvent must be used using QVector::append; using QVector::insert; }; #ifndef QT_NO_THREAD class QThreadPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QThread) public: QThreadPrivate(QThreadData *d = 0); ~QThreadPrivate(); mutable QMutex mutex; QAtomicInt quitLockRef; 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); static void finish(void *); #endif // Q_OS_UNIX #ifdef Q_OS_WIN static unsigned int __stdcall start(void *); static void finish(void *, bool lockAnyway=true); Qt::HANDLE handle; unsigned int id; int waiters; bool terminationEnabled, terminatePending; # endif QThreadData *data; static void createEventDispatcher(QThreadData *data); void ref() { quitLockRef.ref(); } void deref() { if (!quitLockRef.deref() && running) { QCoreApplication::instance()->postEvent(q_ptr, new QEvent(QEvent::Quit)); } } }; #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); void ref() {} void deref() {} 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 eventLoops; QPostEventList postEventList; bool canWait; QVector tls; bool isAdopted; }; class QScopedLoopLevelCounter { QThreadData *threadData; public: inline QScopedLoopLevelCounter(QThreadData *threadData) : threadData(threadData) { ++threadData->loopLevel; } inline ~QScopedLoopLevelCounter() { --threadData->loopLevel; } }; // thread wrapper for the main() thread class QAdoptedThread : public QThread { Q_DECLARE_PRIVATE(QThread) public: QAdoptedThread(QThreadData *data = 0); ~QAdoptedThread(); void init(); private: void run(); }; QT_END_NAMESPACE #endif // QTHREAD_P_H