finally move buildroot-ng to trunk
[openwrt.git] / package / nvram / src / linux_timer.c
1 /*
2  * Copyright 2004, 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.
9  *
10  * Low resolution timer interface linux specific implementation.
11  *
12  * $Id$
13  */
14
15 /*
16 * debug facilities
17 */
18 #define TIMER_DEBUG     0
19 #if TIMER_DEBUG
20 #define TIMERDBG(fmt, args...) printf("%s: " fmt "\n" , __FUNCTION__ , ## args)
21 #else
22 #define TIMERDBG(fmt, args...)
23 #endif
24
25
26 /*
27  * POSIX timer support for Linux. Taken from linux_timer.c in upnp
28  */
29
30 #define __USE_GNU
31
32
33 #include <stdlib.h>         // for malloc, free, etc.
34 #include <string.h>         // for memset, strncasecmp, etc.
35 #include <assert.h>         // for assert, of course.
36 #include <signal.h>         // for sigemptyset, etc.
37 #include <stdio.h>          // for printf, etc.
38 #include <sys/time.h>
39 #include <time.h>
40
41 /* define TIMER_PROFILE to enable code which guages how accurate the timer functions are.
42    For each expiring timer the code will print the expected time interval and the actual time interval.
43 #define TIMER_PROFILE
44 */
45 #undef TIMER_PROFILE
46
47 /*
48 timer_cancel( ) - cancel a timer
49 timer_connect( ) - connect a user routine to the timer signal
50 timer_create( ) - allocate a timer using the specified clock for a timing base (POSIX)
51 timer_delete( ) - remove a previously created timer (POSIX)
52 timer_gettime( ) - get the remaining time before expiration and the reload value (POSIX)
53 timer_getoverrun( ) - return the timer expiration overrun (POSIX)
54 timer_settime( ) - set the time until the next expiration and arm timer (POSIX)
55 nanosleep( ) - suspend the current task until the time interval elapses (POSIX)
56 */
57
58 #define MS_PER_SEC 1000
59 #define US_PER_SEC 1000000
60 #define US_PER_MS  1000
61 #define UCLOCKS_PER_SEC 1000000
62
63 typedef void (*event_callback_t)(timer_t, int);
64
65 #ifndef TIMESPEC_TO_TIMEVAL
66 # define TIMESPEC_TO_TIMEVAL(tv, ts) {                                   \
67         (tv)->tv_sec = (ts)->tv_sec;                                    \
68         (tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
69 }
70 #endif
71
72 #ifndef TIMEVAL_TO_TIMESPEC
73 # define TIMEVAL_TO_TIMESPEC(tv, ts) {                                   \
74         (ts)->tv_sec = (tv)->tv_sec;                                    \
75         (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
76 }
77 #endif
78
79 #define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y))
80
81 #define timerroundup(t,g) \
82     do { \
83         if (!timerisset(t)) (t)->tv_usec=1; \
84         if ((t)->tv_sec == 0) (t)->tv_usec=ROUNDUP((t)->tv_usec, g); \
85     } while (0)
86
87 typedef long uclock_t;
88
89 #define TFLAG_NONE      0
90 #define TFLAG_CANCELLED (1<<0)
91 #define TFLAG_DELETED   (1<<1)
92
93 struct event {
94     struct timeval it_interval;
95     struct timeval it_value;
96     event_callback_t func;
97     int arg;
98     unsigned short flags;
99     struct event *next;
100 #ifdef TIMER_PROFILE
101     uint expected_ms;
102     uclock_t start;
103 #endif
104 };
105
106 void timer_cancel(timer_t timerid);
107
108 static void alarm_handler(int i);
109 static void check_event_queue();
110 static void print_event_queue();
111 static void check_timer();
112 #if THIS_FINDS_USE
113 static int count_queue(struct event *);
114 #endif
115 static int timer_change_settime(timer_t timer_id, const struct itimerspec *timer_spec);
116 void block_timer();
117 void unblock_timer();
118
119 static struct event *event_queue = NULL;
120 static struct event *event_freelist;
121 static uint g_granularity;
122 static int g_maxevents = 0;
123
124 uclock_t uclock()
125 {
126     struct timeval tv;
127
128     gettimeofday(&tv, NULL);
129     return ((tv.tv_sec * US_PER_SEC) + tv.tv_usec);
130 }
131
132
133 void init_event_queue(int n)
134 {
135     int i;
136     struct itimerval tv;
137     
138     g_maxevents = n;
139     event_freelist = (struct event *) malloc(n * sizeof(struct event));
140     memset(event_freelist, 0, n * sizeof(struct event));
141
142     for (i = 0; i < (n-1); i++) 
143         event_freelist[i].next = &event_freelist[i+1];
144
145     event_freelist[i].next = NULL;
146
147     tv.it_interval.tv_sec = 0;
148     tv.it_interval.tv_usec = 1;
149     tv.it_value.tv_sec = 0;
150     tv.it_value.tv_usec = 0;
151     setitimer (ITIMER_REAL, &tv, 0);
152     setitimer (ITIMER_REAL, 0, &tv);
153     g_granularity = tv.it_interval.tv_usec;
154
155     signal(SIGALRM, alarm_handler);
156 }
157
158
159 int clock_gettime(
160     clockid_t         clock_id, /* clock ID (always CLOCK_REALTIME) */
161     struct timespec * tp        /* where to store current time */
162 )
163 {
164     struct timeval tv;
165     int n;
166
167
168     n = gettimeofday(&tv, NULL);
169     TIMEVAL_TO_TIMESPEC(&tv, tp);
170     
171     return n;
172 }
173
174
175 int timer_create(
176     clockid_t         clock_id, /* clock ID (always CLOCK_REALTIME) */
177     struct sigevent * evp,      /* user event handler */
178     timer_t *         pTimer    /* ptr to return value */
179 )
180 {
181     struct event *event;
182
183     if (clock_id != CLOCK_REALTIME) {
184         TIMERDBG("timer_create can only support clock id CLOCK_REALTIME");
185         exit(1);
186     }
187
188     if (evp != NULL) {
189         if (evp->sigev_notify != SIGEV_SIGNAL || evp->sigev_signo != SIGALRM) {
190             TIMERDBG("timer_create can only support signalled alarms using SIGALRM");
191             exit(1);
192         }
193     }
194
195     event = event_freelist;
196     if (event == NULL) {
197         print_event_queue();
198     }
199     assert(event != NULL);
200
201     event->flags = TFLAG_NONE;
202     
203     event_freelist = event->next;
204     event->next = NULL;
205
206     check_event_queue();
207
208     *pTimer = (timer_t) event;
209
210     return 0;
211 }
212
213 int timer_delete(
214     timer_t timerid /* timer ID */
215 )
216 {
217     struct event *event = (struct event *) timerid;
218     
219     if (event->flags & TFLAG_DELETED) {
220         TIMERDBG("Cannot delete a deleted event");
221         return 1;
222     }
223
224     timer_cancel(timerid);
225     
226     event->flags |= TFLAG_DELETED;
227
228     event->next = event_freelist;
229     event_freelist = event;
230
231     return 0;
232 }
233
234 int timer_connect
235 (
236     timer_t     timerid, /* timer ID */
237     void (*routine)(timer_t, int), /* user routine */
238     int         arg      /* user argument */
239 )
240 {
241     struct event *event = (struct event *) timerid;
242
243     assert(routine != NULL);
244     event->func = routine;
245     event->arg = arg;
246     
247     return 0;
248 }    
249
250 /* 
251  * Please Call this function only from the call back functions of the alarm_handler.
252  * This is just a hack 
253 */
254 int timer_change_settime
255 (
256     timer_t                   timerid, /* timer ID */
257     const struct itimerspec * value   /* time to be set */
258 )
259 {
260     struct event *event = (struct event *) timerid;
261
262     TIMESPEC_TO_TIMEVAL(&event->it_interval, &value->it_interval);
263     TIMESPEC_TO_TIMEVAL(&event->it_value, &value->it_value);
264
265     return 1;   
266 }
267
268 int timer_settime
269 (
270     timer_t                   timerid, /* timer ID */
271     int                       flags,   /* absolute or relative */
272     const struct itimerspec * value,   /* time to be set */
273     struct itimerspec *       ovalue   /* previous time set (NULL=no result) */
274 )
275 {
276     struct itimerval itimer;
277     struct event *event = (struct event *) timerid;
278     struct event **ppevent;
279
280     TIMESPEC_TO_TIMEVAL(&event->it_interval, &value->it_interval);
281     TIMESPEC_TO_TIMEVAL(&event->it_value, &value->it_value);
282
283     /* if .it_value is zero, the timer is disarmed */
284     if (!timerisset(&event->it_value)) {
285         timer_cancel(timerid);
286         return 0;
287     }
288
289     block_timer();
290
291 #ifdef TIMER_PROFILE
292     event->expected_ms = (event->it_value.tv_sec * MS_PER_SEC) + (event->it_value.tv_usec / US_PER_MS);
293     event->start = uclock();
294 #endif
295     if (event->next) {
296         TIMERDBG("calling timer_settime with a timer that is already on the queue.");
297     }
298
299
300     /* We always want to make sure that the event at the head of the
301        queue has a timeout greater than the itimer granularity.
302        Otherwise we end up with the situation that the time remaining
303        on an itimer is greater than the time at the head of the queue
304        in the first place. */
305     timerroundup(&event->it_value, g_granularity);
306
307     timerclear(&itimer.it_value);
308     getitimer(ITIMER_REAL, &itimer);
309     if (timerisset(&itimer.it_value)) {
310         // reset the top timer to have an interval equal to the remaining interval 
311         // when the timer was cancelled.
312         if (event_queue) {
313             if (timercmp(&(itimer.it_value), &(event_queue->it_value), >)) {
314                 // it is an error if the amount of time remaining is more than the amount of time 
315                 // requested by the top event.
316                 //
317                 TIMERDBG("timer_settime: TIMER ERROR!");
318
319             } else {
320                 // some portion of the top event has already expired.
321                 // Reset the interval of the top event to remaining
322                 // time left in that interval.
323                 //
324                 event_queue->it_value = itimer.it_value;
325
326                 // if we were the earliest timer before now, we are still the earliest timer now.
327                 // we do not need to reorder the list.
328             }
329         }
330     }
331
332     // Now, march down the list, decrementing the new timer by the
333     // current it_value of each event on the queue.
334     ppevent = &event_queue;
335     while (*ppevent) {
336         if ( timercmp(&(event->it_value), &((*ppevent)->it_value), <) ) {
337             // if the proposed event will trigger sooner than the next event
338             // in the queue, we will insert the new event just before the next one.
339             //
340             // we also need to adjust the delta value to the next event.
341             timersub(&((*ppevent)->it_value), &(event->it_value), &((*ppevent)->it_value));
342             break;
343         }
344         // subtract the interval of the next event from the proposed interval.
345         timersub(&(event->it_value), &((*ppevent)->it_value), &(event->it_value));
346
347         ppevent = &((*ppevent)->next);
348     }
349     
350     // we have found our proper place in the queue, 
351     // link our new event into the pending event queue.
352     event->next = *ppevent;
353     *ppevent = event;
354
355     check_event_queue();
356
357     // if our new event ended up at the front of the queue, reissue the timer.
358     if (event == event_queue) {
359         timerroundup(&event_queue->it_value, g_granularity);
360         timerclear(&itimer.it_interval);
361         itimer.it_value = event_queue->it_value;
362         
363         // we want to be sure to never turn off the timer completely, 
364         // so if the next interval is zero, set it to some small value.
365         if (!timerisset(&(itimer.it_value)))
366             itimer.it_value = (struct timeval) { 0, 1 };
367         
368         assert(!timerisset(&itimer.it_interval));
369         assert(itimer.it_value.tv_sec > 0 || itimer.it_value.tv_usec >= g_granularity);
370         assert(event_queue->it_value.tv_sec > 0 || event_queue->it_value.tv_usec >= g_granularity);
371         setitimer(ITIMER_REAL, &itimer, NULL);
372         check_timer();
373     }
374
375     event->flags &= ~TFLAG_CANCELLED;
376     
377     unblock_timer();
378
379     return 0;
380 }
381
382 static void check_timer()
383 {
384     struct itimerval itimer;
385     
386     getitimer(ITIMER_REAL, &itimer);
387     if (timerisset(&itimer.it_interval)) {
388         TIMERDBG("ERROR timer interval is set.");
389     }
390     if (timercmp(&(itimer.it_value), &(event_queue->it_value), >)) {
391         TIMERDBG("ERROR timer expires later than top event.");
392     }
393 }
394
395
396 static void check_event_queue()
397 {
398     struct timeval sum;
399     struct event *event;
400     int i = 0;
401
402 #ifdef notdef
403     int nfree = 0;
404     struct event *p;
405     for (p = event_freelist; p; p = p->next)
406         nfree++;
407     printf("%d free events\n", nfree);
408 #endif
409     
410     timerclear(&sum);
411     for (event = event_queue; event; event = event->next) {
412         if (i > g_maxevents) {
413             TIMERDBG("timer queue looks like it loops back on itself!");
414             print_event_queue();
415             exit(1);
416         }
417         i++;
418     }
419 }
420
421 #if THIS_FINDS_USE
422 /* The original upnp version has this unused function, so I left it in
423    to maintain the resemblance. */
424 static int count_queue(struct event *event_queue)
425 {
426     struct event *event;
427     int i = 0;
428     for (event = event_queue; event; event = event->next) 
429         i++;
430     return i;
431 }
432 #endif
433
434 static void print_event_queue()
435 {
436     struct event *event;
437     int i = 0;
438
439     for (event = event_queue; event; event = event->next) {
440         printf("#%d (0x%x)->0x%x: \t%d sec %d usec\t%p\n", 
441                i++, (unsigned int) event, (unsigned int) event->next, (int) event->it_value.tv_sec, (int) event->it_value.tv_usec, event->func);
442         if (i > g_maxevents) {
443             printf("...(giving up)\n");
444             break;
445         }
446     }
447 }
448
449 // The top element of the event queue must have expired.
450 // Remove that element, run its function, and reset the timer.
451 // if there is no interval, recycle the event structure.
452 static void alarm_handler(int i)
453 {
454     struct event *event, **ppevent;
455     struct itimerval itimer;
456     struct timeval small_interval = { 0, g_granularity/2 };
457 #ifdef TIMER_PROFILE
458     uint junk;
459     uclock_t end;
460     uint actual;
461 #endif
462
463     block_timer();
464
465     // Loop through the event queue and remove the first event plus any 
466     // subsequent events that will expire very soon thereafter (within 'small_interval'}.
467     //
468     do {
469         // remove the top event.
470         event = event_queue;
471         event_queue = event_queue->next;
472         event->next = NULL;
473
474 #ifdef TIMER_PROFILE
475         end = uclock();
476         actual = ((end-event->start)/((uclock_t)UCLOCKS_PER_SEC/1000));
477         if (actual < 0)
478             junk = end;
479         TIMERDBG("expected %d ms  actual %d ms", event->expected_ms, ((end-event->start)/((uclock_t)UCLOCKS_PER_SEC/1000)));
480 #endif
481         
482             // call the event callback function
483             (*(event->func))((timer_t) event, (int)event->arg);
484
485         /* If the event has been cancelled, do NOT put it back on the queue. */
486         if ( !(event->flags & TFLAG_CANCELLED) ) {
487
488             // if the event is a recurring event, reset the timer and
489             // find its correct place in the sorted list of events.
490             //
491             if (timerisset(&event->it_interval)) {
492                 // event is recurring...
493                 //
494                 event->it_value = event->it_interval;
495 #ifdef TIMER_PROFILE
496                 event->expected_ms = (event->it_value.tv_sec * MS_PER_SEC) + (event->it_value.tv_usec / US_PER_MS);
497                 event->start = uclock();
498 #endif
499                 timerroundup(&event->it_value, g_granularity);
500
501                 // Now, march down the list, decrementing the new timer by the
502                 // current delta of each event on the queue.
503                 ppevent = &event_queue;
504                 while (*ppevent) {
505                     if ( timercmp(&(event->it_value), &((*ppevent)->it_value), <) ) {
506                         // if the proposed event will trigger sooner than the next event
507                         // in the queue, we will insert the new event just before the next one.
508                         //
509                         // we also need to adjust the delta value to the next event.
510                         timersub(&((*ppevent)->it_value), &(event->it_value), &((*ppevent)->it_value));
511                         break;
512                     }
513                     timersub(&(event->it_value), &((*ppevent)->it_value), &(event->it_value));
514                     ppevent = &((*ppevent)->next);
515                 }
516
517                 // we have found our proper place in the queue, 
518                 // link our new event into the pending event queue.
519                 event->next = *ppevent;
520                 *ppevent = event;
521             } else {
522                 // there is no interval, so recycle the event structure.
523                 //timer_delete((timer_t) event);
524             }
525         }
526
527         check_event_queue();
528         
529     } while (event_queue && timercmp(&event_queue->it_value, &small_interval, <));
530     
531     // re-issue the timer...
532     if (event_queue) {
533         timerroundup(&event_queue->it_value, g_granularity);
534
535         timerclear(&itimer.it_interval);
536         itimer.it_value = event_queue->it_value;
537         // we want to be sure to never turn off the timer completely, 
538         // so if the next interval is zero, set it to some small value.
539         if (!timerisset(&(itimer.it_value)))
540             itimer.it_value = (struct timeval) { 0, 1 };
541
542         setitimer(ITIMER_REAL, &itimer, NULL);
543         check_timer();
544     } else {
545         TIMERDBG("There are no events in the queue - timer not reset.");
546     }
547
548     unblock_timer();
549 }
550
551 static int block_count = 0;
552
553 void block_timer()
554 {
555     sigset_t set;
556
557     if (block_count++ == 0) {
558         sigemptyset(&set);
559         sigaddset(&set, SIGALRM);
560         sigprocmask(SIG_BLOCK, &set, NULL);
561     }
562 }
563
564 void unblock_timer()
565 {
566     sigset_t set;
567
568     if (--block_count == 0) {
569         sigemptyset(&set);
570         sigaddset(&set, SIGALRM);
571         sigprocmask(SIG_UNBLOCK, &set, NULL);
572     }
573 }
574
575 void timer_cancel_all()
576 {
577     struct itimerval timeroff = { { 0, 0 }, { 0, 0} };
578     struct event *event;
579     struct event **ppevent;
580
581     setitimer(ITIMER_REAL, &timeroff, NULL);
582
583     ppevent = &event_queue;
584     while (*ppevent) {
585         event = *ppevent;
586         *ppevent = event->next;
587         event->next = NULL;
588     }
589 }
590
591
592
593 void timer_cancel(timer_t timerid)
594 {
595     struct itimerval itimer;
596     struct itimerval timeroff = { { 0, 0 }, { 0, 0} };
597     struct event *event = (struct event *) timerid;
598     struct event **ppevent;
599
600     if (event->flags & TFLAG_CANCELLED) {
601         TIMERDBG("Cannot cancel a cancelled event");
602         return;
603     }
604
605     block_timer();
606     
607     ppevent = &event_queue;
608     while (*ppevent) {
609         if ( *ppevent == event ) {
610
611             /* RACE CONDITION - if the alarm goes off while we are in
612                this loop, and if the timer we want to cancel is the
613                next to expire, the alarm will end up firing
614                after this routine is complete, causing it to go off early. */
615
616             /* If the cancelled timer is the next to expire, 
617                we need to do something special to clean up correctly. */
618             if (event == event_queue && event->next != NULL) {
619                 timerclear(&itimer.it_value);
620                 getitimer(ITIMER_REAL, &itimer);
621                 
622                 /* subtract the time that has already passed while waiting for this timer... */
623                 timersub(&(event->it_value), &(itimer.it_value), &(event->it_value));
624
625                 /* and add any remainder to the next timer in the list */
626                 timeradd(&(event->next->it_value), &(event->it_value), &(event->next->it_value));
627             }
628
629             *ppevent = event->next;
630             event->next = NULL;
631
632             if (event_queue) {
633                 timerroundup(&event_queue->it_value, g_granularity);
634                 timerclear(&itimer.it_interval);
635                 itimer.it_value = event_queue->it_value;
636                 
637                 /* We want to be sure to never turn off the timer
638                    completely if there are more events on the queue,
639                    so if the next interval is zero, set it to some
640                    small value.  */
641
642                 if (!timerisset(&(itimer.it_value)))
643                     itimer.it_value = (struct timeval) { 0, 1 };
644                 
645                 assert(itimer.it_value.tv_sec > 0 || itimer.it_value.tv_usec >= g_granularity);
646                 assert(event_queue->it_value.tv_sec > 0 || event_queue->it_value.tv_usec >= g_granularity);
647                 setitimer(ITIMER_REAL, &itimer, NULL);
648                 check_timer();
649             } else {
650                 setitimer(ITIMER_REAL, &timeroff, NULL);
651             }
652             break;
653         }
654         ppevent = &((*ppevent)->next);
655     }
656
657     event->flags |= TFLAG_CANCELLED;
658
659     unblock_timer();
660 }
661
662 /*
663 * timer related headers
664 */
665 #include "bcmtimer.h"
666
667 /*
668 * locally used global variables and constants
669 */
670
671 /*
672 * Initialize internal resources used in the timer module. It must be called
673 * before any other timer function calls. The param 'timer_entries' is used
674 * to pre-allocate fixed number of timer entries.
675 */
676 int bcm_timer_module_init(int timer_entries, bcm_timer_module_id *module_id)
677 {
678         init_event_queue(timer_entries);
679         *module_id = (bcm_timer_module_id)event_freelist;
680         return 0;
681 }
682
683 /*
684 * Cleanup internal resources used by this timer module. It deletes all
685 * pending timer entries from the backend timer system as well.
686 */
687 int bcm_timer_module_cleanup(bcm_timer_module_id module_id)
688 {
689         module_id = 0;
690         return 0;
691 }
692
693 /* Enable/Disable timer module */
694 int bcm_timer_module_enable(bcm_timer_module_id module_id, int enable)
695 {
696         if (enable)
697                 unblock_timer();
698         else
699                 block_timer();
700         return 0;
701 }
702
703 int bcm_timer_create(bcm_timer_module_id module_id, bcm_timer_id *timer_id)
704 {
705         module_id = 0;
706         return timer_create(CLOCK_REALTIME, NULL, (timer_t *)timer_id);
707 }
708
709 int bcm_timer_delete(bcm_timer_id timer_id)
710 {
711         return timer_delete((timer_t)timer_id);
712 }
713
714 int bcm_timer_gettime(bcm_timer_id timer_id, struct itimerspec *timer_spec)
715 {
716         return -1;
717 }
718
719 int bcm_timer_settime(bcm_timer_id timer_id, const struct itimerspec *timer_spec)
720 {
721         return timer_settime((timer_t)timer_id, 0, timer_spec, NULL);
722 }
723
724 int bcm_timer_connect(bcm_timer_id timer_id, bcm_timer_cb func, int data)
725 {
726         return timer_connect((timer_t)timer_id, (void *)func, data);
727 }
728
729 int bcm_timer_cancel(bcm_timer_id timer_id)
730 {
731         timer_cancel((timer_t)timer_id);
732         return 0;
733 }
734 int bcm_timer_change_expirytime(bcm_timer_id timer_id, const struct itimerspec *timer_spec)
735 {
736         timer_change_settime((timer_t)timer_id, timer_spec);
737         return 1;
738 }