Qt 4.8
qeventdispatcher_qpa.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui 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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qplatformdefs.h"
43 #include "qapplication.h"
44 #include "qeventdispatcher_qpa_p.h"
45 #include "private/qeventdispatcher_unix_p.h"
46 #include "qapplication_p.h"
48 
49 #include <QWindowSystemInterface>
50 #include <QtCore/QElapsedTimer>
51 #include <QtCore/QAtomicInt>
52 #include <QtCore/QSemaphore>
53 
54 #include <QtCore/QDebug>
55 
56 #include <errno.h>
57 #include <limits.h>
58 
60 
62 
64 {
65 public:
66  void checkpoint()
67  {
68  if (state.testAndSetOrdered(0,1)) {
70  } else if (state.testAndSetAcquire(1,0)) {
72  } else {
73  qWarning("Barrier internal error");
74  }
75  }
76 private:
79 };
80 
81 class SelectWorker : public QThread
82 {
83 public:
84  SelectWorker(QEventDispatcherQPAPrivate *eventDispatcherPrivate)
85  : QThread(),
86  m_edPrivate(eventDispatcherPrivate),
87  m_retVal(0)
88  {
89  }
90 
91  void setSelectValues(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
92  {
93  m_nfds = nfds;
94  m_readfds = readfds;
95  m_writefds = writefds;
96  m_exceptfds = exceptfds;
97 
98 
99  }
100 
101  int retVal() const {
102  return m_retVal;
103  }
104 
105 protected:
106  void run();
107 
108 private:
110  int m_retVal;
111 
112  int m_nfds;
113  fd_set *m_readfds, *m_writefds, *m_exceptfds;
114 };
115 
117 {
119 public:
121  : eventLoopIntegration(0),
122  barrierBeforeBlocking(0),
123  barrierReturnValue(0),
124  selectReturnMutex(0),
125  selectWorkerNeedsSync(true),
126  selectWorkerHasResult(false),
127  selectWorker(0),
128  m_integrationInitialised(false),
129  m_hasIntegration(false),
130  m_isEventLoopIntegrationRunning(false)
131  {
132 
133  }
134 
136  {
137  delete selectWorker;
138  delete eventLoopIntegration;
139  delete barrierBeforeBlocking;
140  delete barrierReturnValue;
141  delete selectReturnMutex;
142  }
143 
144  bool hasIntegration() const
145  {
146  if (!m_integrationInitialised) {
147  QEventDispatcherQPAPrivate *that = const_cast<QEventDispatcherQPAPrivate *>(this);
148  if (qApp && (qApp->thread() == QThread::currentThread())) { // guiThread
149  if (QApplicationPrivate::platformIntegration()) {
150  that->eventLoopIntegration = QApplicationPrivate::platformIntegration()->createEventLoopIntegration();
151  if (that->eventLoopIntegration) {
152  that->selectWorker = new SelectWorker(that);
153  that->barrierBeforeBlocking = new Rendezvous;
154  that->barrierReturnValue = new Rendezvous;
155  that->selectReturnMutex = new QMutex;
156  that->selectWorker->start();
157  that->m_hasIntegration = true;
159  qWarning("Having eventloop integration without monotonic timers can lead to undefined behaviour");
160  }
161  }
162  }
163  that->m_integrationInitialised = true;
164  }
165  return m_hasIntegration;
166  }
167 
169  {
170  return m_isEventLoopIntegrationRunning;
171  }
172 
174  {
175  if (qApp && (qApp->thread() == QThread::currentThread())) {
176  m_isEventLoopIntegrationRunning = true;
177  eventLoopIntegration->startEventLoop();
178  }
179  }
180 
184 
188 
190 private:
194 };
195 
198 { }
199 
201 { }
202 
203 bool QEventDispatcherQPA::processEvents(QEventLoop::ProcessEventsFlags flags)
204 {
206 
207  if (d->hasIntegration()) {
208  if (!d->isEventLoopIntegrationRunning()) {
209  d->runEventLoopIntegration();
210  }
211  if (d->threadData->quitNow) {
212  d->eventLoopIntegration->quitEventLoop();
213  return false;
214  }
215  }
216 
217  int nevents = 0;
218 
219  // handle gui and posted events
220  d->interrupt = false;
222 
223  while (!d->interrupt) { // also flushes output buffer ###can be optimized
227  // process a pending user input event
229  if (!event)
230  break;
231  } else {
232  break;
233  }
234 
235  if (filterEvent(event)) {
236  delete event;
237  continue;
238  }
239  nevents++;
240 
241  QApplicationPrivate::processWindowSystemEvent(event);
242  delete event;
243  }
244 
245  if (!d->interrupt) {
247  return true;
248  }
249 
250  return (nevents > 0);
251 }
252 
254 {
255  extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
257 }
258 
260 {
263  if (d->hasIntegration())
264  wakeUp();
265 
266 }
267 
269 {
272  if (d->hasIntegration())
273  wakeUp();
274 }
275 
277 {
278  if(qApp)
279  qApp->sendPostedEvents();
280 }
281 
282 int QEventDispatcherQPA::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
283  timeval *timeout)
284 {
286  int retVal = 0;
287  if (d->hasIntegration()) {
288  qint64 timeoutmsec = LONG_MAX; // wait if we don't have timers
289  if (timeout)
290  timeoutmsec = timeout->tv_sec * 1000 + (timeout->tv_usec/1000);
291  d->selectReturnMutex->lock();
292  if (d->selectWorkerNeedsSync) {
293  if (d->selectWorkerHasResult) {
294  retVal = d->selectWorker->retVal();
295  d->selectWorkerHasResult = false;
296 
297  d->selectReturnMutex->unlock();
298  d->barrierReturnValue->checkpoint();
299  d->eventLoopIntegration->setNextTimerEvent(0);
300  return retVal;
301  } else {
302  d->selectWorkerNeedsSync = false;
303  d->selectWorker->setSelectValues(nfds,readfds, writefds, exceptfds);
304  d->barrierBeforeBlocking->checkpoint();
305  }
306  }
307  d->selectReturnMutex->unlock();
308  d->eventLoopIntegration->setNextTimerEvent(timeoutmsec);
309  retVal = 0; //is 0 if select has not returned
310  } else {
311  retVal = QEventDispatcherUNIX::select(nfds, readfds, writefds, exceptfds, timeout);
312  }
313  return retVal;
314 }
315 
316 
318 {
319 
320  while(true) {
321  m_retVal = 0;
322  m_edPrivate->barrierBeforeBlocking->checkpoint(); // wait for mainthread
323  int tmpRet = qt_safe_select(m_nfds,m_readfds,m_writefds,m_exceptfds,0);
324  m_edPrivate->selectReturnMutex->lock();
325  m_edPrivate->eventLoopIntegration->qtNeedsToProcessEvents();
326 
327  m_edPrivate->selectWorkerNeedsSync = true;
328  m_edPrivate->selectWorkerHasResult = true;
329  m_retVal = tmpRet;
330 
331  m_edPrivate->selectReturnMutex->unlock();
332  m_edPrivate->barrierReturnValue->checkpoint();
333  }
334 }
double d
Definition: qnumeric_p.h:62
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timeval *timeout)
QEventDispatcherQPA(QObject *parent=0)
bool filterEvent(void *message)
Sends message through the event filter that was set by setEventFilter().
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
The QSemaphore class provides a general counting semaphore.
Definition: qsemaphore.h:57
The QMutex class provides access serialization between threads.
Definition: qmutex.h:60
The QAtomicInt class provides platform-independent atomic operations on integers. ...
Definition: qatomic.h:55
bool testAndSetAcquire(int expectedValue, int newValue)
Atomic test-and-set.
QEventDispatcherQPAPrivate * m_edPrivate
void unregisterSocketNotifier(QSocketNotifier *notifier)
Unregisters notifier from the event dispatcher.
void release(int n=1)
Releases n resources guarded by the semaphore.
Definition: qsemaphore.cpp:161
void registerSocketNotifier(QSocketNotifier *notifier)
Registers notifier with the event loop.
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
virtual bool event(QEvent *)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition: qobject.cpp:1200
#define Q_D(Class)
Definition: qglobal.h:2482
static bool isMonotonic()
Returns true if this is a monotonic clock, false otherwise.
The QSocketNotifier class provides support for monitoring activity on a file descriptor.
void registerSocketNotifier(QSocketNotifier *notifier)
Registers notifier with the event loop.
static QThread * currentThread()
Returns a pointer to a QThread which manages the currently executing thread.
Definition: qthread.cpp:419
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
#define qApp
Q_CORE_EXPORT void qWarning(const char *,...)
unsigned int uint
Definition: qglobal.h:996
bool processEvents(QEventLoop::ProcessEventsFlags flags)
Processes pending events that match flags until there are no more events to process.
bool hasPendingEvents()
Returns true if there is an event waiting; otherwise returns false.
static void sendPostedEvents()
__int64 qint64
Definition: qglobal.h:942
Q_CORE_EXPORT uint qGlobalPostedEventsCount()
void wakeUp()
Wakes up the event loop.
void acquire(int n=1)
Tries to acquire n resources guarded by the semaphore.
Definition: qsemaphore.cpp:142
void flush()
Flushes the event queue.
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
static WindowSystemEvent * getWindowSystemEvent()
int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, const struct timeval *orig_timeout)
Definition: qcore_unix.cpp:73
void start(Priority=InheritPriority)
Begins execution of the thread by calling run().
void run()
The starting point for the thread.
bool processEvents(QEventLoop::ProcessEventsFlags flags)
Processes pending events that match flags until there are no more events to process.
virtual int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timeval *timeout)
#define QT_USE_NAMESPACE
This macro expands to using QT_NAMESPACE if QT_NAMESPACE is defined and nothing otherwise.
Definition: qglobal.h:88
QFuture< T > run(Function function,...)
void setSelectValues(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
QPlatformEventLoopIntegration * eventLoopIntegration
The QThread class provides a platform-independent way to manage threads.
Definition: qthread.h:59
void unregisterSocketNotifier(QSocketNotifier *notifier)
Unregisters notifier from the event dispatcher.
bool testAndSetOrdered(int expectedValue, int newValue)
Atomic test-and-set.
SelectWorker(QEventDispatcherQPAPrivate *eventDispatcherPrivate)
QSemaphore semaphore