/* * Cleanup internal resources used by this timer module. It deletes all * pending timer entries from the backend timer system as well. */ int bcm_timer_module_cleanup(bcm_timer_module_id module_id) { ecos_timer_list_t *list = (ecos_timer_list_t *)module_id; ecos_timer_entry_t *entry; int key; TIMERDBG("list %08x", list); /* * do nothing if the list has not been initialized */ if (!(list->flags&TIMER_LIST_FLAG_INIT)) return -1; /* * mark the big bang flag here so that no more callbacks * shall be scheduled or called from this point on... */ list->flags |= TIMER_LIST_FLAG_EXIT; /* * remove all backend timers here so that no timer expires after here. */ TIMER_LIST_LOCK(list); key = INTLOCK(); for (entry = list->used; entry != NULL; entry = entry->next) { ecos_del_timer(entry); } INTUNLOCK(key); TIMER_LIST_UNLOCK(list); /* * have to wait till all expired entries to have been handled */ for (entry = list->used; entry != NULL; entry = entry->next) { if ((entry->flags&TIMER_FLAG_DEFERRED) && !(entry->flags&TIMER_FLAG_FINISHED)) break; } cyg_mutex_destroy(&(list->lock)); /* now it should be safe to blindly free all the resources */ TIMER_FREE_LOCK_MECHANISM(); free(list); TIMERDBG("done"); return 0; }
/* add entry into top of list */ static int put_entry(ecos_timer_entry_t **list, ecos_timer_entry_t *entry) { /* add the entry into top of the list */ TIMERDBG("list = %08x", *list); TIMERDBG("entry = %08x", entry); entry->next = *list; entry->prev = NULL; if (*list != NULL) (*list)->prev = entry; *list = entry; TIMERDBG("new list = %08x", *list); return 0; }
int bcm_timer_delete(bcm_timer_id timer_id) { ecos_timer_entry_t *entry = (ecos_timer_entry_t *)timer_id; ecos_timer_list_t *list = entry->list; int status; int key; TIMERDBG("entry %08x timer %08x", entry, entry->timer); /* make sure no interrupts can happen */ key = INTLOCK(); /* lock the timer list */ TIMER_LIST_LOCK(list); /* remove the entry from the used list first */ status = remove_entry(&list->used, entry); if (status != 0) goto exit0; /* delete the backend timer */ ecos_del_timer(entry); /* free the entry back to freed list */ put_entry(&list->freed, entry); entry->flags = TIMER_FLAG_NONE; entry->list = NULL; TIMER_LIST_UNLOCK(list); INTUNLOCK(key); TIMERDBG("done"); return 0; /* error handling */ exit0: TIMER_LIST_UNLOCK(list); INTUNLOCK(key); return status; }
int bcm_timer_cancel(bcm_timer_id timer_id) { ecos_timer_entry_t *entry = (ecos_timer_entry_t *)timer_id; TIMERDBG("entry %08x timer %08x", entry, entry->timer); ecos_del_timer(entry); entry->flags &= ~TIMER_FLAG_ARMED; return 0; }
int dd_timer_create( clockid_t clock_id, /* clock ID (always CLOCK_REALTIME) */ struct sigevent *evp, /* user event handler */ timer_t * pTimer /* ptr to return value */ ) { struct event *event; if( clock_id != CLOCK_REALTIME ) { TIMERDBG( "timer_create can only support clock id CLOCK_REALTIME" ); exit( 1 ); } if( evp != NULL ) { if( evp->sigev_notify != SIGEV_SIGNAL || evp->sigev_signo != SIGALRM ) { TIMERDBG ( "timer_create can only support signalled alarms using SIGALRM" ); exit( 1 ); } } event = event_freelist; if( event == NULL ) { print_event_queue( ); } assert( event != NULL ); event->flags = TFLAG_NONE; event_freelist = event->next; event->next = NULL; check_event_queue( ); *pTimer = ( timer_t ) event; return 0; }
int bcm_timer_settime(bcm_timer_id timer_id, const struct itimerspec *timer_spec) { unsigned int ms; ecos_timer_entry_t *entry = (ecos_timer_entry_t *)timer_id; TIMERDBG("entry %08x timer %08x", entry, entry->timer); ms = (timer_spec->it_value.tv_sec*1000) + ((timer_spec->it_value.tv_nsec/1000)/1000); return ecos_add_timer(entry, ms, 1) ? 0 : 1; }
/* alloc entry from top of list */ static int get_entry(ecos_timer_entry_t **list, ecos_timer_entry_t **entry) { /* take an entry from top of the list */ TIMERDBG("list = %08x", *list); *entry = *list; if (*entry == NULL) return -1; *list = (*entry)->next; if (*list != NULL) (*list)->prev = NULL; TIMERDBG("new list = %08x", *list); (*entry)->next = NULL; (*entry)->prev = NULL; TIMERDBG("entry = %08x", *entry); return 0; }
int bcm_timer_connect(bcm_timer_id timer_id, bcm_timer_cb func, int data) { ecos_timer_entry_t *entry = (ecos_timer_entry_t *)timer_id; entry->func = func; entry->data = data; TIMERDBG("entry %08x timer %08x func %08x data %08x", entry, entry->timer, entry->func, entry->data); entry->flags |= TIMER_FLAG_ARMED; return 0; }
/* remove entry from list */ static int remove_entry(ecos_timer_entry_t **list, ecos_timer_entry_t *entry) { /* remove the entry from the list */ TIMERDBG("list = %08x", *list); TIMERDBG("entry = %08x", entry); if (entry->prev != NULL) entry->prev->next = entry->next; if (entry->next != NULL) entry->next->prev = entry->prev; if (*list == entry) *list = entry->next; entry->next = NULL; entry->prev = NULL; TIMERDBG("new list = %08x", *list); return 0; }
/* * Initialize internal resources used in the timer module. It must be called * before any other timer function calls. The param 'timer_entries' is used * to pre-allocate fixed number of timer entries. */ int bcm_timer_module_init(int timer_entries, bcm_timer_module_id *module_id) { int size = timer_entries*sizeof(ecos_timer_entry_t); ecos_timer_list_t *list; int i; TIMERDBG("entries %d", timer_entries); /* alloc fixed number of entries upfront */ list = malloc(sizeof(ecos_timer_list_t)+size); if (list == NULL) goto exit0; cyg_mutex_init(&(list->lock)); list->flags = TIMER_LIST_FLAG_NONE; list->entry = (ecos_timer_entry_t *)(list + 1); list->entries = timer_entries; TIMERDBG("entry %08x", list->entry); /* init the timer entries to form two list - freed and used */ list->freed = NULL; list->used = NULL; memset(list->entry, 0, timer_entries*sizeof(ecos_timer_entry_t)); for (i = 0; i < timer_entries; i ++) { put_entry(&list->freed, &list->entry[i]); } list->flags = TIMER_LIST_FLAG_INIT; *module_id = (bcm_timer_module_id)list; TIMERDBG("list %08x freed %08x used %08x", list, list->freed, list->used); return 0; exit0: return -1; }
int bcm_timer_create(bcm_timer_module_id module_id, bcm_timer_id *timer_id) { ecos_timer_list_t *list = (ecos_timer_list_t *)module_id; ecos_timer_entry_t *entry; int status = -1; TIMERDBG("list %08x", list); /* lock the timer list */ TIMER_LIST_LOCK(list); /* check if timer is allowed */ if (list->flags & TIMER_LIST_FLAG_EXIT) goto exit0; /* alloc an entry first */ status = get_entry(&list->freed, &entry); if (status != 0) goto exit0; /* add the entry into used list */ put_entry(&list->used, entry); entry->flags = TIMER_FLAG_IN_USE; entry->list = list; *timer_id = (bcm_timer_id)(void *)entry; TIMER_LIST_UNLOCK(list); TIMERDBG("entry %08x timer %08x", entry, entry->timer); return 0; /* error handling */ exit0: TIMER_LIST_UNLOCK(list); return status; }
int dd_timer_delete( timer_t timerid /* timer ID */ ) { struct event *event = ( struct event * )timerid; if( event->flags & TFLAG_DELETED ) { TIMERDBG( "Cannot delete a deleted event" ); return 1; } dd_timer_cancel( timerid ); event->flags |= TFLAG_DELETED; event->next = event_freelist; event_freelist = event; return 0; }
int dd_timer_settime( timer_t timerid, /* timer ID */ int flags, /* absolute or relative */ const struct itimerspec *value, /* time to be set */ struct itimerspec *ovalue /* previous time set (NULL=no * result) */ ) { struct itimerval itimer; struct event *event = ( struct event * )timerid; struct event **ppevent; TIMESPEC_TO_TIMEVAL( &event->it_interval, &value->it_interval ); TIMESPEC_TO_TIMEVAL( &event->it_value, &value->it_value ); /* * if .it_value is zero, the timer is disarmed */ if( !timerisset( &event->it_value ) ) { dd_timer_cancel( timerid ); return 0; } dd_block_timer( ); #ifdef TIMER_PROFILE event->expected_ms = ( event->it_value.tv_sec * MS_PER_SEC ) + ( event->it_value.tv_usec / US_PER_MS ); event->start = uclock( ); #endif if( event->next ) { TIMERDBG ( "calling timer_settime with a timer that is already on the queue." ); } /* * We always want to make sure that the event at the head of the queue * has a timeout greater than the itimer granularity. Otherwise we end up * with the situation that the time remaining on an itimer is greater * than the time at the head of the queue in the first place. */ timerroundup( &event->it_value, g_granularity ); timerclear( &itimer.it_value ); getitimer( ITIMER_REAL, &itimer ); if( timerisset( &itimer.it_value ) ) { // reset the top timer to have an interval equal to the remaining // interval // when the timer was cancelled. if( event_queue ) { if( timercmp ( &( itimer.it_value ), &( event_queue->it_value ), > ) ) { // it is an error if the amount of time remaining is more // than the amount of time // requested by the top event. // TIMERDBG( "timer_settime: TIMER ERROR!" ); } else { // some portion of the top event has already expired. // Reset the interval of the top event to remaining // time left in that interval. // event_queue->it_value = itimer.it_value; // if we were the earliest timer before now, we are still the // earliest timer now. // we do not need to reorder the list. } } }