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