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