1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtCore module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
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);
415 void QTimerInfoList::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object)
417 QTimerInfo *t = new QTimerInfo;
419 t->interval = interval;
420 t->timerType = timerType;
424 timeval expected = updateCurrentTime() + interval;
427 case Qt::PreciseTimer:
428 // high precision timer is based on millisecond precision
429 // so no adjustment is necessary
430 t->timeout = expected;
433 case Qt::CoarseTimer:
434 // this timer has up to 5% coarseness
435 // so our boundaries are 20 ms and 20 s
436 // below 20 ms, 5% inaccuracy is below 1 ms, so we convert to high precision
437 // above 20 s, 5% inaccuracy is above 1 s, so we convert to VeryCoarseTimer
438 if (interval >= 20000) {
439 t->timerType = Qt::VeryCoarseTimer;
442 t->timeout = expected;
443 if (interval <= 20) {
444 t->timerType = Qt::PreciseTimer;
445 // no adjustment is necessary
446 } else if (interval <= 20000) {
447 calculateCoarseTimerTimeout(t, currentTime);
452 case Qt::VeryCoarseTimer:
453 // the very coarse timer is based on full second precision,
454 // so we keep the interval in seconds (round to closest second)
458 t->timeout.tv_sec = currentTime.tv_sec + t->interval;
459 t->timeout.tv_usec = 0;
461 // if we're past the half-second mark, increase the timeout again
462 if (currentTime.tv_usec > 500*1000)
468 #ifdef QTIMERINFO_DEBUG
469 t->expected = expected;
470 t->cumulativeError = 0;
472 if (t->timerType != Qt::PreciseTimer)
473 qDebug() << "timer" << t->timerType << hex <<t->id << dec << "interval" << t->interval << "expected at"
474 << t->expected << "will fire first at" << t->timeout;
478 bool QTimerInfoList::unregisterTimer(int timerId)
480 // set timer inactive
481 for (int i = 0; i < count(); ++i) {
482 register QTimerInfo *t = at(i);
483 if (t->id == timerId) {
486 if (t == firstTimerInfo)
489 *(t->activateRef) = 0;
498 bool QTimerInfoList::unregisterTimers(QObject *object)
502 for (int i = 0; i < count(); ++i) {
503 register QTimerInfo *t = at(i);
504 if (t->obj == object) {
507 if (t == firstTimerInfo)
510 *(t->activateRef) = 0;
512 // move back one so that we don't skip the new current item
519 QList<QAbstractEventDispatcher::TimerInfo> QTimerInfoList::registeredTimers(QObject *object) const
521 QList<QAbstractEventDispatcher::TimerInfo> list;
522 for (int i = 0; i < count(); ++i) {
523 register const QTimerInfo * const t = at(i);
524 if (t->obj == object) {
525 list << QAbstractEventDispatcher::TimerInfo(t->id,
526 (t->timerType == Qt::VeryCoarseTimer
536 Activate pending timers, returning how many where activated.
538 int QTimerInfoList::activateTimers()
540 if (qt_disable_lowpriority_timers || isEmpty())
541 return 0; // nothing to do
543 int n_act = 0, maxCount = 0;
546 timeval currentTime = updateCurrentTime();
547 // qDebug() << "Thread" << QThread::currentThreadId() << "woken up at" << currentTime;
548 repairTimersIfNeeded();
551 // Find out how many timer have expired
552 for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
553 if (currentTime < (*it)->timeout)
563 QTimerInfo *currentTimerInfo = first();
564 if (currentTime < currentTimerInfo->timeout)
565 break; // no timer has expired
567 if (!firstTimerInfo) {
568 firstTimerInfo = currentTimerInfo;
569 } else if (firstTimerInfo == currentTimerInfo) {
570 // avoid sending the same timer multiple times
572 } else if (currentTimerInfo->interval < firstTimerInfo->interval
573 || currentTimerInfo->interval == firstTimerInfo->interval) {
574 firstTimerInfo = currentTimerInfo;
580 #ifdef QTIMERINFO_DEBUG
582 if (currentTime < currentTimerInfo->expected) {
584 timeval early = currentTimerInfo->expected - currentTime;
585 diff = -(early.tv_sec + early.tv_usec / 1000000.0);
587 timeval late = currentTime - currentTimerInfo->expected;
588 diff = late.tv_sec + late.tv_usec / 1000000.0;
590 currentTimerInfo->cumulativeError += diff;
591 ++currentTimerInfo->count;
592 if (currentTimerInfo->timerType != Qt::PreciseTimer)
593 qDebug() << "timer" << currentTimerInfo->timerType << hex << currentTimerInfo->id << dec << "interval"
594 << currentTimerInfo->interval << "firing at" << currentTime
595 << "(orig" << currentTimerInfo->expected << "scheduled at" << currentTimerInfo->timeout
596 << ") off by" << diff << "activation" << currentTimerInfo->count
597 << "avg error" << (currentTimerInfo->cumulativeError / currentTimerInfo->count);
600 // determine next timeout time
601 calculateNextTimeout(currentTimerInfo, currentTime);
604 timerInsert(currentTimerInfo);
605 if (currentTimerInfo->interval > 0)
608 if (!currentTimerInfo->activateRef) {
609 // send event, but don't allow it to recurse
610 currentTimerInfo->activateRef = ¤tTimerInfo;
612 QTimerEvent e(currentTimerInfo->id);
613 QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
615 if (currentTimerInfo)
616 currentTimerInfo->activateRef = 0;
621 // qDebug() << "Thread" << QThread::currentThreadId() << "activated" << n_act << "timers";