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

Last change on this file since 641 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 14.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37** Nokia 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 events
172
173 An event dispatcher receives events from the window system and other
174 sources. It then sends them to the QCoreApplication or QApplication
175 instance for processing and delivery. QAbstractEventDispatcher provides
176 fine-grained control over event delivery.
177
178 For simple control of event processing use
179 QCoreApplication::processEvents().
180
181 For finer control of the application's event loop, call
182 instance() and call functions on the QAbstractEventDispatcher
183 object that is returned. If you want to use your own instance of
184 QAbstractEventDispatcher or of a QAbstractEventDispatcher
185 subclass, you must create your instance \e before you create the
186 QApplication object.
187
188 The main event loop is started by calling
189 QCoreApplication::exec(), and stopped by calling
190 QCoreApplication::exit(). Local event loops can be created using
191 QEventLoop.
192
193 Programs that perform long operations can call processEvents()
194 with a bitwise OR combination of various QEventLoop::ProcessEventsFlag
195 values to control which events should be delivered.
196
197 QAbstractEventDispatcher also allows the integration of an
198 external event loop with the Qt event loop. For example, the
199 \l{Qt Solutions}{Motif Extension Qt Solution} includes a
200 reimplementation of QAbstractEventDispatcher that merges Qt and
201 Motif events together.
202
203 \sa QEventLoop, QCoreApplication
204*/
205
206/*!
207 Constructs a new event dispatcher with the given \a parent.
208*/
209QAbstractEventDispatcher::QAbstractEventDispatcher(QObject *parent)
210 : QObject(*new QAbstractEventDispatcherPrivate, parent)
211{
212 Q_D(QAbstractEventDispatcher);
213 d->init();
214}
215
216/*!
217 \internal
218*/
219QAbstractEventDispatcher::QAbstractEventDispatcher(QAbstractEventDispatcherPrivate &dd,
220 QObject *parent)
221 : QObject(dd, parent)
222{
223 Q_D(QAbstractEventDispatcher);
224 d->init();
225}
226
227/*!
228 Destroys the event dispatcher.
229*/
230QAbstractEventDispatcher::~QAbstractEventDispatcher()
231{ }
232
233/*!
234 Returns a pointer to the event dispatcher object for the specified
235 \a thread. If \a thread is zero, the current thread is used. If no
236 event dispatcher exists for the specified thread, this function
237 returns 0.
238
239 \bold{Note:} If Qt is built without thread support, the \a thread
240 argument is ignored.
241 */
242QAbstractEventDispatcher *QAbstractEventDispatcher::instance(QThread *thread)
243{
244 QThreadData *data = thread ? QThreadData::get2(thread) : QThreadData::current();
245 return data->eventDispatcher;
246}
247
248/*!
249 \fn bool QAbstractEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
250
251 Processes pending events that match \a flags until there are no
252 more events to process. Returns true if an event was processed;
253 otherwise returns false.
254
255 This function is especially useful if you have a long running
256 operation and want to show its progress without allowing user
257 input; i.e. by using the QEventLoop::ExcludeUserInputEvents flag.
258
259 If the QEventLoop::WaitForMoreEvents flag is set in \a flags, the
260 behavior of this function is as follows:
261
262 \list
263
264 \i If events are available, this function returns after processing
265 them.
266
267 \i If no events are available, this function will wait until more
268 are available and return after processing newly available events.
269
270 \endlist
271
272 If the QEventLoop::WaitForMoreEvents flag is not set in \a flags,
273 and no events are available, this function will return
274 immediately.
275
276 \bold{Note:} This function does not process events continuously; it
277 returns after all available events are processed.
278
279 \sa hasPendingEvents()
280*/
281
282/*! \fn bool QAbstractEventDispatcher::hasPendingEvents()
283
284 Returns true if there is an event waiting; otherwise returns
285 false.
286*/
287
288/*!
289 \fn void QAbstractEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
290
291 Registers \a notifier with the event loop. Subclasses must
292 implement this method to tie a socket notifier into another
293 event loop.
294*/
295
296/*! \fn void QAbstractEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
297
298 Unregisters \a notifier from the event dispatcher. Subclasses must
299 reimplement this method to tie a socket notifier into another
300 event loop. Reimplementations must call the base
301 implementation.
302*/
303
304/*!
305 \fn int QAbstractEventDispatcher::registerTimer(int interval, QObject *object)
306
307 Registers a timer with the specified \a interval for the given \a object.
308*/
309int QAbstractEventDispatcher::registerTimer(int interval, QObject *object)
310{
311 int id = QAbstractEventDispatcherPrivate::allocateTimerId();
312 registerTimer(id, interval, object);
313 return id;
314}
315
316/*!
317 \fn void QAbstractEventDispatcher::registerTimer(int timerId, int interval, QObject *object)
318
319 Register a timer with the specified \a timerId and \a interval for
320 the given \a object.
321*/
322
323/*!
324 \fn bool QAbstractEventDispatcher::unregisterTimer(int timerId)
325
326 Unregisters the timer with the given \a timerId.
327 Returns true if successful; otherwise returns false.
328
329 \sa registerTimer(), unregisterTimers()
330*/
331
332/*!
333 \fn bool QAbstractEventDispatcher::unregisterTimers(QObject *object)
334
335 Unregisters all the timers associated with the given \a object.
336 Returns true if all timers were successful removed; otherwise returns false.
337
338 \sa unregisterTimer(), registeredTimers()
339*/
340
341/*!
342 \fn QList<TimerInfo> QAbstractEventDispatcher::registeredTimers(QObject *object) const
343
344 Returns a list of registered timers for \a object. The timer ID
345 is the first member in each pair; the interval is the second.
346*/
347
348/*! \fn void QAbstractEventDispatcher::wakeUp()
349 \threadsafe
350
351 Wakes up the event loop.
352
353 \sa awake()
354*/
355
356/*!
357 \fn void QAbstractEventDispatcher::interrupt()
358
359 Interrupts event dispatching; i.e. the event dispatcher will
360 return from processEvents() as soon as possible.
361*/
362
363/*! \fn void QAbstractEventDispatcher::flush()
364
365 Flushes the event queue. This normally returns almost
366 immediately. Does nothing on platforms other than X11.
367*/
368
369// ### DOC: Are these called when the _application_ starts/stops or just
370// when the current _event loop_ starts/stops?
371/*! \internal */
372void QAbstractEventDispatcher::startingUp()
373{ }
374
375/*! \internal */
376void QAbstractEventDispatcher::closingDown()
377{ }
378
379/*!
380 \typedef QAbstractEventDispatcher::TimerInfo
381
382 Typedef for QPair<int, int>. The first component of
383 the pair is the timer ID; the second component is
384 the interval.
385
386 \sa registeredTimers()
387*/
388
389/*!
390 \typedef QAbstractEventDispatcher::EventFilter
391
392 Typedef for a function with the signature
393
394 \snippet doc/src/snippets/code/src_corelib_kernel_qabstracteventdispatcher.cpp 0
395
396 \sa setEventFilter(), filterEvent()
397*/
398
399/*!
400 Replaces the event filter function for this
401 QAbstractEventDispatcher with \a filter and returns the replaced
402 event filter function. Only the current event filter function is
403 called. If you want to use both filter functions, save the
404 replaced EventFilter in a place where yours can call it.
405
406 The event filter function set here is called for all messages
407 taken from the system event loop before the event is dispatched to
408 the respective target, including the messages not meant for Qt
409 objects.
410
411 The event filter function should return true if the message should
412 be filtered, (i.e. stopped). It should return false to allow
413 processing the message to continue.
414
415 By default, no event filter function is set (i.e., this function
416 returns a null EventFilter the first time it is called).
417*/
418QAbstractEventDispatcher::EventFilter QAbstractEventDispatcher::setEventFilter(EventFilter filter)
419{
420 Q_D(QAbstractEventDispatcher);
421 EventFilter oldFilter = d->event_filter;
422 d->event_filter = filter;
423 return oldFilter;
424}
425
426/*!
427 Sends \a message through the event filter that was set by
428 setEventFilter(). If no event filter has been set, this function
429 returns false; otherwise, this function returns the result of the
430 event filter function.
431
432 Subclasses of QAbstractEventDispatcher \e must call this function
433 for \e all messages received from the system to ensure
434 compatibility with any extensions that may be used in the
435 application.
436
437 \sa setEventFilter()
438*/
439bool QAbstractEventDispatcher::filterEvent(void *message)
440{
441 Q_D(QAbstractEventDispatcher);
442 if (d->event_filter)
443 return d->event_filter(message);
444 return false;
445}
446
447/*! \fn void QAbstractEventDispatcher::awake()
448
449 This signal is emitted after the event loop returns from a
450 function that could block.
451
452 \sa wakeUp() aboutToBlock()
453*/
454
455/*! \fn void QAbstractEventDispatcher::aboutToBlock()
456
457 This signal is emitted before the event loop calls a function that
458 could block.
459
460 \sa awake()
461*/
462
463QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.