PageRenderTime 61ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/src/qt/qtbase/src/corelib/kernel/qtimerinfo_unix.cpp

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