]> git.sur5r.net Git - freertos/blobdiff - Source/tasks.c
Update to V4.3.0 as described in http://www.FreeRTOS.org/History.txt
[freertos] / Source / tasks.c
index d6b468e166d3bc45905c0cd7b919c4ab196be87d..23c9271cbe45a153d17a0a70db8e7bbdccadb112 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-       FreeRTOS.org V4.0.4 - Copyright (C) 2003-2006 Richard Barry.\r
+       FreeRTOS.org V4.3.0 - Copyright (C) 2003-2007 Richard Barry.\r
 \r
        This file is part of the FreeRTOS.org distribution.\r
 \r
@@ -27,6 +27,9 @@
        See http://www.FreeRTOS.org for documentation, latest information, license\r
        and contact details.  Please ensure to read the configuration and relevant\r
        port sections of the online documentation.\r
+\r
+       Also see http://www.SafeRTOS.com for an IEC 61508 compliant version, along\r
+       with development and support options.\r
        ***************************************************************************\r
 */\r
 \r
@@ -153,17 +156,46 @@ Changes from V4.0.0
 Changes from V4.0.1\r
 \r
        + The function vTaskList() now suspends the scheduler rather than disabling\r
-         interrups during the creation of the task list.  \r
+         interrupts during the creation of the task list.  \r
        + Allow a task to delete itself by passing in its own handle.  Previously \r
          this could only be done by passing in NULL.\r
        + The tick hook function is now called only within a tick isr.  Previously\r
          it was also called when the tick function was called during the scheduler\r
          unlocking process.\r
 \r
-Changes from V4.0.4\r
+Changes from V4.0.3\r
 \r
        + Extra checks have been placed in vTaskPrioritySet() to avoid unnecessary\r
          yields.\r
+\r
+Changed from V4.0.4\r
+\r
+       + Bug fix:  The 'value' of the event list item is updated when the priority\r
+         of a task is changed.  Previously only the priority of the TCB itself was\r
+         changed.\r
+       + When resuming a task a check is first made to see if the task is actually\r
+         suspended.\r
+       + vTaskPrioritySet() and vTaskResume() no longer use the event list item.\r
+         This has not been necessary since V4.0.1 when the xMissedYield handling\r
+         was added.\r
+       + Implement xTaskResumeFromISR().\r
+\r
+Changes from V4.0.5\r
+\r
+       + Added utility functions and xOverflowCount variable to facilitate the\r
+         queue.c changes.\r
+\r
+Changes from V4.1.2\r
+       \r
+       + Tasks that block on events with a timeout of portMAX_DELAY are now\r
+         blocked indefinitely if configINCLUDE_vTaskSuspend is defined. \r
+         Previously portMAX_DELAY was just the longest block time possible.\r
+\r
+Changes from V4.1.3\r
+\r
+       + Very small change made to xTaskCheckForTimeout() as a result of the \r
+       SafeRTOS testing.  This corrects the case where the function can return an\r
+       invalid value - but only in an extremely unlikely scenario.\r
 */\r
 \r
 #include <stdio.h>\r
@@ -200,6 +232,9 @@ Changes from V4.0.4
        #define configMAX_TASK_NAME_LEN 1\r
 #endif\r
 \r
+#ifndef INCLUDE_xTaskResumeFromISR\r
+       #define INCLUDE_xTaskResumeFromISR 1\r
+#endif \r
 \r
 /*\r
  * Task control block.  A task control block (TCB) is allocated to each task,\r
@@ -246,13 +281,13 @@ static xList xPendingReadyList;                                                   /*< Tasks that have been readied while the
 /* File private variables. --------------------------------*/\r
 static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks  = ( unsigned portBASE_TYPE ) 0;\r
 static volatile portTickType xTickCount                                                        = ( portTickType ) 0;\r
-static unsigned portBASE_TYPE uxTopUsedPriority                                = tskIDLE_PRIORITY;\r
+static unsigned portBASE_TYPE uxTopUsedPriority                                        = tskIDLE_PRIORITY;\r
 static volatile unsigned portBASE_TYPE uxTopReadyPriority              = tskIDLE_PRIORITY;\r
 static volatile signed portBASE_TYPE xSchedulerRunning                 = pdFALSE;\r
 static volatile unsigned portBASE_TYPE uxSchedulerSuspended            = ( unsigned portBASE_TYPE ) pdFALSE;\r
 static volatile unsigned portBASE_TYPE uxMissedTicks                   = ( unsigned portBASE_TYPE ) 0;\r
 static volatile portBASE_TYPE xMissedYield                                             = ( portBASE_TYPE ) pdFALSE;\r
-\r
+static volatile portBASE_TYPE xNumOfOverflows                                  = ( portBASE_TYPE ) 0;\r
 /* Debugging and trace facilities private variables and macros. ------------*/\r
 \r
 /*\r
@@ -290,28 +325,28 @@ static volatile portBASE_TYPE xMissedYield                                                = ( portBASE_TYPE ) pdFALSE;
  */\r
 #if ( configUSE_TRACE_FACILITY == 1 )\r
 \r
-       #define vWriteTraceToBuffer()                                                                                                           \\r
-       {                                                                                                                                                                       \\r
-               if( xTracing )                                                                                                                                  \\r
-               {                                                                                                                                                               \\r
-                       static unsigned portBASE_TYPE uxPreviousTask = 255;                                                     \\r
-                                                                                                                                                                               \\r
-                       if( uxPreviousTask != pxCurrentTCB->uxTCBNumber )                                                       \\r
-                       {                                                                                                                                                       \\r
-                               if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \\r
-                               {                                                                                                                                               \\r
-                                       uxPreviousTask = pxCurrentTCB->uxTCBNumber;                                                     \\r
+       #define vWriteTraceToBuffer()                                                                                                                                   \\r
+       {                                                                                                                                                                                               \\r
+               if( xTracing )                                                                                                                                                          \\r
+               {                                                                                                                                                                                       \\r
+                       static unsigned portBASE_TYPE uxPreviousTask = 255;                                                                             \\r
+                                                                                                                                                                                                       \\r
+                       if( uxPreviousTask != pxCurrentTCB->uxTCBNumber )                                                                               \\r
+                       {                                                                                                                                                                               \\r
+                               if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd )                         \\r
+                               {                                                                                                                                                                       \\r
+                                       uxPreviousTask = pxCurrentTCB->uxTCBNumber;                                                                             \\r
                                        *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) xTickCount;              \\r
-                                       pcTraceBuffer += sizeof( unsigned portLONG );                                           \\r
+                                       pcTraceBuffer += sizeof( unsigned portLONG );                                                                   \\r
                                        *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) uxPreviousTask;  \\r
-                                       pcTraceBuffer += sizeof( unsigned portLONG );                                           \\r
-                               }                                                                                                                                               \\r
-                               else                                                                                                                                    \\r
-                               {                                                                                                                                               \\r
-                                       xTracing = pdFALSE;                                                                                                     \\r
-                               }                                                                                                                                               \\r
-                       }                                                                                                                                                       \\r
-               }                                                                                                                                                               \\r
+                                       pcTraceBuffer += sizeof( unsigned portLONG );                                                                   \\r
+                               }                                                                                                                                                                       \\r
+                               else                                                                                                                                                            \\r
+                               {                                                                                                                                                                       \\r
+                                       xTracing = pdFALSE;                                                                                                                             \\r
+                               }                                                                                                                                                                       \\r
+                       }                                                                                                                                                                               \\r
+               }                                                                                                                                                                                       \\r
        }\r
 \r
 #else\r
@@ -335,8 +370,7 @@ static volatile portBASE_TYPE xMissedYield                                          = ( portBASE_TYPE ) pdFALSE;
                uxTopReadyPriority = pxTCB->uxPriority;                                                                                                                                 \\r
        }                                                                                                                                                                                                                       \\r
        vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) );        \\r
-}      \r
-\r
+}              \r
 \r
 /*\r
  * Macro that looks at the list of tasks that are currently delayed to see if\r
@@ -346,24 +380,24 @@ static volatile portBASE_TYPE xMissedYield                                                = ( portBASE_TYPE ) pdFALSE;
  * once one tasks has been found whose timer has not expired we need not look\r
  * any further down the list.\r
  */\r
-#define prvCheckDelayedTasks()                                                                                                                                 \\r
-{                                                                                                                                                                                              \\r
-register tskTCB *pxTCB;                                                                                                                                                        \\r
-                                                                                                                                                                                               \\r
-       while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL )      \\r
-       {                                                                                                                                                                                       \\r
-               if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) )                              \\r
-               {                                                                                                                                                                               \\r
-                       break;                                                                                                                                                          \\r
-               }                                                                                                                                                                               \\r
-               vListRemove( &( pxTCB->xGenericListItem ) );                                                                                    \\r
-               /* Is the task waiting on an event also? */                                                                                             \\r
-               if( pxTCB->xEventListItem.pvContainer )                                                                                                 \\r
-               {                                                                                                                                                                               \\r
-                       vListRemove( &( pxTCB->xEventListItem ) );                                                                                      \\r
-               }                                                                                                                                                                               \\r
+#define prvCheckDelayedTasks()                                                                                                                                                                         \\r
+{                                                                                                                                                                                                                                      \\r
+register tskTCB *pxTCB;                                                                                                                                                                                                \\r
+                                                                                                                                                                                                                                       \\r
+       while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL )                                              \\r
+       {                                                                                                                                                                                                                               \\r
+               if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) )                                                                      \\r
+               {                                                                                                                                                                                                                       \\r
+                       break;                                                                                                                                                                                                  \\r
+               }                                                                                                                                                                                                                       \\r
+               vListRemove( &( pxTCB->xGenericListItem ) );                                                                                                                            \\r
+               /* Is the task waiting on an event also? */                                                                                                                                     \\r
+               if( pxTCB->xEventListItem.pvContainer )                                                                                                                                         \\r
+               {                                                                                                                                                                                                                       \\r
+                       vListRemove( &( pxTCB->xEventListItem ) );                                                                                                                              \\r
+               }                                                                                                                                                                                                                       \\r
                prvAddTaskToReadyQueue( pxTCB );                                                                                                                \\r
-       }                                                                                                                                                                                       \\r
+       }                                                                                                                                                                                                                               \\r
 }                                                                                                                                                                                      \r
 \r
 /*\r
@@ -615,9 +649,12 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat
                taskEXIT_CRITICAL();\r
 \r
                /* Force a reschedule if we have just deleted the current task. */\r
-               if( ( void * ) pxTaskToDelete == NULL )\r
+               if( xSchedulerRunning != pdFALSE ) \r
                {\r
-                       taskYIELD();\r
+                       if( ( void * ) pxTaskToDelete == NULL )\r
+                       {\r
+                               taskYIELD();\r
+                       }\r
                }\r
        }\r
 \r
@@ -831,6 +868,7 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat
                                }\r
                        \r
                                pxTCB->uxPriority = uxNewPriority;\r
+                               listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxNewPriority );\r
 \r
                                /* If the task is in the blocked or suspended list we need do\r
                                nothing more than change it's priority variable. However, if\r
@@ -838,19 +876,11 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat
                                in the queue appropriate to its new priority. */\r
                                if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )\r
                                {\r
-                                       if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
-                                       {\r
-                                               /* The task is currently in its ready list - remove before adding\r
-                                               it to it's new ready list. */\r
-                                               vListRemove( &( pxTCB->xGenericListItem ) );\r
-                                               prvAddTaskToReadyQueue( pxTCB );\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               /* We cannot access the delayed or ready lists, so will hold this\r
-                                               task pending until the scheduler is resumed. */\r
-                                               vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );\r
-                                       }\r
+                                       /* The task is currently in its ready list - remove before adding\r
+                                       it to it's new ready list.  As we are in a critical section we\r
+                                       can do this even if the scheduler is suspended. */\r
+                                       vListRemove( &( pxTCB->xGenericListItem ) );\r
+                                       prvAddTaskToReadyQueue( pxTCB );\r
                                }                       \r
                                \r
                                if( xYieldRequired == pdTRUE )\r
@@ -911,7 +941,6 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat
        void vTaskResume( xTaskHandle pxTaskToResume )\r
        {\r
        tskTCB *pxTCB;\r
-       portBASE_TYPE xYieldRequired;\r
 \r
                /* Remove the task from whichever list it is currently in, and place\r
                it in the ready list. */\r
@@ -922,31 +951,68 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat
                if( pxTCB != NULL )\r
                {\r
                        taskENTER_CRITICAL();\r
+                       {\r
+                               /* Is the task we are attempting to resume actually suspended? */\r
+                               if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )\r
+                               {\r
+                                       /* Has the task already been resumed from within an ISR? */\r
+                                       if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )\r
+                                       {                       \r
+                                               /* As we are in a critical section we can access the ready \r
+                                               lists even if the scheduler is suspended. */\r
+                                               vListRemove(  &( pxTCB->xGenericListItem ) );\r
+                                               prvAddTaskToReadyQueue( pxTCB );\r
+\r
+                                               /* We may have just resumed a higher priority task. */\r
+                                               if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )\r
+                                               {\r
+                                                       /* This yield may not cause the task just resumed to run, but\r
+                                                       will leave the lists in the correct state for the next yield. */\r
+                                                       taskYIELD();\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       taskEXIT_CRITICAL();\r
+               }\r
+       }\r
+\r
+#endif\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )\r
+\r
+       portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )\r
+       {\r
+       portBASE_TYPE xYieldRequired = pdFALSE;\r
+       tskTCB *pxTCB;\r
+\r
+               pxTCB = ( tskTCB * ) pxTaskToResume;\r
+\r
+               /* Is the task we are attempting to resume actually suspended? */\r
+               if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )\r
+               {\r
+                       /* Has the task already been resumed from within an ISR? */\r
+                       if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )\r
                        {\r
                                if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )\r
                                {\r
                                        xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );\r
-                                       vListRemove(  &( pxTCB->xGenericListItem ) );\r
+                                       vListRemove(  &( pxTCB->xGenericListItem ) );   \r
                                        prvAddTaskToReadyQueue( pxTCB );\r
                                }\r
                                else\r
                                {\r
                                        /* We cannot access the delayed or ready lists, so will hold this\r
-                                       task pending until the scheduler is resumed. */\r
-                                       xYieldRequired = pdFALSE;\r
+                                       task pending until the scheduler is resumed, at which point a \r
+                                       yield will be preformed if necessary. */\r
                                        vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );\r
                                }\r
                        }\r
-                       taskEXIT_CRITICAL();\r
-\r
-                       /* We may have just resumed a higher priority task. */\r
-                       if( xYieldRequired )\r
-                       {\r
-                               /* This yield may not cause the task just resumed to run, but\r
-                               will leave the lists in the correct state for the next yield. */\r
-                               taskYIELD();\r
-                       }\r
                }\r
+\r
+               return xYieldRequired;\r
        }\r
 \r
 #endif\r
@@ -954,7 +1020,6 @@ static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberat
 \r
 \r
 \r
-\r
 /*-----------------------------------------------------------\r
  * PUBLIC SCHEDULER CONTROL documented in task.h\r
  *----------------------------------------------------------*/\r
@@ -1236,6 +1301,7 @@ inline void vTaskIncrementTick( void )
                        pxTemp = pxDelayedTaskList;\r
                        pxDelayedTaskList = pxOverflowDelayedTaskList;\r
                        pxOverflowDelayedTaskList = pxTemp;\r
+            xNumOfOverflows++;\r
                }\r
 \r
                /* See if this tick has made a timeout expire. */\r
@@ -1367,27 +1433,61 @@ portTickType xTimeToWake;
        is the first to be woken by the event. */\r
        vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );\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
-\r
        /* We must remove ourselves from the ready list before adding ourselves\r
        to the blocked list as the same list item is used for both lists.  We have\r
        exclusive access to the ready lists as the scheduler is locked. */\r
        vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
 \r
-       listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
 \r
-       if( xTimeToWake < xTickCount )\r
-       {\r
-               /* Wake time has overflowed.  Place this item in the overflow list. */\r
-               vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
+       #if ( INCLUDE_vTaskSuspend == 1 )\r
+       {                        \r
+               if( xTicksToWait == portMAX_DELAY )\r
+               {\r
+                       /* Add ourselves to the suspended task list instead of a delayed task\r
+                       list to ensure we are not woken by a timing event.  We will block\r
+                       indefinitely. */\r
+                       vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
+               }\r
+               else\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
+               \r
+                       listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
+               \r
+                       if( xTimeToWake < xTickCount )\r
+                       {\r
+                               /* Wake time has overflowed.  Place this item in the overflow list. */\r
+                               vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
+                       }\r
+                       else\r
+                       {\r
+                               /* The wake time has not overflowed, so we can use the current block list. */\r
+                               vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
+                       }\r
+               }\r
        }\r
-       else\r
+       #else\r
        {\r
-               /* The wake time has not overflowed, so we can use the current block list. */\r
-               vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\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
+               \r
+                       listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );\r
+               \r
+                       if( xTimeToWake < xTickCount )\r
+                       {\r
+                               /* Wake time has overflowed.  Place this item in the overflow list. */\r
+                               vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
+                       }\r
+                       else\r
+                       {\r
+                               /* The wake time has not overflowed, so we can use the current block list. */\r
+                               vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );\r
+                       }\r
        }\r
+       #endif\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
@@ -1436,10 +1536,47 @@ portBASE_TYPE xReturn;
 \r
        return xReturn;\r
 }\r
+/*-----------------------------------------------------------*/\r
 \r
+void vTaskSetTimeOutState( xTimeOutType *pxTimeOut )\r
+{\r
+    pxTimeOut->xOverflowCount = xNumOfOverflows;\r
+    pxTimeOut->xTimeOnEntering = xTickCount;\r
+}\r
+/*-----------------------------------------------------------*/\r
 \r
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType *pxTicksToWait )\r
+{\r
+portBASE_TYPE xReturn;\r
 \r
+    if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xTickCount >= pxTimeOut->xTimeOnEntering ) )\r
+    {\r
+        /* The tick count is greater than the time at which vTaskSetTimeout() \r
+               was called, but has also overflowed since vTaskSetTimeOut() was called.\r
+        It must have wrapped all the way around and gone past us again. This\r
+        passed since vTaskSetTimeout() was called. */\r
+        xReturn = pdTRUE;\r
+    }\r
+    else if( ( xTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait )\r
+    {\r
+        /* Not a genuine timeout. Adjust parameters for time remaining. */\r
+        *pxTicksToWait -= ( xTickCount - pxTimeOut->xTimeOnEntering );\r
+        vTaskSetTimeOutState( pxTimeOut );\r
+        xReturn = pdFALSE;\r
+    }\r
+    else\r
+    {\r
+        xReturn = pdTRUE;\r
+    }\r
+\r
+    return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
 \r
+void vTaskMissedYield( void )\r
+{\r
+       xMissedYield = pdTRUE;\r
+}\r
 \r
 /*\r
  * -----------------------------------------------------------\r