/** * Main function of the timer task. This function is in charge of * calling the callbacks associated with the timers. * * This function is run in a high priority task on microkernel builds. * This function is run in a high priority fiber on nanokernel builds. * It implements an infinite loop that waits for any of the semaphores from * g_TimerSem. * When a semaphore is signaled, this function fetches the pointer to the * associated callback in g_TimerDesc, then calls it. * * @param dummy1 not used (required by ZEPHYR API) * @param dummy2 not used (required by ZEPHYR API) * * */ void timer_task(int dummy1, int dummy2) { int32_t timeout = UINT32_MAX; uint32_t now; UNUSED(dummy1); UNUSED(dummy2); while (1) { /* the Timer task shall never stop */ /* Before waiting for next timeout, publish it to warn QUARK cpu */ publish_cpu_timeout(timeout); /* block until g_TimerSem is signaled or until the next timeout expires */ #ifdef CONFIG_MICROKERNEL (void)task_sem_take(g_TimerSem, CONVERT_MS_TO_TICKS(timeout)); #else nano_sem_take(&g_TimerSem, CONVERT_MS_TO_TICKS(timeout)); #endif now = get_uptime_ms(); /* task is unblocked: check for expired timers */ while (g_CurrentTimerHead && is_after_expiration(now, &(g_CurrentTimerHead->desc))) { execute_callback(g_CurrentTimerHead); now = get_uptime_ms(); } /* Compute timeout until the expiration of the next timer */ if (g_CurrentTimerHead != NULL) { /* In micro kernel context, timeout = 0 or timeout < 0 works. * In nano kernel context timeout must be a positive value. */ timeout = g_CurrentTimerHead->desc.expiration - now; if (timeout < 0) panic(E_OS_ERR_OVERFLOW); } else { timeout = UINT32_MAX; } #ifdef __DEBUG_OS_ABSTRACTION_TIMER if (NULL != g_CurrentTimerHead) _log( "\nINFO : timer_task : now = %u, next timer expires at %u, timeout = %u", get_uptime_ms(), g_CurrentTimerHead->desc.expiration, timeout); else _log( "\nINFO : timer_task : now = %u, no next timer, timeout = OS_WAIT_FOREVER", get_uptime_ms()); #endif } /* end while(1) */ }
/** * Insert a timer in the list of active timer, * according to its expiration date. * * @param newTimer pointer on the timer to insert * * WARNING: newTimer MUST NOT be null (rem: static function ) * */ static void add_timer(T_TIMER_LIST_ELT *newTimer) { T_TIMER_LIST_ELT *insertionPoint; T_TIMER_LIST_ELT *listTail; bool found; #ifdef __DEBUG_OS_ABSTRACTION_TIMER _log( "\nINFO : add_timer - start: adding 0x%x to expire at %d (now = %d - delay = %d - ticktime = %d)", (uint32_t)newTimer, newTimer->desc.expiration, get_uptime_ms(), newTimer->desc.delay, sys_clock_us_per_tick); display_list(); #endif if (NULL == g_CurrentTimerHead) { /* there is no active timer, make newTimer the head timer */ g_CurrentTimerHead = newTimer; newTimer->prev = NULL; newTimer->next = NULL; } else { /* find the next timer to expire after newTimer->desc.expiration */ insertionPoint = g_CurrentTimerHead; listTail = g_CurrentTimerHead; found = false; while ((NULL != insertionPoint) && (false == found)) { if (!is_after_expiration(newTimer->desc.expiration, &(insertionPoint->desc))) { /* newTimer is due to expire before insertionPoint */ if (g_CurrentTimerHead == insertionPoint) { /* insert newTimer before the head timer */ g_CurrentTimerHead->prev = newTimer; newTimer->prev = NULL; newTimer->next = g_CurrentTimerHead; g_CurrentTimerHead = newTimer; } else { /* insert newTimer between insertionPoint and insertionPoint->prev */ newTimer->prev = insertionPoint->prev; newTimer->next = insertionPoint; insertionPoint->prev = newTimer; newTimer->prev->next = newTimer; } /* done */ found = true; } else { /* newTimer is due to expire after insertionPoint, continue searching */ listTail = insertionPoint; /* update list head marker = last non null insertionPoint */ /* move downward */ insertionPoint = insertionPoint->next; } } if ((false == found) && (NULL != listTail)) { /* newTimer is due to expire after all others have expired */ listTail->next = newTimer; newTimer->prev = listTail; } } newTimer->desc.status = E_TIMER_RUNNING; #ifdef __DEBUG_OS_ABSTRACTION_TIMER _log("\nINFO : add_timer - end "); display_list(); display_list(); #endif }
/** * Main function of the timer task. This function is in charge of * calling the callbacks associated with the timers. * * This function is run in a high priority task on microkernel builds. * This function is run in a high priority fiber on nanokernel builds. * It implements an infinite loop that waits for any of the semaphores from * g_TimerSem. * When a semaphore is signaled, this function fetches the pointer to the * associated callback in g_TimerDesc, then calls it. * * @param dummy1 not used (required by ZEPHYR API) * @param dummy2 not used (required by ZEPHYR API) * * */ void timer_task(int dummy1, int dummy2) { uint32_t timeout; uint32_t now; UNUSED(dummy1); UNUSED(dummy2); timeout = OS_WAIT_FOREVER; while (1) /* the Timer task shall never stop */ { #ifdef CONFIG_MICROKERNEL /********************** MICRO KERNEL SPECIFIC: */ /* block until g_TimerSem is signaled or until the next timeout expires */ (void) task_sem_take_wait_timeout(g_TimerSem, timeout); #else if (NULL == g_CurrentTimerHead) { /* Start a background timer with max positive delay */ nano_fiber_timer_start (&g_NanoTimer, 0x7FFFFFFF); /* wait until the next timer expires or one is added or removed */ nano_fiber_timer_wait (&g_NanoTimer); } #endif now = _GET_TICK(); /* task is unblocked: check for expired timers */ while (is_after_expiration (now, &(g_CurrentTimerHead->desc))) { execute_callback(g_CurrentTimerHead); } /* Compute timeout until the expiration of the next timer */ if ( NULL != g_CurrentTimerHead ) { now = _GET_TICK(); /* In micro kernel context, timeout = 0 or timeout < 0 works. * In nano kernel context timeout must be a positive value. */ #ifdef CONFIG_NANOKERNEL if (g_CurrentTimerHead->desc.expiration > now) { #endif timeout = g_CurrentTimerHead->desc.expiration - now; if (OS_WAIT_FOREVER == timeout) { /* cannot have timeout = OS_WAIT_FOREVER while there is still at least one active timer */ timeout++; } #ifdef CONFIG_NANOKERNEL nano_fiber_timer_start (&g_NanoTimer, timeout); /* wait until the next timer expires or one is added or removed */ nano_fiber_timer_wait (&g_NanoTimer); /* nano_fiber_timer_wait will wait until "natural" timer * expiration, or until nano_fiber_timer_stop(&g_NanoTimer) * is called by the timer_callback or by timer_stop() */ } #endif } #ifdef CONFIG_MICROKERNEL else { timeout = OS_WAIT_FOREVER; } #endif #ifdef __DEBUG_OS_ABSTRACTION_TIMER if (NULL != g_CurrentTimerHead ) _log ("\nINFO : timer_task : now = %u, next timer expires at %u, timeout = %u", _GET_TICK() , g_CurrentTimerHead->desc.expiration, timeout ); else _log ("\nINFO : timer_task : now = %u, no next timer, timeout = OS_WAIT_FOREVER", _GET_TICK() ); #endif } /* end while(1) */ }