blob: e2aefacc185f733e24e9f76c8c3f148a681cdef8 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossman79621342016-10-07 16:02:18 +02002 * Copyright 2016 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
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>
Pierre Ossman9c181ba2015-11-09 15:27:54 +010023#include <sys/time.h>
24
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000025#include <rfb/Timer.h>
26#include <rfb/util.h>
27#include <rfb/LogWriter.h>
28
29// XXX Lynx/OS 2.3: proto for gettimeofday()
30#ifdef Lynx
31#include <sys/proto.h>
32#endif
33
34using namespace rfb;
35
36#ifndef __NO_DEFINE_VLOG__
37static LogWriter vlog("Timer");
38#endif
39
40
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000041// Millisecond timeout processing helper functions
42
43inline static timeval addMillis(timeval inTime, int millis) {
44 int secs = millis / 1000;
45 millis = millis % 1000;
46 inTime.tv_sec += secs;
47 inTime.tv_usec += millis * 1000;
48 if (inTime.tv_usec >= 1000000) {
49 inTime.tv_sec++;
50 inTime.tv_usec -= 1000000;
51 }
52 return inTime;
53}
54
55inline static int diffTimeMillis(timeval later, timeval earlier) {
56 return ((later.tv_sec - earlier.tv_sec) * 1000) + ((later.tv_usec - earlier.tv_usec) / 1000);
57}
58
59std::list<Timer*> Timer::pending;
60
61int Timer::checkTimeouts() {
Pierre Ossman79621342016-10-07 16:02:18 +020062 timeval start;
63
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000064 if (pending.empty())
65 return 0;
Pierre Ossman79621342016-10-07 16:02:18 +020066
67 gettimeofday(&start, 0);
68 while (pending.front()->isBefore(start)) {
69 Timer* timer;
70 timeval before;
71
72 timer = pending.front();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000073 pending.pop_front();
Pierre Ossman79621342016-10-07 16:02:18 +020074
75 gettimeofday(&before, 0);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000076 if (timer->cb->handleTimeout(timer)) {
Pierre Ossman79621342016-10-07 16:02:18 +020077 timeval now;
78
79 gettimeofday(&now, 0);
80
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000081 timer->dueTime = addMillis(timer->dueTime, timer->timeoutMs);
82 if (timer->isBefore(now)) {
Pierre Ossman79621342016-10-07 16:02:18 +020083 // Time has jumped forwards, or we're not getting enough
84 // CPU time for the timers
85
86 timer->dueTime = addMillis(before, timer->timeoutMs);
87 if (timer->isBefore(now))
88 timer->dueTime = now;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000089 }
Pierre Ossman79621342016-10-07 16:02:18 +020090
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000091 insertTimer(timer);
92 } else if (pending.empty()) {
93 return 0;
94 }
95 }
96 return getNextTimeout();
97}
98
99int Timer::getNextTimeout() {
100 timeval now;
101 gettimeofday(&now, 0);
102 int toWait = __rfbmax(1, diffTimeMillis(pending.front()->dueTime, now));
103 if (toWait > pending.front()->timeoutMs) {
104 if (toWait - pending.front()->timeoutMs < 1000) {
105 vlog.info("gettimeofday is broken...");
106 return toWait;
107 }
108 // Time has jumped backwards!
109 vlog.info("time has moved backwards!");
110 pending.front()->dueTime = now;
111 toWait = 1;
112 }
113 return toWait;
114}
115
116void Timer::insertTimer(Timer* t) {
117 std::list<Timer*>::iterator i;
118 for (i=pending.begin(); i!=pending.end(); i++) {
119 if (t->isBefore((*i)->dueTime)) {
120 pending.insert(i, t);
121 return;
122 }
123 }
124 pending.push_back(t);
125}
126
127void Timer::start(int timeoutMs_) {
128 timeval now;
129 gettimeofday(&now, 0);
130 stop();
131 timeoutMs = timeoutMs_;
Pierre Ossmane0a3ad42016-11-30 07:59:30 +0100132 // The rest of the code assumes non-zero timeout
133 if (timeoutMs <= 0)
134 timeoutMs = 1;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000135 dueTime = addMillis(now, timeoutMs);
136 insertTimer(this);
137}
138
139void Timer::stop() {
140 pending.remove(this);
141}
142
143bool Timer::isStarted() {
144 std::list<Timer*>::iterator i;
145 for (i=pending.begin(); i!=pending.end(); i++) {
146 if (*i == this)
147 return true;
148 }
149 return false;
150}
151
152int Timer::getTimeoutMs() {
153 return timeoutMs;
154}
155
156bool Timer::isBefore(timeval other) {
157 return (dueTime.tv_sec < other.tv_sec) ||
158 ((dueTime.tv_sec == other.tv_sec) &&
159 (dueTime.tv_usec < other.tv_usec));
160}