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