source: trunk/src/corelib/kernel/qabstracteventdispatcher.cpp@ 385

Last change on this file since 385 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 14.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qabstracteventdispatcher.h"
43#include "qabstracteventdispatcher_p.h"
44
45#include "qthread.h"
46#include <private/qthread_p.h>
47#include <private/qcoreapplication_p.h>
48
49QT_BEGIN_NAMESPACE
50
51// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers
52enum { NumberOfBuckets = 8, FirstBucketSize = 8 };
53
54static const int BucketSize[NumberOfBuckets] =
55 { 8, 64, 512, 4096, 32768, 262144, 2097152, 16777216 - 2396744 };
56static const int BucketOffset[NumberOfBuckets] =
57 { 0, 8, 72, 584, 4680, 37448, 299592, 2396744 };
58
59static int FirstBucket[FirstBucketSize] = { 1, 2, 3, 4, 5, 6, 7, 8 };
60static QBasicAtomicPointer<int> timerIds[NumberOfBuckets] =
61 { Q_BASIC_ATOMIC_INITIALIZER(FirstBucket),
62 Q_BASIC_ATOMIC_INITIALIZER(0),
63 Q_BASIC_ATOMIC_INITIALIZER(0),
64 Q_BASIC_ATOMIC_INITIALIZER(0),
65 Q_BASIC_ATOMIC_INITIALIZER(0),
66 Q_BASIC_ATOMIC_INITIALIZER(0),
67 Q_BASIC_ATOMIC_INITIALIZER(0),
68 Q_BASIC_ATOMIC_INITIALIZER(0) };
69
70static void timerIdsDestructorFunction()
71{
72 // start at one, the first bucket is pre-allocated
73 for (int i = 1; i < NumberOfBuckets; ++i)
74 delete [] static_cast<int *>(timerIds[i]);
75}
76Q_DESTRUCTOR_FUNCTION(timerIdsDestructorFunction)
77
78static QBasicAtomicInt nextFreeTimerId = Q_BASIC_ATOMIC_INITIALIZER(1);
79
80// avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number
81static inline int prepareNewValueWithSerialNumber(int oldId, int newId)
82{
83 return (newId & 0x00FFFFFF) | ((oldId + 0x01000000) & 0x7f000000);
84}
85
86static inline int bucketOffset(int timerId)
87{
88 for (int i = 0; i < NumberOfBuckets; ++i) {
89 if (timerId < BucketSize[i])
90 return i;
91 timerId -= BucketSize[i];
92 }
93 qFatal("QAbstractEventDispatcher: INTERNAL ERROR, timer ID %d is too large", timerId);
94 return -1;
95}
96
97static inline int bucketIndex(int bucket, int timerId)
98{
99 return timerId - BucketOffset[bucket];
100}
101
102static inline int *allocateBucket(int bucket)
103{
104 // allocate a new bucket
105 const int size = BucketSize[bucket];
106 const int offset = BucketOffset[bucket];
107 int *b = new int[size];
108 for (int i = 0; i != size; ++i)
109 b[i] = offset + i + 1;
110 return b;
111}
112
113void QAbstractEventDispatcherPrivate::init()
114{
115 Q_Q(QAbstractEventDispatcher);
116 if (threadData->eventDispatcher != 0) {
117 qWarning("QAbstractEventDispatcher: An event dispatcher has already been created for this thread");
118 } else {
119 threadData->eventDispatcher = q;
120 }
121}
122
123int QAbstractEventDispatcherPrivate::allocateTimerId()
124{
125 int timerId, newTimerId;
126 do {
127 timerId = nextFreeTimerId;
128
129 // which bucket are we looking in?
130 int which = timerId & 0x00ffffff;
131 int bucket = bucketOffset(which);
132 int at = bucketIndex(bucket, which);
133 int *b = timerIds[bucket];
134
135 if (!b) {
136 // allocate a new bucket
137 b = allocateBucket(bucket);
138 if (!timerIds[bucket].testAndSetRelease(0, b)) {
139 // another thread won the race to allocate the bucket
140 delete [] b;
141 b = timerIds[bucket];
142 }
143 }
144
145 newTimerId = b[at];
146 } while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId));
147
148 return timerId;
149}
150
151void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId)
152{
153 int which = timerId & 0x00ffffff;
154 int bucket = bucketOffset(which);
155 int at = bucketIndex(bucket, which);
156 int *b = timerIds[bucket];
157
158 int freeId, newTimerId;
159 do {
160 freeId = nextFreeTimerId;
161 b[at] = freeId & 0x00ffffff;
162
163 newTimerId = prepareNewValueWithSerialNumber(freeId, timerId);
164 } while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId));
165}
166
167/*!
168 \class QAbstractEventDispatcher
169 \brief The QAbstractEventDispatcher class provides an interface to manage Qt's event queue.
170
171 \ingroup application
172 \ingroup events
173
174 An event dispatcher receives events from the window system and other
175 sources. It then sends them to the QCoreApplication or QApplication
176 instance for processing and delivery. QAbstractEventDispatcher provides
177 fine-grained control over event delivery.
178
179 For simple control of event processing use
180 QCoreApplication::processEvents().
181
182 For finer control of the application's event loop, call
183 instance() and call functions on the QAbstractEventDispatcher
184 object that is returned. If you want to use your own instance of
185 QAbstractEventDispatcher or of a QAbstractEventDispatcher
186 subclass, you must create your instance \e before you create the
187 QApplication object.
188
189 The main event loop is started by calling
190 QCoreApplication::exec(), and stopped by calling
191 QCoreApplication::exit(). Local event loops can be created using
192 QEventLoop.
193
194 Programs that perform long operations can call processEvents()
195 with a bitwise OR combination of various QEventLoop::ProcessEventsFlag
196 values to control which events should be delivered.
197
198 QAbstractEventDispatcher also allows the integration of an
199 external event loop with the Qt event loop. For example, the
200 \l{Qt Solutions}{Motif Extension Qt Solution} includes a
201 reimplementation of QAbstractEventDispatcher that merges Qt and
202 Motif events together.
203
204 \sa QEventLoop, QCoreApplication
205*/
206
207/*!
208 Constructs a new event dispatcher with the given \a parent.
209*/
210QAbstractEventDispatcher::QAbstractEventDispatcher(QObject *parent)
211 : QObject(*new QAbstractEventDispatcherPrivate, parent)
212{
213 Q_D(QAbstractEventDispatcher);
214 d->init();
215}
216
217/*!
218 \internal
219*/
220QAbstractEventDispatcher::QAbstractEventDispatcher(QAbstractEventDispatcherPrivate &dd,
221 QObject *parent)
222 : QObject(dd, parent)
223{
224 Q_D(QAbstractEventDispatcher);
225 d->init();
226}
227
228/*!
229 Destroys the event dispatcher.
230*/
231QAbstractEventDispatcher::~QAbstractEventDispatcher()
232{ }
233
234/*!
235 Returns a pointer to the event dispatcher object for the specified
236 \a thread. If \a thread is zero, the current thread is used. If no
237 event dispatcher exists for the specified thread, this function
238 returns 0.
239
240 \bold{Note:} If Qt is built without thread support, the \a thread
241 argument is ignored.
242 */
243QAbstractEventDispatcher *QAbstractEventDispatcher::instance(QThread *thread)
244{
245 QThreadData *data = thread ? QThreadData::get2(thread) : QThreadData::current();
246 return data->eventDispatcher;
247}
248
249/*!
250 \fn bool QAbstractEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
251
252 Processes pending events that match \a flags until there are no
253 more events to process. Returns true if an event was processed;
254 otherwise returns false.
255
256 This function is especially useful if you have a long running
257 operation and want to show its progress without allowing user
258 input; i.e. by using the QEventLoop::ExcludeUserInputEvents flag.
259
260 If the QEventLoop::WaitForMoreEvents flag is set in \a flags, the
261 behavior of this function is as follows:
262
263 \list
264
265 \i If events are available, this function returns after processing
266 them.
267
268 \i If no events are available, this function will wait until more
269 are available and return after processing newly available events.
270
271 \endlist
272
273 If the QEventLoop::WaitForMoreEvents flag is not set in \a flags,
274 and no events are available, this function will return
275 immediately.
276
277 \bold{Note:} This function does not process events continuously; it
278 returns after all available events are processed.
279
280 \sa hasPendingEvents()
281*/