From c26b230d280de74cc56bd7d0ba0f31111e4729ce Mon Sep 17 00:00:00 2001 From: Richard Barry Date: Sun, 6 Feb 2011 15:44:56 +0000 Subject: [PATCH] Some time and code size optimisations. --- Source/croutine.c | 11 ++- Source/include/list.h | 2 +- Source/queue.c | 12 +-- Source/tasks.c | 203 +++++++++++++++++++++++++----------------- 4 files changed, 133 insertions(+), 95 deletions(-) diff --git a/Source/croutine.c b/Source/croutine.c index f180a8774..61ada1c29 100644 --- a/Source/croutine.c +++ b/Source/croutine.c @@ -222,7 +222,7 @@ static void prvCheckPendingReadyList( void ) /* Are there any co-routines waiting to get moved to the ready list? These are co-routines that have been readied by an ISR. The ISR cannot access the ready lists itself. */ - while( !listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) ) + while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE ) { corCRCB *pxUnblockedCRCB; @@ -263,8 +263,10 @@ corCRCB *pxCRCB; } /* See if this tick has made a timeout expire. */ - while( ( pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ) ) != NULL ) - { + while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE ) + { + pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ); + if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) ) { /* Timeout not yet expired. */ @@ -352,7 +354,8 @@ corCRCB *pxUnblockedCRCB; signed portBASE_TYPE xReturn; /* This function is called from within an interrupt. It can only access - event lists and the pending ready list. */ + event lists and the pending ready list. This function assumes that a + check has already been made to ensure pxEventList is not empty. */ pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); vListRemove( &( pxUnblockedCRCB->xEventListItem ) ); vListInsertEnd( ( xList * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) ); diff --git a/Source/include/list.h b/Source/include/list.h index 5a09fd1d6..ec1d08ce4 100644 --- a/Source/include/list.h +++ b/Source/include/list.h @@ -214,7 +214,7 @@ xList * const pxConstList = pxList; \ * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY * \ingroup LinkedList */ -#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( ( pxList->uxNumberOfItems != ( unsigned portBASE_TYPE ) 0 ) ? ( (&( pxList->xListEnd ))->pxNext->pvOwner ) : ( NULL ) ) +#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( pxList->xListEnd ))->pxNext->pvOwner ) /* * Check to see if a list item is within a list. The list item maintains a diff --git a/Source/queue.c b/Source/queue.c index a62d179e9..30c30b076 100644 --- a/Source/queue.c +++ b/Source/queue.c @@ -697,7 +697,7 @@ xTimeOutType xTimeOut; /* The data is being left in the queue, so see if there are any other tasks waiting for the data. */ - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { /* Tasks that are removed from the event list will get added to the pending ready list as the scheduler is still suspended. */ @@ -790,7 +790,7 @@ unsigned portBASE_TYPE uxSavedInterruptStatus; be done when the queue is unlocked later. */ if( pxQueue->xTxLock == queueUNLOCKED ) { - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) { @@ -880,7 +880,7 @@ signed char *pcOriginalReadPosition; /* The data is being left in the queue, so see if there are any other tasks waiting for the data. */ - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { /* Tasks that are removed from the event list will get added to the pending ready list as the scheduler is still suspended. */ @@ -988,7 +988,7 @@ unsigned portBASE_TYPE uxSavedInterruptStatus; that an ISR has removed data while the queue was locked. */ if( pxQueue->xRxLock == queueUNLOCKED ) { - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { @@ -1117,7 +1117,7 @@ static void prvUnlockQueue( xQueueHandle pxQueue ) { /* Data was posted while the queue was locked. Are any tasks blocked waiting for data to become available? */ - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) { /* Tasks that are removed from the event list will get added to the pending ready list as the scheduler is still suspended. */ @@ -1145,7 +1145,7 @@ static void prvUnlockQueue( xQueueHandle pxQueue ) { while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED ) { - if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) ) + if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) { if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) { diff --git a/Source/tasks.c b/Source/tasks.c index 120f8f7e3..965d0a015 100644 --- a/Source/tasks.c +++ b/Source/tasks.c @@ -161,6 +161,7 @@ PRIVILEGED_DATA static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsi PRIVILEGED_DATA static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE; PRIVILEGED_DATA static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0; PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned portBASE_TYPE ) 0; +PRIVILEGED_DATA static portTickType xNextTaskUnblockTime = ( portTickType ) portMAX_DELAY; #if ( configGENERATE_RUN_TIME_STATS == 1 ) @@ -220,10 +221,10 @@ PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned po if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \ { \ uxPreviousTask = pxCurrentTCB->uxTCBNumber; \ - *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \ - pcTraceBuffer += sizeof( unsigned long ); \ - *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \ - pcTraceBuffer += sizeof( unsigned long ); \ + *( unsigned long * ) pcTraceBuffer = ( unsigned long ) xTickCount; \ + pcTraceBuffer += sizeof( unsigned long ); \ + *( unsigned long * ) pcTraceBuffer = ( unsigned long ) uxPreviousTask; \ + pcTraceBuffer += sizeof( unsigned long ); \ } \ else \ { \ @@ -265,24 +266,57 @@ PRIVILEGED_DATA static unsigned portBASE_TYPE uxTaskNumber = ( unsigned po * once one tasks has been found whose timer has not expired we need not look * any further down the list. */ -#define prvCheckDelayedTasks() \ -{ \ -register tskTCB *pxTCB; \ - \ - while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \ - { \ - if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \ - { \ - break; \ - } \ - vListRemove( &( pxTCB->xGenericListItem ) ); \ - /* Is the task waiting on an event also? */ \ - if( pxTCB->xEventListItem.pvContainer ) \ - { \ - vListRemove( &( pxTCB->xEventListItem ) ); \ - } \ - prvAddTaskToReadyQueue( pxTCB ); \ - } \ +#define prvCheckDelayedTasks() \ +{ \ +register tskTCB *pxTCB; \ +portTickType xItemValue; \ + \ + /* Is the tick count greater than or equal to the wake time of the first \ + task referenced from the delayed tasks list? */ \ + if( xTickCount >= xNextTaskUnblockTime ) \ + { \ + for( ;; ) \ + { \ + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) \ + { \ + /* The delayed list is empty. Set xNextTaskUnblockTime to the \ + maximum possible value so it is extremely unlikely that the \ + if( xTickCount >= xNextTaskUnblockTime ) test will pass next \ + time through. */ \ + xNextTaskUnblockTime = portMAX_DELAY; \ + break; \ + } \ + else \ + { \ + /* The delayed list is not empty, get the value of the item at \ + the head of the delayed list. This is the time at which the \ + task at the head of the delayed list should be removed from \ + the Blocked state. */ \ + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); \ + xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); \ + \ + if( xTickCount < xItemValue ) \ + { \ + /* It is not time to unblock this item yet, but the item \ + value is the time at which the task at the head of the \ + blocked list should be removed from the Blocked state - \ + so record the item value in xNextTaskUnblockTime. */ \ + xNextTaskUnblockTime = xItemValue; \ + break; \ + } \ + \ + /* It is time to remove the item from the Blocked state. */ \ + vListRemove( &( pxTCB->xGenericListItem ) ); \ + \ + /* Is the task waiting on an event also? */ \ + if( pxTCB->xEventListItem.pvContainer ) \ + { \ + vListRemove( &( pxTCB->xEventListItem ) ); \ + } \ + prvAddTaskToReadyQueue( pxTCB ); \ + } \ + } \ + } \ } /*-----------------------------------------------------------*/ @@ -342,6 +376,12 @@ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ); */ static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION; +/* + * The currently executing task is entering the Blocked state. Add the task to + * either the current or the overflow delayed task list. + */ +static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) PRIVILEGED_FUNCTION; + /* * Allocates memory from the heap for a TCB and associated stack. Checks the * allocation was successful. @@ -637,7 +677,7 @@ tskTCB * pxNewTCB; /* Update the wake time ready for the next call. */ *pxPreviousWakeTime = xTimeToWake; - if( xShouldDelay ) + if( xShouldDelay != pdFALSE ) { traceTASK_DELAY_UNTIL(); @@ -645,22 +685,7 @@ tskTCB * pxNewTCB; ourselves to the blocked list as the same list item is used for both lists. */ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - - /* The list item will be inserted in wake time order. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); - - if( xTimeToWake < xTickCount ) - { - /* Wake time has overflowed. Place this item in the - overflow list. */ - vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* The wake time has not overflowed, so we can use the - current block list. */ - vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } + prvAddCurrentTaskToDelayedList( xTimeToWake ); } } xAlreadyYielded = xTaskResumeAll(); @@ -706,22 +731,7 @@ tskTCB * pxNewTCB; ourselves to the blocked list as the same list item is used for both lists. */ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - - /* The list item will be inserted in wake time order. */ - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); - - if( xTimeToWake < xTickCount ) - { - /* Wake time has overflowed. Place this item in the - overflow list. */ - vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* The wake time has not overflowed, so we can use the - current block list. */ - vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } + prvAddCurrentTaskToDelayedList( xTimeToWake ); } xAlreadyYielded = xTaskResumeAll(); } @@ -1125,8 +1135,9 @@ signed portBASE_TYPE xAlreadyYielded = pdFALSE; /* Move any readied tasks from the pending list into the appropriate ready list. */ - while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL ) + while( listLIST_IS_EMPTY( ( xList * ) &xPendingReadyList ) == pdFALSE ) { + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ); vListRemove( &( pxTCB->xEventListItem ) ); vListRemove( &( pxTCB->xGenericListItem ) ); prvAddTaskToReadyQueue( pxTCB ); @@ -1413,6 +1424,25 @@ void vTaskIncrementTick( void ) pxDelayedTaskList = pxOverflowDelayedTaskList; pxOverflowDelayedTaskList = pxTemp; xNumOfOverflows++; + if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) + { + /* The delayed list is empty. Set xNextTaskUnblockTime to the + maximum possible value so it is extremely unlikely that the + if( xTickCount >= xNextTaskUnblockTime ) test will pass + until there is an item in the delayed list. */ + xNextTaskUnblockTime = portMAX_DELAY; + } + else + { + tskTCB * pxTCB; + + /* The delayed list is not empty, get the value of the item at + the head of the delayed list. This is the time at which the + task at the head of the delayed list should be removed from + the Blocked state. */ + pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); + xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ); + } } /* See if this tick has made a timeout expire. */ @@ -1672,19 +1702,7 @@ portTickType xTimeToWake; /* Calculate the time at which the task should be woken if the event does not occur. This may overflow but this doesn't matter. */ xTimeToWake = xTickCount + xTicksToWait; - - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); - - if( xTimeToWake < xTickCount ) - { - /* Wake time has overflowed. Place this item in the overflow list. */ - vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* The wake time has not overflowed, so we can use the current block list. */ - vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } + prvAddCurrentTaskToDelayedList( xTimeToWake ); } } #else @@ -1692,19 +1710,7 @@ portTickType xTimeToWake; /* Calculate the time at which the task should be woken if the event does not occur. This may overflow but this doesn't matter. */ xTimeToWake = xTickCount + xTicksToWait; - - listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); - - if( xTimeToWake < xTickCount ) - { - /* Wake time has overflowed. Place this item in the overflow list. */ - vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } - else - { - /* The wake time has not overflowed, so we can use the current block list. */ - vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); - } + prvAddCurrentTaskToDelayedList( xTimeToWake ); } #endif } @@ -1724,7 +1730,10 @@ portBASE_TYPE xReturn; If an event is for a queue that is locked then this function will never get called - the lock count on the queue will get modified instead. This - means we can always expect exclusive access to the event list here. */ + means we can always expect exclusive access to the event list here. + + This function assumes that a check has already been made to ensure that + pxEventList is not empty. */ pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); vListRemove( &( pxUnblockedTCB->xEventListItem ) ); @@ -2020,7 +2029,7 @@ static void prvCheckTasksWaitingTermination( void ) xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination ); xTaskResumeAll(); - if( !xListIsEmpty ) + if( xListIsEmpty == pdFALSE ) { tskTCB *pxTCB; @@ -2041,6 +2050,32 @@ static void prvCheckTasksWaitingTermination( void ) } /*-----------------------------------------------------------*/ +static void prvAddCurrentTaskToDelayedList( portTickType xTimeToWake ) +{ + /* The list item will be inserted in wake time order. */ + listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake ); + + if( xTimeToWake < xTickCount ) + { + /* Wake time has overflowed. Place this item in the overflow list. */ + vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); + } + else + { + /* The wake time has not overflowed, so we can use the current block list. */ + vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); + + /* If the task entering the blocked state was placed at the head of the + list of blocked tasks then xNextTaskUnmblockTime needs to be updated + too. */ + if( xTimeToWake < xNextTaskUnblockTime ) + { + xNextTaskUnblockTime = xTimeToWake; + } + } +} +/*-----------------------------------------------------------*/ + static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) { tskTCB *pxNewTCB;