1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativethread_p.h"
44 #include <private/qfieldlist_p.h>
46 #include <QtCore/qmutex.h>
47 #include <QtCore/qthread.h>
48 #include <QtCore/qcoreevent.h>
49 #include <QtCore/qwaitcondition.h>
50 #include <QtCore/qcoreapplication.h>
54 class QDeclarativeThreadPrivate : public QThread
57 QDeclarativeThreadPrivate(QDeclarativeThread *);
58 QDeclarativeThread *q;
62 inline void lock() { _mutex.lock(); }
63 inline void unlock() { _mutex.unlock(); }
64 inline void wait() { _wait.wait(&_mutex); }
65 inline void wakeOne() { _wait.wakeOne(); }
66 inline void wakeAll() { _wait.wakeAll(); }
68 quint32 m_threadProcessing:1; // Set when the thread is processing messages
69 quint32 m_mainProcessing:1; // Set when the main thread is processing messages
70 quint32 m_shutdown:1; // Set by main thread to request a shutdown
71 quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty
73 typedef QFieldList<QDeclarativeThread::Message, &QDeclarativeThread::Message::next> MessageList;
74 MessageList threadList;
77 QDeclarativeThread::Message *mainSync;
79 void triggerMainEvent();
80 void triggerThreadEvent();
86 virtual bool event(QEvent *);
89 struct MainObject : public QObject {
90 MainObject(QDeclarativeThreadPrivate *p);
91 virtual bool event(QEvent *e);
92 QDeclarativeThreadPrivate *p;
94 MainObject m_mainObject;
100 QDeclarativeThreadPrivate::MainObject::MainObject(QDeclarativeThreadPrivate *p)
105 // Trigger mainEvent in main thread. Must be called from thread.
106 void QDeclarativeThreadPrivate::triggerMainEvent()
108 Q_ASSERT(q->isThisThread());
109 QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User));
112 // Trigger even in thread. Must be called from main thread.
113 void QDeclarativeThreadPrivate::triggerThreadEvent()
115 Q_ASSERT(!q->isThisThread());
116 QCoreApplication::postEvent(this, new QEvent(QEvent::User));
119 bool QDeclarativeThreadPrivate::MainObject::event(QEvent *e)
121 if (e->type() == QEvent::User)
123 return QObject::event(e);
126 QDeclarativeThreadPrivate::QDeclarativeThreadPrivate(QDeclarativeThread *q)
127 : q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false),
128 m_mainThreadWaiting(false), mainSync(0), m_mainObject(this)
132 bool QDeclarativeThreadPrivate::event(QEvent *e)
134 if (e->type() == QEvent::User)
136 return QThread::event(e);
139 void QDeclarativeThreadPrivate::run()
151 void QDeclarativeThreadPrivate::mainEvent()
155 m_mainProcessing = true;
157 while (!mainList.isEmpty() || mainSync) {
158 bool isSync = mainSync != 0;
159 QDeclarativeThread::Message *message = isSync?mainSync:mainList.takeFirst();
173 m_mainProcessing = false;
178 void QDeclarativeThreadPrivate::threadEvent()
188 m_threadProcessing = true;
190 while (!threadList.isEmpty()) {
191 QDeclarativeThread::Message *message = threadList.first();
199 delete threadList.takeFirst();
204 m_threadProcessing = false;
210 QDeclarativeThread::QDeclarativeThread()
211 : d(new QDeclarativeThreadPrivate(this))
221 QDeclarativeThread::~QDeclarativeThread()
226 void QDeclarativeThread::shutdown()
229 Q_ASSERT(!d->m_shutdown);
230 d->m_shutdown = true;
231 if (d->threadList.isEmpty() && d->m_threadProcessing == false)
232 d->triggerThreadEvent();
238 void QDeclarativeThread::lock()
243 void QDeclarativeThread::unlock()
248 void QDeclarativeThread::wakeOne()
253 void QDeclarativeThread::wakeAll()
258 void QDeclarativeThread::wait()
263 bool QDeclarativeThread::isThisThread() const
265 return QThread::currentThread() == d;
268 QThread *QDeclarativeThread::thread() const
270 return const_cast<QThread *>(static_cast<const QThread *>(d));
273 // Called when the thread starts. Do startup stuff in here.
274 void QDeclarativeThread::startupThread()
278 // Called when the thread shuts down. Do cleanup in here.
279 void QDeclarativeThread::shutdownThread()
283 void QDeclarativeThread::internalCallMethodInThread(Message *message)
285 Q_ASSERT(!isThisThread());
287 Q_ASSERT(d->m_mainThreadWaiting == false);
289 bool wasEmpty = d->threadList.isEmpty();
290 d->threadList.append(message);
291 if (wasEmpty && d->m_threadProcessing == false)
292 d->triggerThreadEvent();
294 d->m_mainThreadWaiting = true;
298 QDeclarativeThread::Message *message = d->mainSync;
308 } while (d->mainSync || !d->threadList.isEmpty());
310 d->m_mainThreadWaiting = false;
314 void QDeclarativeThread::internalCallMethodInMain(Message *message)
316 Q_ASSERT(isThisThread());
320 Q_ASSERT(d->mainSync == 0);
321 d->mainSync = message;
323 if (d->m_mainThreadWaiting) {
325 } else if (d->m_mainProcessing) {
326 // Do nothing - it is already looping
328 d->triggerMainEvent();
331 while (d->mainSync && !d->m_shutdown)
337 void QDeclarativeThread::internalPostMethodToThread(Message *message)
339 Q_ASSERT(!isThisThread());
341 bool wasEmpty = d->threadList.isEmpty();
342 d->threadList.append(message);
343 if (wasEmpty && d->m_threadProcessing == false)
344 d->triggerThreadEvent();
348 void QDeclarativeThread::internalPostMethodToMain(Message *message)
350 Q_ASSERT(isThisThread());
352 bool wasEmpty = d->mainList.isEmpty();
353 d->mainList.append(message);
354 if (wasEmpty && d->m_mainProcessing == false)
355 d->triggerMainEvent();