]> git.sur5r.net Git - freertos/commitdiff
Add some tick interrupt overflow protection to the timers module. This is not tested...
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Thu, 10 Feb 2011 19:09:35 +0000 (19:09 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Thu, 10 Feb 2011 19:09:35 +0000 (19:09 +0000)
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1291 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

Source/include/task.h
Source/include/timers.h
Source/queue.c
Source/tasks.c
Source/timers.c

index fbffae73fba2d7e27cd100b0734eaadaed320581..3a64d096631ae91161919aa90498825e6745950c 100644 (file)
@@ -1191,6 +1191,21 @@ void vTaskIncrementTick( void ) PRIVILEGED_FUNCTION;
  */\r
 void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;\r
 \r
+/*\r
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE.  IT IS AN\r
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.\r
+ *\r
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.\r
+ *\r
+ * This function performs nearly the same function as vTaskPlaceOnEventList().\r
+ * The difference being that this function does not permit tasks to block\r
+ * indefinitely, whereas vTaskPlaceOnEventList() does.\r
+ *\r
+ * @return pdTRUE if the task being removed has a higher priority than the task\r
+ * making the call, otherwise pdFALSE.\r
+ */\r
+void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;\r
+\r
 /*\r
  * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE.  IT IS AN\r
  * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.\r
index 09db215b21331e951c5f5324abb76ab8a76d673e..e735140a82b1744240ab318ff7f0257009271e9c 100644 (file)
@@ -67,10 +67,11 @@ extern "C" {
 #endif\r
 \r
 /* IDs for commands that can be sent/received on the timer queue. */\r
-#define tmrCOMMAND_START                       0\r
-#define tmrCOMMAND_STOP                                1\r
-#define tmrCOMMAND_CHANGE_PERIOD       2\r
-#define tmrCOMMAND_DELETE                      3\r
+#define trmCOMMAND_PROCESS_TIMER_OVERFLOW      0 /* For use by the kernel only! */\r
+#define tmrCOMMAND_START                                       1\r
+#define tmrCOMMAND_STOP                                                2\r
+#define tmrCOMMAND_CHANGE_PERIOD                       3\r
+#define tmrCOMMAND_DELETE                                      4\r
 \r
 /*-----------------------------------------------------------\r
  * MACROS AND DEFINITIONS\r
index 96552f783dc8380a516bc831e0244b6980317dec..806413071b7e10d677df714bc0990d334937d794 100644 (file)
@@ -1481,7 +1481,7 @@ signed portBASE_TYPE xReturn;
                if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U )\r
                {\r
                        /* There is nothing in the queue, block for the specified period. */\r
-                       vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
+                       vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
                }\r
        }\r
 \r
index 6f305f725fc7a183eec5dd723d6543cd624d12fe..3e4fb525cea4944f0017410f3487c0adb55a1e70 100644 (file)
@@ -1448,6 +1448,15 @@ void vTaskIncrementTick( void )
                        pxDelayedTaskList = pxOverflowDelayedTaskList;\r
                        pxOverflowDelayedTaskList = pxTemp;\r
                        xNumOfOverflows++;\r
+                       \r
+                       #if configUSE_TIMERS == 1\r
+                       {\r
+                               /* The timer service task needs to know to switch its lists\r
+                               too. */\r
+                               xTimerGenericCommand( NULL, trmCOMMAND_PROCESS_TIMER_OVERFLOW, 0, 0 );\r
+                       }\r
+                       #endif\r
+                       \r
                        if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )\r
                        {\r
                                /* The delayed list is empty.  Set xNextTaskUnblockTime to the\r
@@ -1741,6 +1750,38 @@ portTickType xTimeToWake;
 }\r
 /*-----------------------------------------------------------*/\r
 \r
+#if configUSE_TIMERS == 1\r
+\r
+       void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )\r
+       {\r
+       portTickType xTimeToWake;\r
+\r
+               /* This function should not be called by application code hence the \r
+               'Restricted' in its name.  It is not part of the public API.  It is \r
+               designed for use by kernel code, and has special calling requirements - \r
+               it should be called from a critical section. */\r
+\r
+       \r
+               /* Place the event list item of the TCB in the appropriate event list.\r
+               In this case it is assume that this is the only task that is going to\r
+               be waiting on this event list, so the faster vListInsertEnd() function\r
+               can be used in place of vListInsert. */\r
+               vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );\r
+\r
+               /* We must remove this task from the ready list before adding it to the\r
+               blocked list as the same list item is used for both lists.  This \r
+               function is called form a critical section. */\r
+               vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
+\r
+               /* Calculate the time at which the task should be woken if the event does\r
+               not occur.  This may overflow but this doesn't matter. */\r
+               xTimeToWake = xTickCount + xTicksToWait;\r
+               prvAddCurrentTaskToDelayedList( xTimeToWake );\r
+       }\r
+       \r
+#endif /* configUSE_TIMERS */\r
+/*-----------------------------------------------------------*/\r
+\r
 signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )\r
 {\r
 tskTCB *pxUnblockedTCB;\r
index 6b2e602358923ab70c0fd28af80af076f1af6802..b153fd9e281df807b7572d373fa5dc146c5a7c5a 100644 (file)
@@ -1,4 +1,7 @@
-/* Need a method of switching to an overflow list. _RB_*/\r
+/* Need to consider the switching of timer lists, and the placement of tasks into\r
+the current and overflow timer lists very carefully.  For example, should the\r
+assessment as to which list a timer should be inserted into be relative the the\r
+tick count at the timer, or the tick count when the timer task unblocked, etc. */\r
 \r
 /*\r
     FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
@@ -92,7 +95,10 @@ typedef struct tmrTimerQueueMessage
 /* The list in which active timers are stored.  Timers are referenced in expire\r
 time order, with the nearest expiry time at the front of the list.  Only the\r
 timer service task is allowed to access xActiveTimerList. */\r
-PRIVILEGED_DATA static xList xActiveTimerList;\r
+PRIVILEGED_DATA static xList xActiveTimerList1;\r
+PRIVILEGED_DATA static xList xActiveTimerList2;\r
+PRIVILEGED_DATA static xList *pxCurrentTimerList;\r
+PRIVILEGED_DATA static xList *pxOverflowTimerList;\r
 \r
 /* A queue that is used to send commands to the timer service task. */\r
 PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;\r
@@ -118,6 +124,12 @@ static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
  */\r
 static void    prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;\r
 \r
+/*\r
+ * Insert the timer into either xActiveTimerList1, or xActiveTimerList2, \r
+ * depending on if the expire time causes a timer counter overflow. \r
+ */\r
+static void prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime );\r
+\r
 /*-----------------------------------------------------------*/\r
 \r
 portBASE_TYPE xTimerCreateTimerTask( void )\r
@@ -207,9 +219,9 @@ xTIMER *pxTimer;
                the timer with the nearest expiry time will expire.  If there are no\r
                active timers then just set the next expire time to the maximum possible\r
                time to ensure this task does not run unnecessarily. */\r
-               if( listLIST_IS_EMPTY( &xActiveTimerList ) == pdFALSE )\r
+               if( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )\r
                {\r
-                       xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );\r
+                       xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );\r
                }\r
                else\r
                {\r
@@ -220,15 +232,14 @@ xTIMER *pxTimer;
                if( xNextExpireTime <= xTaskGetTickCount() )\r
                {\r
                        /* Remove the timer from the list of active timers. */\r
-                       pxTimer = listGET_OWNER_OF_HEAD_ENTRY( &xActiveTimerList );\r
+                       pxTimer = listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );\r
                        vListRemove( &( pxTimer->xTimerListItem ) );\r
 \r
                        /* If the timer is an autoreload timer then calculate the next\r
                        expiry time and re-insert the timer in the list of active timers. */\r
                        if( pxTimer->uxAutoReload == pdTRUE )\r
                        {\r
-                               listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ) );\r
-                               vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );\r
+                               prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ) );                              \r
                        }\r
 \r
                        /* Call the timer callback. */\r
@@ -263,31 +274,49 @@ xTIMER *pxTimer;
 }\r
 /*-----------------------------------------------------------*/\r
 \r
+static void prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime )\r
+{\r
+       listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );\r
+       listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );\r
+       \r
+       if( xNextExpiryTime < xTaskGetTickCount() )\r
+       {\r
+               vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );\r
+       }\r
+       else\r
+       {\r
+               vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
 static void    prvProcessReceivedCommands( void )\r
 {\r
 xTIMER_MESSAGE xMessage;\r
-portTickType xTimeToExpire;\r
 xTIMER *pxTimer;\r
+xList *pxTemp;\r
 \r
        while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )\r
        {\r
                pxTimer = xMessage.pxTimer;\r
 \r
-               /* Is the timer already in the list of active timers? */\r
-               if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )\r
+               /* Is the timer already in the list of active timers?  When the command\r
+               is trmCOMMAND_PROCESS_TIMER_OVERFLOW, the timer will be NULL as the\r
+               command is to the task rather than to an individual timer. */\r
+               if( pxTimer != NULL )\r
                {\r
-                       /* The timer is in the list, remove it. */\r
-                       vListRemove( &( pxTimer->xTimerListItem ) );\r
+                       if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )\r
+                       {\r
+                               /* The timer is in the list, remove it. */\r
+                               vListRemove( &( pxTimer->xTimerListItem ) );\r
+                       }\r
                }\r
 \r
                switch( xMessage.xMessageID )\r
                {\r
                        case tmrCOMMAND_START : \r
                                /* Start or restart a timer. */\r
-                               xTimeToExpire = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;\r
-                               listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToExpire );\r
-                               listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );\r
-                               vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );\r
+                               prvInsertTimerInActiveList( pxTimer,  xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks );\r
                                break;\r
 \r
                        case tmrCOMMAND_STOP :  \r
@@ -297,10 +326,7 @@ xTIMER *pxTimer;
 \r
                        case tmrCOMMAND_CHANGE_PERIOD :\r
                                pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;\r
-                               xTimeToExpire = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;\r
-                               listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToExpire );\r
-                               listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );\r
-                               vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );\r
+                               prvInsertTimerInActiveList( pxTimer, ( xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks ) );\r
                                break;\r
 \r
                        case tmrCOMMAND_DELETE :\r
@@ -308,6 +334,14 @@ xTIMER *pxTimer;
                                just free up the memory. */\r
                                vPortFree( pxTimer );\r
                                break;\r
+                               \r
+                       case trmCOMMAND_PROCESS_TIMER_OVERFLOW :\r
+                               /* The tick count has overflowed.  The timer lists must be\r
+                               switched. */\r
+                               pxTemp = pxCurrentTimerList;\r
+                               pxCurrentTimerList = pxOverflowTimerList;\r
+                               pxOverflowTimerList = pxTemp;\r
+                               break;\r
 \r
                        default :                       \r
                                /* Don't expect to get here. */\r
@@ -326,7 +360,10 @@ static void prvCheckForValidListAndQueue( void )
        {\r
                if( xTimerQueue == NULL )\r
                {\r
-                       vListInitialise( &xActiveTimerList );\r
+                       vListInitialise( &xActiveTimerList1 );\r
+                       vListInitialise( &xActiveTimerList2 );\r
+                       pxCurrentTimerList = &xActiveTimerList1;\r
+                       pxOverflowTimerList = &xActiveTimerList2;\r
                        xTimerQueue = xQueueCreate( configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );\r
                }\r
        }\r
@@ -342,7 +379,10 @@ xTIMER *pxTimer = ( xTIMER * ) xTimer;
        /* Is the timer in the list of active timers? */\r
        taskENTER_CRITICAL();\r
        {\r
-               xTimerIsInActiveList = listIS_CONTAINED_WITHIN( &xActiveTimerList, &( pxTimer->xTimerListItem ) );\r
+               /* Checking to see if it is in the NULL list in effect checks to see if\r
+               it is referenced from either the current or the overflow timer lists in\r
+               one go, but the logic has to be reversed, hence the '!'. */\r
+               xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );\r
        }\r
        taskEXIT_CRITICAL();\r
 \r