1 // -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 #include "timerqueue.h"
10 static PyObject *list = NULL; // PyListObject
12 void OtkTimerQueue_Initialize()
17 void OtkTimerQueue_Add(OtkTimer* timer)
19 PyList_Append(list, (PyObject*)timer);
23 void OtkTimerQueue_Remove(OtkTimer* timer)
27 index = PySequence_Index(list, (PyObject*)timer);
29 PySequence_DelItem(list, index);
32 static Bool shouldFire(OtkTimer *timer, const struct timeval *now)
34 return ! ((now->tv_sec < timer->end.tv_sec) ||
35 (now->tv_sec == timer->end.tv_sec &&
36 now->tv_usec < timer->end.tv_usec));
39 static void normalizeTimeval(struct timeval *time)
41 while (time->tv_usec < 0) {
42 if (time->tv_sec > 0) {
44 time->tv_usec += 1000000;
50 if (time->tv_usec >= 1000000) {
51 time->tv_sec += time->tv_usec / 1000000;
52 time->tv_usec %= 1000000;
55 if (time->tv_sec < 0) time->tv_sec = 0;
58 void OtkTimerQueue_Fire()
61 struct timeval now, tm, *timeout = NULL;
63 const int xfd = ConnectionNumber(OBDisplay->display);
66 FD_SET(xfd, &rfds); // break on any x events
68 // check for timer timeout
69 gettimeofday(&now, 0);
71 // there is a small chance for deadlock here:
72 // *IF* the timer list keeps getting refreshed *AND* the time between
73 // timer->start() and timer->shouldFire() is within the timer's period
74 // then the timer will keep firing. This should be VERY near impossible.
75 while (PyList_Size(list)) {
76 OtkTimer *timer = (OtkTimer*)PyList_GetItem(list, 0);
78 if (! shouldFire(timer, &now)) {
79 tm.tv_sec = timer->end.tv_sec - now.tv_sec;
80 tm.tv_usec = timer->end.tv_usec - now.tv_usec;
81 normalizeTimeval(&tm);
82 timeout = &tm; // set the timeout for the select
83 break; // go on and wait
86 // stop and remove the timer from the queue
87 PySequence_DelItem(list, 0);
88 timer->timing = False;
91 timer->handler(timer->data);
94 OtkTimer_Start(timer);
97 select(xfd + 1, &rfds, 0, 0, timeout);