Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
64 : QObject(*new QEventLoopPrivate, parent)
65{
66 Q_D(QEventLoop);
68 qWarning("QEventLoop: Cannot be used without QApplication");
69 } else {
70 d->threadData.loadRelaxed()->ensureEventDispatcher();
71 }
72}
73
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 qCDebug(lcDeleteLater) << "Increased" << threadData->thread
155 << "loop level to" << threadData->loopLevel
156 << "with leaf loop now" << threadData->eventLoops.last();
157
158 locker.unlock();
159 }
160
161 ~LoopReference()
162 {
163 if (exceptionCaught) {
164 qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
165 "exceptions from an event handler is not supported in Qt.\n"
166 "You must not let any exception whatsoever propagate through Qt code.");
167 }
168 locker.relock();
169 auto threadData = d->threadData.loadRelaxed();
170 QEventLoop *eventLoop = threadData->eventLoops.pop();
171 Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
172 Q_UNUSED(eventLoop); // --release warning
173 d->inExec = false;
174 --threadData->loopLevel;
175
176 qCDebug(lcDeleteLater) << "Decreased" << threadData->thread
177 << "loop level to" << threadData->loopLevel
178 << "with leaf loop now" << (threadData->eventLoops.isEmpty()
179 ? nullptr : threadData->eventLoops.last());
180
181 }
182 };
183 LoopReference ref(d, locker);
184
185 // remove posted quit events when entering a new event loop
187 if (app && app->thread() == thread())
189
190 while (!d->exit.loadAcquire())
192
193 ref.exceptionCaught = false;
194 return d->returnCode.loadRelaxed();
195}
196
209void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
210{
212}
213
232{
233 Q_D(QEventLoop);
234 if (!d->threadData.loadRelaxed()->hasEventDispatcher())
235 return;
236
238 if (deadline.hasExpired())
239 break;
240 }
241}
242
258void QEventLoop::exit(int returnCode)
259{
260 Q_D(QEventLoop);
261 auto threadData = d->threadData.loadAcquire();
262 if (!threadData->hasEventDispatcher())
263 return;
264
265 d->returnCode.storeRelaxed(returnCode);
266 d->exit.storeRelease(true);
267 threadData->eventDispatcher.loadRelaxed()->interrupt();
268}
269
278{
279 Q_D(const QEventLoop);
280 return !d->exit.loadAcquire();
281}
282
289{
290 Q_D(QEventLoop);
291 auto threadData = d->threadData.loadAcquire();
292 if (!threadData->hasEventDispatcher())
293 return;
294 threadData->eventDispatcher.loadRelaxed()->wakeUp();
295}
296
297
302{
303 if (event->type() == QEvent::Quit) {
304 quit();
305 return true;
306 } else {
307 return QObject::event(event);
308 }
309}
310
319{ exit(0); }
320
321// If any of these trigger, the Type bits will interfere with the pointer values:
322static_assert(alignof(QEventLoop) >= 4);
323static_assert(alignof(QThread) >= 4);
324static_assert(alignof(QCoreApplication) >= 4);
325
358 : QEventLoopLocker{QCoreApplication::instance(), Type::Application}
359{
360
361}
362
371 : QEventLoopLocker{loop, Type::EventLoop}
372{
373
374}
375
384 : QEventLoopLocker{thread, Type::Thread}
385{
386
387}
388
429{
430 visit([](auto p) { p->d_func()->deref(); });
431}
432
437 : p{quintptr(ptr) | quintptr(t)}
438{
439 visit([](auto p) { p->d_func()->ref(); });
440}
441
445template <typename Func>
446void QEventLoopLocker::visit(Func f) const
447{
448 const auto ptr = pointer();
449 if (!ptr)
450 return;
451 switch (type()) {
452 case Type::EventLoop: return f(static_cast<QEventLoop *>(ptr));
453 case Type::Thread: return f(static_cast<QThread *>(ptr));
454 case Type::Application: return f(static_cast<QCoreApplication *>(ptr));
455 }
456 Q_UNREACHABLE();
457}
458
460
461#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:313
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
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:1389
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
auto visit(Fn &&fn, QIODevice *socket, Args &&...args)
Combined button and popup list for selecting options.
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
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:167
QDeadlineTimer deadline(30s)
QObject::connect nullptr
QApplication app(argc, argv)
[0]
Definition moc.h:23