2 * Copyright 2004, Broadcom Corporation
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.
20 #define TIMERDBG(fmt, args...) printf("%s: " fmt "\n" , __FUNCTION__ , ## args)
22 #define TIMERDBG(fmt, args...)
27 * POSIX timer support for Linux. Taken from linux_timer.c in upnp
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.
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.
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)
58 #define MS_PER_SEC 1000
59 #define US_PER_SEC 1000000
60 #define US_PER_MS 1000
61 #define UCLOCKS_PER_SEC 1000000
63 typedef void (*event_callback_t
)(timer_t
, int);
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; \
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; \
79 #define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y))
81 #define timerroundup(t,g) \
83 if (!timerisset(t)) (t)->tv_usec=1; \
84 if ((t)->tv_sec == 0) (t)->tv_usec=ROUNDUP((t)->tv_usec, g); \
87 typedef long uclock_t
;
90 #define TFLAG_CANCELLED (1<<0)
91 #define TFLAG_DELETED (1<<1)
94 struct timeval it_interval
;
95 struct timeval it_value
;
96 event_callback_t func
;
106 void timer_cancel(timer_t timerid
);
108 static void alarm_handler(int i
);
109 static void check_event_queue();
110 static void print_event_queue();
111 static void check_timer();
113 static int count_queue(struct event
*);
115 static int timer_change_settime(timer_t timer_id
, const struct itimerspec
*timer_spec
);
117 void unblock_timer();
119 static struct event
*event_queue
= NULL
;
120 static struct event
*event_freelist
;
121 static uint g_granularity
;
122 static int g_maxevents
= 0;
128 gettimeofday(&tv
, NULL
);
129 return ((tv
.tv_sec
* US_PER_SEC
) + tv
.tv_usec
);
133 void init_event_queue(int n
)
139 event_freelist
= (struct event
*) malloc(n
* sizeof(struct event
));
140 memset(event_freelist
, 0, n
* sizeof(struct event
));
142 for (i
= 0; i
< (n
-1); i
++)
143 event_freelist
[i
].next
= &event_freelist
[i
+1];
145 event_freelist
[i
].next
= NULL
;
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
;
155 signal(SIGALRM
, alarm_handler
);
160 clockid_t clock_id
, /* clock ID (always CLOCK_REALTIME) */
161 struct timespec
* tp
/* where to store current time */
168 n
= gettimeofday(&tv
, NULL
);
169 TIMEVAL_TO_TIMESPEC(&tv
, tp
);
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 */
183 if (clock_id
!= CLOCK_REALTIME
) {
184 TIMERDBG("timer_create can only support clock id CLOCK_REALTIME");
189 if (evp
->sigev_notify
!= SIGEV_SIGNAL
|| evp
->sigev_signo
!= SIGALRM
) {
190 TIMERDBG("timer_create can only support signalled alarms using SIGALRM");
195 event
= event_freelist
;
199 assert(event
!= NULL
);
201 event
->flags
= TFLAG_NONE
;
203 event_freelist
= event
->next
;
208 *pTimer
= (timer_t
) event
;
214 timer_t timerid
/* timer ID */
217 struct event
*event
= (struct event
*) timerid
;
219 if (event
->flags
& TFLAG_DELETED
) {
220 TIMERDBG("Cannot delete a deleted event");
224 timer_cancel(timerid
);
226 event
->flags
|= TFLAG_DELETED
;
228 event
->next
= event_freelist
;
229 event_freelist
= event
;
236 timer_t timerid
, /* timer ID */
237 void (*routine
)(timer_t
, int), /* user routine */
238 int arg
/* user argument */
241 struct event
*event
= (struct event
*) timerid
;
243 assert(routine
!= NULL
);
244 event
->func
= routine
;
251 * Please Call this function only from the call back functions of the alarm_handler.
252 * This is just a hack
254 int timer_change_settime
256 timer_t timerid
, /* timer ID */
257 const struct itimerspec
* value
/* time to be set */
260 struct event
*event
= (struct event
*) timerid
;
262 TIMESPEC_TO_TIMEVAL(&event
->it_interval
, &value
->it_interval
);
263 TIMESPEC_TO_TIMEVAL(&event
->it_value
, &value
->it_value
);
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) */
276 struct itimerval itimer
;
277 struct event
*event
= (struct event
*) timerid
;
278 struct event
**ppevent
;
280 TIMESPEC_TO_TIMEVAL(&event
->it_interval
, &value
->it_interval
);
281 TIMESPEC_TO_TIMEVAL(&event
->it_value
, &value
->it_value
);
283 /* if .it_value is zero, the timer is disarmed */
284 if (!timerisset(&event
->it_value
)) {
285 timer_cancel(timerid
);
292 event
->expected_ms
= (event
->it_value
.tv_sec
* MS_PER_SEC
) + (event
->it_value
.tv_usec
/ US_PER_MS
);
293 event
->start
= uclock();
296 TIMERDBG("calling timer_settime with a timer that is already on the queue.");
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
);
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.
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.
317 TIMERDBG("timer_settime: TIMER ERROR!");
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.
324 event_queue
->it_value
= itimer
.it_value
;
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.
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
;
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.
340 // we also need to adjust the delta value to the next event.
341 timersub(&((*ppevent
)->it_value
), &(event
->it_value
), &((*ppevent
)->it_value
));
344 // subtract the interval of the next event from the proposed interval.
345 timersub(&(event
->it_value
), &((*ppevent
)->it_value
), &(event
->it_value
));
347 ppevent
= &((*ppevent
)->next
);
350 // we have found our proper place in the queue,
351 // link our new event into the pending event queue.
352 event
->next
= *ppevent
;
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
;
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 };
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
);
375 event
->flags
&= ~TFLAG_CANCELLED
;
382 static void check_timer()
384 struct itimerval itimer
;
386 getitimer(ITIMER_REAL
, &itimer
);
387 if (timerisset(&itimer
.it_interval
)) {
388 TIMERDBG("ERROR timer interval is set.");
390 if (timercmp(&(itimer
.it_value
), &(event_queue
->it_value
), >)) {
391 TIMERDBG("ERROR timer expires later than top event.");
396 static void check_event_queue()
405 for (p
= event_freelist
; p
; p
= p
->next
)
407 printf("%d free events\n", nfree
);
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!");
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
)
428 for (event
= event_queue
; event
; event
= event
->next
)
434 static void print_event_queue()
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");
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
)
454 struct event
*event
, **ppevent
;
455 struct itimerval itimer
;
456 struct timeval small_interval
= { 0, g_granularity
/2 };
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'}.
469 // remove the top event.
471 event_queue
= event_queue
->next
;
476 actual
= ((end
-event
->start
)/((uclock_t
)UCLOCKS_PER_SEC
/1000));
479 TIMERDBG("expected %d ms actual %d ms", event
->expected_ms
, ((end
-event
->start
)/((uclock_t
)UCLOCKS_PER_SEC
/1000)));
482 // call the event callback function
483 (*(event
->func
))((timer_t
) event
, (int)event
->arg
);
485 /* If the event has been cancelled, do NOT put it back on the queue. */
486 if ( !(event
->flags
& TFLAG_CANCELLED
) ) {
488 // if the event is a recurring event, reset the timer and
489 // find its correct place in the sorted list of events.
491 if (timerisset(&event
->it_interval
)) {
492 // event is recurring...
494 event
->it_value
= event
->it_interval
;
496 event
->expected_ms
= (event
->it_value
.tv_sec
* MS_PER_SEC
) + (event
->it_value
.tv_usec
/ US_PER_MS
);
497 event
->start
= uclock();
499 timerroundup(&event
->it_value
, g_granularity
);
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
;
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.
509 // we also need to adjust the delta value to the next event.
510 timersub(&((*ppevent
)->it_value
), &(event
->it_value
), &((*ppevent
)->it_value
));
513 timersub(&(event
->it_value
), &((*ppevent
)->it_value
), &(event
->it_value
));
514 ppevent
= &((*ppevent
)->next
);
517 // we have found our proper place in the queue,
518 // link our new event into the pending event queue.
519 event
->next
= *ppevent
;
522 // there is no interval, so recycle the event structure.
523 //timer_delete((timer_t) event);
529 } while (event_queue
&& timercmp(&event_queue
->it_value
, &small_interval
, <));
531 // re-issue the timer...
533 timerroundup(&event_queue
->it_value
, g_granularity
);
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 };
542 setitimer(ITIMER_REAL
, &itimer
, NULL
);
545 TIMERDBG("There are no events in the queue - timer not reset.");
551 static int block_count
= 0;
557 if (block_count
++ == 0) {
559 sigaddset(&set
, SIGALRM
);
560 sigprocmask(SIG_BLOCK
, &set
, NULL
);
568 if (--block_count
== 0) {
570 sigaddset(&set
, SIGALRM
);
571 sigprocmask(SIG_UNBLOCK
, &set
, NULL
);
575 void timer_cancel_all()
577 struct itimerval timeroff
= { { 0, 0 }, { 0, 0} };
579 struct event
**ppevent
;
581 setitimer(ITIMER_REAL
, &timeroff
, NULL
);
583 ppevent
= &event_queue
;
586 *ppevent
= event
->next
;
593 void timer_cancel(timer_t timerid
)
595 struct itimerval itimer
;
596 struct itimerval timeroff
= { { 0, 0 }, { 0, 0} };
597 struct event
*event
= (struct event
*) timerid
;
598 struct event
**ppevent
;
600 if (event
->flags
& TFLAG_CANCELLED
) {
601 TIMERDBG("Cannot cancel a cancelled event");
607 ppevent
= &event_queue
;
609 if ( *ppevent
== event
) {
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. */
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
);
622 /* subtract the time that has already passed while waiting for this timer... */
623 timersub(&(event
->it_value
), &(itimer
.it_value
), &(event
->it_value
));
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
));
629 *ppevent
= event
->next
;
633 timerroundup(&event_queue
->it_value
, g_granularity
);
634 timerclear(&itimer
.it_interval
);
635 itimer
.it_value
= event_queue
->it_value
;
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
642 if (!timerisset(&(itimer
.it_value
)))
643 itimer
.it_value
= (struct timeval
) { 0, 1 };
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
);
650 setitimer(ITIMER_REAL
, &timeroff
, NULL
);
654 ppevent
= &((*ppevent
)->next
);
657 event
->flags
|= TFLAG_CANCELLED
;
663 * timer related headers
665 #include "bcmtimer.h"
668 * locally used global variables and constants
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.
676 int bcm_timer_module_init(int timer_entries
, bcm_timer_module_id
*module_id
)
678 init_event_queue(timer_entries
);
679 *module_id
= (bcm_timer_module_id
)event_freelist
;
684 * Cleanup internal resources used by this timer module. It deletes all
685 * pending timer entries from the backend timer system as well.
687 int bcm_timer_module_cleanup(bcm_timer_module_id module_id
)
693 /* Enable/Disable timer module */
694 int bcm_timer_module_enable(bcm_timer_module_id module_id
, int enable
)
703 int bcm_timer_create(bcm_timer_module_id module_id
, bcm_timer_id
*timer_id
)
706 return timer_create(CLOCK_REALTIME
, NULL
, (timer_t
*)timer_id
);
709 int bcm_timer_delete(bcm_timer_id timer_id
)
711 return timer_delete((timer_t
)timer_id
);
714 int bcm_timer_gettime(bcm_timer_id timer_id
, struct itimerspec
*timer_spec
)
719 int bcm_timer_settime(bcm_timer_id timer_id
, const struct itimerspec
*timer_spec
)
721 return timer_settime((timer_t
)timer_id
, 0, timer_spec
, NULL
);
724 int bcm_timer_connect(bcm_timer_id timer_id
, bcm_timer_cb func
, int data
)
726 return timer_connect((timer_t
)timer_id
, (void *)func
, data
);
729 int bcm_timer_cancel(bcm_timer_id timer_id
)
731 timer_cancel((timer_t
)timer_id
);
734 int bcm_timer_change_expirytime(bcm_timer_id timer_id
, const struct itimerspec
*timer_spec
)
736 timer_change_settime((timer_t
)timer_id
, timer_spec
);