~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/corelib/kernel/qtimerinfo_unix.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 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
 
 
42
#include <qelapsedtimer.h>
 
43
#include <qcoreapplication.h>
 
44
 
 
45
#include "private/qcore_unix_p.h"
 
46
#include "private/qtimerinfo_unix_p.h"
 
47
#include "private/qobject_p.h"
 
48
#include "private/qabstracteventdispatcher_p.h"
 
49
 
 
50
#ifdef QTIMERINFO_DEBUG
 
51
#  include <QDebug>
 
52
#  include <QThread>
 
53
#endif
 
54
 
 
55
#include <sys/times.h>
 
56
 
 
57
QT_BEGIN_NAMESPACE
 
58
 
 
59
Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false;
 
60
 
 
61
/*
 
62
 * Internal functions for manipulating timer data structures.  The
 
63
 * timerBitVec array is used for keeping track of timer identifiers.
 
64
 */
 
65
 
 
66
QTimerInfoList::QTimerInfoList()
 
67
{
 
68
#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_NACL)
 
69
    if (!QElapsedTimer::isMonotonic()) {
 
70
        // not using monotonic timers, initialize the timeChanged() machinery
 
71
        previousTime = qt_gettime();
 
72
 
 
73
        tms unused;
 
74
        previousTicks = times(&unused);
 
75
 
 
76
        ticksPerSecond = sysconf(_SC_CLK_TCK);
 
77
        msPerTick = 1000/ticksPerSecond;
 
78
    } else {
 
79
        // detected monotonic timers
 
80
        previousTime.tv_sec = previousTime.tv_usec = 0;
 
81
        previousTicks = 0;
 
82
        ticksPerSecond = 0;
 
83
        msPerTick = 0;
 
84
    }
 
85
#endif
 
86
 
 
87
    firstTimerInfo = 0;
 
88
}
 
89
 
 
90
timeval QTimerInfoList::updateCurrentTime()
 
91
{
 
92
    return (currentTime = qt_gettime());
 
93
}
 
94
 
 
95
#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED)
 
96
 
 
97
template <>
 
98
timeval qAbs(const timeval &t)
 
99
{
 
100
    timeval tmp = t;
 
101
    if (tmp.tv_sec < 0) {
 
102
        tmp.tv_sec = -tmp.tv_sec - 1;
 
103
        tmp.tv_usec -= 1000000;
 
104
    }
 
105
    if (tmp.tv_sec == 0 && tmp.tv_usec < 0) {
 
106
        tmp.tv_usec = -tmp.tv_usec;
 
107
    }
 
108
    return normalizedTimeval(tmp);
 
109
}
 
110
 
 
111
/*
 
112
  Returns true if the real time clock has changed by more than 10%
 
113
  relative to the processor time since the last time this function was
 
114
  called. This presumably means that the system time has been changed.
 
115
 
 
116
  If /a delta is nonzero, delta is set to our best guess at how much the system clock was changed.
 
117
*/
 
118
bool QTimerInfoList::timeChanged(timeval *delta)
 
119
{
 
120
#ifdef Q_OS_NACL
 
121
    Q_UNUSED(delta)
 
122
    return false; // Calling "times" crashes.
 
123
#endif
 
124
    struct tms unused;
 
125
    clock_t currentTicks = times(&unused);
 
126
 
 
127
    clock_t elapsedTicks = currentTicks - previousTicks;
 
128
    timeval elapsedTime = currentTime - previousTime;
 
129
 
 
130
    timeval elapsedTimeTicks;
 
131
    elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond;
 
132
    elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000;
 
133
 
 
134
    timeval dummy;
 
135
    if (!delta)
 
136
        delta = &dummy;
 
137
    *delta = elapsedTime - elapsedTimeTicks;
 
138
 
 
139
    previousTicks = currentTicks;
 
140
    previousTime = currentTime;
 
141
 
 
142
    // If tick drift is more than 10% off compared to realtime, we assume that the clock has
 
143
    // been set. Of course, we have to allow for the tick granularity as well.
 
144
    timeval tickGranularity;
 
145
    tickGranularity.tv_sec = 0;
 
146
    tickGranularity.tv_usec = msPerTick * 1000;
 
147
    return elapsedTimeTicks < ((qAbs(*delta) - tickGranularity) * 10);
 
148
}
 
149
 
 
150
/*
 
151
  repair broken timer
 
152
*/
 
153
void QTimerInfoList::timerRepair(const timeval &diff)
 
154
{
 
155
    // repair all timers
 
156
    for (int i = 0; i < size(); ++i) {
 
157
        register QTimerInfo *t = at(i);
 
158
        t->timeout = t->timeout + diff;
 
159
    }
 
160
}
 
161
 
 
162
void QTimerInfoList::repairTimersIfNeeded()
 
163
{
 
164
    if (QElapsedTimer::isMonotonic())
 
165
        return;
 
166
    timeval delta;
 
167
    if (timeChanged(&delta))
 
168
        timerRepair(delta);
 
169
}
 
170
 
 
171
#else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED)
 
172
 
 
173
void QTimerInfoList::repairTimersIfNeeded()
 
174
{
 
175
}
 
176
 
 
177
#endif
 
178
 
 
179
/*
 
180
  insert timer info into list
 
181
*/
 
182
void QTimerInfoList::timerInsert(QTimerInfo *ti)
 
183
{
 
184
    int index = size();
 
185
    while (index--) {
 
186
        register const QTimerInfo * const t = at(index);
 
187
        if (!(ti->timeout < t->timeout))
 
188
            break;
 
189
    }
 
190
    insert(index+1, ti);
 
191
}
 
192
 
 
193
inline timeval &operator+=(timeval &t1, int ms)
 
194
{
 
195
    t1.tv_sec += ms / 1000;
 
196
    t1.tv_usec += ms % 1000 * 1000;
 
197
    return normalizedTimeval(t1);
 
198
}
 
199
 
 
200
inline timeval operator+(const timeval &t1, int ms)
 
201
{
 
202
    timeval t2 = t1;
 
203
    return t2 += ms;
 
204
}
 
205
 
 
206
static timeval roundToMillisecond(timeval val)
 
207
{
 
208
    // always round up
 
209
    // worst case scenario is that the first trigger of a 1-ms timer is 0.999 ms late
 
210
 
 
211
    int us = val.tv_usec % 1000;
 
212
    val.tv_usec += 1000 - us;
 
213
    return normalizedTimeval(val);
 
214
}
 
215
 
 
216
#ifdef QTIMERINFO_DEBUG
 
217
QDebug operator<<(QDebug s, timeval tv)
 
218
{
 
219
    s.nospace() << tv.tv_sec << "." << qSetFieldWidth(6) << qSetPadChar(QChar(48)) << tv.tv_usec << reset;
 
220
    return s.space();
 
221
}
 
222
QDebug operator<<(QDebug s, Qt::TimerType t)
 
223
{
 
224
    s << (t == Qt::PreciseTimer ? "P" :
 
225
          t == Qt::CoarseTimer ? "C" : "VC");
 
226
    return s;
 
227
}
 
228
#endif
 
229
 
 
230
static void calculateCoarseTimerTimeout(QTimerInfo *t, timeval currentTime)
 
231
{
 
232
    // The coarse timer works like this:
 
233
    //  - interval under 40 ms: round to even
 
234
    //  - between 40 and 99 ms: round to multiple of 4
 
235
    //  - otherwise: try to wake up at a multiple of 25 ms, with a maximum error of 5%
 
236
    //
 
237
    // We try to wake up at the following second-fraction, in order of preference:
 
238
    //    0 ms
 
239
    //  500 ms
 
240
    //  250 ms or 750 ms
 
241
    //  200, 400, 600, 800 ms
 
242
    //  other multiples of 100
 
243
    //  other multiples of 50
 
244
    //  other multiples of 25
 
245
    //
 
246
    // The objective is to make most timers wake up at the same time, thereby reducing CPU wakeups.
 
247
 
 
248
    register uint interval = uint(t->interval);
 
249
    register uint msec = uint(t->timeout.tv_usec) / 1000;
 
250
    Q_ASSERT(interval >= 20);
 
251
 
 
252
    // Calculate how much we can round and still keep within 5% error
 
253
    uint absMaxRounding = interval / 20;
 
254
 
 
255
    if (interval < 100 && interval != 25 && interval != 50 && interval != 75) {
 
256
        // special mode for timers of less than 100 ms
 
257
        if (interval < 50) {
 
258
            // round to even
 
259
            // round towards multiples of 50 ms
 
260
            register bool roundUp = (msec % 50) >= 25;
 
261
            msec >>= 1;
 
262
            msec |= uint(roundUp);
 
263
            msec <<= 1;
 
264
        } else {
 
265
            // round to multiple of 4
 
266
            // round towards multiples of 100 ms
 
267
            register bool roundUp = (msec % 100) >= 50;
 
268
            msec >>= 2;
 
269
            msec |= uint(roundUp);
 
270
            msec <<= 2;
 
271
        }
 
272
    } else {
 
273
        uint min = qMax<int>(0, msec - absMaxRounding);
 
274
        uint max = qMin(1000u, msec + absMaxRounding);
 
275
 
 
276
        // find the boundary that we want, according to the rules above
 
277
        // extra rules:
 
278
        // 1) whatever the interval, we'll take any round-to-the-second timeout
 
279
        if (min == 0) {
 
280
            msec = 0;
 
281
            goto recalculate;
 
282
        } else if (max == 1000) {
 
283
            msec = 1000;
 
284
            goto recalculate;
 
285
        }
 
286
 
 
287
        uint wantedBoundaryMultiple;
 
288
 
 
289
        // 2) if the interval is a multiple of 500 ms and > 5000 ms, we'll always round
 
290
        //    towards a round-to-the-second
 
291
        // 3) if the interval is a multiple of 500 ms, we'll round towards the nearest
 
292
        //    multiple of 500 ms
 
293
        if ((interval % 500) == 0) {
 
294
            if (interval >= 5000) {
 
295
                msec = msec >= 500 ? max : min;
 
296
                goto recalculate;
 
297
            } else {
 
298
                wantedBoundaryMultiple = 500;
 
299
            }
 
300
        } else if ((interval % 50) == 0) {
 
301
            // 4) same for multiples of 250, 200, 100, 50
 
302
            uint mult50 = interval / 50;
 
303
            if ((mult50 % 4) == 0) {
 
304
                // multiple of 200
 
305
                wantedBoundaryMultiple = 200;
 
306
            } else if ((mult50 % 2) == 0) {
 
307
                // multiple of 100
 
308
                wantedBoundaryMultiple = 100;
 
309
            } else if ((mult50 % 5) == 0) {
 
310
                // multiple of 250
 
311
                wantedBoundaryMultiple = 250;
 
312
            } else {
 
313
                // multiple of 50
 
314
                wantedBoundaryMultiple = 50;
 
315
            }
 
316
        } else {
 
317
            wantedBoundaryMultiple = 25;
 
318
        }
 
319
 
 
320
        uint base = msec / wantedBoundaryMultiple * wantedBoundaryMultiple;
 
321
        uint middlepoint = base + wantedBoundaryMultiple / 2;
 
322
        if (msec < middlepoint)
 
323
            msec = qMax(base, min);
 
324
        else
 
325
            msec = qMin(base + wantedBoundaryMultiple, max);
 
326
    }
 
327
 
 
328
recalculate:
 
329
    if (msec == 1000u) {
 
330
        ++t->timeout.tv_sec;
 
331
        t->timeout.tv_usec = 0;
 
332
    } else {
 
333
        t->timeout.tv_usec = msec * 1000;
 
334
    }
 
335
 
 
336
    if (t->timeout < currentTime)
 
337
        t->timeout += interval;
 
338
}
 
339
 
 
340
static void calculateNextTimeout(QTimerInfo *t, timeval currentTime)
 
341
{
 
342
    switch (t->timerType) {
 
343
    case Qt::PreciseTimer:
 
344
    case Qt::CoarseTimer:
 
345
        t->timeout += t->interval;
 
346
        if (t->timeout < currentTime) {
 
347
            t->timeout = currentTime;
 
348
            t->timeout += t->interval;
 
349
        }
 
350
#ifdef QTIMERINFO_DEBUG
 
351
        t->expected += t->interval;
 
352
        if (t->expected < currentTime) {
 
353
            t->expected = currentTime;
 
354
            t->expected += t->interval;
 
355
        }
 
356
#endif
 
357
        if (t->timerType == Qt::CoarseTimer)
 
358
            calculateCoarseTimerTimeout(t, currentTime);
 
359
        return;
 
360
 
 
361
    case Qt::VeryCoarseTimer:
 
362
        // we don't need to take care of the microsecond component of t->interval
 
363
        t->timeout.tv_sec += t->interval;
 
364
        if (t->timeout.tv_sec <= currentTime.tv_sec)
 
365
            t->timeout.tv_sec = currentTime.tv_sec + t->interval;
 
366
#ifdef QTIMERINFO_DEBUG
 
367
        t->expected.tv_sec += t->interval;
 
368
        if (t->expected.tv_sec <= currentTime.tv_sec)
 
369
            t->expected.tv_sec = currentTime.tv_sec + t->interval;
 
370
#endif
 
371
        return;
 
372
    }
 
373
 
 
374
#ifdef QTIMERINFO_DEBUG
 
375
    if (t->timerType != Qt::PreciseTimer)
 
376
    qDebug() << "timer" << t->timerType << hex << t->id << dec << "interval" << t->interval
 
377
            << "originally expected at" << t->expected << "will fire at" << t->timeout
 
378
            << "or" << (t->timeout - t->expected) << "s late";
 
379
#endif
 
380
}
 
381
 
 
382
/*
 
383
  Returns the time to wait for the next timer, or null if no timers
 
384
  are waiting.
 
385
*/
 
386
bool QTimerInfoList::timerWait(timeval &tm)
 
387
{
 
388
    timeval currentTime = updateCurrentTime();
 
389
    repairTimersIfNeeded();
 
390
 
 
391
    // Find first waiting timer not already active
 
392
    QTimerInfo *t = 0;
 
393
    for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
 
394
        if (!(*it)->activateRef) {
 
395
            t = *it;
 
396
            break;
 
397
        }
 
398
    }
 
399
 
 
400
    if (!t)
 
401
      return false;
 
402
 
 
403
    if (currentTime < t->timeout) {
 
404
        // time to wait
 
405
        tm = roundToMillisecond(t->timeout - currentTime);
 
406
    } else {
 
407
        // no time to wait
 
408
        tm.tv_sec  = 0;
 
409
        tm.tv_usec = 0;
 
410
    }
 
411
 
 
412
    return true;
 
413
}
 
414
 
 
415
/*
 
416
  Returns the timer's remaining time in milliseconds with the given timerId, or
 
417
  null if there is nothing left. If the timer id is not found in the list, the
 
418
  returned value will be -1. If the timer is overdue, the returned value will be 0.
 
419
*/
 
420
int QTimerInfoList::timerRemainingTime(int timerId)
 
421
{
 
422
    timeval currentTime = updateCurrentTime();
 
423
    repairTimersIfNeeded();
 
424
    timeval tm = {0, 0};
 
425
 
 
426
    for (int i = 0; i < count(); ++i) {
 
427
        register QTimerInfo *t = at(i);
 
428
        if (t->id == timerId) {
 
429
            if (currentTime < t->timeout) {
 
430
                // time to wait
 
431
                tm = roundToMillisecond(t->timeout - currentTime);
 
432
                return tm.tv_sec*1000 + tm.tv_usec/1000;
 
433
            } else {
 
434
                return 0;
 
435
            }
 
436
        }
 
437
    }
 
438
 
 
439
#ifndef QT_NO_DEBUG
 
440
    qWarning("QTimerInfoList::timerRemainingTime: timer id %i not found", timerId);
 
441
#endif
 
442
 
 
443
    return -1;
 
444
}
 
445
 
 
446
void QTimerInfoList::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object)
 
447
{
 
448
    QTimerInfo *t = new QTimerInfo;
 
449
    t->id = timerId;
 
450
    t->interval = interval;
 
451
    t->timerType = timerType;
 
452
    t->obj = object;
 
453
    t->activateRef = 0;
 
454
 
 
455
    timeval expected = updateCurrentTime() + interval;
 
456
 
 
457
    switch (timerType) {
 
458
    case Qt::PreciseTimer:
 
459
        // high precision timer is based on millisecond precision
 
460
        // so no adjustment is necessary
 
461
        t->timeout = expected;
 
462
        break;
 
463
 
 
464
    case Qt::CoarseTimer:
 
465
        // this timer has up to 5% coarseness
 
466
        // so our boundaries are 20 ms and 20 s
 
467
        // below 20 ms, 5% inaccuracy is below 1 ms, so we convert to high precision
 
468
        // above 20 s, 5% inaccuracy is above 1 s, so we convert to VeryCoarseTimer
 
469
        if (interval >= 20000) {
 
470
            t->timerType = Qt::VeryCoarseTimer;
 
471
            // fall through
 
472
        } else {
 
473
            t->timeout = expected;
 
474
            if (interval <= 20) {
 
475
                t->timerType = Qt::PreciseTimer;
 
476
                // no adjustment is necessary
 
477
            } else if (interval <= 20000) {
 
478
                calculateCoarseTimerTimeout(t, currentTime);
 
479
            }
 
480
            break;
 
481
        }
 
482
        // fall through
 
483
    case Qt::VeryCoarseTimer:
 
484
        // the very coarse timer is based on full second precision,
 
485
        // so we keep the interval in seconds (round to closest second)
 
486
        t->interval /= 500;
 
487
        t->interval += 1;
 
488
        t->interval >>= 1;
 
489
        t->timeout.tv_sec = currentTime.tv_sec + t->interval;
 
490
        t->timeout.tv_usec = 0;
 
491
 
 
492
        // if we're past the half-second mark, increase the timeout again
 
493
        if (currentTime.tv_usec > 500*1000)
 
494
            ++t->timeout.tv_sec;
 
495
    }
 
496
 
 
497
    timerInsert(t);
 
498
 
 
499
#ifdef QTIMERINFO_DEBUG
 
500
    t->expected = expected;
 
501
    t->cumulativeError = 0;
 
502
    t->count = 0;
 
503
    if (t->timerType != Qt::PreciseTimer)
 
504
    qDebug() << "timer" << t->timerType << hex <<t->id << dec << "interval" << t->interval << "expected at"
 
505
            << t->expected << "will fire first at" << t->timeout;
 
506
#endif
 
507
}
 
508
 
 
509
bool QTimerInfoList::unregisterTimer(int timerId)
 
510
{
 
511
    // set timer inactive
 
512
    for (int i = 0; i < count(); ++i) {
 
513
        register QTimerInfo *t = at(i);
 
514
        if (t->id == timerId) {
 
515
            // found it
 
516
            removeAt(i);
 
517
            if (t == firstTimerInfo)
 
518
                firstTimerInfo = 0;
 
519
            if (t->activateRef)
 
520
                *(t->activateRef) = 0;
 
521
            delete t;
 
522
            return true;
 
523
        }
 
524
    }
 
525
    // id not found
 
526
    return false;
 
527
}
 
528
 
 
529
bool QTimerInfoList::unregisterTimers(QObject *object)
 
530
{
 
531
    if (isEmpty())
 
532
        return false;
 
533
    for (int i = 0; i < count(); ++i) {
 
534
        register QTimerInfo *t = at(i);
 
535
        if (t->obj == object) {
 
536
            // object found
 
537
            removeAt(i);
 
538
            if (t == firstTimerInfo)
 
539
                firstTimerInfo = 0;
 
540
            if (t->activateRef)
 
541
                *(t->activateRef) = 0;
 
542
            delete t;
 
543
            // move back one so that we don't skip the new current item
 
544
            --i;
 
545
        }
 
546
    }
 
547
    return true;
 
548
}
 
549
 
 
550
QList<QAbstractEventDispatcher::TimerInfo> QTimerInfoList::registeredTimers(QObject *object) const
 
551
{
 
552
    QList<QAbstractEventDispatcher::TimerInfo> list;
 
553
    for (int i = 0; i < count(); ++i) {
 
554
        register const QTimerInfo * const t = at(i);
 
555
        if (t->obj == object) {
 
556
            list << QAbstractEventDispatcher::TimerInfo(t->id,
 
557
                                                        (t->timerType == Qt::VeryCoarseTimer
 
558
                                                         ? t->interval * 1000
 
559
                                                         : t->interval),
 
560
                                                        t->timerType);
 
561
        }
 
562
    }
 
563
    return list;
 
564
}
 
565
 
 
566
/*
 
567
    Activate pending timers, returning how many where activated.
 
568
*/
 
569
int QTimerInfoList::activateTimers()
 
570
{
 
571
    if (qt_disable_lowpriority_timers || isEmpty())
 
572
        return 0; // nothing to do
 
573
 
 
574
    int n_act = 0, maxCount = 0;
 
575
    firstTimerInfo = 0;
 
576
 
 
577
    timeval currentTime = updateCurrentTime();
 
578
    // qDebug() << "Thread" << QThread::currentThreadId() << "woken up at" << currentTime;
 
579
    repairTimersIfNeeded();
 
580
 
 
581
 
 
582
    // Find out how many timer have expired
 
583
    for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
 
584
        if (currentTime < (*it)->timeout)
 
585
            break;
 
586
        maxCount++;
 
587
    }
 
588
 
 
589
    //fire the timers.
 
590
    while (maxCount--) {
 
591
        if (isEmpty())
 
592
            break;
 
593
 
 
594
        QTimerInfo *currentTimerInfo = first();
 
595
        if (currentTime < currentTimerInfo->timeout)
 
596
            break; // no timer has expired
 
597
 
 
598
        if (!firstTimerInfo) {
 
599
            firstTimerInfo = currentTimerInfo;
 
600
        } else if (firstTimerInfo == currentTimerInfo) {
 
601
            // avoid sending the same timer multiple times
 
602
            break;
 
603
        } else if (currentTimerInfo->interval <  firstTimerInfo->interval
 
604
                   || currentTimerInfo->interval == firstTimerInfo->interval) {
 
605
            firstTimerInfo = currentTimerInfo;
 
606
        }
 
607
 
 
608
        // remove from list
 
609
        removeFirst();
 
610
 
 
611
#ifdef QTIMERINFO_DEBUG
 
612
        float diff;
 
613
        if (currentTime < currentTimerInfo->expected) {
 
614
            // early
 
615
            timeval early = currentTimerInfo->expected - currentTime;
 
616
            diff = -(early.tv_sec + early.tv_usec / 1000000.0);
 
617
        } else {
 
618
            timeval late = currentTime - currentTimerInfo->expected;
 
619
            diff = late.tv_sec + late.tv_usec / 1000000.0;
 
620
        }
 
621
        currentTimerInfo->cumulativeError += diff;
 
622
        ++currentTimerInfo->count;
 
623
        if (currentTimerInfo->timerType != Qt::PreciseTimer)
 
624
        qDebug() << "timer" << currentTimerInfo->timerType << hex << currentTimerInfo->id << dec << "interval"
 
625
                << currentTimerInfo->interval << "firing at" << currentTime
 
626
                << "(orig" << currentTimerInfo->expected << "scheduled at" << currentTimerInfo->timeout
 
627
                << ") off by" << diff << "activation" << currentTimerInfo->count
 
628
                << "avg error" << (currentTimerInfo->cumulativeError / currentTimerInfo->count);
 
629
#endif
 
630
 
 
631
        // determine next timeout time
 
632
        calculateNextTimeout(currentTimerInfo, currentTime);
 
633
 
 
634
        // reinsert timer
 
635
        timerInsert(currentTimerInfo);
 
636
        if (currentTimerInfo->interval > 0)
 
637
            n_act++;
 
638
 
 
639
        if (!currentTimerInfo->activateRef) {
 
640
            // send event, but don't allow it to recurse
 
641
            currentTimerInfo->activateRef = &currentTimerInfo;
 
642
 
 
643
            QTimerEvent e(currentTimerInfo->id);
 
644
            QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
 
645
 
 
646
            if (currentTimerInfo)
 
647
                currentTimerInfo->activateRef = 0;
 
648
        }
 
649
    }
 
650
 
 
651
    firstTimerInfo = 0;
 
652
    // qDebug() << "Thread" << QThread::currentThreadId() << "activated" << n_act << "timers";
 
653
    return n_act;
 
654
}
 
655
 
 
656
QT_END_NAMESPACE