Introduce QMetaType::UnknownType.
[profile/ivi/qtbase.git] / src / corelib / kernel / qtimerinfo_unix.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
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 void QTimerInfoList::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object)
416 {
417     QTimerInfo *t = new QTimerInfo;
418     t->id = timerId;
419     t->interval = interval;
420     t->timerType = timerType;
421     t->obj = object;
422     t->activateRef = 0;
423
424     timeval expected = updateCurrentTime() + interval;
425
426     switch (timerType) {
427     case Qt::PreciseTimer:
428         // high precision timer is based on millisecond precision
429         // so no adjustment is necessary
430         t->timeout = expected;
431         break;
432
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;
440             // fall through
441         } else {
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);
448             }
449             break;
450         }
451         // fall through
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)
455         t->interval /= 500;
456         t->interval += 1;
457         t->interval >>= 1;
458         t->timeout.tv_sec = currentTime.tv_sec + t->interval;
459         t->timeout.tv_usec = 0;
460
461         // if we're past the half-second mark, increase the timeout again
462         if (currentTime.tv_usec > 500*1000)
463             ++t->timeout.tv_sec;
464     }
465
466     timerInsert(t);
467
468 #ifdef QTIMERINFO_DEBUG
469     t->expected = expected;
470     t->cumulativeError = 0;
471     t->count = 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;
475 #endif
476 }
477
478 bool QTimerInfoList::unregisterTimer(int timerId)
479 {
480     // set timer inactive
481     for (int i = 0; i < count(); ++i) {
482         register QTimerInfo *t = at(i);
483         if (t->id == timerId) {
484             // found it
485             removeAt(i);
486             if (t == firstTimerInfo)
487                 firstTimerInfo = 0;
488             if (t->activateRef)
489                 *(t->activateRef) = 0;
490             delete t;
491             return true;
492         }
493     }
494     // id not found
495     return false;
496 }
497
498 bool QTimerInfoList::unregisterTimers(QObject *object)
499 {
500     if (isEmpty())
501         return false;
502     for (int i = 0; i < count(); ++i) {
503         register QTimerInfo *t = at(i);
504         if (t->obj == object) {
505             // object found
506             removeAt(i);
507             if (t == firstTimerInfo)
508                 firstTimerInfo = 0;
509             if (t->activateRef)
510                 *(t->activateRef) = 0;
511             delete t;
512             // move back one so that we don't skip the new current item
513             --i;
514         }
515     }
516     return true;
517 }
518
519 QList<QAbstractEventDispatcher::TimerInfo> QTimerInfoList::registeredTimers(QObject *object) const
520 {
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
527                                                          ? t->interval * 1000
528                                                          : t->interval),
529                                                         t->timerType);
530         }
531     }
532     return list;
533 }
534
535 /*
536     Activate pending timers, returning how many where activated.
537 */
538 int QTimerInfoList::activateTimers()
539 {
540     if (qt_disable_lowpriority_timers || isEmpty())
541         return 0; // nothing to do
542
543     int n_act = 0, maxCount = 0;
544     firstTimerInfo = 0;
545
546     timeval currentTime = updateCurrentTime();
547     // qDebug() << "Thread" << QThread::currentThreadId() << "woken up at" << currentTime;
548     repairTimersIfNeeded();
549
550
551     // Find out how many timer have expired
552     for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) {
553         if (currentTime < (*it)->timeout)
554             break;
555         maxCount++;
556     }
557
558     //fire the timers.
559     while (maxCount--) {
560         if (isEmpty())
561             break;
562
563         QTimerInfo *currentTimerInfo = first();
564         if (currentTime < currentTimerInfo->timeout)
565             break; // no timer has expired
566
567         if (!firstTimerInfo) {
568             firstTimerInfo = currentTimerInfo;
569         } else if (firstTimerInfo == currentTimerInfo) {
570             // avoid sending the same timer multiple times
571             break;
572         } else if (currentTimerInfo->interval <  firstTimerInfo->interval
573                    || currentTimerInfo->interval == firstTimerInfo->interval) {
574             firstTimerInfo = currentTimerInfo;
575         }
576
577         // remove from list
578         removeFirst();
579
580 #ifdef QTIMERINFO_DEBUG
581         float diff;
582         if (currentTime < currentTimerInfo->expected) {
583             // early
584             timeval early = currentTimerInfo->expected - currentTime;
585             diff = -(early.tv_sec + early.tv_usec / 1000000.0);
586         } else {
587             timeval late = currentTime - currentTimerInfo->expected;
588             diff = late.tv_sec + late.tv_usec / 1000000.0;
589         }
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);
598 #endif
599
600         // determine next timeout time
601         calculateNextTimeout(currentTimerInfo, currentTime);
602
603         // reinsert timer
604         timerInsert(currentTimerInfo);
605         if (currentTimerInfo->interval > 0)
606             n_act++;
607
608         if (!currentTimerInfo->activateRef) {
609             // send event, but don't allow it to recurse
610             currentTimerInfo->activateRef = &currentTimerInfo;
611
612             QTimerEvent e(currentTimerInfo->id);
613             QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
614
615             if (currentTimerInfo)
616                 currentTimerInfo->activateRef = 0;
617         }
618     }
619
620     firstTimerInfo = 0;
621     // qDebug() << "Thread" << QThread::currentThreadId() << "activated" << n_act << "timers";
622     return n_act;
623 }
624
625 QT_END_NAMESPACE