1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtCore module of the Qt Toolkit.
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.
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.
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.
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.
40
****************************************************************************/
42
#include <qelapsedtimer.h>
43
#include <qcoreapplication.h>
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"
50
#ifdef QTIMERINFO_DEBUG
55
#include <sys/times.h>
59
Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false;
62
* Internal functions for manipulating timer data structures. The
63
* timerBitVec array is used for keeping track of timer identifiers.
66
QTimerInfoList::QTimerInfoList()
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();
74
previousTicks = times(&unused);
76
ticksPerSecond = sysconf(_SC_CLK_TCK);
77
msPerTick = 1000/ticksPerSecond;
79
// detected monotonic timers
80
previousTime.tv_sec = previousTime.tv_usec = 0;
90
timeval QTimerInfoList::updateCurrentTime()
92
return (currentTime = qt_gettime());
95
#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED)
98
timeval qAbs(const timeval &t)
101
if (tmp.tv_sec < 0) {
102
tmp.tv_sec = -tmp.tv_sec - 1;
103
tmp.tv_usec -= 1000000;
105
if (tmp.tv_sec == 0 && tmp.tv_usec < 0) {
106
tmp.tv_usec = -tmp.tv_usec;
108
return normalizedTimeval(tmp);
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.
116
If /a delta is nonzero, delta is set to our best guess at how much the system clock was changed.
118
bool QTimerInfoList::timeChanged(timeval *delta)
122
return false; // Calling "times" crashes.
125
clock_t currentTicks = times(&unused);
127
clock_t elapsedTicks = currentTicks - previousTicks;
128
timeval elapsedTime = currentTime - previousTime;
130
timeval elapsedTimeTicks;
131
elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond;
132
elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000;
137
*delta = elapsedTime - elapsedTimeTicks;
139
previousTicks = currentTicks;
140
previousTime = currentTime;
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);
153
void QTimerInfoList::timerRepair(const timeval &diff)
156
for (int i = 0; i < size(); ++i) {
157
register QTimerInfo *t = at(i);
158
t->timeout = t->timeout + diff;
162
void QTimerInfoList::repairTimersIfNeeded()
164
if (QElapsedTimer::isMonotonic())
167
if (timeChanged(&delta))
171
#else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED)
173
void QTimerInfoList::repairTimersIfNeeded()
180
insert timer info into list
182
void QTimerInfoList::timerInsert(QTimerInfo *ti)
186
register const QTimerInfo * const t = at(index);
187
if (!(ti->timeout < t->timeout))
193
inline timeval &operator+=(timeval &t1, int ms)
195
t1.tv_sec += ms / 1000;
196
t1.tv_usec += ms % 1000 * 1000;
197
return normalizedTimeval(t1);
200
inline timeval operator+(const timeval &t1, int ms)
206
static timeval roundToMillisecond(timeval val)
209
// worst case scenario is that the first trigger of a 1-ms timer is 0.999 ms late
211
int us = val.tv_usec % 1000;
212
val.tv_usec += 1000 - us;
213
return normalizedTimeval(val);
216
#ifdef QTIMERINFO_DEBUG
217
QDebug operator<<(QDebug s, timeval tv)
219
s.nospace() << tv.tv_sec << "." << qSetFieldWidth(6) << qSetPadChar(QChar(48)) << tv.tv_usec << reset;
222
QDebug operator<<(QDebug s, Qt::TimerType t)
224
s << (t == Qt::PreciseTimer ? "P" :
225
t == Qt::CoarseTimer ? "C" : "VC");
230
static void calculateCoarseTimerTimeout(QTimerInfo *t, timeval currentTime)
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%
237
// We try to wake up at the following second-fraction, in order of preference:
241
// 200, 400, 600, 800 ms
242
// other multiples of 100
243
// other multiples of 50
244
// other multiples of 25
246
// The objective is to make most timers wake up at the same time, thereby reducing CPU wakeups.
248
register uint interval = uint(t->interval);
249
register uint msec = uint(t->timeout.tv_usec) / 1000;
250
Q_ASSERT(interval >= 20);
252
// Calculate how much we can round and still keep within 5% error
253
uint absMaxRounding = interval / 20;
255
if (interval < 100 && interval != 25 && interval != 50 && interval != 75) {
256
// special mode for timers of less than 100 ms
259
// round towards multiples of 50 ms
260
register bool roundUp = (msec % 50) >= 25;
262
msec |= uint(roundUp);
265
// round to multiple of 4
266
// round towards multiples of 100 ms
267
register bool roundUp = (msec % 100) >= 50;
269
msec |= uint(roundUp);
273
uint min = qMax<int>(0, msec - absMaxRounding);
274
uint max = qMin(1000u, msec + absMaxRounding);
276
// find the boundary that we want, according to the rules above
278
// 1) whatever the interval, we'll take any round-to-the-second timeout
282
} else if (max == 1000) {
287
uint wantedBoundaryMultiple;
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;
298
wantedBoundaryMultiple = 500;
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) {
305
wantedBoundaryMultiple = 200;
306
} else if ((mult50 % 2) == 0) {
308
wantedBoundaryMultiple = 100;
309
} else if ((mult50 % 5) == 0) {
311
wantedBoundaryMultiple = 250;
314
wantedBoundaryMultiple = 50;
317
wantedBoundaryMultiple = 25;
320
uint base = msec / wantedBoundaryMultiple * wantedBoundaryMultiple;
321
uint middlepoint = base + wantedBoundaryMultiple / 2;
322
if (msec < middlepoint)
323
msec = qMax(base, min);
325
msec = qMin(base + wantedBoundaryMultiple, max);
331
t->timeout.tv_usec = 0;
333
t->timeout.tv_usec = msec * 1000;
336
if (t->timeout < currentTime)
337
t->timeout += interval;
340
static void calculateNextTimeout(QTimerInfo *t, timeval currentTime)
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;
350
#ifdef QTIMERINFO_DEBUG
351
t->expected += t->interval;
352
if (t->expected < currentTime) {
353
t->expected = currentTime;
354
t->expected += t->interval;
357
if (t->timerType == Qt::CoarseTimer)
358
calculateCoarseTimerTimeout(t, currentTime);
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;
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";
383
Returns the time to wait for the next timer, or null if no timers
386
bool QTimerInfoList::timerWait(timeval &tm)
388
timeval currentTime = updateCurrentTime();
389
repairTimersIfNeeded();
391
// Find first waiting timer not already active
393
for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
394
if (!(*it)->activateRef) {
403
if (currentTime < t->timeout) {
405
tm = roundToMillisecond(t->timeout - currentTime);
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.
420
int QTimerInfoList::timerRemainingTime(int timerId)
422
timeval currentTime = updateCurrentTime();
423
repairTimersIfNeeded();
426
for (int i = 0; i < count(); ++i) {
427
register QTimerInfo *t = at(i);
428
if (t->id == timerId) {
429
if (currentTime < t->timeout) {
431
tm = roundToMillisecond(t->timeout - currentTime);
432
return tm.tv_sec*1000 + tm.tv_usec/1000;
440
qWarning("QTimerInfoList::timerRemainingTime: timer id %i not found", timerId);
446
void QTimerInfoList::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object)
448
QTimerInfo *t = new QTimerInfo;
450
t->interval = interval;
451
t->timerType = timerType;
455
timeval expected = updateCurrentTime() + interval;
458
case Qt::PreciseTimer:
459
// high precision timer is based on millisecond precision
460
// so no adjustment is necessary
461
t->timeout = expected;
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;
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);
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)
489
t->timeout.tv_sec = currentTime.tv_sec + t->interval;
490
t->timeout.tv_usec = 0;
492
// if we're past the half-second mark, increase the timeout again
493
if (currentTime.tv_usec > 500*1000)
499
#ifdef QTIMERINFO_DEBUG
500
t->expected = expected;
501
t->cumulativeError = 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;
509
bool QTimerInfoList::unregisterTimer(int timerId)
511
// set timer inactive
512
for (int i = 0; i < count(); ++i) {
513
register QTimerInfo *t = at(i);
514
if (t->id == timerId) {
517
if (t == firstTimerInfo)
520
*(t->activateRef) = 0;
529
bool QTimerInfoList::unregisterTimers(QObject *object)
533
for (int i = 0; i < count(); ++i) {
534
register QTimerInfo *t = at(i);
535
if (t->obj == object) {
538
if (t == firstTimerInfo)
541
*(t->activateRef) = 0;
543
// move back one so that we don't skip the new current item
550
QList<QAbstractEventDispatcher::TimerInfo> QTimerInfoList::registeredTimers(QObject *object) const
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
567
Activate pending timers, returning how many where activated.
569
int QTimerInfoList::activateTimers()
571
if (qt_disable_lowpriority_timers || isEmpty())
572
return 0; // nothing to do
574
int n_act = 0, maxCount = 0;
577
timeval currentTime = updateCurrentTime();
578
// qDebug() << "Thread" << QThread::currentThreadId() << "woken up at" << currentTime;
579
repairTimersIfNeeded();
582
// Find out how many timer have expired
583
for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
584
if (currentTime < (*it)->timeout)
594
QTimerInfo *currentTimerInfo = first();
595
if (currentTime < currentTimerInfo->timeout)
596
break; // no timer has expired
598
if (!firstTimerInfo) {
599
firstTimerInfo = currentTimerInfo;
600
} else if (firstTimerInfo == currentTimerInfo) {
601
// avoid sending the same timer multiple times
603
} else if (currentTimerInfo->interval < firstTimerInfo->interval
604
|| currentTimerInfo->interval == firstTimerInfo->interval) {
605
firstTimerInfo = currentTimerInfo;
611
#ifdef QTIMERINFO_DEBUG
613
if (currentTime < currentTimerInfo->expected) {
615
timeval early = currentTimerInfo->expected - currentTime;
616
diff = -(early.tv_sec + early.tv_usec / 1000000.0);
618
timeval late = currentTime - currentTimerInfo->expected;
619
diff = late.tv_sec + late.tv_usec / 1000000.0;
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);
631
// determine next timeout time
632
calculateNextTimeout(currentTimerInfo, currentTime);
635
timerInsert(currentTimerInfo);
636
if (currentTimerInfo->interval > 0)
639
if (!currentTimerInfo->activateRef) {
640
// send event, but don't allow it to recurse
641
currentTimerInfo->activateRef = ¤tTimerInfo;
643
QTimerEvent e(currentTimerInfo->id);
644
QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
646
if (currentTimerInfo)
647
currentTimerInfo->activateRef = 0;
652
// qDebug() << "Thread" << QThread::currentThreadId() << "activated" << n_act << "timers";