diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-08-07 11:39:16 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-08-07 11:39:16 -0600 |
commit | e45f88d7cc67518a52a056602506de1fd489ca74 (patch) | |
tree | 267a9e3b9e04a429415de49bf7ede19c47552f0e /nuttx/sched/wd_start.c | |
parent | e70f66c7c493fafd4e319c9fd1c7c6d0422fafbe (diff) | |
download | nuttx-e45f88d7cc67518a52a056602506de1fd489ca74.tar.gz nuttx-e45f88d7cc67518a52a056602506de1fd489ca74.tar.bz2 nuttx-e45f88d7cc67518a52a056602506de1fd489ca74.zip |
Implements the tickless OS
Diffstat (limited to 'nuttx/sched/wd_start.c')
-rw-r--r-- | nuttx/sched/wd_start.c | 258 |
1 files changed, 189 insertions, 69 deletions
diff --git a/nuttx/sched/wd_start.c b/nuttx/sched/wd_start.c index 440c83b0c..6f519f915 100644 --- a/nuttx/sched/wd_start.c +++ b/nuttx/sched/wd_start.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/wd_start.c * - * Copyright (C) 2007-2009, 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include <wdog.h> #include <unistd.h> #include <sched.h> +#include <assert.h> #include <errno.h> #include <nuttx/arch.h> @@ -56,6 +57,14 @@ * Pre-processor Definitions ****************************************************************************/ +#ifndef MIN +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +# define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + /**************************************************************************** * Private Type Declarations ****************************************************************************/ @@ -87,6 +96,97 @@ typedef void (*wdentry4_t)(int argc, uint32_t arg1, uint32_t arg2, /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: wd_expiration + * + * Description: + * Check if the timer for the watchdog at the head of list is ready to + * run. If so, remove the watchdog from the list and execute it. + * + * Parameters: + * None + * + * Return Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static inline void wd_expiration(void) +{ + FAR wdog_t *wdog; + + /* Check if the watchdog at the head of the list is ready to run */ + + if (((FAR wdog_t*)g_wdactivelist.head)->lag <= 0) + { + /* Process the watchdog at the head of the list as well as any + * other watchdogs that became ready to run at this time + */ + + while (g_wdactivelist.head && + ((FAR wdog_t*)g_wdactivelist.head)->lag <= 0) + { + /* Remove the watchdog from the head of the list */ + + wdog = (FAR wdog_t*)sq_remfirst(&g_wdactivelist); + + /* If there is another watchdog behind this one, update its + * its lag (this shouldn't be necessary). + */ + + if (g_wdactivelist.head) + { + ((FAR wdog_t*)g_wdactivelist.head)->lag += wdog->lag; + } + + /* Indicate that the watchdog is no longer active. */ + + wdog->active = false; + + /* Execute the watchdog function */ + + up_setpicbase(wdog->picbase); + switch (wdog->argc) + { + default: + DEBUGPANIC(); + break; + + case 0: + (*((wdentry0_t)(wdog->func)))(0); + break; + +#if CONFIG_MAX_WDOGPARMS > 0 + case 1: + (*((wdentry1_t)(wdog->func)))(1, wdog->parm[0]); + break; +#endif +#if CONFIG_MAX_WDOGPARMS > 1 + case 2: + (*((wdentry2_t)(wdog->func)))(2, + wdog->parm[0], wdog->parm[1]); + break; +#endif +#if CONFIG_MAX_WDOGPARMS > 2 + case 3: + (*((wdentry3_t)(wdog->func)))(3, + wdog->parm[0], wdog->parm[1], + wdog->parm[2]); + break; +#endif +#if CONFIG_MAX_WDOGPARMS > 3 + case 4: + (*((wdentry4_t)(wdog->func)))(4, + wdog->parm[0], wdog->parm[1], + wdog->parm[2] ,wdog->parm[3]); + break; +#endif + } + } + } +} /**************************************************************************** * Public Functions @@ -101,7 +201,7 @@ typedef void (*wdentry4_t)(int argc, uint32_t arg1, uint32_t arg2, * specified number of ticks has elapsed. Watchdog timers may be started * from the interrupt level. * - * Watchdog timers execute in the address enviroment that was in effect + * Watchdog timers execute in the address environment that was in effect * when wd_start() is called. * * Watchdog timers execute only once. @@ -133,6 +233,9 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...) FAR wdog_t *next; int32_t now; irqstate_t saved_state; +#ifdef CONFIG_SCHED_TICKLESS + bool reassess = false; +#endif int i; /* Verify the wdog */ @@ -189,7 +292,17 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...) if (g_wdactivelist.head == NULL) { + /* Add the watchdog to the head of the queue. */ + sq_addlast((FAR sq_entry_t*)wdog,&g_wdactivelist); + +#ifdef CONFIG_SCHED_TICKLESS + /* Whenever the watchdog at the head of the queue changes, then we + * need to reassess the interval timer setting. + */ + + reassess = true; +#endif } /* There are other active watchdogs in the timer queue */ @@ -232,12 +345,24 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...) if (curr == (FAR wdog_t*)g_wdactivelist.head) { + /* Insert the watchdog in mid- or end-of-queue */ + sq_addfirst((FAR sq_entry_t*)wdog, &g_wdactivelist); } else { + /* Insert the watchdog in mid- or end-of-queue */ + sq_addafter((FAR sq_entry_t*)prev, (FAR sq_entry_t*)wdog, &g_wdactivelist); + +#ifdef CONFIG_SCHED_TICKLESS + /* If the watchdog at the head of the queue changes, then we + * need to reassess the interval timer setting. + */ + + reassess = true; +#endif } } @@ -265,9 +390,23 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...) /* Put the lag into the watchdog structure and mark it as active. */ - wdog->lag = delay; + wdog->lag = delay; wdog->active = true; +#ifdef CONFIG_SCHED_TICKLESS + /* Reassess the interval timer that will generate the next interval event. + * In many cases, this will be unnecessary: This is really only necessary + * when the watchdog timer at the head of the queue is change. If the + * timer is inserted later in the queue then the timer at the head is + * unchanged. + */ + + if (reassess) + { + sched_timer_reassess(); + } +#endif + irqrestore(saved_state); return OK; } @@ -278,98 +417,79 @@ int wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...) * Description: * This function is called from the timer interrupt handler to determine * if it is time to execute a watchdog function. If so, the watchdog - * function will be executed in the context of the timer interrupt handler. + * function will be executed in the context of the timer interrupt + * handler. * * Parameters: - * None + * ticks - If CONFIG_SCHED_TICKLESS is defined then the number of ticks + * in the the interval that just expired is provided. Otherwise, + * this function is called on each timer interrupt and a value of one + * is implicit. * * Return Value: - * None + * If CONFIG_SCHED_TICKLESS is defined then the number of ticks for the + * next delay is provided (zero if no delay). Otherwise, this function + * has no returned value. * * Assumptions: + * Called from interrupt handler logic with interrupts disabled. * ****************************************************************************/ -void wd_timer(void) +#ifdef CONFIG_SCHED_TICKLESS +unsigned int wd_timer(int ticks) { FAR wdog_t *wdog; + int decr; /* Check if there are any active watchdogs to process */ - if (g_wdactivelist.head) + while (g_wdactivelist.head && ticks > 0) { - /* There are. Decrement the lag counter */ + /* Get the watchdog at the head of the list */ - --(((FAR wdog_t*)g_wdactivelist.head)->lag); + wdog = (FAR wdog_t*)g_wdactivelist.head; - /* Check if the watchdog at the head of the list is ready to run */ + /* Decrement the lag for this watchdog. + * + * There is logic to handle the case where ticks is greater than + * the watchdog lag, but if the scheduling is working properly + * that should never happen. + */ - if (((FAR wdog_t*)g_wdactivelist.head)->lag <= 0) - { - /* Process the watchdog at the head of the list as well as any - * other watchdogs that became ready to run at this time - */ + DEBUGASSERT(ticks <= wdog->lag); + decr = MIN(wdog->lag, ticks); - while (g_wdactivelist.head && - ((FAR wdog_t*)g_wdactivelist.head)->lag <= 0) - { - /* Remove the watchdog from the head of the list */ + /* There are. Decrement the lag counter */ - wdog = (FAR wdog_t*)sq_remfirst(&g_wdactivelist); + wdog->lag -= decr; + ticks -= ticks; - /* If there is another watchdog behind this one, update its - * its lag (this shouldn't be necessary). - */ + /* Check if the watchdog at the head of the list is ready to run */ - if (g_wdactivelist.head) - { - ((FAR wdog_t*)g_wdactivelist.head)->lag += wdog->lag; - } + wd_expiration(); + } - /* Indicate that the watchdog is no longer active. */ + /* Return the delay for the next watchdog to expire */ - wdog->active = false; + return g_wdactivelist.head ? + ((FAR wdog_t*)g_wdactivelist.head)->lag : 0; +} - /* Execute the watchdog function */ +#else +void wd_timer(void) +{ + /* Check if there are any active watchdogs to process */ - up_setpicbase(wdog->picbase); - switch (wdog->argc) - { - default: -#ifdef CONFIG_DEBUG - PANIC(); -#endif - case 0: - (*((wdentry0_t)(wdog->func)))(0); - break; + if (g_wdactivelist.head) + { + /* There are. Decrement the lag counter */ -#if CONFIG_MAX_WDOGPARMS > 0 - case 1: - (*((wdentry1_t)(wdog->func)))(1, wdog->parm[0]); - break; -#endif -#if CONFIG_MAX_WDOGPARMS > 1 - case 2: - (*((wdentry2_t)(wdog->func)))(2, - wdog->parm[0], wdog->parm[1]); - break; -#endif -#if CONFIG_MAX_WDOGPARMS > 2 - case 3: - (*((wdentry3_t)(wdog->func)))(3, - wdog->parm[0], wdog->parm[1], - wdog->parm[2]); - break; -#endif -#if CONFIG_MAX_WDOGPARMS > 3 - case 4: - (*((wdentry4_t)(wdog->func)))(4, - wdog->parm[0], wdog->parm[1], - wdog->parm[2] ,wdog->parm[3]); - break; -#endif - } - } - } + --(((FAR wdog_t*)g_wdactivelist.head)->lag); + + /* Check if the watchdog at the head of the list is ready to run */ + + wd_expiration(); } } +#endif /* CONFIG_SCHED_TICKLESS */ |