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
20 // -=- Timer.cxx
21
22 #include <stdio.h>
23 #include <sys/time.h>
24
25 #include <rfb/Timer.h>
26 #include <rfb/util.h>
27 #include <rfb/LogWriter.h>
28
29 using namespace rfb;
30
31 #ifndef __NO_DEFINE_VLOG__
32 static LogWriter vlog("Timer");
33 #endif
34
35
36 // Millisecond timeout processing helper functions
37
addMillis(timeval inTime,int millis)38 inline static timeval addMillis(timeval inTime, int millis) {
39 int secs = millis / 1000;
40 millis = millis % 1000;
41 inTime.tv_sec += secs;
42 inTime.tv_usec += millis * 1000;
43 if (inTime.tv_usec >= 1000000) {
44 inTime.tv_sec++;
45 inTime.tv_usec -= 1000000;
46 }
47 return inTime;
48 }
49
diffTimeMillis(timeval later,timeval earlier)50 inline static int diffTimeMillis(timeval later, timeval earlier) {
51 return ((later.tv_sec - earlier.tv_sec) * 1000) + ((later.tv_usec - earlier.tv_usec) / 1000);
52 }
53
54 std::list<Timer*> Timer::pending;
55
checkTimeouts()56 int Timer::checkTimeouts() {
57 timeval start;
58
59 if (pending.empty())
60 return 0;
61
62 gettimeofday(&start, 0);
63 while (pending.front()->isBefore(start)) {
64 Timer* timer;
65 timeval before;
66
67 timer = pending.front();
68 pending.pop_front();
69
70 gettimeofday(&before, 0);
71 if (timer->cb->handleTimeout(timer)) {
72 timeval now;
73
74 gettimeofday(&now, 0);
75
76 timer->dueTime = addMillis(timer->dueTime, timer->timeoutMs);
77 if (timer->isBefore(now)) {
78 // Time has jumped forwards, or we're not getting enough
79 // CPU time for the timers
80
81 timer->dueTime = addMillis(before, timer->timeoutMs);
82 if (timer->isBefore(now))
83 timer->dueTime = now;
84 }
85
86 insertTimer(timer);
87 } else if (pending.empty()) {
88 return 0;
89 }
90 }
91 return getNextTimeout();
92 }
93
getNextTimeout()94 int Timer::getNextTimeout() {
95 timeval now;
96 gettimeofday(&now, 0);
97 int toWait = __rfbmax(1, pending.front()->getRemainingMs());
98 if (toWait > pending.front()->timeoutMs) {
99 if (toWait - pending.front()->timeoutMs < 1000) {
100 vlog.info("gettimeofday is broken...");
101 return toWait;
102 }
103 // Time has jumped backwards!
104 vlog.info("time has moved backwards!");
105 pending.front()->dueTime = now;
106 toWait = 1;
107 }
108 return toWait;
109 }
110
insertTimer(Timer * t)111 void Timer::insertTimer(Timer* t) {
112 std::list<Timer*>::iterator i;
113 for (i=pending.begin(); i!=pending.end(); i++) {
114 if (t->isBefore((*i)->dueTime)) {
115 pending.insert(i, t);
116 return;
117 }
118 }
119 pending.push_back(t);
120 }
121
start(int timeoutMs_)122 void Timer::start(int timeoutMs_) {
123 timeval now;
124 gettimeofday(&now, 0);
125 stop();
126 timeoutMs = timeoutMs_;
127 // The rest of the code assumes non-zero timeout
128 if (timeoutMs <= 0)
129 timeoutMs = 1;
130 dueTime = addMillis(now, timeoutMs);
131 insertTimer(this);
132 }
133
stop()134 void Timer::stop() {
135 pending.remove(this);
136 }
137
isStarted()138 bool Timer::isStarted() {
139 std::list<Timer*>::iterator i;
140 for (i=pending.begin(); i!=pending.end(); i++) {
141 if (*i == this)
142 return true;
143 }
144 return false;
145 }
146
getTimeoutMs()147 int Timer::getTimeoutMs() {
148 return timeoutMs;
149 }
150
getRemainingMs()151 int Timer::getRemainingMs() {
152 timeval now;
153 gettimeofday(&now, 0);
154 return __rfbmax(0, diffTimeMillis(dueTime, now));
155 }
156
isBefore(timeval other)157 bool Timer::isBefore(timeval other) {
158 return (dueTime.tv_sec < other.tv_sec) ||
159 ((dueTime.tv_sec == other.tv_sec) &&
160 (dueTime.tv_usec < other.tv_usec));
161 }
162