/*************************************************************************** * * * This program 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. * * * *************************************************************************** * timer.cc * (c) Murat Deligonul 2002 */ #include "autoconf.h" #include "timer.h" #include "linkedlist.h" #include "debug.h" /** * This a simple implementation of interval timers .. */ list timer::timers; int timer::poll_interval = 0; time_t timer::counter = 0; timer::timer(int _int, int _opt, int _id) { DEBUG("timer::timer() -- %p started at %d, [interval: %d options: %d]\n", this, counter, _int, _opt); assert(_int != 0); interval = _int; id = _id; options = _opt; epoch = counter; } timer::~timer() { DEBUG("timer::~timer() -- %p\n", this); } /** * Add this timer to the active timers list. * Figure out the poll interval and return * Never call from a timer_proc */ int timer::enable(timer * t) { DEBUG("timer::enable() -- %p\n", t); timers.add(t); poll_interval = calc_interval(); return get_poll_interval(); } /** * Remove from the active timers list * Never call from a timer_proc * FIXME: current we do not re-calculate the poll-interval after a disable * */ int timer::disable(timer * t) { DEBUG("timer::disable() -- %p\n", t); timers.remove(t); // poll_interval = calc_interval(); return get_poll_interval(); } /** * Figure out what interval to poll the timers * (with the gcd algorithm) */ int timer::calc_interval() { if (!timers.size()) return 0; list_iterator i(&timers); int * array = new int[timers.size()]; int idx = 0; while (i.has_next()) { timer * t = i.next(); array[idx++] = t->interval; } int r = gcd(array, idx); delete[] array; return r; } /** * Recursively compute greatest common divisor * of two ints */ int timer::gcd(int i, int j) { if (j > i) { int t = i; i = j; j = t; } int r = i % j; if (!r) return j; return gcd(j, r); } /** * Find the GCD of an array of int */ int timer::gcd(int * array, int num) { if (num < 2) return array[0]; int r = gcd(array[0], array[1]); for (int i = 2; i < num; ++i) r = gcd(r, array[i]); return r; } /** * Poll the timers */ int timer::poll(time_t realtime) { list_iterator i(&timers); counter += poll_interval; DEBUG("timer::poll() @ time index %lu [real: %lu]\n", counter, realtime); while (i.has_next()) { /** * Call the handler: * Check for < 0 return value, and remove that * timer if necessary */ timer * t = i.next(); if (!((counter - t->epoch) % t->interval) ) if ( (t->timer_proc(realtime) < 0) || (t->options & TIMER_ONESHOT)) i.remove(); } return 1; } int generic_timer::timer_proc(time_t t) { DEBUG("generic_timer()::timer_proc() -- %p\n", this); return callback(t, get_id(), data); }