Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qeventloop.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#
include
"qeventloop.h"
6
7
#
include
"qabstracteventdispatcher.h"
8
#
include
"qcoreapplication.h"
9
#
include
"qcoreapplication_p.h"
10
#
include
"qdeadlinetimer.h"
11
12
#
include
"qobject_p.h"
13
#
include
"qeventloop_p.h"
14
#
include
<
private
/
qthread_p
.
h
>
15
16
#
if
__has_include
(
<
cxxabi
.
h
>
)
17
#
include
<
cxxabi
.
h
>
18
#
endif
19
20
QT_BEGIN_NAMESPACE
21
22
QEventLoopPrivate::~QEventLoopPrivate()
23
=
default
;
24
25
/*!
26
\class QEventLoop
27
\inmodule QtCore
28
\brief The QEventLoop class provides a means of entering and leaving an event loop.
29
30
At any time, you can create a QEventLoop object and call exec()
31
on it to start a local event loop. From within the event loop,
32
calling exit() will force exec() to return.
33
34
\sa QAbstractEventDispatcher
35
*/
36
37
/*!
38
\enum QEventLoop::ProcessEventsFlag
39
40
This enum controls the types of events processed by the
41
processEvents() functions.
42
43
\value AllEvents All events. Note that
44
\l{QEvent::DeferredDelete}{DeferredDelete} events are processed
45
specially. See QObject::deleteLater() for more details.
46
47
\value ExcludeUserInputEvents Do not process user input events,
48
such as ButtonPress and KeyPress. Note that the events are not
49
discarded; they will be delivered the next time processEvents() is
50
called without the ExcludeUserInputEvents flag.
51
52
\value ExcludeSocketNotifiers Do not process socket notifier
53
events. Note that the events are not discarded; they will be
54
delivered the next time processEvents() is called without the
55
ExcludeSocketNotifiers flag.
56
57
\value WaitForMoreEvents Wait for events if no pending events are
58
available.
59
60
\omitvalue X11ExcludeTimers
61
\omitvalue EventLoopExec
62
\omitvalue DialogExec
63
\omitvalue ApplicationExec
64
65
\sa processEvents()
66
*/
67
68
/*!
69
Constructs an event loop object with the given \a parent.
70
*/
71
QEventLoop::QEventLoop(QObject *parent)
72
: QObject(*
new
QEventLoopPrivate, parent)
73
{
74
Q_D(QEventLoop);
75
QThreadData *threadData = d->threadData.loadRelaxed();
76
if
(!QCoreApplication::instanceExists() && threadData->requiresCoreApplication) {
77
qWarning(
"QEventLoop: Cannot be used without QCoreApplication"
);
78
}
else
{
79
threadData->ensureEventDispatcher();
80
}
81
}
82
83
/*!
84
Destroys the event loop object.
85
*/
86
QEventLoop::~QEventLoop()
87
{ }
88
89
90
/*!
91
Processes some pending events that match \a flags.
92
Returns \c true if pending events were handled;
93
otherwise returns \c false.
94
95
This function is especially useful if you have a long running
96
operation and want to show its progress without allowing user
97
input; i.e. by using the \l ExcludeUserInputEvents flag.
98
99
This function is simply a wrapper for
100
QAbstractEventDispatcher::processEvents(). See the documentation
101
for that function for details.
102
*/
103
bool
QEventLoop::processEvents(ProcessEventsFlags flags)
104
{
105
Q_D(QEventLoop);
106
auto
threadData = d->threadData.loadRelaxed();
107
if
(!threadData->hasEventDispatcher())
108
return
false
;
109
return
threadData->eventDispatcher.loadRelaxed()->processEvents(flags);
110
}
111
112
/*!
113
Enters the main event loop and waits until exit() is called.
114
Returns the value that was passed to exit().
115
116
If \a flags are specified, only events of the types allowed by
117
the \a flags will be processed.
118
119
It is necessary to call this function to start event handling. The
120
main event loop receives events from the window system and
121
dispatches these to the application widgets.
122
123
Generally speaking, no user interaction can take place before
124
calling exec(). As a special case, modal widgets like QMessageBox
125
can be used before calling exec(), because modal widgets
126
use their own local event loop.
127
128
To make your application perform idle processing (i.e. executing a special
129
function whenever there are no pending events), use a QChronoTimer with
130
0ns timeout. More sophisticated idle processing schemes can be achieved
131
using processEvents().
132
133
\sa QCoreApplication::quit(), exit(), processEvents()
134
*/
135
int
QEventLoop::exec(ProcessEventsFlags flags)
136
{
137
Q_D(QEventLoop);
138
auto
threadData = d->threadData.loadRelaxed();
139
140
//we need to protect from race condition with QThread::exit
141
QMutexLocker locker(&
static_cast
<QThreadPrivate *>(QObjectPrivate::get(threadData->thread.loadAcquire()))->mutex);
142
if
(threadData->quitNow)
143
return
-1;
144
145
if
(d->inExec) {
146
qWarning(
"QEventLoop::exec: instance %p has already called exec()"
,
this
);
147
return
-1;
148
}
149
150
struct
LoopReference {
151
QEventLoopPrivate *d;
152
QMutexLocker<QMutex> &locker;
153
154
bool
exceptionCaught;
155
LoopReference(QEventLoopPrivate *d, QMutexLocker<QMutex> &locker) : d(d), locker(locker), exceptionCaught(
true
)
156
{
157
d->inExec =
true
;
158
d->exit.storeRelease(
false
);
159
160
auto
threadData = d->threadData.loadRelaxed();
161
++threadData->loopLevel;
162
threadData->eventLoops.push(d->q_func());
163
164
locker.unlock();
165
}
166
167
~LoopReference()
168
{
169
if
(exceptionCaught) {
170
const
char
*type =
nullptr
;
171
#
if
__has_include
(
<
cxxabi
.
h
>
)
172
// Note: exception name will be mangled
173
if
(
const
std::type_info *ti = abi::__cxa_current_exception_type())
174
type = ti->name();
175
#
endif
176
qWarning(
"Qt has caught an exception thrown from an event handler. Throwing \n"
177
"exceptions from an event handler is not supported in Qt. \n"
178
"You must not let any exception whatsoever propagate through Qt code.%s%s"
,
179
type ?
"\nException was of type: "
:
""
, type ? type :
""
);
180
}
181
locker.relock();
182
auto
threadData = d->threadData.loadRelaxed();
183
QEventLoop *eventLoop = threadData->eventLoops.pop();
184
Q_ASSERT_X(eventLoop == d->q_func(),
"QEventLoop::exec()"
,
"internal error"
);
185
Q_UNUSED(eventLoop);
// --release warning
186
d->inExec =
false
;
187
--threadData->loopLevel;
188
}
189
};
190
LoopReference ref(d, locker);
191
192
// remove posted quit events when entering a new event loop
193
QCoreApplication *app = QCoreApplication::instance();
194
if
(app && app->thread() == thread())
195
QCoreApplication::removePostedEvents(app, QEvent::Quit);
196
197
while
(!d->exit.loadAcquire())
198
processEvents(flags | WaitForMoreEvents | EventLoopExec);
199
200
ref.exceptionCaught =
false
;
201
return
d->returnCode.loadRelaxed();
202
}
203
204
/*!
205
\overload
206
207
Process pending events that match \a flags for a maximum of \a
208
maxTime milliseconds, or until there are no more events to
209
process, whichever is shorter.
210
211
Equivalent to calling:
212
\code
213
processEvents(flags, QDeadlineTimer(maxTime));
214
\endcode
215
*/
216
void
QEventLoop::processEvents(ProcessEventsFlags flags,
int
maxTime)
217
{
218
processEvents(flags, QDeadlineTimer(maxTime));
219
}
220
221
/*!
222
\since 6.7
223
224
Process pending events that match \a flags until \a deadline has expired,
225
or until there are no more events to process, whichever happens first.
226
This function is especially useful if you have a long running
227
operation and want to show its progress without allowing user
228
input, i.e. by using the \l ExcludeUserInputEvents flag.
229
230
\b{Notes:}
231
\list
232
\li This function does not process events continuously; it
233
returns after all available events are processed.
234
\li Specifying the \l WaitForMoreEvents flag makes no sense
235
and will be ignored.
236
\endlist
237
*/
238
void
QEventLoop::processEvents(ProcessEventsFlags flags, QDeadlineTimer deadline)
239
{
240
Q_D(QEventLoop);
241
if
(!d->threadData.loadRelaxed()->hasEventDispatcher())
242
return
;
243
244
while
(processEvents(flags & ~WaitForMoreEvents)) {
245
if
(deadline.hasExpired())
246
break
;
247
}
248
}
249
250
/*!
251
Tells the event loop to exit with a return code.
252
253
After this function has been called, the event loop returns from
254
the call to exec(). The exec() function returns \a returnCode.
255
256
By convention, a \a returnCode of 0 means success, and any non-zero
257
value indicates an error.
258
259
Note that unlike the C library function of the same name, this
260
function \e does return to the caller -- it is event processing that
261
stops.
262
263
\sa QCoreApplication::quit(), quit(), exec()
264
*/
265
void
QEventLoop::exit(
int
returnCode)
266
{
267
Q_D(QEventLoop);
268
auto
threadData = d->threadData.loadAcquire();
269
if
(!threadData->hasEventDispatcher())
270
return
;
271
272
d->returnCode.storeRelaxed(returnCode);
273
d->exit.storeRelease(
true
);
274
threadData->eventDispatcher.loadRelaxed()->interrupt();
275
}
276
277
/*!
278
Returns \c true if the event loop is running; otherwise returns
279
false. The event loop is considered running from the time when
280
exec() is called until exit() is called.
281
282
\sa exec(), exit()
283
*/
284
bool
QEventLoop::isRunning()
const
285
{
286
Q_D(
const
QEventLoop);
287
return
!d->exit.loadAcquire();
288
}
289
290
/*!
291
Wakes up the event loop.
292
293
\sa QAbstractEventDispatcher::wakeUp()
294
*/
295
void
QEventLoop::wakeUp()
296
{
297
Q_D(QEventLoop);
298
auto
threadData = d->threadData.loadAcquire();
299
if
(!threadData->hasEventDispatcher())
300
return
;
301
threadData->eventDispatcher.loadRelaxed()->wakeUp();
302
}
303
304
305
/*!
306
\reimp
307
*/
308
bool
QEventLoop::event(QEvent *event)
309
{
310
if
(event->type() == QEvent::Quit) {
311
quit();
312
return
true
;
313
}
else
{
314
return
QObject::event(event);
315
}
316
}
317
318
/*!
319
Tells the event loop to exit normally.
320
321
Same as exit(0).
322
323
\sa QCoreApplication::quit(), exit()
324
*/
325
void
QEventLoop::quit()
326
{ exit(0); }
327
328
// If any of these trigger, the Type bits will interfere with the pointer values:
329
static_assert
(
alignof
(
QEventLoop
) >= 4);
330
static_assert
(
alignof
(QThread) >= 4);
331
static_assert
(
alignof
(
QCoreApplication
) >= 4);
332
333
/*!
334
\class QEventLoopLocker
335
\inmodule QtCore
336
\brief The QEventLoopLocker class provides a means to quit an event loop when it is no longer needed.
337
\since 5.0
338
339
The QEventLoopLocker operates on particular objects - either a QCoreApplication
340
instance, a QEventLoop instance or a QThread instance.
341
342
This makes it possible to, for example, run a batch of jobs with an event loop
343
and exit that event loop after the last job is finished. That is accomplished
344
by keeping a QEventLoopLocker with each job instance.
345
346
The variant which operates on QCoreApplication makes it possible to finish
347
asynchronously running jobs after the last gui window has been closed. This
348
can be useful for example for running a job which uploads data to a network.
349
350
\sa QEventLoop, QCoreApplication
351
*/
352
353
/*!
354
Creates an event locker operating on the QCoreApplication.
355
356
The application will attempt to quit when there are no more QEventLoopLockers
357
operating on it, as long as QCoreApplication::isQuitLockEnabled() is \c true.
358
359
Note that attempting a quit may not necessarily result in the application quitting,
360
if there for example are open windows, or the QEvent::Quit event is ignored.
361
362
\sa QCoreApplication::quit(), QCoreApplication::isQuitLockEnabled()
363
*/
364
QEventLoopLocker
::QEventLoopLocker()
noexcept
365
: QEventLoopLocker{QCoreApplication::instance(), Type::Application}
366
{
367
368
}
369
370
/*!
371
Creates an event locker operating on the \a loop.
372
373
This particular QEventLoop will quit when there are no more QEventLoopLockers operating on it.
374
375
\sa QEventLoop::quit()
376
*/
377
QEventLoopLocker
::QEventLoopLocker(QEventLoop *loop)
noexcept
378
:
QEventLoopLocker
{loop, Type::EventLoop}
379
{
380
381
}
382
383
/*!
384
Creates an event locker operating on the \a thread.
385
386
This particular QThread will quit when there are no more QEventLoopLockers operating on it.
387
388
\sa QThread::quit()
389
*/
390
QEventLoopLocker
::QEventLoopLocker(QThread *thread)
noexcept
391
:
QEventLoopLocker
{thread, Type::Thread}
392
{
393
394
}
395
396
/*!
397
\fn QEventLoopLocker::QEventLoopLocker(QEventLoopLocker &&other)
398
\since 6.7
399
400
Move-constructs an event-loop locker from \a other. \a other will have a
401
no-op destructor, while responsibility for preventing the
402
QEventLoop/QThread/QCoreApplication from quitting is transferred to the new
403
object.
404
*/
405
406
/*!
407
\fn QEventLoopLocker &QEventLoopLocker::operator=(QEventLoopLocker &&other)
408
\since 6.7
409
410
Move-assigns this event-loop locker from \a other. \a other will have a
411
no-op destructor, while responsibility for preventing the
412
QEventLoop/QThread/QCoreApplication from quitting is transferred to this
413
object.
414
*/
415
416
/*!
417
\fn QEventLoopLocker::swap(QEventLoopLocker &other)
418
\since 6.7
419
420
Swaps the object and the state of this QEventLoopLocker with \a other.
421
This operation is very fast and never fails.
422
*/
423
424
/*!
425
\fn QEventLoopLocker::swap(QEventLoopLocker &lhs, QEventLoopLocker &rhs)
426
\since 6.7
427
428
Swaps the object and the state of \a lhs with \a rhs.
429
This operation is very fast and never fails.
430
*/
431
432
/*!
433
Destroys this event loop locker object
434
*/
435
QEventLoopLocker
::~
QEventLoopLocker
()
436
{
437
visit([](
auto
p) { p->d_func()->deref(); });
438
}
439
440
/*!
441
\internal
442
*/
443
QEventLoopLocker
::QEventLoopLocker(
void
*ptr, Type t)
noexcept
444
: p{quintptr(ptr) | quintptr(t)}
445
{
446
visit([](
auto
p) { p->d_func()->ref(); });
447
}
448
449
/*!
450
\internal
451
*/
452
template
<
typename
Func>
453
void
QEventLoopLocker
::visit(Func f)
const
454
{
455
const
auto
ptr = pointer();
456
if
(!ptr)
457
return
;
458
switch
(type()) {
459
case
Type::EventLoop:
return
f(
static_cast
<QEventLoop *>(ptr));
460
case
Type::Thread:
return
f(
static_cast
<QThread *>(ptr));
461
case
Type::Application:
return
f(
static_cast
<QCoreApplication *>(ptr));
462
}
463
Q_UNREACHABLE();
464
}
465
466
QT_END_NAMESPACE
467
468
#
include
"moc_qeventloop.cpp"
QCoreApplication
\inmodule QtCore
Definition
qcoreapplication.h:45
QEventLoopLocker
\inmodule QtCore
Definition
qeventloop.h:60
QEventLoopLocker::~QEventLoopLocker
Q_CORE_EXPORT ~QEventLoopLocker()
Destroys this event loop locker object.
Definition
qeventloop.cpp:435
QEventLoop
\inmodule QtCore
Definition
qeventloop.h:17
__has_include
#define __has_include(x)
Definition
qcompilerdetection.h:459
qtbase
src
corelib
kernel
qeventloop.cpp
Generated on
for Qt by
1.18.0