You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Timer.cxx 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2016-2018 Pierre Ossman for Cendio AB
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. // -=- Timer.cxx
  20. #include <stdio.h>
  21. #include <sys/time.h>
  22. #include <rfb/Timer.h>
  23. #include <rfb/util.h>
  24. #include <rfb/LogWriter.h>
  25. using namespace rfb;
  26. #ifndef __NO_DEFINE_VLOG__
  27. static LogWriter vlog("Timer");
  28. #endif
  29. // Millisecond timeout processing helper functions
  30. inline static timeval addMillis(timeval inTime, int millis) {
  31. int secs = millis / 1000;
  32. millis = millis % 1000;
  33. inTime.tv_sec += secs;
  34. inTime.tv_usec += millis * 1000;
  35. if (inTime.tv_usec >= 1000000) {
  36. inTime.tv_sec++;
  37. inTime.tv_usec -= 1000000;
  38. }
  39. return inTime;
  40. }
  41. inline static int diffTimeMillis(timeval later, timeval earlier) {
  42. return ((later.tv_sec - earlier.tv_sec) * 1000) + ((later.tv_usec - earlier.tv_usec) / 1000);
  43. }
  44. std::list<Timer*> Timer::pending;
  45. int Timer::checkTimeouts() {
  46. timeval start;
  47. if (pending.empty())
  48. return 0;
  49. gettimeofday(&start, 0);
  50. while (pending.front()->isBefore(start)) {
  51. Timer* timer;
  52. timeval before;
  53. timer = pending.front();
  54. pending.pop_front();
  55. gettimeofday(&before, 0);
  56. if (timer->cb->handleTimeout(timer)) {
  57. timeval now;
  58. gettimeofday(&now, 0);
  59. timer->dueTime = addMillis(timer->dueTime, timer->timeoutMs);
  60. if (timer->isBefore(now)) {
  61. // Time has jumped forwards, or we're not getting enough
  62. // CPU time for the timers
  63. timer->dueTime = addMillis(before, timer->timeoutMs);
  64. if (timer->isBefore(now))
  65. timer->dueTime = now;
  66. }
  67. insertTimer(timer);
  68. } else if (pending.empty()) {
  69. return 0;
  70. }
  71. }
  72. return getNextTimeout();
  73. }
  74. int Timer::getNextTimeout() {
  75. timeval now;
  76. gettimeofday(&now, 0);
  77. int toWait = __rfbmax(1, pending.front()->getRemainingMs());
  78. if (toWait > pending.front()->timeoutMs) {
  79. if (toWait - pending.front()->timeoutMs < 1000) {
  80. vlog.info("gettimeofday is broken...");
  81. return toWait;
  82. }
  83. // Time has jumped backwards!
  84. vlog.info("time has moved backwards!");
  85. pending.front()->dueTime = now;
  86. toWait = 1;
  87. }
  88. return toWait;
  89. }
  90. void Timer::insertTimer(Timer* t) {
  91. std::list<Timer*>::iterator i;
  92. for (i=pending.begin(); i!=pending.end(); i++) {
  93. if (t->isBefore((*i)->dueTime)) {
  94. pending.insert(i, t);
  95. return;
  96. }
  97. }
  98. pending.push_back(t);
  99. }
  100. void Timer::start(int timeoutMs_) {
  101. timeval now;
  102. gettimeofday(&now, 0);
  103. stop();
  104. timeoutMs = timeoutMs_;
  105. // The rest of the code assumes non-zero timeout
  106. if (timeoutMs <= 0)
  107. timeoutMs = 1;
  108. dueTime = addMillis(now, timeoutMs);
  109. insertTimer(this);
  110. }
  111. void Timer::stop() {
  112. pending.remove(this);
  113. }
  114. bool Timer::isStarted() {
  115. std::list<Timer*>::iterator i;
  116. for (i=pending.begin(); i!=pending.end(); i++) {
  117. if (*i == this)
  118. return true;
  119. }
  120. return false;
  121. }
  122. int Timer::getTimeoutMs() {
  123. return timeoutMs;
  124. }
  125. int Timer::getRemainingMs() {
  126. timeval now;
  127. gettimeofday(&now, 0);
  128. return __rfbmax(0, diffTimeMillis(dueTime, now));
  129. }
  130. bool Timer::isBefore(timeval other) {
  131. return (dueTime.tv_sec < other.tv_sec) ||
  132. ((dueTime.tv_sec == other.tv_sec) &&
  133. (dueTime.tv_usec < other.tv_usec));
  134. }