9883e53e930e07857039da2f35ac690248a09fbf
[profile/ivi/qtdeclarative.git] / src / declarative / qml / ftw / qdeclarativethread.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativethread_p.h"
43
44 #include <private/qfieldlist_p.h>
45
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>
51
52 QT_BEGIN_NAMESPACE
53
54 class QDeclarativeThreadPrivate : public QThread
55 {
56 public:
57     QDeclarativeThreadPrivate(QDeclarativeThread *);
58     QDeclarativeThread *q;
59
60     virtual void run();
61
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(); }
67
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
72
73     typedef QFieldList<QDeclarativeThread::Message, &QDeclarativeThread::Message::next> MessageList;
74     MessageList threadList;
75     MessageList mainList;
76
77     QDeclarativeThread::Message *mainSync;
78
79     void triggerMainEvent();
80     void triggerThreadEvent();
81
82     void mainEvent();
83     void threadEvent();
84
85 protected:
86     virtual bool event(QEvent *); 
87
88 private:
89     struct MainObject : public QObject { 
90         MainObject(QDeclarativeThreadPrivate *p);
91         virtual bool event(QEvent *e);
92         QDeclarativeThreadPrivate *p;
93     };
94     MainObject m_mainObject;
95
96     QMutex _mutex;
97     QWaitCondition _wait;
98 };
99
100 QDeclarativeThreadPrivate::MainObject::MainObject(QDeclarativeThreadPrivate *p) 
101 : p(p) 
102 {
103 }
104
105 // Trigger mainEvent in main thread.  Must be called from thread.
106 void QDeclarativeThreadPrivate::triggerMainEvent()
107 {
108     Q_ASSERT(q->isThisThread());
109     QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User));
110 }
111
112 // Trigger even in thread.  Must be called from main thread.
113 void QDeclarativeThreadPrivate::triggerThreadEvent()
114 {
115     Q_ASSERT(!q->isThisThread());
116     QCoreApplication::postEvent(this, new QEvent(QEvent::User));
117 }
118
119 bool QDeclarativeThreadPrivate::MainObject::event(QEvent *e) 
120 {
121     if (e->type() == QEvent::User) 
122         p->mainEvent();
123     return QObject::event(e);
124 }
125     
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)
129 {
130 }
131
132 bool QDeclarativeThreadPrivate::event(QEvent *e)
133 {
134     if (e->type() == QEvent::User) 
135         threadEvent();
136     return QThread::event(e);
137 }
138
139 void QDeclarativeThreadPrivate::run()
140 {
141     lock();
142
143     wakeOne();
144
145     unlock();
146
147     q->startupThread();
148     exec();
149 }
150
151 void QDeclarativeThreadPrivate::mainEvent()
152 {
153     lock();
154
155     m_mainProcessing = true;
156
157     while (!mainList.isEmpty() || mainSync) {
158         bool isSync = mainSync != 0;
159         QDeclarativeThread::Message *message = isSync?mainSync:mainList.takeFirst();
160         unlock();
161
162         message->call(q);
163         delete message;
164
165         lock();
166
167         if (isSync) {
168             mainSync = 0;
169             wakeOne();
170         }
171     }
172
173     m_mainProcessing = false;
174
175     unlock();
176 }
177
178 void QDeclarativeThreadPrivate::threadEvent() 
179 {
180     lock();
181
182     if (m_shutdown) {
183         quit();
184         wakeOne();
185         unlock();
186         q->shutdownThread();
187     } else {
188         m_threadProcessing = true;
189
190         while (!threadList.isEmpty()) {
191             QDeclarativeThread::Message *message = threadList.first();
192
193             unlock();
194
195             message->call(q);
196
197             lock();
198
199             delete threadList.takeFirst();
200         }
201
202         wakeOne();
203
204         m_threadProcessing = false;
205
206         unlock();
207     }
208 }
209
210 QDeclarativeThread::QDeclarativeThread()
211 : d(new QDeclarativeThreadPrivate(this))
212 {
213     d->lock();
214     d->start();
215     d->wait();
216     d->unlock();
217     d->moveToThread(d);
218
219 }
220
221 QDeclarativeThread::~QDeclarativeThread()
222 {
223     delete d;
224 }
225
226 void QDeclarativeThread::shutdown()
227 {
228     d->lock();
229     Q_ASSERT(!d->m_shutdown);
230     d->m_shutdown = true;
231     if (d->threadList.isEmpty() && d->m_threadProcessing == false)
232         d->triggerThreadEvent();
233     d->wait();
234     d->unlock();
235     d->QThread::wait();
236 }
237
238 void QDeclarativeThread::lock()
239 {
240     d->lock();
241 }
242
243 void QDeclarativeThread::unlock()
244 {
245     d->unlock();
246 }
247
248 void QDeclarativeThread::wakeOne()
249 {
250     d->wakeOne();
251 }
252
253 void QDeclarativeThread::wakeAll()
254 {
255     d->wakeAll();
256 }
257
258 void QDeclarativeThread::wait()
259 {
260     d->wait();
261 }
262
263 bool QDeclarativeThread::isThisThread() const
264 {
265     return QThread::currentThread() == d;
266 }
267
268 QThread *QDeclarativeThread::thread() const
269 {
270     return const_cast<QThread *>(static_cast<const QThread *>(d));
271 }
272
273 // Called when the thread starts.  Do startup stuff in here.
274 void QDeclarativeThread::startupThread()
275 {
276 }
277
278 // Called when the thread shuts down.  Do cleanup in here.
279 void QDeclarativeThread::shutdownThread()
280 {
281 }
282
283 void QDeclarativeThread::internalCallMethodInThread(Message *message)
284 {
285     Q_ASSERT(!isThisThread());
286     d->lock();
287     Q_ASSERT(d->m_mainThreadWaiting == false);
288
289     bool wasEmpty = d->threadList.isEmpty();
290     d->threadList.append(message);
291     if (wasEmpty && d->m_threadProcessing == false)
292         d->triggerThreadEvent();
293
294     d->m_mainThreadWaiting = true;
295
296     do {
297         if (d->mainSync) {
298             QDeclarativeThread::Message *message = d->mainSync;
299             unlock();
300             message->call(this);
301             delete message;
302             lock();
303             d->mainSync = 0;
304             wakeOne();
305         } else {
306             d->wait();
307         }
308     } while (d->mainSync || !d->threadList.isEmpty());
309
310     d->m_mainThreadWaiting = false;
311     d->unlock();
312 }
313
314 void QDeclarativeThread::internalCallMethodInMain(Message *message)
315 {
316     Q_ASSERT(isThisThread());
317
318     d->lock();
319
320     Q_ASSERT(d->mainSync == 0);
321     d->mainSync = message;
322
323     if (d->m_mainThreadWaiting) {
324         d->wakeOne();
325     } else if (d->m_mainProcessing) {
326         // Do nothing - it is already looping
327     } else {
328         d->triggerMainEvent();
329     }
330
331     while (d->mainSync && !d->m_shutdown)
332         d->wait();
333
334     d->unlock();
335 }
336
337 void QDeclarativeThread::internalPostMethodToThread(Message *message)
338 {
339     Q_ASSERT(!isThisThread());
340     d->lock();
341     bool wasEmpty = d->threadList.isEmpty();
342     d->threadList.append(message);
343     if (wasEmpty && d->m_threadProcessing == false)
344         d->triggerThreadEvent();
345     d->unlock();
346 }
347
348 void QDeclarativeThread::internalPostMethodToMain(Message *message)
349 {
350     Q_ASSERT(isThisThread());
351     d->lock();
352     bool wasEmpty = d->mainList.isEmpty();
353     d->mainList.append(message);
354     if (wasEmpty && d->m_mainProcessing == false)
355         d->triggerMainEvent();
356     d->unlock();
357 }
358
359 QT_END_NAMESPACE