QtBase  v6.3.1
qeventloop.cpp
Go to the documentation of this file.
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 
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 
52 
101 {
102  Q_D(QEventLoop);
104  qWarning("QEventLoop: Cannot be used without QApplication");
105  } else {
106  d->threadData.loadRelaxed()->ensureEventDispatcher();
107  }
108 }
109 
114 { }
115 
116 
130 bool QEventLoop::processEvents(ProcessEventsFlags flags)
131 {
132  Q_D(QEventLoop);
133  auto threadData = d->threadData.loadRelaxed();
134  if (!threadData->hasEventDispatcher())
135  return false;
136  return threadData->eventDispatcher.loadRelaxed()->processEvents(flags);
137 }
138 
162 int QEventLoop::exec(ProcessEventsFlags flags)
163 {
164  Q_D(QEventLoop);
165  auto threadData = d->threadData.loadRelaxed();
166 
167  //we need to protect from race condition with QThread::exit
168  QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(threadData->thread.loadAcquire()))->mutex);
169  if (threadData->quitNow)
170  return -1;
171 
172  if (d->inExec) {
173  qWarning("QEventLoop::exec: instance %p has already called exec()", this);
174  return -1;
175  }
176 
177  struct LoopReference {
179  QMutexLocker<QMutex> &locker;
180 
181  bool exceptionCaught;
182  LoopReference(QEventLoopPrivate *d, QMutexLocker<QMutex> &locker) : d(d), locker(locker), exceptionCaught(true)
183  {
184  d->inExec = true;
185  d->exit.storeRelease(false);
186 
187  auto threadData = d->threadData.loadRelaxed();
188  ++threadData->loopLevel;
189  threadData->eventLoops.push(d->q_func());
190 
191  locker.unlock();
192  }
193 
194  ~LoopReference()
195  {
196  if (exceptionCaught) {
197  qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
198  "exceptions from an event handler is not supported in Qt.\n"
199  "You must not let any exception whatsoever propagate through Qt code.");
200  }
201  locker.relock();
202  auto threadData = d->threadData.loadRelaxed();
203  QEventLoop *eventLoop = threadData->eventLoops.pop();
204  Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
205  Q_UNUSED(eventLoop); // --release warning
206  d->inExec = false;
207  --threadData->loopLevel;
208  }
209  };
210  LoopReference ref(d, locker);
211 
212  // remove posted quit events when entering a new event loop
214  if (app && app->thread() == thread())
216 
217  while (!d->exit.loadAcquire())
219 
220  ref.exceptionCaught = false;
221  return d->returnCode.loadRelaxed();
222 }
223 
240 void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
241 {
242  Q_D(QEventLoop);
243  if (!d->threadData.loadRelaxed()->hasEventDispatcher())
244  return;
245 
247  start.start();
249  if (start.elapsed() > maxTime)
250  break;
251  }
252 }
253 
269 void QEventLoop::exit(int returnCode)
270 {
271  Q_D(QEventLoop);
272  auto threadData = d->threadData.loadAcquire();
273  if (!threadData->hasEventDispatcher())
274  return;
275 
276  d->returnCode.storeRelaxed(returnCode);
277  d->exit.storeRelease(true);
278  threadData->eventDispatcher.loadRelaxed()->interrupt();
279 }
280 
289 {
290  Q_D(const QEventLoop);
291  return !d->exit.loadAcquire();
292 }
293 
300 {
301  Q_D(QEventLoop);
302  auto threadData = d->threadData.loadAcquire();
303  if (!threadData->hasEventDispatcher())
304  return;
305  threadData->eventDispatcher.loadRelaxed()->wakeUp();
306 }
307 
308 
313 {
314  if (event->type() == QEvent::Quit) {
315  quit();
316  return true;
317  } else {
318  return QObject::event(event);
319  }
320 }
321 
330 { exit(0); }
331 
332 
334 {
335 public:
337  : loop(loop), type(EventLoop)
338  {
339  loop->ref();
340  }
341 
343  : thread(thread), type(Thread)
344  {
345  thread->ref();
346  }
347 
349  : app(app), type(Application)
350  {
351  app->ref();
352  }
353 
355  {
356  switch (type)
357  {
358  case EventLoop:
359  loop->deref();
360  break;
361  case Thread:
362  thread->deref();
363  break;
364  default:
365  app->deref();
366  break;
367  }
368  }
369 
370 private:
371  union {
375  };
376  enum Type {
377  EventLoop,
378  Thread,
379  Application
380  };
381  const Type type;
382 };
383 
412  : d_ptr(new QEventLoopLockerPrivate(static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()))))
413 {
414 
415 }
416 
425  : d_ptr(new QEventLoopLockerPrivate(static_cast<QEventLoopPrivate*>(QObjectPrivate::get(loop))))
426 {
427 
428 }
429 
438  : d_ptr(new QEventLoopLockerPrivate(static_cast<QThreadPrivate*>(QObjectPrivate::get(thread))))
439 {
440 
441 }
442 
447 {
448  delete d_ptr;
449 }
450 
452 
453 #include "moc_qeventloop.cpp"
The QCoreApplication class provides an event loop for Qt applications without UI.
static QCoreApplication * instance()
static void removePostedEvents(QObject *receiver, int eventType=0)
static bool threadRequiresCoreApplication()
The QElapsedTimer class provides a fast way to calculate elapsed times.
Definition: qelapsedtimer.h:49
The QEvent class is the base class of all event classes. Event objects contain event parameters.
Definition: qcoreevent.h:58
@ Quit
Definition: qcoreevent.h:92
The QEventLoop class provides a means of entering and leaving an event loop.
Definition: qeventloop.h:50
int exec(ProcessEventsFlags flags=AllEvents)
Definition: qeventloop.cpp:162
@ EventLoopExec
Definition: qeventloop.h:64
@ WaitForMoreEvents
Definition: qeventloop.h:62
void exit(int returnCode=0)
Definition: qeventloop.cpp:269
bool isRunning() const
Definition: qeventloop.cpp:288
bool processEvents(ProcessEventsFlags flags=AllEvents)
Definition: qeventloop.cpp:130
bool event(QEvent *event) override
Definition: qeventloop.cpp:312
void wakeUp()
Definition: qeventloop.cpp:299
QEventLoop(QObject *parent=nullptr)
Definition: qeventloop.cpp:99
void quit()
Definition: qeventloop.cpp:329
QEventLoopLockerPrivate(QThreadPrivate *thread)
Definition: qeventloop.cpp:342
QThreadPrivate * thread
Definition: qeventloop.cpp:373
QEventLoopLockerPrivate(QCoreApplicationPrivate *app)
Definition: qeventloop.cpp:348
QEventLoopPrivate * loop
Definition: qeventloop.cpp:372
QCoreApplicationPrivate * app
Definition: qeventloop.cpp:374
QEventLoopLockerPrivate(QEventLoopPrivate *loop)
Definition: qeventloop.cpp:336
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes.
Definition: qmutex.h:317
void unlock() noexcept
Definition: qmutex.h:322
void relock() noexcept
Definition: qmutex.h:323
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
virtual bool event(QEvent *event)
Definition: qobject.cpp:1329
QThread * thread() const
Definition: qobject.cpp:1527
static QObjectPrivate * get(QObject *o)
Definition: qobject_p.h:368
void deref()
Definition: qthread_p.h:229
QMutex mutex
Definition: qthread_p.h:221
#define qWarning
Definition: qlogging.h:179
GLenum type
Definition: qopengl.h:270
GLbitfield flags
GLuint start
GLint ref
struct _cl_event * event
Definition: qopenglext.h:2998
#define Q_ASSERT_X(cond, x, msg)
Definition: qrandom.cpp:85
Q_UNUSED(salary)
[21]
QApplication app(argc, argv)
[0]
http get(QUrl::toPercentEncoding("/index.html"))
Definition: moc.h:48
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent