00001
00002
00003 #ifdef HAVE_CONFIG_H
00004 # include "../config.h"
00005 #endif // HAVE_CONFIG_H
00006
00007 #include "timer.hh"
00008 #include "display.hh"
00009
00010 extern "C" {
00011 #ifdef HAVE_SYS_SELECT_H
00012 # include <sys/select.h>
00013 #else
00014 # ifdef HAVE_UNISTD_H
00015 # include <sys/types.h>
00016 # include <unistd.h>
00017 # endif // HAVE_UNISTD_H
00018 #endif // HAVE_SYS_SELECT_H
00019 }
00020
00021 namespace otk {
00022
00023 timeval Timer::_nearest_timeout, Timer::_now;
00024 Timer::TimerQ Timer::_q;
00025
00026 void Timer::timevalAdd(timeval &a, long msec)
00027 {
00028 a.tv_sec += msec / 1000;
00029 a.tv_usec += (msec % 1000) * 1000;
00030 a.tv_sec += a.tv_usec / 1000000;
00031 a.tv_usec %= 1000000;
00032 }
00033
00034 bool Timer::nearestTimeout(struct timeval &tm)
00035 {
00036 if (_q.empty())
00037 return false;
00038 tm.tv_sec = _nearest_timeout.tv_sec - _now.tv_sec;
00039 tm.tv_usec = _nearest_timeout.tv_usec - _now.tv_usec;
00040
00041 while (tm.tv_usec < 0) {
00042 tm.tv_usec += 1000000;
00043 tm.tv_sec--;
00044 }
00045 tm.tv_sec += tm.tv_usec / 1000000;
00046 tm.tv_usec %= 1000000;
00047 if (tm.tv_sec < 0)
00048 tm.tv_sec = 0;
00049
00050 return true;
00051 }
00052
00053 void Timer::dispatchTimers(bool wait)
00054 {
00055 fd_set selset;
00056 int fd;
00057 timeval next;
00058 Timer *curr;
00059
00060 gettimeofday(&_now, NULL);
00061 _nearest_timeout = _now;
00062 _nearest_timeout.tv_sec += 10000;
00063
00064 while (!_q.empty()) {
00065 curr = _q.top();
00066
00067
00068
00069 if (curr->_del_me) {
00070 _q.pop();
00071 realDelete(curr);
00072 continue;
00073 }
00074
00075
00076 _nearest_timeout = curr->_timeout;
00077 if (!timercmp(&_now, &_nearest_timeout, >))
00078 break;
00079
00080
00081
00082
00083
00084 _q.pop();
00085 timevalAdd(curr->_last, curr->_delay);
00086 curr->_action(curr->_data);
00087 timevalAdd(curr->_timeout, curr->_delay);
00088 _q.push(curr);
00089 }
00090
00091 if (wait) {
00092
00093 fd = ConnectionNumber(**display);
00094 FD_ZERO(&selset);
00095 FD_SET(fd, &selset);
00096 if (nearestTimeout(next))
00097 select(fd + 1, &selset, NULL, NULL, &next);
00098 else
00099 select(fd + 1, &selset, NULL, NULL, NULL);
00100 }
00101 }
00102
00103 Timer::Timer(long delay, Timer::TimeoutHandler action, void *data)
00104 : _delay(delay),
00105 _action(action),
00106 _data(data),
00107 _del_me(false),
00108 _last(_now),
00109 _timeout(_now)
00110 {
00111 timevalAdd(_timeout, delay);
00112 _q.push(this);
00113 }
00114
00115 void Timer::operator delete(void *self)
00116 {
00117 Timer *t;
00118 t = (Timer *)self;
00119 t->_del_me = true;
00120 }
00121
00122 void Timer::realDelete(Timer *me)
00123 {
00124 ::delete me;
00125 }
00126
00127 void Timer::initialize(void)
00128 {
00129 gettimeofday(&_now, NULL);
00130 _nearest_timeout.tv_sec = 100000;
00131 _nearest_timeout.tv_usec = 0;
00132 }
00133
00134 void Timer::destroy(void)
00135 {
00136 while(!_q.empty()) {
00137 realDelete(_q.top());
00138 _q.pop();
00139 }
00140 }
00141
00142 }