kernel: scheduling fix for ARM
[minix.git] / lib / libddekit / src / timer.c
blob818fd419c4bb6e6610e0985909c0d0e354f4a60e
1 #include "common.h"
3 #include <ddekit/memory.h>
4 #include <ddekit/semaphore.h>
5 #include <ddekit/thread.h>
6 #include <ddekit/timer.h>
8 #ifdef DDEBUG_LEVEL_TIMER
9 #undef DDEBUG
10 #define DDEBUG DDEBUG_LEVEL_TIMER
11 #endif
13 #include "debug.h"
14 #include "thread.h"
16 #define DDEBUG_MSG_TIMER(t) \
17 DDEBUG_MSG_VERBOSE("id: %d, exp: %d, fn: %d, now %d", \
18 (t)->id, (t)->exp, (t)->fn, jiffies)
20 typedef clock_t myclock_t;
22 struct ddekit_timer_s {
23 void (*fn)(void *);
24 void *args;
25 int id;
26 myclock_t exp;
27 struct ddekit_timer_s * next;
31 static ddekit_sem_t *pending_timer_ints;
33 /* are we currently expecting a alarm notify? */
34 int _ddekit_timer_pending = 0;
36 unsigned long long jiffies;
37 unsigned long HZ;
39 static struct ddekit_timer_s list = {0,0,-1,1,0};
40 static int _id = 0 ;
41 static ddekit_thread_t *th;
42 static ddekit_lock_t lock;
44 static void lock_timer(void);
45 static void unlock_timer(void);
46 static clock_t get_current_clock(void);
47 static void remove_timer(int id);
48 static int insert_timer(struct ddekit_timer_s *t);
49 static struct ddekit_timer_s * get_next( myclock_t exp );
50 static void ddekit_timer_thread(void *data);
52 /****************************************************************************
53 * Private funtions *
54 ****************************************************************************/
56 /*****************************************************************************
57 * lock_timer *
58 ****************************************************************************/
59 static void lock_timer()
61 ddekit_lock_lock(&lock);
64 /*****************************************************************************
65 * unlock_timer *
66 ****************************************************************************/
67 static void unlock_timer()
69 ddekit_lock_unlock(&lock);
72 /*****************************************************************************
73 * get_current_clock *
74 ****************************************************************************/
75 static myclock_t get_current_clock()
77 /* returns the current clock tick */
78 myclock_t ret;
79 getuptime(&ret);
80 return ret;
83 /*****************************************************************************
84 * remove_timer *
85 ****************************************************************************/
86 static void remove_timer(int id)
88 /* removes a timer from the timer list */
89 struct ddekit_timer_s *l,*m;
91 lock_timer();
93 for (l = &list; l && l->next && l->next->id!=id; l = l->next )
96 if (l && l->next) {
97 m = l->next;
99 DDEBUG_MSG_VERBOSE(
100 "deleting timer at for tick: %d fn: %p, (now: %d)\n",
101 m->exp, m->fn, jiffies);
103 l->next = m->next;
104 DDEBUG_MSG_TIMER(m);
106 ddekit_simple_free(m);
109 unlock_timer();
112 /*****************************************************************************
113 * insert_timer *
114 ****************************************************************************/
115 static int insert_timer(struct ddekit_timer_s *t)
117 /* inserts a timer to the timer list */
118 int ret;
120 lock_timer();
122 struct ddekit_timer_s *l;
124 for (l = &list; l->next && l->next->exp <= t->exp; l = l->next) {
128 t->next = l->next;
129 l->next = t;
131 t->id = ret = _id;
133 _id++;
135 if (_id==0) {
136 DDEBUG_MSG_WARN("Timer ID overflow...");
139 DDEBUG_MSG_TIMER(t);
141 unlock_timer();
143 return ret;
146 /*****************************************************************************
147 * get_next *
148 ****************************************************************************/
149 static struct ddekit_timer_s * get_next( myclock_t exp )
152 * this one get the next timer, which's timeout expired,
153 * returns NULL if no timer is pending
155 struct ddekit_timer_s * ret = 0;
156 lock_timer();
157 if (list.next)
159 if (list.next->exp <= exp)
161 ret = list.next;
162 list.next = ret->next;
165 unlock_timer();
166 return ret;
169 /*****************************************************************************
170 * ddekit_timer_thread *
171 ****************************************************************************/
172 static void ddekit_timer_thread(void * data)
174 struct ddekit_timer_s * l;
176 /* rock around the clock! */
177 for ( ; ; )
179 /* wait for timer interrupts */
180 ddekit_sem_down(pending_timer_ints);
181 DDEBUG_MSG_VERBOSE("handling timer interrupt");
183 /* execute all expired timers */
184 while( (l = get_next(jiffies)) != 0 ) {
185 DDEBUG_MSG_TIMER(l);
186 if (l->fn) {
187 l->fn(l->args);
189 ddekit_simple_free(l);
195 /****************************************************************************
196 * Public functions (ddekit/timer.h) *
197 ****************************************************************************/
199 /*****************************************************************************
200 * ddekit_add_timer *
201 ****************************************************************************/
202 int ddekit_add_timer
203 (void (*fn)(void *), void *args, unsigned long timeout)
205 struct ddekit_timer_s *t;
207 t = (struct ddekit_timer_s *)
208 ddekit_simple_malloc(sizeof(struct ddekit_timer_s ));
210 t->fn = fn;
211 t->args = args;
212 t->exp = (myclock_t) timeout;
214 return insert_timer(t);
217 /*****************************************************************************
218 * ddekit_del_timer *
219 ****************************************************************************/
220 int ddekit_del_timer(int timer)
222 remove_timer(timer);
223 return 0;
226 /*****************************************************************************
227 * ddekit_timer_pending *
228 ****************************************************************************/
229 int ddekit_timer_pending(int timer)
231 int ret=0;
232 struct ddekit_timer_s *t;
233 lock_timer();
234 for (t=list.next; t; t = t->next) {
235 if (t->id==timer) {
236 ret = 1;
240 unlock_timer();
241 return ret;
244 /*****************************************************************************
245 * ddekit_init_timers *
246 ****************************************************************************/
247 void ddekit_init_timers(void)
249 static int first_time=0;
251 if (!first_time)
253 ddekit_lock_init(&lock);
254 jiffies = get_current_clock();
255 HZ = sys_hz();
256 pending_timer_ints = ddekit_sem_init(0);
257 th = ddekit_thread_create(ddekit_timer_thread, 0, "timer");
258 first_time=1;
259 DDEBUG_MSG_INFO("DDEkit timer subsustem initialized");
263 /*****************************************************************************
264 * ddekit_get_timer_thread *
265 ****************************************************************************/
266 ddekit_thread_t *ddekit_get_timer_thread(void)
268 return th;
271 /****************************************************************************
272 * ddekit_internal (src/timer.h) *
273 ****************************************************************************/
275 /*****************************************************************************
276 * _ddekit_timer_interrupt *
277 ****************************************************************************/
278 void _ddekit_timer_interrupt(void)
280 jiffies = get_current_clock();
281 DDEBUG_MSG_VERBOSE("now: %d", jiffies);
282 ddekit_sem_up(pending_timer_ints);
285 /*****************************************************************************
286 * _ddekit_timer_update *
287 ****************************************************************************/
288 void _ddekit_timer_update()
290 lock_timer();
292 static myclock_t next_timout;
293 if(list.next)
295 if(!_ddekit_timer_pending || list.next->exp < next_timout) {
297 unsigned to = list.next->exp - jiffies;
299 _ddekit_timer_pending = 1;
301 if (list.next->exp <= jiffies) {
302 DDEBUG_MSG_WARN("Timeout lies in past to %d, now: %d",
303 list.next->exp, jiffies);
304 to = 1;
307 sys_setalarm(to, 0 /* REL */);
309 DDEBUG_MSG_VERBOSE("requesting alarm for clock tick %d , now %d",
310 list.next->exp, jiffies);
312 next_timout = list.next->exp;
314 unlock_timer();