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 
55 QT_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 */
QEventLoop(QObject * parent)102 QEventLoop::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 */
~QEventLoop()116 QEventLoop::~QEventLoop()
117 { }
118 
119 
120 /*!
121     Processes some pending events that match \a flags.
122     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 */
processEvents(ProcessEventsFlags flags)133 bool 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 */
exec(ProcessEventsFlags flags)165 int 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 &locker;
183 
184         bool exceptionCaught;
185         LoopReference(QEventLoopPrivate *d, QMutexLocker &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 */
processEvents(ProcessEventsFlags flags,int maxTime)254 void 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 */
exit(int returnCode)283 void 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  */
isRunning() const313 bool 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 */
wakeUp()324 void 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 */
event(QEvent * event)337 bool 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 */
quit()354 void QEventLoop::quit()
355 { exit(0); }
356 
357 
358 class QEventLoopLockerPrivate
359 {
360 public:
QEventLoopLockerPrivate(QEventLoopPrivate * loop)361     explicit QEventLoopLockerPrivate(QEventLoopPrivate *loop)
362       : loop(loop), type(EventLoop)
363     {
364         loop->ref();
365     }
366 
QEventLoopLockerPrivate(QThreadPrivate * thread)367     explicit QEventLoopLockerPrivate(QThreadPrivate *thread)
368       : thread(thread), type(Thread)
369     {
370         thread->ref();
371     }
372 
QEventLoopLockerPrivate(QCoreApplicationPrivate * app)373     explicit QEventLoopLockerPrivate(QCoreApplicationPrivate *app)
374       : app(app), type(Application)
375     {
376         app->ref();
377     }
378 
~QEventLoopLockerPrivate()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 
395 private:
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  */
QEventLoopLocker()436 QEventLoopLocker::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  */
QEventLoopLocker(QEventLoop * loop)449 QEventLoopLocker::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  */
QEventLoopLocker(QThread * thread)462 QEventLoopLocker::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  */
~QEventLoopLocker()471 QEventLoopLocker::~QEventLoopLocker()
472 {
473     delete d_ptr;
474 }
475 
476 QT_END_NAMESPACE
477 
478 #include "moc_qeventloop.cpp"
479