Qt 4.8
qeventdispatcher_glib.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 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 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 
44 
45 #include <private/qmutexpool_p.h>
46 #include <private/qthread_p.h>
47 
48 #include "qcoreapplication.h"
49 #include "qsocketnotifier.h"
50 
51 #include <QtCore/qhash.h>
52 #include <QtCore/qlist.h>
53 #include <QtCore/qpair.h>
54 
55 #include <glib.h>
56 
58 
60 {
61  GPollFD pollfd;
63 };
64 
66 {
67  GSource source;
69 };
70 
71 static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout)
72 {
73  if (timeout)
74  *timeout = -1;
75  return false;
76 }
77 
78 static gboolean socketNotifierSourceCheck(GSource *source)
79 {
80  GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source);
81 
82  bool pending = false;
83  for (int i = 0; !pending && i < src->pollfds.count(); ++i) {
85 
86  if (p->pollfd.revents & G_IO_NVAL) {
87  // disable the invalid socket notifier
88  static const char *t[] = { "Read", "Write", "Exception" };
89  qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...",
90  p->pollfd.fd, t[int(p->socketNotifier->type())]);
91  // ### note, modifies src->pollfds!
92  p->socketNotifier->setEnabled(false);
93  }
94 
95  pending = ((p->pollfd.revents & p->pollfd.events) != 0);
96  }
97 
98  return pending;
99 }
100 
101 static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFunc, gpointer)
102 {
104 
105  GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source);
106  for (int i = 0; i < src->pollfds.count(); ++i) {
108 
109  if ((p->pollfd.revents & p->pollfd.events) != 0)
111  }
112 
113  return true; // ??? don't remove, right?
114 }
115 
116 static GSourceFuncs socketNotifierSourceFuncs = {
120  NULL,
121  NULL,
122  NULL
123 };
124 
126 {
127  GSource source;
129  QEventLoop::ProcessEventsFlags processEventsFlags;
131 };
132 
133 static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout)
134 {
135  timeval tv = { 0l, 0l };
137  *timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
138  else
139  *timeout = -1;
140 
141  return (*timeout == 0);
142 }
143 
145 {
146  if (src->timerList.isEmpty()
148  return false;
149 
150  if (src->timerList.updateCurrentTime() < src->timerList.first()->timeout)
151  return false;
152 
153  return true;
154 }
155 
156 static gboolean timerSourcePrepare(GSource *source, gint *timeout)
157 {
158  gint dummy;
159  if (!timeout)
160  timeout = &dummy;
161 
162  GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
163  if (src->runWithIdlePriority) {
164  if (timeout)
165  *timeout = -1;
166  return false;
167  }
168 
169  return timerSourcePrepareHelper(src, timeout);
170 }
171 
172 static gboolean timerSourceCheck(GSource *source)
173 {
174  GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
175  if (src->runWithIdlePriority)
176  return false;
177  return timerSourceCheckHelper(src);
178 }
179 
180 static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer)
181 {
182  GTimerSource *timerSource = reinterpret_cast<GTimerSource *>(source);
184  return true;
185  timerSource->runWithIdlePriority = true;
186  (void) timerSource->timerList.activateTimers();
187  return true; // ??? don't remove, right again?
188 }
189 
190 static GSourceFuncs timerSourceFuncs = {
194  NULL,
195  NULL,
196  NULL
197 };
198 
200 {
201  GSource source;
203 };
204 
205 static gboolean idleTimerSourcePrepare(GSource *source, gint *timeout)
206 {
207  GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
208  GTimerSource *timerSource = idleTimerSource->timerSource;
209  if (!timerSource->runWithIdlePriority) {
210  // Yield to the normal priority timer source
211  if (timeout)
212  *timeout = -1;
213  return false;
214  }
215 
216  return timerSourcePrepareHelper(timerSource, timeout);
217 }
218 
219 static gboolean idleTimerSourceCheck(GSource *source)
220 {
221  GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
222  GTimerSource *timerSource = idleTimerSource->timerSource;
223  if (!timerSource->runWithIdlePriority) {
224  // Yield to the normal priority timer source
225  return false;
226  }
227  return timerSourceCheckHelper(timerSource);
228 }
229 
230 static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gpointer)
231 {
232  GTimerSource *timerSource = reinterpret_cast<GIdleTimerSource *>(source)->timerSource;
233  (void) timerSourceDispatch(&timerSource->source, 0, 0);
234  return true;
235 }
236 
237 static GSourceFuncs idleTimerSourceFuncs = {
241  NULL,
242  NULL,
243  NULL
244 };
245 
247 {
248  GSource source;
252 };
253 
254 static gboolean postEventSourcePrepare(GSource *s, gint *timeout)
255 {
257  if (!data)
258  return false;
259 
260  gint dummy;
261  if (!timeout)
262  timeout = &dummy;
263  const bool canWait = data->canWaitLocked();
264  *timeout = canWait ? -1 : 0;
265 
266  GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
267  return (!canWait
268  || (source->serialNumber != source->lastSerialNumber));
269 }
270 
271 static gboolean postEventSourceCheck(GSource *source)
272 {
273  return postEventSourcePrepare(source, 0);
274 }
275 
276 static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer)
277 {
278  GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
279  source->lastSerialNumber = source->serialNumber;
282  return true; // i dunno, george...
283 }
284 
285 static GSourceFuncs postEventSourceFuncs = {
289  NULL,
290  NULL,
291  NULL
292 };
293 
294 
296  : mainContext(context)
297 {
298  if (qgetenv("QT_NO_THREADED_GLIB").isEmpty()) {
299  static int dummyValue = 0; // only used for its address
300  QMutexLocker locker(QMutexPool::instance()->get(&dummyValue));
301  if (!g_thread_supported())
302  g_thread_init(NULL);
303  }
304 
305  if (mainContext) {
306  g_main_context_ref(mainContext);
307  } else {
309  if (app && QThread::currentThread() == app->thread()) {
310  mainContext = g_main_context_default();
311  g_main_context_ref(mainContext);
312  } else {
313  mainContext = g_main_context_new();
314  }
315  }
316 
317 #if GLIB_CHECK_VERSION (2, 22, 0)
318  g_main_context_push_thread_default (mainContext);
319 #endif
320 
321  // setup post event source
322  postEventSource = reinterpret_cast<GPostEventSource *>(g_source_new(&postEventSourceFuncs,
323  sizeof(GPostEventSource)));
325  postEventSource->d = this;
326  g_source_set_can_recurse(&postEventSource->source, true);
327  g_source_attach(&postEventSource->source, mainContext);
328 
329  // setup socketNotifierSource
331  reinterpret_cast<GSocketNotifierSource *>(g_source_new(&socketNotifierSourceFuncs,
332  sizeof(GSocketNotifierSource)));
334  g_source_set_can_recurse(&socketNotifierSource->source, true);
335  g_source_attach(&socketNotifierSource->source, mainContext);
336 
337  // setup normal and idle timer sources
338  timerSource = reinterpret_cast<GTimerSource *>(g_source_new(&timerSourceFuncs,
339  sizeof(GTimerSource)));
340  (void) new (&timerSource->timerList) QTimerInfoList();
343  g_source_set_can_recurse(&timerSource->source, true);
344  g_source_attach(&timerSource->source, mainContext);
345 
346  idleTimerSource = reinterpret_cast<GIdleTimerSource *>(g_source_new(&idleTimerSourceFuncs,
347  sizeof(GIdleTimerSource)));
349  g_source_set_can_recurse(&idleTimerSource->source, true);
350  g_source_set_priority(&idleTimerSource->source, G_PRIORITY_DEFAULT_IDLE);
351  g_source_attach(&idleTimerSource->source, mainContext);
352 }
353 
355 {
357 }
358 
361 {
362 }
363 
365  : QAbstractEventDispatcher(*(new QEventDispatcherGlibPrivate(mainContext)), parent)
366 { }
367 
369 {
371 
372  // destroy all timer sources
373  qDeleteAll(d->timerSource->timerList);
374  d->timerSource->timerList.~QTimerInfoList();
375  g_source_destroy(&d->timerSource->source);
376  g_source_unref(&d->timerSource->source);
377  d->timerSource = 0;
378  g_source_destroy(&d->idleTimerSource->source);
379  g_source_unref(&d->idleTimerSource->source);
380  d->idleTimerSource = 0;
381 
382  // destroy socket notifier source
383  for (int i = 0; i < d->socketNotifierSource->pollfds.count(); ++i) {
384  GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds[i];
385  g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd);
386  delete p;
387  }
388  d->socketNotifierSource->pollfds.~QList<GPollFDWithQSocketNotifier *>();
389  g_source_destroy(&d->socketNotifierSource->source);
390  g_source_unref(&d->socketNotifierSource->source);
391  d->socketNotifierSource = 0;
392 
393  // destroy post event source
394  g_source_destroy(&d->postEventSource->source);
395  g_source_unref(&d->postEventSource->source);
396  d->postEventSource = 0;
397 
398  Q_ASSERT(d->mainContext != 0);
399 #if GLIB_CHECK_VERSION (2, 22, 0)
400  g_main_context_pop_thread_default (d->mainContext);
401 #endif
402  g_main_context_unref(d->mainContext);
403  d->mainContext = 0;
404 }
405 
406 bool QEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags)
407 {
409 
410  const bool canWait = (flags & QEventLoop::WaitForMoreEvents);
411  if (canWait)
412  emit aboutToBlock();
413  else
414  emit awake();
415 
416  // tell postEventSourcePrepare() and timerSource about any new flags
417  QEventLoop::ProcessEventsFlags savedFlags = d->timerSource->processEventsFlags;
418  d->timerSource->processEventsFlags = flags;
419 
420  if (!(flags & QEventLoop::EventLoopExec)) {
421  // force timers to be sent at normal priority
422  d->timerSource->runWithIdlePriority = false;
423  }
424 
425  bool result = g_main_context_iteration(d->mainContext, canWait);
426  while (!result && canWait)
427  result = g_main_context_iteration(d->mainContext, canWait);
428 
429  d->timerSource->processEventsFlags = savedFlags;
430 
431  if (canWait)
432  emit awake();
433 
434  return result;
435 }
436 
438 {
440  return g_main_context_pending(d->mainContext);
441 }
442 
444 {
445  Q_ASSERT(notifier);
446  int sockfd = notifier->socket();
447  int type = notifier->type();
448 #ifndef QT_NO_DEBUG
449  if (sockfd < 0) {
450  qWarning("QSocketNotifier: Internal error");
451  return;
452  } else if (notifier->thread() != thread()
453  || thread() != QThread::currentThread()) {
454  qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
455  return;
456  }
457 #endif
458 
460 
461 
463  p->pollfd.fd = sockfd;
464  switch (type) {
466  p->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
467  break;
469  p->pollfd.events = G_IO_OUT | G_IO_ERR;
470  break;
472  p->pollfd.events = G_IO_PRI | G_IO_ERR;
473  break;
474  }
475  p->socketNotifier = notifier;
476 
477  d->socketNotifierSource->pollfds.append(p);
478 
479  g_source_add_poll(&d->socketNotifierSource->source, &p->pollfd);
480 }
481 
483 {
484  Q_ASSERT(notifier);
485 #ifndef QT_NO_DEBUG
486  int sockfd = notifier->socket();
487  if (sockfd < 0) {
488  qWarning("QSocketNotifier: Internal error");
489  return;
490  } else if (notifier->thread() != thread()
491  || thread() != QThread::currentThread()) {
492  qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
493  return;
494  }
495 #endif
496 
498 
499  for (int i = 0; i < d->socketNotifierSource->pollfds.count(); ++i) {
500  GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds.at(i);
501  if (p->socketNotifier == notifier) {
502  // found it
503  g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd);
504 
505  d->socketNotifierSource->pollfds.removeAt(i);
506  delete p;
507 
508  return;
509  }
510  }
511 }
512 
513 void QEventDispatcherGlib::registerTimer(int timerId, int interval, QObject *object)
514 {
515 #ifndef QT_NO_DEBUG
516  if (timerId < 1 || interval < 0 || !object) {
517  qWarning("QEventDispatcherGlib::registerTimer: invalid arguments");
518  return;
519  } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
520  qWarning("QObject::startTimer: timers cannot be started from another thread");
521  return;
522  }
523 #endif
524 
526  d->timerSource->timerList.registerTimer(timerId, interval, object);
527 }
528 
530 {
531 #ifndef QT_NO_DEBUG
532  if (timerId < 1) {
533  qWarning("QEventDispatcherGlib::unregisterTimer: invalid argument");
534  return false;
535  } else if (thread() != QThread::currentThread()) {
536  qWarning("QObject::killTimer: timers cannot be stopped from another thread");
537  return false;
538  }
539 #endif
540 
542  return d->timerSource->timerList.unregisterTimer(timerId);
543 }
544 
546 {
547 #ifndef QT_NO_DEBUG
548  if (!object) {
549  qWarning("QEventDispatcherGlib::unregisterTimers: invalid argument");
550  return false;
551  } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
552  qWarning("QObject::killTimers: timers cannot be stopped from another thread");
553  return false;
554  }
555 #endif
556 
558  return d->timerSource->timerList.unregisterTimers(object);
559 }
560 
562 {
563  if (!object) {
564  qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument");
565  return QList<TimerInfo>();
566  }
567 
568  Q_D(const QEventDispatcherGlib);
569  return d->timerSource->timerList.registeredTimers(object);
570 }
571 
573 {
574  wakeUp();
575 }
576 
578 {
580  d->postEventSource->serialNumber.ref();
581  g_main_context_wakeup(d->mainContext);
582 }
583 
585 {
586 }
587 
589 {
590 #if !defined(GLIB_MAJOR_VERSION) || !defined(GLIB_MINOR_VERSION) || !defined(GLIB_MICRO_VERSION)
591  return false;
592 #else
593  return ((GLIB_MAJOR_VERSION << 16) + (GLIB_MINOR_VERSION << 8) + GLIB_MICRO_VERSION) >= 0x020301;
594 #endif
595 }
596 
598  : QAbstractEventDispatcher(dd, parent)
599 {
600 }
601 
bool canWaitLocked()
Definition: qthread_p.h:226
double d
Definition: qnumeric_p.h:62
static gboolean timerSourceCheckHelper(GTimerSource *src)
void unregisterSocketNotifier(QSocketNotifier *socketNotifier)
Unregisters notifier from the event dispatcher.
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
QEventLoop::ProcessEventsFlags processEventsFlags
int type
Definition: qmetatype.cpp:239
static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
EventRef event
static gboolean postEventSourcePrepare(GSource *s, gint *timeout)
void wakeUp()
Wakes up the event loop.
The QAtomicInt class provides platform-independent atomic operations on integers. ...
Definition: qatomic.h:55
static GSourceFuncs postEventSourceFuncs
static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gpointer)
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout)
static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFunc, gpointer)
static gboolean postEventSourceCheck(GSource *source)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
static gboolean socketNotifierSourceCheck(GSource *source)
#define Q_D(Class)
Definition: qglobal.h:2482
Type type() const
Returns the socket event type specified to the constructor.
QEventDispatcherGlibPrivate * d
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
The QSocketNotifier class provides support for monitoring activity on a file descriptor.
static GSourceFuncs socketNotifierSourceFuncs
bool hasPendingEvents()
Returns true if there is an event waiting; otherwise returns false.
static QThread * currentThread()
Returns a pointer to a QThread which manages the currently executing thread.
Definition: qthread.cpp:419
void flush()
Flushes the event queue.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void awake()
This signal is emitted after the event loop returns from a function that could block.
static bool isEmpty(const char *str)
static GSourceFuncs timerSourceFuncs
QEventDispatcherGlibPrivate(GMainContext *context=0)
static gboolean idleTimerSourceCheck(GSource *source)
void interrupt()
Interrupts event dispatching; i.
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
static QMutexPool * instance()
Returns the global QMutexPool instance.
Definition: qmutexpool.cpp:124
Q_CORE_EXPORT void qWarning(const char *,...)
static const char * data(const QByteArray &arr)
static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer)
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static void sendPostedEvents()
static GSourceFuncs idleTimerSourceFuncs
static gboolean idleTimerSourcePrepare(GSource *source, gint *timeout)
QList< GPollFDWithQSocketNotifier * > pollfds
T & first()
Returns a reference to the first item in the list.
Definition: qlist.h:282
The QCoreApplication class provides an event loop for console Qt applications.
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes...
Definition: qmutex.h:101
void aboutToBlock()
This signal is emitted before the event loop calls a function that could block.
QTimerInfoList timerList
void registerTimer(int timerId, int interval, QObject *object)
Register a timer with the specified timerId and interval for the given object.
static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout)
static QCoreApplication * instance()
Returns a pointer to the application&#39;s QCoreApplication (or QApplication) instance.
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
void setEnabled(bool)
If enable is true, the notifier is enabled; otherwise the notifier is disabled.
QFactoryLoader * l
static gboolean timerSourceCheck(GSource *source)
static QThreadData * current()
void registerSocketNotifier(QSocketNotifier *socketNotifier)
Registers notifier with the event loop.
QObject * parent
Definition: qobject.h:92
bool unregisterTimers(QObject *object)
Unregisters all the timers associated with the given object.
QEventDispatcherGlib(QObject *parent=0)
bool timerWait(timeval &)
struct _GMainContext GMainContext
QThread * thread() const
Returns the thread in which the object lives.
Definition: qobject.cpp:1419
static gboolean timerSourcePrepare(GSource *source, gint *timeout)
QList< TimerInfo > registeredTimers(QObject *object) const
Returns a list of registered timers for object.
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end)
Definition: qalgorithms.h:319
The QAbstractEventDispatcher class provides an interface to manage Qt&#39;s event queue.
bool processEvents(QEventLoop::ProcessEventsFlags flags)
Processes pending events that match flags until there are no more events to process.
int socket() const
Returns the socket identifier specified to the constructor.
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
bool unregisterTimer(int timerId)
Unregisters the timer with the given timerId.
GSocketNotifierSource * socketNotifierSource