Qt 6.x
The Qt SDK
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
4#include "qeventloop.h"
5
7#include "qcoreapplication.h"
9#include "qdeadlinetimer.h"
10
11#include "qobject_p.h"
12#include "qeventloop_p.h"
13#include <private/qthread_p.h>
14
16
65{
66 Q_D(QEventLoop);
68 qWarning("QEventLoop: Cannot be used without QApplication");
69 } else {
70 d->threadData.loadRelaxed()->ensureEventDispatcher();
71 }
72}
73
78{ }
79
80
94bool QEventLoop::processEvents(ProcessEventsFlags flags)
95{
96 Q_D(QEventLoop);
97 auto threadData = d->threadData.loadRelaxed();
98 if (!threadData->hasEventDispatcher())
99 return false;
100 return threadData->eventDispatcher.loadRelaxed()->processEvents(flags);
101}
102
126int QEventLoop::exec(ProcessEventsFlags flags)
127{
128 Q_D(QEventLoop);
129 auto threadData = d->threadData.loadRelaxed();
130
131 //we need to protect from race condition with QThread::exit
132 QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(threadData->thread.loadAcquire()))->mutex);
133 if (threadData->quitNow)
134 return -1;
135
136 if (d->inExec) {
137 qWarning("QEventLoop::exec: instance %p has already called exec()", this);
138 return -1;
139 }
140
141 struct LoopReference {
143 QMutexLocker<QMutex> &locker;
144
145 bool exceptionCaught;
146 LoopReference(QEventLoopPrivate *d, QMutexLocker<QMutex> &locker) : d(d), locker(locker), exceptionCaught(true)
147 {
148 d->inExec = true;
149 d->exit.storeRelease(false);
150
151 auto threadData = d->threadData.loadRelaxed();
152 ++threadData->loopLevel;
153 threadData->eventLoops.push(d->q_func());
154
155 locker.unlock();
156 }
157
158 ~LoopReference()
159 {
160 if (exceptionCaught) {
161 qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
162 "exceptions from an event handler is not supported in Qt.\n"
163 "You must not let any exception whatsoever propagate through Qt code.");
164 }
165 locker.relock();
166 auto threadData = d->threadData.loadRelaxed();
167 QEventLoop *eventLoop = threadData->eventLoops.pop();
168 Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
169 Q_UNUSED(eventLoop); // --release warning
170 d->inExec = false;
171 --threadData->loopLevel;
172 }
173 };
174 LoopReference ref(d, locker);
175
176 // remove posted quit events when entering a new event loop
178 if (app && app->thread() == thread())
180
181 while (!d->exit.loadAcquire())
183
184 ref.exceptionCaught = false;
185 return d->returnCode.loadRelaxed();
186}
187
200void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
201{
203}
204
223{
224 Q_D(QEventLoop);
225 if (!d->threadData.loadRelaxed()->hasEventDispatcher())
226 return;
227
229 if (deadline.hasExpired())
230 break;
231 }
232}
233
249void QEventLoop::exit(int returnCode)
250{
251 Q_D(QEventLoop);
252 auto threadData = d->threadData.loadAcquire();
253 if (!threadData->hasEventDispatcher())
254 return;
255
256 d->returnCode.storeRelaxed(returnCode);
257 d->exit.storeRelease(true);
258 threadData->eventDispatcher.loadRelaxed()->interrupt();
259}
260
269{
270 Q_D(const QEventLoop);
271 return !d->exit.loadAcquire();
272}
273
280{
281 Q_D(QEventLoop);
282 auto threadData = d->threadData.loadAcquire();
283 if (!threadData->hasEventDispatcher())
284 return;
285 threadData->eventDispatcher.loadRelaxed()->wakeUp();
286}
287
288
293{
294 if (event->type() == QEvent::Quit) {
295 quit();
296 return true;
297 } else {
298 return QObject::event(event);
299 }
300}
301
310{ exit(0); }
311
312// If any of these trigger, the Type bits will interfere with the pointer values:
313static_assert(alignof(QEventLoop) >= 4);
314static_assert(alignof(QThread) >= 4);
315static_assert(alignof(QCoreApplication) >= 4);
316
345 : QEventLoopLocker{QCoreApplication::instance(), Type::Application}
346{
347
348}
349
358 : QEventLoopLocker{loop, Type::EventLoop}
359{
360
361}
362
371 : QEventLoopLocker{thread, Type::Thread}
372{
373
374}
375
417{
418 visit([](auto p) { p->d_func()->deref(); });
419}
420
425 : p{quintptr(ptr) | quintptr(t)}
426{
427 visit([](auto p) { p->d_func()->ref(); });
428}
429
433template <typename Func>
434void QEventLoopLocker::visit(Func f) const
435{
436 const auto ptr = pointer();
437 if (!ptr)
438 return;
439 switch (type()) {
440 case Type::EventLoop: return f(static_cast<QEventLoop *>(ptr));
441 case Type::Thread: return f(static_cast<QThread *>(ptr));
442 case Type::Application: return f(static_cast<QCoreApplication *>(ptr));
443 }
444 Q_UNREACHABLE();
445}
446
448
449#include "moc_qeventloop.cpp"
static bool threadRequiresCoreApplication()
\inmodule QtCore
static void removePostedEvents(QObject *receiver, int eventType=0)
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
\inmodule QtCore
bool hasExpired() const noexcept
Returns true if this QDeadlineTimer object has expired, false if there remains time left.
\inmodule QtCore
Definition qeventloop.h:59
Q_NODISCARD_CTOR Q_CORE_EXPORT QEventLoopLocker() noexcept
Creates an event locker operating on the QCoreApplication.
Q_CORE_EXPORT ~QEventLoopLocker()
Destroys this event loop locker object.
\inmodule QtCore
Definition qeventloop.h:16
int exec(ProcessEventsFlags flags=AllEvents)
Enters the main event loop and waits until exit() is called.
~QEventLoop()
Destroys the event loop object.
@ WaitForMoreEvents
Definition qeventloop.h:29
void exit(int returnCode=0)
Tells the event loop to exit with a return code.
bool isRunning() const
Returns true if the event loop is running; otherwise returns false.
bool processEvents(ProcessEventsFlags flags=AllEvents)
Processes some pending events that match flags.
bool event(QEvent *event) override
\reimp
void wakeUp()
Wakes up the event loop.
QEventLoop(QObject *parent=nullptr)
Constructs an event loop object with the given parent.
void quit()
Tells the event loop to exit normally.
\inmodule QtCore
Definition qcoreevent.h:45
\inmodule QtCore
Definition qmutex.h:317
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:323
void relock() noexcept
Relocks an unlocked mutex locker.
Definition qmutex.h:324
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1363
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1561
Combined button and popup list for selecting options.
#define qWarning
Definition qlogging.h:162
static ControlElement< T > * ptr(QWidget *widget)
GLfloat GLfloat f
GLenum type
GLbitfield flags
GLint ref
struct _cl_event * event
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const void * pointer
Definition qopenglext.h:384
GLfloat GLfloat p
[1]
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define Q_UNUSED(x)
size_t quintptr
Definition qtypes.h:72
QDeadlineTimer deadline(30s)
QApplication app(argc, argv)
[0]
Definition moc.h:24
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent