1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include <qelapsedtimer.h>
42 #include <qcoreapplication.h>
43 
44 #include "private/qcore_unix_p.h"
45 #include "private/qtimerinfo_unix_p.h"
46 #include "private/qobject_p.h"
47 #include "private/qabstracteventdispatcher_p.h"
48 
49 #ifdef QTIMERINFO_DEBUG
50 #  include <QDebug>
51 #  include <QThread>
52 #endif
53 
54 #include <sys/times.h>
55 
56 QT_BEGIN_NAMESPACE
57 
58 Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false;
59 
60 /*
61  * Internal functions for manipulating timer data structures.  The
62  * timerBitVec array is used for keeping track of timer identifiers.
63  */
64 
QTimerInfoList()65 QTimerInfoList::QTimerInfoList()
66 {
67 #if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_NACL)
68     if (!QElapsedTimer::isMonotonic()) {
69         // not using monotonic timers, initialize the timeChanged() machinery
70         previousTime = qt_gettime();
71 
72         tms unused;
73         previousTicks = times(&unused);
74 
75         ticksPerSecond = sysconf(_SC_CLK_TCK);
76         msPerTick = 1000/ticksPerSecond;
77     } else {
78         // detected monotonic timers
79         previousTime.tv_sec = previousTime.tv_nsec = 0;
80         previousTicks = 0;
81         ticksPerSecond = 0;
82         msPerTick = 0;
83     }
84 #endif
85 
86     firstTimerInfo = nullptr;
87 }
88 
updateCurrentTime()89 timespec QTimerInfoList::updateCurrentTime()
90 {
91     return (currentTime = qt_gettime());
92 }
93 
94 #if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED)
95 
qAbsTimespec(const timespec & t)96 timespec qAbsTimespec(const timespec &t)
97 {
98     timespec tmp = t;
99     if (tmp.tv_sec < 0) {
100         tmp.tv_sec = -tmp.tv_sec - 1;
101         tmp.tv_nsec -= 1000000000;
102     }
103     if (tmp.tv_sec == 0 && tmp.tv_nsec < 0) {
104         tmp.tv_nsec = -tmp.tv_nsec;
105     }
106     return normalizedTimespec(tmp);
107 }
108 
109 /*
110   Returns \c true if the real time clock has changed by more than 10%
111   relative to the processor time since the last time this function was
112   called. This presumably means that the system time has been changed.
113 
114   If /a delta is nonzero, delta is set to our best guess at how much the system clock was changed.
115 */
timeChanged(timespec * delta)116 bool QTimerInfoList::timeChanged(timespec *delta)
117 {
118 #ifdef Q_OS_NACL
119     Q_UNUSED(delta)
120     return false; // Calling "times" crashes.
121 #endif
122     struct tms unused;
123     clock_t currentTicks = times(&unused);
124 
125     clock_t elapsedTicks = currentTicks - previousTicks;
126     timespec elapsedTime = currentTime - previousTime;
127 
128     timespec elapsedTimeTicks;
129     elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond;
130     elapsedTimeTicks.tv_nsec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000 * 1000;
131 
132     timespec dummy;
133     if (!delta)
134         delta = &dummy;
135     *delta = elapsedTime - elapsedTimeTicks;
136 
137     previousTicks = currentTicks;
138     previousTime = currentTime;
139 
140     // If tick drift is more than 10% off compared to realtime, we assume that the clock has
141     // been set. Of course, we have to allow for the tick granularity as well.
142     timespec tickGranularity;
143     tickGranularity.tv_sec = 0;
144     tickGranularity.tv_nsec = msPerTick * 1000 * 1000;
145     return elapsedTimeTicks < ((qAbsTimespec(*delta) - tickGranularity) * 10);
146 }
147 
148 /*
149   repair broken timer
150 */
timerRepair(const timespec & diff)151 void QTimerInfoList::timerRepair(const timespec &diff)
152 {
153     // repair all timers
154     for (int i = 0; i < size(); ++i) {
155         QTimerInfo *t = at(i);
156         t->timeout = t->timeout + diff;
157     }
158 }
159 
repairTimersIfNeeded()160 void QTimerInfoList::repairTimersIfNeeded()
161 {
162     if (QElapsedTimer::isMonotonic())
163         return;
164     timespec delta;
165     if (timeChanged(&delta))
166         timerRepair(delta);
167 }
168 
169 #else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED)
170 
repairTimersIfNeeded()171 void QTimerInfoList::repairTimersIfNeeded()
172 {
173 }
174 
175 #endif
176 
177 /*
178   insert timer info into list
179 */
timerInsert(QTimerInfo * ti)180 void QTimerInfoList::timerInsert(QTimerInfo *ti)
181 {
182     int index = size();
183     while (index--) {
184         const QTimerInfo * const t = at(index);
185         if (!(ti->timeout < t->timeout))
186             break;
187     }
188     insert(index+1, ti);
189 }
190 
operator +=(timespec & t1,int ms)191 inline timespec &operator+=(timespec &t1, int ms)
192 {
193     t1.tv_sec += ms / 1000;
194     t1.tv_nsec += ms % 1000 * 1000 * 1000;
195     return normalizedTimespec(t1);
196 }
197 
operator +(const timespec & t1,int ms)198 inline timespec operator+(const timespec &t1, int ms)
199 {
200     timespec t2 = t1;
201     return t2 += ms;
202 }
203 
roundToMillisecond(timespec val)204 static timespec roundToMillisecond(timespec val)
205 {
206     // always round up
207     // worst case scenario is that the first trigger of a 1-ms timer is 0.999 ms late
208 
209     int ns = val.tv_nsec % (1000 * 1000);
210     val.tv_nsec += 1000 * 1000 - ns;
211     return normalizedTimespec(val);
212 }
213 
214 #ifdef QTIMERINFO_DEBUG
operator <<(QDebug s,timeval tv)215 QDebug operator<<(QDebug s, timeval tv)
216 {
217     QDebugStateSaver saver(s);
218     s.nospace() << tv.tv_sec << "." << qSetFieldWidth(6) << qSetPadChar(QChar(48)) << tv.tv_usec << Qt::reset;
219     return s;
220 }
operator <<(QDebug s,Qt::TimerType t)221 QDebug operator<<(QDebug s, Qt::TimerType t)
222 {
223     QDebugStateSaver saver(s);
224     s << (t == Qt::PreciseTimer ? "P" :
225           t == Qt::CoarseTimer ? "C" : "VC");
226     return s;
227 }
228 #endif
229 
calculateCoarseTimerTimeout(QTimerInfo * t,timespec currentTime)230 static void calculateCoarseTimerTimeout(QTimerInfo *t, timespec 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     uint interval = uint(t->interval);
249     uint msec = uint(t->timeout.tv_nsec) / 1000 / 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             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             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_nsec = 0;
332     } else {
333         t->timeout.tv_nsec = msec * 1000 * 1000;
334     }
335 
336     if (t->timeout < currentTime)
337         t->timeout += interval;
338 }
339 
calculateNextTimeout(QTimerInfo * t,timespec currentTime)340 static void calculateNextTimeout(QTimerInfo *t, timespec 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 << Qt::hex << t->id << Qt::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 */
timerWait(timespec & tm)386 bool QTimerInfoList::timerWait(timespec &tm)
387 {
388     timespec currentTime = updateCurrentTime();
389     repairTimersIfNeeded();
390 
391     // Find first waiting timer not already active
392     QTimerInfo *t = nullptr;
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_nsec = 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 */
timerRemainingTime(int timerId)420 int QTimerInfoList::timerRemainingTime(int timerId)
421 {
422     timespec currentTime = updateCurrentTime();
423     repairTimersIfNeeded();
424     timespec tm = {0, 0};
425 
426     for (int i = 0; i < count(); ++i) {
427         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_nsec/1000/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 
registerTimer(int timerId,int interval,Qt::TimerType timerType,QObject * object)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 = nullptr;
454 
455     timespec 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         } else {
472             t->timeout = expected;
473             if (interval <= 20) {
474                 t->timerType = Qt::PreciseTimer;
475                 // no adjustment is necessary
476             } else if (interval <= 20000) {
477                 calculateCoarseTimerTimeout(t, currentTime);
478             }
479             break;
480         }
481         Q_FALLTHROUGH();
482     case Qt::VeryCoarseTimer:
483         // the very coarse timer is based on full second precision,
484         // so we keep the interval in seconds (round to closest second)
485         t->interval /= 500;
486         t->interval += 1;
487         t->interval >>= 1;
488         t->timeout.tv_sec = currentTime.tv_sec + t->interval;
489         t->timeout.tv_nsec = 0;
490 
491         // if we're past the half-second mark, increase the timeout again
492         if (currentTime.tv_nsec > 500*1000*1000)
493             ++t->timeout.tv_sec;
494     }
495 
496     timerInsert(t);
497 
498 #ifdef QTIMERINFO_DEBUG
499     t->expected = expected;
500     t->cumulativeError = 0;
501     t->count = 0;
502     if (t->timerType != Qt::PreciseTimer)
503     qDebug() << "timer" << t->timerType << Qt::hex <<t->id << Qt::dec << "interval" << t->interval << "expected at"
504             << t->expected << "will fire first at" << t->timeout;
505 #endif
506 }
507 
unregisterTimer(int timerId)508 bool QTimerInfoList::unregisterTimer(int timerId)
509 {
510     // set timer inactive
511     for (int i = 0; i < count(); ++i) {
512         QTimerInfo *t = at(i);
513         if (t->id == timerId) {
514             // found it
515             removeAt(i);
516             if (t == firstTimerInfo)
517                 firstTimerInfo = nullptr;
518             if (t->activateRef)
519                 *(t->activateRef) = nullptr;
520             delete t;
521             return true;
522         }
523     }
524     // id not found
525     return false;
526 }
527 
unregisterTimers(QObject * object)528 bool QTimerInfoList::unregisterTimers(QObject *object)
529 {
530     if (isEmpty())
531         return false;
532     for (int i = 0; i < count(); ++i) {
533         QTimerInfo *t = at(i);
534         if (t->obj == object) {
535             // object found
536             removeAt(i);
537             if (t == firstTimerInfo)
538                 firstTimerInfo = nullptr;
539             if (t->activateRef)
540                 *(t->activateRef) = nullptr;
541             delete t;
542             // move back one so that we don't skip the new current item
543             --i;
544         }
545     }
546     return true;
547 }
548 
registeredTimers(QObject * object) const549 QList<QAbstractEventDispatcher::TimerInfo> QTimerInfoList::registeredTimers(QObject *object) const
550 {
551     QList<QAbstractEventDispatcher::TimerInfo> list;
552     for (int i = 0; i < count(); ++i) {
553         const QTimerInfo * const t = at(i);
554         if (t->obj == object) {
555             list << QAbstractEventDispatcher::TimerInfo(t->id,
556                                                         (t->timerType == Qt::VeryCoarseTimer
557                                                          ? t->interval * 1000
558                                                          : t->interval),
559                                                         t->timerType);
560         }
561     }
562     return list;
563 }
564 
565 /*
566     Activate pending timers, returning how many where activated.
567 */
activateTimers()568 int QTimerInfoList::activateTimers()
569 {
570     if (qt_disable_lowpriority_timers || isEmpty())
571         return 0; // nothing to do
572 
573     int n_act = 0, maxCount = 0;
574     firstTimerInfo = nullptr;
575 
576     timespec currentTime = updateCurrentTime();
577     // qDebug() << "Thread" << QThread::currentThreadId() << "woken up at" << currentTime;
578     repairTimersIfNeeded();
579 
580 
581     // Find out how many timer have expired
582     for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
583         if (currentTime < (*it)->timeout)
584             break;
585         maxCount++;
586     }
587 
588     //fire the timers.
589     while (maxCount--) {
590         if (isEmpty())
591             break;
592 
593         QTimerInfo *currentTimerInfo = constFirst();
594         if (currentTime < currentTimerInfo->timeout)
595             break; // no timer has expired
596 
597         if (!firstTimerInfo) {
598             firstTimerInfo = currentTimerInfo;
599         } else if (firstTimerInfo == currentTimerInfo) {
600             // avoid sending the same timer multiple times
601             break;
602         } else if (currentTimerInfo->interval <  firstTimerInfo->interval
603                    || currentTimerInfo->interval == firstTimerInfo->interval) {
604             firstTimerInfo = currentTimerInfo;
605         }
606 
607         // remove from list
608         removeFirst();
609 
610 #ifdef QTIMERINFO_DEBUG
611         float diff;
612         if (currentTime < currentTimerInfo->expected) {
613             // early
614             timeval early = currentTimerInfo->expected - currentTime;
615             diff = -(early.tv_sec + early.tv_usec / 1000000.0);
616         } else {
617             timeval late = currentTime - currentTimerInfo->expected;
618             diff = late.tv_sec + late.tv_usec / 1000000.0;
619         }
620         currentTimerInfo->cumulativeError += diff;
621         ++currentTimerInfo->count;
622         if (currentTimerInfo->timerType != Qt::PreciseTimer)
623         qDebug() << "timer" << currentTimerInfo->timerType << Qt::hex << currentTimerInfo->id << Qt::dec << "interval"
624                 << currentTimerInfo->interval << "firing at" << currentTime
625                 << "(orig" << currentTimerInfo->expected << "scheduled at" << currentTimerInfo->timeout
626                 << ") off by" << diff << "activation" << currentTimerInfo->count
627                 << "avg error" << (currentTimerInfo->cumulativeError / currentTimerInfo->count);
628 #endif
629 
630         // determine next timeout time
631         calculateNextTimeout(currentTimerInfo, currentTime);
632 
633         // reinsert timer
634         timerInsert(currentTimerInfo);
635         if (currentTimerInfo->interval > 0)
636             n_act++;
637 
638         if (!currentTimerInfo->activateRef) {
639             // send event, but don't allow it to recurse
640             currentTimerInfo->activateRef = &currentTimerInfo;
641 
642             QTimerEvent e(currentTimerInfo->id);
643             QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
644 
645             if (currentTimerInfo)
646                 currentTimerInfo->activateRef = nullptr;
647         }
648     }
649 
650     firstTimerInfo = nullptr;
651     // qDebug() << "Thread" << QThread::currentThreadId() << "activated" << n_act << "timers";
652     return n_act;
653 }
654 
655 QT_END_NAMESPACE
656