]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Source/tasks.c
Update to the latest atomic.h.
[freertos] / FreeRTOS / Source / tasks.c
index 3274e830f185083789b6dbc8b6983bfeb7143d83..c5b2256817f68571d2911f504f5bbd61a66877dd 100644 (file)
@@ -300,7 +300,10 @@ typedef struct tskTaskControlBlock                         /* The old naming convention is used to pr
                responsible for resulting newlib operation.  User must be familiar with\r
                newlib and must provide system-wide implementations of the necessary\r
                stubs. Be warned that (at the time of writing) the current newlib design\r
-               implements a system-wide malloc() that must be provided with locks. */\r
+               implements a system-wide malloc() that must be provided with locks.\r
+\r
+               See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html\r
+               for additional information. */\r
                struct  _reent xNewLib_reent;\r
        #endif\r
 \r
@@ -368,7 +371,7 @@ PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks  = ( UBaseTyp
 PRIVILEGED_DATA static volatile TickType_t xTickCount                          = ( TickType_t ) configINITIAL_TICK_COUNT;\r
 PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority                 = tskIDLE_PRIORITY;\r
 PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning           = pdFALSE;\r
-PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks                      = ( UBaseType_t ) 0U;\r
+PRIVILEGED_DATA static volatile TickType_t xPendedTicks                        = ( TickType_t ) 0U;\r
 PRIVILEGED_DATA static volatile BaseType_t xYieldPending                       = pdFALSE;\r
 PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows                     = ( BaseType_t ) 0;\r
 PRIVILEGED_DATA static UBaseType_t uxTaskNumber                                        = ( UBaseType_t ) 0U;\r
@@ -993,7 +996,9 @@ UBaseType_t x;
 \r
        #if ( configUSE_NEWLIB_REENTRANT == 1 )\r
        {\r
-               /* Initialise this task's Newlib reent structure. */\r
+               /* Initialise this task's Newlib reent structure.\r
+               See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html\r
+               for additional information. */\r
                _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) );\r
        }\r
        #endif\r
@@ -1164,7 +1169,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
                        being deleted. */\r
                        pxTCB = prvGetTCBFromHandle( xTaskToDelete );\r
 \r
-                       /* Remove task from the ready list. */\r
+                       /* Remove task from the ready/delayed list. */\r
                        if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )\r
                        {\r
                                taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
@@ -1204,6 +1209,10 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
                                check the xTasksWaitingTermination list. */\r
                                ++uxDeletedTasksWaitingCleanUp;\r
 \r
+                               /* Call the delete hook before portPRE_TASK_DELETE_HOOK() as\r
+                               portPRE_TASK_DELETE_HOOK() does not return in the Win32 port. */\r
+                               traceTASK_DELETE( pxTCB );\r
+\r
                                /* The pre-delete hook is primarily for the Windows simulator,\r
                                in which Windows specific clean up operations are performed,\r
                                after which it is not possible to yield away from this task -\r
@@ -1214,14 +1223,13 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
                        else\r
                        {\r
                                --uxCurrentNumberOfTasks;\r
+                               traceTASK_DELETE( pxTCB );\r
                                prvDeleteTCB( pxTCB );\r
 \r
                                /* Reset the next expected unblock time in case it referred to\r
                                the task that has just been deleted. */\r
                                prvResetNextTaskUnblockTime();\r
                        }\r
-\r
-                       traceTASK_DELETE( pxTCB );\r
                }\r
                taskEXIT_CRITICAL();\r
 \r
@@ -2041,7 +2049,9 @@ BaseType_t xReturn;
                #if ( configUSE_NEWLIB_REENTRANT == 1 )\r
                {\r
                        /* Switch Newlib's _impure_ptr variable to point to the _reent\r
-                       structure specific to the task that will run first. */\r
+                       structure specific to the task that will run first.\r
+                       See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html\r
+                       for additional information. */\r
                        _impure_ptr = &( pxCurrentTCB->xNewLib_reent );\r
                }\r
                #endif /* configUSE_NEWLIB_REENTRANT */\r
@@ -2175,6 +2185,7 @@ BaseType_t xTaskResumeAll( void )
 {\r
 TCB_t *pxTCB = NULL;\r
 BaseType_t xAlreadyYielded = pdFALSE;\r
+TickType_t xTicksToNextUnblockTime;\r
 \r
        /* If uxSchedulerSuspended is zero then this function does not match a\r
        previous call to vTaskSuspendAll(). */\r
@@ -2229,30 +2240,51 @@ BaseType_t xAlreadyYielded = pdFALSE;
                                they should be processed now.  This ensures the tick count does\r
                                not     slip, and that any delayed tasks are resumed at the correct\r
                                time. */\r
+                               while( xPendedTicks > ( TickType_t ) 0 )\r
                                {\r
-                                       UBaseType_t uxPendedCounts = uxPendedTicks; /* Non-volatile copy. */\r
+                                       /* Calculate how far into the future the next task will\r
+                                       leave the Blocked state because its timeout expired.  If\r
+                                       there are no tasks due to leave the blocked state between\r
+                                       the time now and the time at which the tick count overflows\r
+                                       then xNextTaskUnblockTime will the tick overflow time.\r
+                                       This means xNextTaskUnblockTime can never be less than\r
+                                       xTickCount, and the following can therefore not\r
+                                       underflow. */\r
+                                       configASSERT( xNextTaskUnblockTime >= xTickCount );\r
+                                       xTicksToNextUnblockTime = xNextTaskUnblockTime - xTickCount;\r
 \r
-                                       if( uxPendedCounts > ( UBaseType_t ) 0U )\r
+                                       /* Don't want to move the tick count more than the number\r
+                                       of ticks that are pending, so cap if necessary. */\r
+                                       if( xTicksToNextUnblockTime > xPendedTicks )\r
                                        {\r
-                                               do\r
-                                               {\r
-                                                       if( xTaskIncrementTick() != pdFALSE )\r
-                                                       {\r
-                                                               xYieldPending = pdTRUE;\r
-                                                       }\r
-                                                       else\r
-                                                       {\r
-                                                               mtCOVERAGE_TEST_MARKER();\r
-                                                       }\r
-                                                       --uxPendedCounts;\r
-                                               } while( uxPendedCounts > ( UBaseType_t ) 0U );\r
+                                               xTicksToNextUnblockTime = xPendedTicks;\r
+                                       }\r
 \r
-                                               uxPendedTicks = 0;\r
+                                       if( xTicksToNextUnblockTime == 0 )\r
+                                       {\r
+                                               /* xTicksToNextUnblockTime could be zero if the tick\r
+                                               count is about to overflow and xTicksToNetUnblockTime\r
+                                               holds the time at which the tick count will overflow\r
+                                               (rather than the time at which the next task will\r
+                                               unblock).  Set to 1 otherwise xPendedTicks won't be\r
+                                               decremented below. */\r
+                                               xTicksToNextUnblockTime = ( TickType_t ) 1;\r
                                        }\r
-                                       else\r
+                                       else if( xTicksToNextUnblockTime > ( TickType_t ) 1 )\r
                                        {\r
-                                               mtCOVERAGE_TEST_MARKER();\r
+                                               /* Move the tick count one short of the next unblock\r
+                                               time, then call xTaskIncrementTick() to move the tick\r
+                                               count up to the next unblock time to unblock the task,\r
+                                               if any.  This will also swap the blocked task and\r
+                                               overflow blocked task lists if necessary. */\r
+                                               xTickCount += ( xTicksToNextUnblockTime - ( TickType_t ) 1 );\r
                                        }\r
+                                       xYieldPending |= xTaskIncrementTick();\r
+\r
+                                       /* Adjust for the number of ticks just added to\r
+                                       xTickCount and go around the loop again if\r
+                                       xTicksToCatchUp is still greater than 0. */\r
+                                       xPendedTicks -= xTicksToNextUnblockTime;\r
                                }\r
 \r
                                if( xYieldPending != pdFALSE )\r
@@ -2586,6 +2618,24 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
 #endif /* configUSE_TICKLESS_IDLE */\r
 /*----------------------------------------------------------*/\r
 \r
+BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp )\r
+{\r
+BaseType_t xYieldRequired = pdFALSE;\r
+\r
+       /* Must not be called with the scheduler suspended as the implementation\r
+       relies on xPendedTicks being wound down to 0 in xTaskResumeAll(). */\r
+       configASSERT( uxSchedulerSuspended == 0 );\r
+\r
+       /* Use xPendedTicks to mimic xTicksToCatchUp number of ticks occuring when\r
+       the scheduler is suspended so the ticks are executed in xTaskResumeAll(). */\r
+       vTaskSuspendAll();\r
+       xPendedTicks += xTicksToCatchUp;\r
+       xYieldRequired = xTaskResumeAll();\r
+\r
+       return xYieldRequired;\r
+}\r
+/*----------------------------------------------------------*/\r
+\r
 #if ( INCLUDE_xTaskAbortDelay == 1 )\r
 \r
        BaseType_t xTaskAbortDelay( TaskHandle_t xTask )\r
@@ -2793,7 +2843,7 @@ BaseType_t xSwitchRequired = pdFALSE;
                {\r
                        /* Guard against the tick hook being called when the pended tick\r
                        count is being unwound (when the scheduler is being unlocked). */\r
-                       if( uxPendedTicks == ( UBaseType_t ) 0U )\r
+                       if( xPendedTicks == ( TickType_t ) 0 )\r
                        {\r
                                vApplicationTickHook();\r
                        }\r
@@ -2803,10 +2853,23 @@ BaseType_t xSwitchRequired = pdFALSE;
                        }\r
                }\r
                #endif /* configUSE_TICK_HOOK */\r
+\r
+               #if ( configUSE_PREEMPTION == 1 )\r
+               {\r
+                       if( xYieldPending != pdFALSE )\r
+                       {\r
+                               xSwitchRequired = pdTRUE;\r
+                       }\r
+                       else\r
+                       {\r
+                               mtCOVERAGE_TEST_MARKER();\r
+                       }\r
+               }\r
+               #endif /* configUSE_PREEMPTION */\r
        }\r
        else\r
        {\r
-               ++uxPendedTicks;\r
+               ++xPendedTicks;\r
 \r
                /* The tick hook gets called at regular intervals, even if the\r
                scheduler is locked. */\r
@@ -2817,19 +2880,6 @@ BaseType_t xSwitchRequired = pdFALSE;
                #endif\r
        }\r
 \r
-       #if ( configUSE_PREEMPTION == 1 )\r
-       {\r
-               if( xYieldPending != pdFALSE )\r
-               {\r
-                       xSwitchRequired = pdTRUE;\r
-               }\r
-               else\r
-               {\r
-                       mtCOVERAGE_TEST_MARKER();\r
-               }\r
-       }\r
-       #endif /* configUSE_PREEMPTION */\r
-\r
        return xSwitchRequired;\r
 }\r
 /*-----------------------------------------------------------*/\r
@@ -3009,7 +3059,9 @@ void vTaskSwitchContext( void )
                #if ( configUSE_NEWLIB_REENTRANT == 1 )\r
                {\r
                        /* Switch Newlib's _impure_ptr variable to point to the _reent\r
-                       structure specific to this task. */\r
+                       structure specific to this task.\r
+                       See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html\r
+                       for additional information. */\r
                        _impure_ptr = &( pxCurrentTCB->xNewLib_reent );\r
                }\r
                #endif /* configUSE_NEWLIB_REENTRANT */\r
@@ -3831,7 +3883,9 @@ static void prvCheckTasksWaitingTermination( void )
                portCLEAN_UP_TCB( pxTCB );\r
 \r
                /* Free up the memory allocated by the scheduler for the task.  It is up\r
-               to the task to free any memory allocated at the application level. */\r
+               to the task to free any memory allocated at the application level.\r
+               See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html\r
+               for additional information. */\r
                #if ( configUSE_NEWLIB_REENTRANT == 1 )\r
                {\r
                        _reclaim_reent( &( pxTCB->xNewLib_reent ) );\r
@@ -3981,7 +4035,10 @@ TCB_t *pxTCB;
                                {\r
                                        if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )\r
                                        {\r
-                                               taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );\r
+                                               /* It is known that the task is in its ready list so\r
+                                               there is no need to check again and the port level\r
+                                               reset macro can be called directly. */\r
+                                               portRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority, uxTopReadyPriority );\r
                                        }\r
                                        else\r
                                        {\r
@@ -4061,7 +4118,7 @@ TCB_t *pxTCB;
                                        the mutex.  If the mutex is held by a task then it cannot be\r
                                        given from an interrupt, and if a mutex is given by the\r
                                        holding task then it must be the running state task.  Remove\r
-                                       the holding task from the ready list. */\r
+                                       the holding task from the ready/delayed list. */\r
                                        if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )\r
                                        {\r
                                                taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
@@ -4182,7 +4239,10 @@ TCB_t *pxTCB;
                                        {\r
                                                if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )\r
                                                {\r
-                                                       taskRESET_READY_PRIORITY( pxTCB->uxPriority );\r
+                                                       /* It is known that the task is in its ready list so\r
+                                                       there is no need to check again and the port level\r
+                                                       reset macro can be called directly. */\r
+                                                       portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority );\r
                                                }\r
                                                else\r
                                                {\r
@@ -5071,10 +5131,12 @@ TickType_t uxReturn;
 /*-----------------------------------------------------------*/\r
 \r
 #if( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) )\r
-       TickType_t xTaskGetIdleRunTimeCounter( void )\r
+\r
+       uint32_t ulTaskGetIdleRunTimeCounter( void )\r
        {\r
                return xIdleTaskHandle->ulRunTimeCounter;\r
        }\r
+\r
 #endif\r
 /*-----------------------------------------------------------*/\r
 \r