Add the quitlock feature to QThread.
[profile/ivi/qtbase.git] / src / corelib / kernel / qeventloop.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qeventloop.h"
43
44 #include "qabstracteventdispatcher.h"
45 #include "qcoreapplication.h"
46 #include "qcoreapplication_p.h"
47 #include "qelapsedtimer.h"
48
49 #include "qobject_p.h"
50 #include "qeventloop_p.h"
51 #include <private/qthread_p.h>
52
53 QT_BEGIN_NAMESPACE
54
55 /*!
56     \class QEventLoop
57     \brief The QEventLoop class provides a means of entering and leaving an event loop.
58
59     At any time, you can create a QEventLoop object and call exec()
60     on it to start a local event loop. From within the event loop,
61     calling exit() will force exec() to return.
62
63     \sa QAbstractEventDispatcher
64 */
65
66 /*!
67     \enum QEventLoop::ProcessEventsFlag
68
69     This enum controls the types of events processed by the
70     processEvents() functions.
71
72     \value AllEvents All events. Note that
73     \l{QEvent::DeferredDelete}{DeferredDelete} events are processed
74     specially. See QObject::deleteLater() for more details.
75
76     \value ExcludeUserInputEvents Do not process user input events,
77     such as ButtonPress and KeyPress. Note that the events are not
78     discarded; they will be delivered the next time processEvents() is
79     called without the ExcludeUserInputEvents flag.
80
81     \value ExcludeSocketNotifiers Do not process socket notifier
82     events. Note that the events are not discarded; they will be
83     delivered the next time processEvents() is called without the
84     ExcludeSocketNotifiers flag.
85
86     \value WaitForMoreEvents Wait for events if no pending events are
87     available.
88
89     \omitvalue X11ExcludeTimers
90     \omitvalue EventLoopExec
91     \omitvalue DialogExec
92
93     \sa processEvents()
94 */
95
96 /*!
97     Constructs an event loop object with the given \a parent.
98 */
99 QEventLoop::QEventLoop(QObject *parent)
100     : QObject(*new QEventLoopPrivate, parent)
101 {
102     Q_D(QEventLoop);
103     if (!QCoreApplication::instance()) {
104         qWarning("QEventLoop: Cannot be used without QApplication");
105     } else if (!d->threadData->eventDispatcher) {
106         QThreadPrivate::createEventDispatcher(d->threadData);
107     }
108 }
109
110 /*!
111     Destroys the event loop object.
112 */
113 QEventLoop::~QEventLoop()
114 { }
115
116
117 /*!
118     Processes pending events that match \a flags until there are no
119     more events to process. Returns true if pending events were handled;
120     otherwise returns false.
121
122     This function is especially useful if you have a long running
123     operation and want to show its progress without allowing user
124     input; i.e. by using the \l ExcludeUserInputEvents flag.
125
126     This function is simply a wrapper for
127     QAbstractEventDispatcher::processEvents(). See the documentation
128     for that function for details.
129 */
130 bool QEventLoop::processEvents(ProcessEventsFlags flags)
131 {
132     Q_D(QEventLoop);
133     if (!d->threadData->eventDispatcher)
134         return false;
135     return d->threadData->eventDispatcher->processEvents(flags);
136 }
137
138 /*!
139     Enters the main event loop and waits until exit() is called.
140     Returns the value that was passed to exit().
141
142     If \a flags are specified, only events of the types allowed by
143     the \a flags will be processed.
144
145     It is necessary to call this function to start event handling. The
146     main event loop receives events from the window system and
147     dispatches these to the application widgets.
148
149     Generally speaking, no user interaction can take place before
150     calling exec(). As a special case, modal widgets like QMessageBox
151     can be used before calling exec(), because modal widgets
152     use their own local event loop.
153
154     To make your application perform idle processing (i.e. executing a
155     special function whenever there are no pending events), use a
156     QTimer with 0 timeout. More sophisticated idle processing schemes
157     can be achieved using processEvents().
158
159     \sa QApplication::quit(), exit(), processEvents()
160 */
161 int QEventLoop::exec(ProcessEventsFlags flags)
162 {
163     Q_D(QEventLoop);
164     //we need to protect from race condition with QThread::exit
165     QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);
166     if (d->threadData->quitNow)
167         return -1;
168
169     if (d->inExec) {
170         qWarning("QEventLoop::exec: instance %p has already called exec()", this);
171         return -1;
172     }
173
174     struct LoopReference {
175         QEventLoopPrivate *d;
176         QMutexLocker &locker;
177
178         bool exceptionCaught;
179         LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
180         {
181             d->inExec = true;
182             d->exit = false;
183             ++d->threadData->loopLevel;
184             d->threadData->eventLoops.push(d->q_func());
185             locker.unlock();
186         }
187
188         ~LoopReference()
189         {
190             if (exceptionCaught) {
191                 qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
192                          "exceptions from an event handler is not supported in Qt. You must\n"
193                          "reimplement QApplication::notify() and catch all exceptions there.\n");
194             }
195             locker.relock();
196             QEventLoop *eventLoop = d->threadData->eventLoops.pop();
197             Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
198             Q_UNUSED(eventLoop); // --release warning
199             d->inExec = false;
200             --d->threadData->loopLevel;
201         }
202     };
203     LoopReference ref(d, locker);
204
205     // remove posted quit events when entering a new event loop
206     QCoreApplication *app = QCoreApplication::instance();
207     if (app && app->thread() == thread())
208         QCoreApplication::removePostedEvents(app, QEvent::Quit);
209
210     while (!d->exit)
211         processEvents(flags | WaitForMoreEvents | EventLoopExec);
212
213     ref.exceptionCaught = false;
214     return d->returnCode;
215 }
216
217 /*!
218     Process pending events that match \a flags for a maximum of \a
219     maxTime milliseconds, or until there are no more events to
220     process, whichever is shorter.
221     This function is especially useful if you have a long running
222     operation and want to show its progress without allowing user
223     input, i.e. by using the \l ExcludeUserInputEvents flag.
224
225     \bold{Notes:}
226     \list
227     \o This function does not process events continuously; it
228        returns after all available events are processed.
229     \o Specifying the \l WaitForMoreEvents flag makes no sense
230        and will be ignored.
231     \endlist
232 */
233 void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
234 {
235     Q_D(QEventLoop);
236     if (!d->threadData->eventDispatcher)
237         return;
238
239     QElapsedTimer start;
240     start.start();
241     while (processEvents(flags & ~WaitForMoreEvents)) {
242         if (start.elapsed() > maxTime)
243             break;
244     }
245 }
246
247 /*!
248     Tells the event loop to exit with a return code.
249
250     After this function has been called, the event loop returns from
251     the call to exec(). The exec() function returns \a returnCode.
252
253     By convention, a \a returnCode of 0 means success, and any non-zero
254     value indicates an error.
255
256     Note that unlike the C library function of the same name, this
257     function \e does return to the caller -- it is event processing that
258     stops.
259
260     \sa QCoreApplication::quit(), quit(), exec()
261 */
262 void QEventLoop::exit(int returnCode)
263 {
264     Q_D(QEventLoop);
265     if (!d->threadData->eventDispatcher)
266         return;
267
268     d->returnCode = returnCode;
269     d->exit = true;
270     d->threadData->eventDispatcher->interrupt();
271 }
272
273 /*!
274     Returns true if the event loop is running; otherwise returns
275     false. The event loop is considered running from the time when
276     exec() is called until exit() is called.
277
278     \sa exec() exit()
279  */
280 bool QEventLoop::isRunning() const
281 {
282     Q_D(const QEventLoop);
283     return !d->exit;
284 }
285
286 /*!
287     Wakes up the event loop.
288
289     \sa QAbstractEventDispatcher::wakeUp()
290 */
291 void QEventLoop::wakeUp()
292 {
293     Q_D(QEventLoop);
294     if (!d->threadData->eventDispatcher)
295         return;
296     d->threadData->eventDispatcher->wakeUp();
297 }
298
299
300 bool QEventLoop::event(QEvent *event)
301 {
302     if (event->type() == QEvent::Quit) {
303         quit();
304         return true;
305     } else {
306         return QObject::event(event);
307     }
308 }
309
310 /*!
311     Tells the event loop to exit normally.
312
313     Same as exit(0).
314
315     \sa QCoreApplication::quit(), exit()
316 */
317 void QEventLoop::quit()
318 { exit(0); }
319
320
321 class QEventLoopLockerPrivate
322 {
323 public:
324     explicit QEventLoopLockerPrivate(QEventLoopPrivate *loop)
325       : loop(loop), thread(0), app(0)
326     {
327         loop->ref();
328     }
329
330     explicit QEventLoopLockerPrivate(QThreadPrivate *thread)
331       : loop(0), thread(thread), app(0)
332     {
333         thread->ref();
334     }
335
336     explicit QEventLoopLockerPrivate(QCoreApplicationPrivate *app)
337       : loop(0), thread(0), app(app)
338     {
339         app->ref();
340     }
341
342     ~QEventLoopLockerPrivate()
343     {
344         if (loop)
345             loop->deref();
346         else if (thread)
347             thread->deref();
348         else
349             app->deref();
350     }
351
352 private:
353     QEventLoopPrivate *loop;
354     QThreadPrivate *thread;
355     QCoreApplicationPrivate *app;
356 };
357
358 /*!
359     \class QEventLoopLocker
360     \brief The QEventLoopLocker class provides a means to quit an event loop when it is no longer needed.
361
362     The QEventLoopLocker operates on particular objects - either a QCoreApplication
363     instance or a QEventLoop instance.
364
365     This makes it possible to, for example, run a batch of jobs with an event loop
366     and exit that event loop after the last job is finished. That is accomplished
367     by keeping a QEventLoopLocker with each job instance.
368
369     The variant which operates on QCoreApplication makes it possible to finish
370     asynchronously running jobs after the last gui window has been closed. This
371     can be useful for example for running a job which uploads data to a network.
372
373     \sa QEventLoop, QCoreApplication
374 */
375
376 /*!
377     Creates an event locker operating on the \p app.
378
379     The application will quit when there are no more QEventLoopLockers operating on it.
380
381     \sa QCoreApplication::quit(), QCoreApplication::isQuitLockEnabled()
382  */
383 QEventLoopLocker::QEventLoopLocker()
384   : d_ptr(new QEventLoopLockerPrivate(static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()))))
385 {
386
387 }
388
389 /*!
390     Creates an event locker operating on the \p app.
391
392     This particular QEventLoop will quit when there are no more QEventLoopLockers operating on it.
393
394     \sa QEventLoop::quit()
395  */
396 QEventLoopLocker::QEventLoopLocker(QEventLoop *loop)
397   : d_ptr(new QEventLoopLockerPrivate(static_cast<QEventLoopPrivate*>(QObjectPrivate::get(loop))))
398 {
399
400 }
401
402 QEventLoopLocker::QEventLoopLocker(QThread *thread)
403   : d_ptr(new QEventLoopLockerPrivate(static_cast<QThreadPrivate*>(QObjectPrivate::get(thread))))
404 {
405
406 }
407
408 /*!
409     Destroys this event loop locker object
410  */
411 QEventLoopLocker::~QEventLoopLocker()
412 {
413     delete d_ptr;
414 }
415
416 QT_END_NAMESPACE