aboutsummaryrefslogtreecommitdiffstats
path: root/common/core/Timer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'common/core/Timer.cxx')
-rw-r--r--common/core/Timer.cxx155
1 files changed, 155 insertions, 0 deletions
diff --git a/common/core/Timer.cxx b/common/core/Timer.cxx
new file mode 100644
index 00000000..77e98daf
--- /dev/null
+++ b/common/core/Timer.cxx
@@ -0,0 +1,155 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2016-2024 Pierre Ossman for Cendio AB
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- Timer.cxx
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <algorithm>
+
+#include <core/LogWriter.h>
+#include <core/Timer.h>
+#include <core/time.h>
+
+using namespace core;
+
+#ifndef __NO_DEFINE_VLOG__
+static LogWriter vlog("Timer");
+#endif
+
+std::list<Timer*> Timer::pending;
+
+int Timer::checkTimeouts() {
+ timeval start;
+
+ if (pending.empty())
+ return -1;
+
+ gettimeofday(&start, nullptr);
+ while (pending.front()->isBefore(start)) {
+ Timer* timer;
+
+ timer = pending.front();
+ pending.pop_front();
+
+ timer->lastDueTime = timer->dueTime;
+ timer->cb->handleTimeout(timer);
+
+ if (pending.empty())
+ return -1;
+ }
+ return getNextTimeout();
+}
+
+int Timer::getNextTimeout() {
+ timeval now;
+ gettimeofday(&now, nullptr);
+
+ if (pending.empty())
+ return -1;
+
+ int toWait = pending.front()->getRemainingMs();
+
+ if (toWait > pending.front()->timeoutMs) {
+ if (toWait - pending.front()->timeoutMs < 1000) {
+ vlog.info("gettimeofday is broken...");
+ return toWait;
+ }
+ // Time has jumped backwards!
+ vlog.info("Time has moved backwards!");
+ pending.front()->dueTime = now;
+ toWait = 0;
+ }
+
+ return toWait;
+}
+
+void Timer::insertTimer(Timer* t) {
+ std::list<Timer*>::iterator i;
+ for (i=pending.begin(); i!=pending.end(); i++) {
+ if (t->isBefore((*i)->dueTime)) {
+ pending.insert(i, t);
+ return;
+ }
+ }
+ pending.push_back(t);
+}
+
+void Timer::start(int timeoutMs_) {
+ timeval now;
+ gettimeofday(&now, nullptr);
+ stop();
+ timeoutMs = timeoutMs_;
+ dueTime = addMillis(now, timeoutMs);
+ insertTimer(this);
+}
+
+void Timer::repeat(int timeoutMs_) {
+ timeval now;
+
+ gettimeofday(&now, nullptr);
+
+ if (isStarted()) {
+ vlog.error("Incorrectly repeating already running timer");
+ stop();
+ }
+
+ if (msBetween(&lastDueTime, &dueTime) != 0)
+ vlog.error("Timer incorrectly modified whilst repeating");
+
+ if (timeoutMs_ != -1)
+ timeoutMs = timeoutMs_;
+
+ dueTime = addMillis(lastDueTime, timeoutMs);
+ if (isBefore(now)) {
+ // Time has jumped forwards, or we're not getting enough
+ // CPU time for the timers
+ dueTime = now;
+ }
+
+ insertTimer(this);
+}
+
+void Timer::stop() {
+ pending.remove(this);
+}
+
+bool Timer::isStarted() {
+ return std::find(pending.begin(), pending.end(),
+ this) != pending.end();
+}
+
+int Timer::getTimeoutMs() {
+ return timeoutMs;
+}
+
+int Timer::getRemainingMs() {
+ return msUntil(&dueTime);
+}
+
+bool Timer::isBefore(timeval other) {
+ return (dueTime.tv_sec < other.tv_sec) ||
+ ((dueTime.tv_sec == other.tv_sec) &&
+ (dueTime.tv_usec < other.tv_usec));
+}