K2.6 patches and update.
[tomato.git] / release / src / router / shared / linux_timer.c
blobe3dc7da27358d43e42fcae882d81d19089d000de
1 /*
2 * Copyright (C) 2008, Broadcom Corporation
3 * All Rights Reserved.
4 *
5 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
6 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
7 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
8 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
10 * Low resolution timer interface linux specific implementation.
12 * $Id: linux_timer.c,v 1.14 2008/07/17 09:22:40 Exp $
15 // xref: nas,upnp
18 * debug facilities
20 #define TIMER_DEBUG 0 /* Turn off the debug */
21 #if TIMER_DEBUG
22 #define TIMERDBG(fmt, args...) printf("%s: " fmt "\n", __FUNCTION__ , ## args)
23 #else
24 #define TIMERDBG(fmt, args...)
25 #endif
29 * POSIX timer support for Linux. Taken from linux_timer.c in upnp
32 #define __USE_GNU
35 #include <stdlib.h> // for malloc, free, etc.
36 #include <string.h> // for memset, strncasecmp, etc.
37 #include <assert.h> // for assert, of course.
38 #include <signal.h> // for sigemptyset, etc.
39 #include <stdio.h> // for printf, etc.
40 #include <sys/time.h>
41 #include <time.h>
43 /* define TIMER_PROFILE to enable code which guages how accurate the timer functions are.
44 * For each expiring timer the code will print the expected time interval and the actual time
45 * interval.
46 * #define TIMER_PROFILE
48 #undef TIMER_PROFILE
51 timer_cancel( ) - cancel a timer
52 timer_connect( ) - connect a user routine to the timer signal
53 timer_create( ) - allocate a timer using the specified clock for a timing base (POSIX)
54 timer_delete( ) - remove a previously created timer (POSIX)
55 timer_gettime( ) - get the remaining time before expiration and the reload value (POSIX)
56 timer_getoverrun( ) - return the timer expiration overrun (POSIX)
57 timer_settime( ) - set the time until the next expiration and arm timer (POSIX)
58 nanosleep( ) - suspend the current task until the time interval elapses (POSIX)
61 #define MS_PER_SEC 1000 /* 1000ms per second */
62 #define US_PER_SEC 1000000 /* 1000000us per second */
63 #define US_PER_MS 1000 /* 1000us per ms */
64 #define UCLOCKS_PER_SEC 1000000 /* Clock ticks per second */
66 typedef void (*event_callback_t)(timer_t, int);
68 #ifdef BCMQT
69 uint htclkratio = 50;
70 static void TIMESPEC_TO_TIMEVAL(struct timeval *tv, const struct timespec *ts)
72 uint ms = (ts->tv_sec * 1000 + ts->tv_nsec / 1000000) * htclkratio;
73 tv->tv_sec = ms / 1000;
74 tv->tv_usec = (ms % 1000) * 1000;
76 static void TIMEVAL_TO_TIMESPEC(const struct timeval *tv, struct timespec *ts)
78 uint ms = (tv->tv_sec * 1000 + tv->tv_usec / 1000) / htclkratio;
79 ts->tv_sec = ms / 1000;
80 ts->tv_nsec = (ms % 1000) * 1000000;
82 #else /* BCMQT */
83 #ifndef TIMESPEC_TO_TIMEVAL
84 # define TIMESPEC_TO_TIMEVAL(tv, ts) { \
85 (tv)->tv_sec = (ts)->tv_sec; \
86 (tv)->tv_usec = (ts)->tv_nsec / 1000; \
88 #endif
90 #ifndef TIMEVAL_TO_TIMESPEC
91 # define TIMEVAL_TO_TIMESPEC(tv, ts) { \
92 (ts)->tv_sec = (tv)->tv_sec; \
93 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
95 #endif
96 #endif /* !BCMQT */
98 #define ROUNDUP(x, y) ((((x)+(y)-1)/(y))*(y))
100 #define timerroundup(t, g) \
101 do { \
102 if (!timerisset(t)) (t)->tv_usec = 1; \
103 if ((t)->tv_sec == 0) (t)->tv_usec = ROUNDUP((t)->tv_usec, g); \
104 } while (0)
106 typedef long uclock_t;
108 #define TFLAG_NONE 0
109 #define TFLAG_CANCELLED (1<<0)
110 #define TFLAG_DELETED (1<<1)
111 #define TFLAG_QUEUED (1<<2)
113 struct event {
114 struct timeval it_interval;
115 struct timeval it_value;
116 event_callback_t func;
117 int arg;
118 unsigned short flags;
119 struct event *next;
120 #ifdef TIMER_PROFILE
121 uint expected_ms;
122 uclock_t start;
123 #endif
126 void timer_cancel(timer_t timerid);
128 static void alarm_handler(int i);
129 static void check_event_queue();
130 static void print_event_queue();
131 static void check_timer();
132 #if THIS_FINDS_USE
133 static int count_queue(struct event *);
134 #endif
135 static int timer_change_settime(timer_t timer_id, const struct itimerspec *timer_spec);
136 void block_timer();
137 void unblock_timer();
139 static struct event *event_queue = NULL;
140 static struct event *event_freelist;
141 static uint g_granularity;
142 static int g_maxevents = 0;
144 #ifdef TIMER_PROFILE
145 uclock_t uclock()
147 struct timeval tv;
149 gettimeofday(&tv, NULL);
150 return ((tv.tv_sec * US_PER_SEC) + tv.tv_usec);
152 #endif
154 void init_event_queue(int n)
156 int i;
157 struct itimerval tv;
159 g_maxevents = n;
160 event_freelist = (struct event *) malloc(n * sizeof(struct event));
161 memset(event_freelist, 0, n * sizeof(struct event));
163 for (i = 0; i < (n-1); i++)
164 event_freelist[i].next = &event_freelist[i+1];
166 event_freelist[i].next = NULL;
168 tv.it_interval.tv_sec = 0;
169 tv.it_interval.tv_usec = 1;
170 tv.it_value.tv_sec = 0;
171 tv.it_value.tv_usec = 1;
173 signal(SIGALRM, alarm_handler);
175 setitimer(ITIMER_REAL, &tv, 0);
176 setitimer(ITIMER_REAL, 0, &tv);
177 g_granularity = tv.it_interval.tv_usec;
181 #if 0
182 int clock_gettime(
183 clockid_t clock_id, /* clock ID (always CLOCK_REALTIME) */
184 struct timespec * tp /* where to store current time */
187 struct timeval tv;
188 int n;
191 n = gettimeofday(&tv, NULL);
192 TIMEVAL_TO_TIMESPEC(&tv, tp);
194 return n;
196 #endif
199 int timer_create(
200 clockid_t clock_id, /* clock ID (always CLOCK_REALTIME) */
201 struct sigevent * evp, /* user event handler */
202 timer_t * pTimer /* ptr to return value */
205 struct event *event;
207 if (clock_id != CLOCK_REALTIME) {
208 TIMERDBG("timer_create can only support clock id CLOCK_REALTIME");
209 exit(1);
212 if (evp != NULL) {
213 if (evp->sigev_notify != SIGEV_SIGNAL || evp->sigev_signo != SIGALRM) {
214 TIMERDBG("timer_create can only support signalled alarms using SIGALRM");
215 exit(1);
219 event = event_freelist;
220 if (event == NULL) {
221 print_event_queue();
223 assert(event != NULL);
225 event->flags = TFLAG_NONE;
227 event_freelist = event->next;
228 event->next = NULL;
229 event->flags &= ~TFLAG_QUEUED;
231 check_event_queue();
233 *pTimer = (timer_t) event;
235 return 0;
238 int timer_delete(
239 timer_t timerid /* timer ID */
242 struct event *event = (struct event *) timerid;
244 if (event->flags & TFLAG_DELETED) {
245 TIMERDBG("Cannot delete a deleted event");
246 return 1;
249 timer_cancel(timerid);
251 event->flags |= TFLAG_DELETED;
253 event->next = event_freelist;
254 event_freelist = event;
256 return 0;
259 int timer_connect
261 timer_t timerid, /* timer ID */
262 void (*routine)(timer_t, int), /* user routine */
263 int arg /* user argument */
266 struct event *event = (struct event *) timerid;
268 assert(routine != NULL);
269 event->func = routine;
270 event->arg = arg;
272 return 0;
276 * Please Call this function only from the call back functions of the alarm_handler.
277 * This is just a hack
279 int timer_change_settime
281 timer_t timerid, /* timer ID */
282 const struct itimerspec * value /* time to be set */
285 struct event *event = (struct event *) timerid;
287 TIMESPEC_TO_TIMEVAL(&event->it_interval, &value->it_interval);
288 TIMESPEC_TO_TIMEVAL(&event->it_value, &value->it_value);
290 return 1;
293 int timer_settime
295 timer_t timerid, /* timer ID */
296 int flags, /* absolute or relative */
297 const struct itimerspec * value, /* time to be set */
298 struct itimerspec * ovalue /* previous time set (NULL=no result) */
301 struct itimerval itimer;
302 struct event *event = (struct event *) timerid;
303 struct event **ppevent;
305 TIMESPEC_TO_TIMEVAL(&event->it_interval, &value->it_interval);
306 TIMESPEC_TO_TIMEVAL(&event->it_value, &value->it_value);
308 /* if .it_value is zero, the timer is disarmed */
309 if (!timerisset(&event->it_value)) {
310 timer_cancel(timerid);
311 return 0;
314 block_timer();
316 #ifdef TIMER_PROFILE
317 event->expected_ms = (event->it_value.tv_sec * MS_PER_SEC) + (event->it_value.tv_usec /
318 US_PER_MS);
319 event->start = uclock();
320 #endif
321 if (event->next) {
322 TIMERDBG("calling timer_settime with a timer that is already on the queue.");
326 /* We always want to make sure that the event at the head of the
327 * queue has a timeout greater than the itimer granularity.
328 * Otherwise we end up with the situation that the time remaining
329 * on an itimer is greater than the time at the head of the queue
330 * in the first place.
332 timerroundup(&event->it_value, g_granularity);
334 timerclear(&itimer.it_value);
335 getitimer(ITIMER_REAL, &itimer);
336 if (timerisset(&itimer.it_value)) {
337 /* reset the top timer to have an interval equal to the remaining interval
338 * when the timer was cancelled.
340 if (event_queue) {
341 /* CSTYLED */
342 if (timercmp(&(itimer.it_value), &(event_queue->it_value), >)) {
343 /* it is an error if the amount of time remaining is more than the
344 * amount of time requested by the top event.
346 TIMERDBG("timer_settime: TIMER ERROR!");
348 } else {
349 /* some portion of the top event has already expired.
350 * Reset the interval of the top event to remaining
351 * time left in that interval.
353 event_queue->it_value = itimer.it_value;
355 /* if we were the earliest timer before now, we are still the
356 * earliest timer now. we do not need to reorder the list.
362 /* Now, march down the list, decrementing the new timer by the
363 * current it_value of each event on the queue.
365 ppevent = &event_queue;
366 while (*ppevent) {
367 /* CSTYLED */
368 if (timercmp(&(event->it_value), &((*ppevent)->it_value), <)) {
369 /* if the proposed event will trigger sooner than the next event
370 * in the queue, we will insert the new event just before the next one.
371 * we also need to adjust the delta value to the next event.
373 timersub(&((*ppevent)->it_value), &(event->it_value),
374 &((*ppevent)->it_value));
375 break;
377 /* subtract the interval of the next event from the proposed interval. */
378 timersub(&(event->it_value), &((*ppevent)->it_value), &(event->it_value));
380 ppevent = &((*ppevent)->next);
383 /* we have found our proper place in the queue, */
384 /* link our new event into the pending event queue. */
385 event->next = *ppevent;
386 *ppevent = event;
388 check_event_queue();
390 /* if our new event ended up at the front of the queue, reissue the timer. */
391 if (event == event_queue) {
392 timerroundup(&event_queue->it_value, g_granularity);
393 timerclear(&itimer.it_interval);
394 itimer.it_value = event_queue->it_value;
396 /* we want to be sure to never turn off the timer completely, */
397 /* so if the next interval is zero, set it to some small value. */
398 if (!timerisset(&(itimer.it_value)))
399 itimer.it_value = (struct timeval) { 0, 1 };
401 assert(!timerisset(&itimer.it_interval));
402 assert(itimer.it_value.tv_sec > 0 || itimer.it_value.tv_usec >= g_granularity);
403 assert(event_queue->it_value.tv_sec > 0 || event_queue->it_value.tv_usec >=
404 g_granularity);
405 setitimer(ITIMER_REAL, &itimer, NULL);
406 check_timer();
409 event->flags &= ~TFLAG_CANCELLED;
410 event->flags |= TFLAG_QUEUED;
412 unblock_timer();
414 return 0;
417 static void check_timer()
419 struct itimerval itimer;
421 getitimer(ITIMER_REAL, &itimer);
422 if (timerisset(&itimer.it_interval)) {
423 TIMERDBG("ERROR timer interval is set.");
425 /* CSTYLED */
426 if (timercmp(&(itimer.it_value), &(event_queue->it_value), >)) {
427 TIMERDBG("ERROR timer expires later than top event.");
432 static void check_event_queue()
434 struct timeval sum;
435 struct event *event;
436 int i = 0;
438 #ifdef notdef
439 int nfree = 0;
440 struct event *p;
441 for (p = event_freelist; p; p = p->next)
442 nfree++;
443 printf("%d free events\n", nfree);
444 #endif
446 timerclear(&sum);
447 for (event = event_queue; event; event = event->next) {
448 if (i > g_maxevents) {
449 TIMERDBG("timer queue looks like it loops back on itself!");
450 print_event_queue();
451 exit(1);
453 i++;
457 #if THIS_FINDS_USE
458 /* The original upnp version has this unused function, so I left it in
459 * to maintain the resemblance.
461 static int count_queue(struct event *event_queue)
463 struct event *event;
464 int i = 0;
465 for (event = event_queue; event; event = event->next)
466 i++;
467 return i;
469 #endif
471 static void print_event_queue()
473 struct event *event;
474 int i = 0;
476 for (event = event_queue; event; event = event->next) {
477 printf("#%d (0x%x)->0x%x: \t%d sec %d usec\t%p\n",
478 i++, (unsigned int) event, (unsigned int) event->next, (int)
479 event->it_value.tv_sec,
480 (int) event->it_value.tv_usec, event->func);
481 if (i > g_maxevents) {
482 printf("...(giving up)\n");
483 break;
488 /* The top element of the event queue must have expired. */
489 /* Remove that element, run its function, and reset the timer. */
490 /* if there is no interval, recycle the event structure. */
491 static void alarm_handler(int i)
493 struct event *event, **ppevent;
494 struct itimerval itimer;
495 struct timeval small_interval = { 0, g_granularity/2 };
496 #ifdef TIMER_PROFILE
497 uint junk;
498 uclock_t end;
499 uint actual;
500 #endif
502 block_timer();
504 /* Loop through the event queue and remove the first event plus any */
505 /* subsequent events that will expire very soon thereafter (within 'small_interval'}. */
506 /* */
507 do {
508 /* remove the top event. */
509 event = event_queue;
510 event_queue = event_queue->next;
511 event->next = NULL;
513 #ifdef TIMER_PROFILE
514 end = uclock();
515 actual = ((end-event->start)/((uclock_t)UCLOCKS_PER_SEC/1000));
516 if (actual < 0)
517 junk = end;
518 TIMERDBG("expected %d ms actual %d ms", event->expected_ms,
519 ((end-event->start)/((uclock_t)UCLOCKS_PER_SEC/1000)));
520 #endif
522 /* call the event callback function */
523 (*(event->func))((timer_t) event, (int)event->arg);
525 /* If the event has been cancelled, do NOT put it back on the queue. */
526 /* Check for TFLAG_QUEUED is to avoid pathologic case, when after
527 * dequeueing event handler deletes its own timer and allocates new one
528 * which (at least in some cases) gets the same pointer and thus its
529 * 'flags' will be rewritten, most notably TFLAG_CANCELLED, and, to
530 * complete the disaster, it will be queued. alarm_handler tries to
531 * enqueue 'event' (which is on the same memory position as newly
532 * allocated timer), which results in queueing the same pointer once
533 * more. And this way, loop in event queue is created. */
534 if (!(event->flags & TFLAG_CANCELLED) && !(event->flags & TFLAG_QUEUED)) {
536 /* if the event is a recurring event, reset the timer and
537 * find its correct place in the sorted list of events.
539 if (timerisset(&event->it_interval)) {
540 /* event is recurring... */
541 event->it_value = event->it_interval;
542 #ifdef TIMER_PROFILE
543 event->expected_ms = (event->it_value.tv_sec * MS_PER_SEC) +
544 (event->it_value.tv_usec / US_PER_MS);
545 event->start = uclock();
546 #endif
547 timerroundup(&event->it_value, g_granularity);
549 /* Now, march down the list, decrementing the new timer by the */
550 /* current delta of each event on the queue. */
551 ppevent = &event_queue;
552 while (*ppevent) {
553 if (timercmp(&(event->it_value), &((*ppevent)->it_value),
554 /* CSTYLED */
555 <)) {
556 /* if the proposed event will trigger sooner than
557 * the next event
558 * in the queue, we will insert the new event just
559 * before the next one.
560 * we also need to adjust the delta value to the
561 * next event.
563 timersub(&((*ppevent)->it_value),
564 &(event->it_value),
565 &((*ppevent)->it_value));
566 break;
568 timersub(&(event->it_value), &((*ppevent)->it_value),
569 &(event->it_value));
570 ppevent = &((*ppevent)->next);
573 /* we have found our proper place in the queue, */
574 /* link our new event into the pending event queue. */
575 event->next = *ppevent;
576 *ppevent = event;
577 event->flags |= TFLAG_QUEUED;
578 } else {
579 /* there is no interval, so recycle the event structure.
580 * timer_delete((timer_t) event);
585 check_event_queue();
587 /* CSTYLED */
588 } while (event_queue && timercmp(&event_queue->it_value, &small_interval, <));
590 /* re-issue the timer... */
591 if (event_queue) {
592 timerroundup(&event_queue->it_value, g_granularity);
594 timerclear(&itimer.it_interval);
595 itimer.it_value = event_queue->it_value;
596 /* we want to be sure to never turn off the timer completely, */
597 /* so if the next interval is zero, set it to some small value. */
598 if (!timerisset(&(itimer.it_value)))
599 itimer.it_value = (struct timeval) { 0, 1 };
601 setitimer(ITIMER_REAL, &itimer, NULL);
602 check_timer();
603 } else {
604 TIMERDBG("There are no events in the queue - timer not reset.");
607 unblock_timer();
610 static int block_count = 0;
612 void block_timer()
614 sigset_t set;
616 if (block_count++ == 0) {
617 sigemptyset(&set);
618 sigaddset(&set, SIGALRM);
619 sigprocmask(SIG_BLOCK, &set, NULL);
623 void unblock_timer()
625 sigset_t set;
627 if (--block_count == 0) {
628 sigemptyset(&set);
629 sigaddset(&set, SIGALRM);
630 sigprocmask(SIG_UNBLOCK, &set, NULL);
634 void timer_cancel_all()
636 struct itimerval timeroff = { { 0, 0 }, { 0, 0} };
637 struct event *event;
638 struct event **ppevent;
640 setitimer(ITIMER_REAL, &timeroff, NULL);
642 ppevent = &event_queue;
643 while (*ppevent) {
644 event = *ppevent;
645 *ppevent = event->next;
646 event->next = NULL;
651 void timer_cancel(timer_t timerid)
653 struct itimerval itimer;
654 struct itimerval timeroff = { { 0, 0 }, { 0, 0} };
655 struct event *event = (struct event *) timerid;
656 struct event **ppevent;
658 if (event->flags & TFLAG_CANCELLED) {
659 TIMERDBG("Cannot cancel a cancelled event");
660 return;
663 block_timer();
665 ppevent = &event_queue;
666 while (*ppevent) {
667 if (*ppevent == event) {
669 /* RACE CONDITION - if the alarm goes off while we are in
670 * this loop, and if the timer we want to cancel is the
671 * next to expire, the alarm will end up firing
672 * after this routine is complete, causing it to go off early.
675 /* If the cancelled timer is the next to expire,
676 * we need to do something special to clean up correctly.
678 if (event == event_queue && event->next != NULL) {
679 timerclear(&itimer.it_value);
680 getitimer(ITIMER_REAL, &itimer);
682 /* subtract the time that has already passed while waiting for this
683 * timer...
685 timersub(&(event->it_value), &(itimer.it_value),
686 &(event->it_value));
688 /* and add any remainder to the next timer in the list */
689 timeradd(&(event->next->it_value), &(event->it_value),
690 &(event->next->it_value));
693 *ppevent = event->next;
694 event->next = NULL;
696 if (event_queue) {
697 timerroundup(&event_queue->it_value, g_granularity);
698 timerclear(&itimer.it_interval);
699 itimer.it_value = event_queue->it_value;
701 /* We want to be sure to never turn off the timer
702 * completely if there are more events on the queue,
703 * so if the next interval is zero, set it to some
704 * small value.
707 if (!timerisset(&(itimer.it_value)))
708 itimer.it_value = (struct timeval) { 0, 1 };
710 assert(itimer.it_value.tv_sec > 0 || itimer.it_value.tv_usec >=
711 g_granularity);
712 assert(event_queue->it_value.tv_sec > 0 ||
713 event_queue->it_value.tv_usec >=
714 g_granularity);
715 setitimer(ITIMER_REAL, &itimer, NULL);
716 check_timer();
717 } else {
718 setitimer(ITIMER_REAL, &timeroff, NULL);
720 break;
722 ppevent = &((*ppevent)->next);
725 event->flags |= TFLAG_CANCELLED;
727 unblock_timer();
731 * timer related headers
733 #include "bcmtimer.h"
736 * locally used global variables and constants
740 * Initialize internal resources used in the timer module. It must be called
741 * before any other timer function calls. The param 'timer_entries' is used
742 * to pre-allocate fixed number of timer entries.
744 int bcm_timer_module_init(int timer_entries, bcm_timer_module_id *module_id)
746 init_event_queue(timer_entries);
747 *module_id = (bcm_timer_module_id)event_freelist;
748 return 0;
752 * Cleanup internal resources used by this timer module. It deletes all
753 * pending timer entries from the backend timer system as well.
755 int bcm_timer_module_cleanup(bcm_timer_module_id module_id)
757 module_id = 0;
758 return 0;
761 /* Enable/Disable timer module */
762 int bcm_timer_module_enable(bcm_timer_module_id module_id, int enable)
764 if (enable)
765 unblock_timer();
766 else
767 block_timer();
768 return 0;
771 int bcm_timer_create(bcm_timer_module_id module_id, bcm_timer_id *timer_id)
773 // module_id = 0;
774 return timer_create(CLOCK_REALTIME, NULL, (timer_t *)timer_id);
777 int bcm_timer_delete(bcm_timer_id timer_id)
779 return timer_delete((timer_t)timer_id);
782 int bcm_timer_gettime(bcm_timer_id timer_id, struct itimerspec *timer_spec)
784 return -1;
787 int bcm_timer_settime(bcm_timer_id timer_id, const struct itimerspec *timer_spec)
789 return timer_settime((timer_t)timer_id, 0, timer_spec, NULL);
792 int bcm_timer_connect(bcm_timer_id timer_id, bcm_timer_cb func, int data)
794 return timer_connect((timer_t)timer_id, (void *)func, data);
797 int bcm_timer_cancel(bcm_timer_id timer_id)
799 timer_cancel((timer_t)timer_id);
800 return 0;
802 int bcm_timer_change_expirytime(bcm_timer_id timer_id, const struct itimerspec *timer_spec)
804 timer_change_settime((timer_t)timer_id, timer_spec);
805 return 1;