Qt 4.8
qabstracteventdispatcher.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 "qthread.h"
46 #include <private/qthread_p.h>
47 #include <private/qcoreapplication_p.h>
48 
50 
51 // we allow for 2^24 = 8^8 = 16777216 simultaneously running timers
52 static const int TimerIdMask = 0x00ffffff;
53 static const int TimerSerialMask = ~TimerIdMask & ~0x80000000;
54 static const int TimerSerialCounter = TimerIdMask + 1;
55 static const int MaxTimerId = TimerIdMask;
56 
57 static int FirstBucket[] = {
58  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
59  17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
60 };
61 
62 enum {
64  SecondBucketOffset = sizeof(FirstBucket) / sizeof(FirstBucket[0]),
67  FifthBucketOffset = 0x10000,
68  SixthBucketOffset = 0x100000
69 };
70 
71 enum {
78 };
79 
80 static const int BucketSize[] = {
83 };
84 enum { NumberOfBuckets = sizeof(BucketSize) / sizeof(BucketSize[0]) };
85 
86 static const int BucketOffset[] = {
88  FourthBucketOffset, FifthBucketOffset, SixthBucketOffset
89 };
90 
98 
100 {
101  // start at one, the first bucket is pre-allocated
102  for (int i = 1; i < NumberOfBuckets; ++i)
103  delete [] static_cast<int *>(timerIds[i]);
104 }
106 
108 
109 // avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number
110 static inline int prepareNewValueWithSerialNumber(int oldId, int newId)
111 {
112  return (newId & TimerIdMask) | ((oldId + TimerSerialCounter) & TimerSerialMask);
113 }
114 
115 namespace {
116  template<bool> struct QStaticAssertType;
117  template<> struct QStaticAssertType<true> { enum { Value = 1 }; };
118 }
119 #define q_static_assert(expr) (void)QStaticAssertType<expr>::Value
120 
121 static inline int bucketOffset(int timerId)
122 {
123  q_static_assert(sizeof BucketSize == sizeof BucketOffset);
124  q_static_assert(sizeof(timerIds) / sizeof(timerIds[0]) == NumberOfBuckets);
125 
126  for (int i = 0; i < NumberOfBuckets; ++i) {
127  if (timerId < BucketSize[i])
128  return i;
129  timerId -= BucketSize[i];
130  }
131  qFatal("QAbstractEventDispatcher: INTERNAL ERROR, timer ID %d is too large", timerId);
132  return -1;
133 }
134 
135 static inline int bucketIndex(int bucket, int timerId)
136 {
137  return timerId - BucketOffset[bucket];
138 }
139 
140 static inline int *allocateBucket(int bucket)
141 {
142  // allocate a new bucket
143  const int size = BucketSize[bucket];
144  const int offset = BucketOffset[bucket];
145  int *b = new int[size];
146  for (int i = 0; i != size; ++i)
147  b[i] = offset + i + 1;
148  return b;
149 }
150 
152 {
154  if (threadData->eventDispatcher != 0) {
155  qWarning("QAbstractEventDispatcher: An event dispatcher has already been created for this thread");
156  } else {
157  threadData->eventDispatcher = q;
158  }
159 }
160 
161 // Timer IDs are implemented using a free-list;
162 // there's a vector initialized with:
163 // X[i] = i + 1
164 // and nextFreeTimerId starts with 1.
165 //
166 // Allocating a timer ID involves taking the ID from
167 // X[nextFreeTimerId]
168 // updating nextFreeTimerId to this value and returning the old value
169 //
170 // When the timer ID is allocated, its cell in the vector is unused (it's a
171 // free list). As an added protection, we use the cell to store an invalid
172 // (negative) value that we can later check for integrity.
173 //
174 // (continues below).
176 {
177  int timerId, newTimerId;
178  int at, *b;
179  do {
180  timerId = nextFreeTimerId; //.loadAcquire(); // ### FIXME Proper memory ordering semantics
181 
182  // which bucket are we looking in?
183  int which = timerId & TimerIdMask;
184  int bucket = bucketOffset(which);
185  at = bucketIndex(bucket, which);
186  b = timerIds[bucket];
187 
188  if (!b) {
189  // allocate a new bucket
190  b = allocateBucket(bucket);
191  if (!timerIds[bucket].testAndSetRelease(0, b)) {
192  // another thread won the race to allocate the bucket
193  delete [] b;
194  b = timerIds[bucket];
195  }
196  }
197 
198  newTimerId = prepareNewValueWithSerialNumber(timerId, b[at]);
199  } while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId));
200 
201  b[at] = -timerId;
202 
203  return timerId;
204 }
205 
206 // Releasing a timer ID requires putting the current ID back in the vector;
207 // we do it by setting:
208 // X[timerId] = nextFreeTimerId;
209 // then we update nextFreeTimerId to the timer we've just released
210 //
211 // The extra code in allocateTimerId and releaseTimerId are ABA prevention
212 // and bucket memory. The buckets are simply to make sure we allocate only
213 // the necessary number of timers. See above.
214 //
215 // ABA prevention simply adds a value to 7 of the top 8 bits when resetting
216 // nextFreeTimerId.
218 {
219  int which = timerId & TimerIdMask;
220  int bucket = bucketOffset(which);
221  int at = bucketIndex(bucket, which);
222  int *b = timerIds[bucket];
223 
224  Q_ASSERT_X(timerId == -b[at], "QAbstractEventDispatcher::releaseTimerId",
225  "Internal error: timer ID not found");
226 
227  int freeId, newTimerId;
228  do {
229  freeId = nextFreeTimerId;//.loadAcquire(); // ### FIXME Proper memory ordering semantics
230  b[at] = freeId & TimerIdMask;
231 
232  newTimerId = prepareNewValueWithSerialNumber(freeId, timerId);
233  } while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId));
234 }
235 
283 {
285  d->init();
286 }
287 
292  QObject *parent)
293  : QObject(dd, parent)
294 {
296  d->init();
297 }
298 
303 { }
304 
315 {
316  QThreadData *data = thread ? QThreadData::get2(thread) : QThreadData::current();
317  return data->eventDispatcher;
318 }
319 
388 {
390  registerTimer(id, interval, object);
391  return id;
392 }
393 
459 // ### DOC: Are these called when the _application_ starts/stops or just
460 // when the current _event loop_ starts/stops?
463 { }
464 
467 { }
468 
537 {
539  EventFilter oldFilter = d->event_filter;
540  d->event_filter = filter;
541  return oldFilter;
542 }
543 
561 {
563  if (d->event_filter) {
564  // Raise the loopLevel so that deleteLater() calls in or triggered
565  // by event_filter() will be processed from the main event loop.
566  QScopedLoopLevelCounter loopLevelCounter(d->threadData);
567  return d->event_filter(message);
568  }
569  return false;
570 }
571 
double d
Definition: qnumeric_p.h:62
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
static QBasicAtomicInt nextFreeTimerId
static int FirstBucket[]
static QAbstractEventDispatcher * instance(QThread *thread=0)
Returns a pointer to the event dispatcher object for the specified thread.
#define at(className, varName)
static QBasicAtomicPointer< int > timerIds[]
static const int TimerIdMask
#define Q_DESTRUCTOR_FUNCTION(AFUNC)
Definition: qglobal.h:839
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_BASIC_ATOMIC_INITIALIZER(a)
Definition: qbasicatomic.h:218
#define Q_D(Class)
Definition: qglobal.h:2482
static const int TimerSerialMask
#define Q_Q(Class)
Definition: qglobal.h:2483
#define q_static_assert(expr)
static QThreadData * get2(QThread *thread)
Definition: qthread_p.h:219
bool testAndSetRelaxed(int expectedValue, int newValue)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
Q_CORE_EXPORT void qWarning(const char *,...)
static const char * data(const QByteArray &arr)
~QAbstractEventDispatcher()
Destroys the event dispatcher.
int registerTimer(int interval, QObject *object)
Registers a timer with the specified interval for the given object.
static const int TimerSerialCounter
bool(* EventFilter)(void *message)
Typedef for a function with the signature.
Q_CORE_EXPORT void qFatal(const char *,...)
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
bool testAndSetRelease(int expectedValue, int newValue)
static void timerIdsDestructorFunction()
static const int BucketOffset[]
EventFilter setEventFilter(EventFilter filter)
Replaces the event filter function for this QAbstractEventDispatcher with filter and returns the repl...
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
QAbstractEventDispatcher(QObject *parent=0)
Constructs a new event dispatcher with the given parent.
static int bucketIndex(int bucket, int timerId)
QFuture< void > filter(Sequence &sequence, FilterFunction filterFunction)
static QThreadData * current()
static const int MaxTimerId
static int * allocateBucket(int bucket)
static const int BucketSize[]
QThread * thread() const
Returns the thread in which the object lives.
Definition: qobject.cpp:1419
The QThread class provides a platform-independent way to manage threads.
Definition: qthread.h:59
static int prepareNewValueWithSerialNumber(int oldId, int newId)
QAbstractEventDispatcher * eventDispatcher
Definition: qthread_p.h:264
The QAbstractEventDispatcher class provides an interface to manage Qt&#39;s event queue.
static int bucketOffset(int timerId)