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

Last change on this file since 425 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*/
282
283/*! \fn bool QAbstractEventDispatcher::hasPendingEvents()
284
285 Returns true if there is an event waiting; otherwise returns
286 false.
287*/
288
289/*!
290 \fn void QAbstractEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
291
292 Registers \a notifier with the event loop. Subclasses must
293 implement this method to tie a socket notifier into another
294 event loop.
295*/
296
297/*! \fn void QAbstractEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
298
299 Unregisters \a notifier from the event dispatcher. Subclasses must
300 reimplement this method to tie a socket notifier into another
301 event loop. Reimplementations must call the base
302 implementation.
303*/
304
305/*!
306 \fn int QAbstractEventDispatcher::registerTimer(int interval, QObject *object)
307
308 Registers a timer with the specified \a interval for the given \a object.
309*/
310int QAbstractEventDispatcher::registerTimer(int interval, QObject *object)
311{
312 int id = QAbstractEventDispatcherPrivate::allocateTimerId();
313 registerTimer(id, interval, object);
314 return id;
315}
316
317/*!
318 \fn void QAbstractEventDispatcher::registerTimer(int timerId, int interval, QObject *object)
319
320 Register a timer with the specified \a timerId and \a interval for
321 the given \a object.
322*/
323
324/*!
325 \fn bool QAbstractEventDispatcher::unregisterTimer(int timerId)
326
327 Unregisters the timer with the given \a timerId.
328 Returns true if successful; otherwise returns false.
329
330 \sa registerTimer(), unregisterTimers()
331*/
332
333/*!
334 \fn bool QAbstractEventDispatcher::unregisterTimers(QObject *object)
335
336 Unregisters all the timers associated with the given \a object.
337 Returns true if all timers were successful removed; otherwise returns false.
338
339 \sa unregisterTimer(), registeredTimers()
340*/
341
342/*!
343 \fn QList<TimerInfo> QAbstractEventDispatcher::registeredTimers(QObject *object) const
344
345 Returns a list of registered timers for \a object. The timer ID
346 is the first member in each pair; the interval is the second.
347*/
348
349/*! \fn void QAbstractEventDispatcher::wakeUp()
350 \threadsafe
351
352 Wakes up the event loop.
353
354 \sa awake()
355*/
356
357/*!
358 \fn void QAbstractEventDispatcher::interrupt()
359
360 Interrupts event dispatching; i.e. the event dispatcher will
361 return from processEvents() as soon as possible.
362*/
363
364/*! \fn void QAbstractEventDispatcher::flush()
365
366 Flushes the event queue. This normally returns almost
367 immediately. Does nothing on platforms other than X11.
368*/
369
370// ### DOC: Are these called when the _application_ starts/stops or just
371// when the current _event loop_ starts/stops?
372/*! \internal */
373void QAbstractEventDispatcher::startingUp()
374{ }
375
376/*! \internal */
377void QAbstractEventDispatcher::closingDown()
378{ }
379
380/*!
381 \typedef QAbstractEventDispatcher::TimerInfo
382
383 Typedef for QPair<int, int>. The first component of
384 the pair is the timer ID; the second component is
385 the interval.
386
387 \sa registeredTimers()
388*/
389
390/*!
391 \typedef QAbstractEventDispatcher::EventFilter
392
393 Typedef for a function with the signature
394
395 \snippet doc/src/snippets/code/src_corelib_kernel_qabstracteventdispatcher.cpp 0
396
397 \sa setEventFilter(), filterEvent()
398*/
399
400/*!
401 Sets the event filter \a filter. Returns a pointer to the filter
402 function previously defined.
403
404 The event filter is a function that receives all messages taken
405 from the system event loop before the event is dispatched to the
406 respective target. This includes messages that are not sent to Qt
407 objects.
408
409 The function can return true to stop the event to be processed by
410 Qt, or false to continue with the standard event processing.
411
412 Only one filter can be defined, but the filter can use the return
413 value to call the previously set event filter. By default, no
414 filter is set (i.e. the function returns 0).
415*/
416QAbstractEventDispatcher::EventFilter QAbstractEventDispatcher::setEventFilter(EventFilter filter)
417{
418 Q_D(QAbstractEventDispatcher);
419 EventFilter oldFilter = d->event_filter;
420 d->event_filter = filter;
421 return oldFilter;
422}
423
424/*!
425 Sends \a message through the event filter that was set by
426 setEventFilter(). If no event filter has been set, this function
427 returns false; otherwise, this function returns the result of the
428 event filter function.
429
430 Subclasses of QAbstractEventDispatcher \e must call this function
431 for \e all messages received from the system to ensure
432 compatibility with any extensions that may be used in the
433 application.
434
435 \sa setEventFilter()
436*/
437bool QAbstractEventDispatcher::filterEvent(void *message)
438{
439 Q_D(QAbstractEventDispatcher);
440 if (d->event_filter)
441 return d->event_filter(message);
442 return false;
443}
444
445/*! \fn void QAbstractEventDispatcher::awake()
446
447 This signal is emitted after the event loop returns from a
448 function that could block.
449
450 \sa wakeUp() aboutToBlock()
451*/
452
453/*! \fn void QAbstractEventDispatcher::aboutToBlock()
454
455 This signal is emitted before the event loop calls a function that
456 could block.
457
458 \sa awake()
459*/
460
461QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.