Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

/otk/timer.cc

Go to the documentation of this file.
00001 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
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     /* since we overload the destructor to keep from removing from the middle of 
00067        the priority queue, set _del_me, we have to do our real delete in here.
00068     */
00069     if (curr->_del_me) {
00070       _q.pop();
00071       realDelete(curr);
00072       continue;
00073     }
00074 
00075     // the queue is sorted, so if this timer shouldn't fire, none are ready
00076     _nearest_timeout = curr->_timeout;
00077     if (!timercmp(&_now, &_nearest_timeout, >))
00078       break;
00079 
00080     /* we set the last fired time to delay msec after the previous firing, then 
00081        re-insert.  timers maintain their order and may trigger more than once if 
00082        they've waited more than one delay's worth of time.
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     // wait for the nearest trigger, or for X to do something interesting
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 }

Generated on Tue Feb 4 22:58:56 2003 for Openbox by doxygen1.3-rc2