diff --git a/include/list.h b/include/list.h index 6f5d15dc7..ce3e51cf1 100644 --- a/include/list.h +++ b/include/list.h @@ -289,6 +289,86 @@ typedef struct xLIST ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \ } +/* + * Version of uxListRemove() that does not return a value. Provided as a slight + * optimisation for xTaskIncrementTick() by being inline. + * + * Remove an item from a list. The list item has a pointer to the list that + * it is in, so only the list item need be passed into the function. + * + * @param uxListRemove The item to be removed. The item will remove itself from + * the list pointed to by it's pxContainer parameter. + * + * @return The number of items that remain in the list after the list item has + * been removed. + * + * \page listREMOVE_ITEM listREMOVE_ITEM + * \ingroup LinkedList + */ +#define listREMOVE_ITEM( pxItemToRemove ) \ +{ \ + /* The list item knows which list it is in. Obtain the list from the list \ + * item. */ \ + List_t * const pxList = ( pxItemToRemove )->pxContainer; \ + \ + ( pxItemToRemove )->pxNext->pxPrevious = ( pxItemToRemove )->pxPrevious; \ + ( pxItemToRemove )->pxPrevious->pxNext = ( pxItemToRemove )->pxNext; \ + /* Make sure the index is left pointing to a valid item. */ \ + if( pxList->pxIndex == ( pxItemToRemove ) ) \ + { \ + pxList->pxIndex = ( pxItemToRemove )->pxPrevious; \ + } \ + \ + ( pxItemToRemove )->pxContainer = NULL; \ + ( pxList->uxNumberOfItems )--; \ +} + +/* + * Inline version of vListInsertEnd() to provide slight optimisation for + * xTaskIncrementTick(). + * + * Insert a list item into a list. The item will be inserted in a position + * such that it will be the last item within the list returned by multiple + * calls to listGET_OWNER_OF_NEXT_ENTRY. + * + * The list member pxIndex is used to walk through a list. Calling + * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list. + * Placing an item in a list using vListInsertEnd effectively places the item + * in the list position pointed to by pxIndex. This means that every other + * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before + * the pxIndex parameter again points to the item being inserted. + * + * @param pxList The list into which the item is to be inserted. + * + * @param pxNewListItem The list item to be inserted into the list. + * + * \page listINSERT_END listINSERT_END + * \ingroup LinkedList + */ +#define listINSERT_END( pxList, pxNewListItem ) \ +{ \ + ListItem_t * const pxIndex = ( pxList )->pxIndex; \ + \ + /* Only effective when configASSERT() is also defined, these tests may catch \ + * the list data structures being overwritten in memory. They will not catch \ + * data errors caused by incorrect configuration or use of FreeRTOS. */ \ + listTEST_LIST_INTEGRITY( ( pxList ) ); \ + listTEST_LIST_ITEM_INTEGRITY( ( pxNewListItem ) ); \ + \ + /* Insert a new list item into ( pxList ), but rather than sort the list, \ + * makes the new list item the last item to be removed by a call to \ + * listGET_OWNER_OF_NEXT_ENTRY(). */ \ + ( pxNewListItem )->pxNext = pxIndex; \ + ( pxNewListItem )->pxPrevious = pxIndex->pxPrevious; \ + \ + pxIndex->pxPrevious->pxNext = ( pxNewListItem ); \ + pxIndex->pxPrevious = ( pxNewListItem ); \ + \ + /* Remember which list the item is in. */ \ + ( pxNewListItem )->pxContainer = ( pxList ); \ + \ + ( ( pxList )->uxNumberOfItems )++; \ +} /* * Access function to obtain the owner of the first entry in a list. Lists diff --git a/tasks.c b/tasks.c index c7be57cb2..9ffbc4ffa 100644 --- a/tasks.c +++ b/tasks.c @@ -219,7 +219,7 @@ #define prvAddTaskToReadyList( pxTCB ) \ traceMOVED_TASK_TO_READY_STATE( pxTCB ); \ taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \ - vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \ + listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \ tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB ) /*-----------------------------------------------------------*/ @@ -2233,8 +2233,9 @@ BaseType_t xTaskResumeAll( void ) while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ) { pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ - ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); - ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + listREMOVE_ITEM( &( pxTCB->xEventListItem ) ); + portMEMORY_BARRIER(); + listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); /* If the moved task has a priority higher than or equal to @@ -2794,13 +2795,13 @@ BaseType_t xTaskIncrementTick( void ) } /* It is time to remove the item from the Blocked state. */ - ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); /* Is the task waiting on an event also? If so remove * it from the event list. */ if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ) { - ( void ) uxListRemove( &( pxTCB->xEventListItem ) ); + listREMOVE_ITEM( &( pxTCB->xEventListItem ) ); } else { @@ -3127,7 +3128,7 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, * event group implementation - and interrupts don't access event groups * directly (instead they access them indirectly by pending function calls to * the task level). */ - vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + listINSERT_END( pxEventList, &( pxCurrentTCB->xEventListItem ) ); prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); } @@ -3151,7 +3152,7 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, * In this case it is assume that this is the only task that is going to * be waiting on this event list, so the faster vListInsertEnd() function * can be used in place of vListInsert. */ - vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) ); + listINSERT_END( pxEventList, &( pxCurrentTCB->xEventListItem ) ); /* If the task should block indefinitely then set the block time to a * value that will be recognised as an indefinite delay inside the @@ -3188,11 +3189,11 @@ BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) * pxEventList is not empty. */ pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ configASSERT( pxUnblockedTCB ); - ( void ) uxListRemove( &( pxUnblockedTCB->xEventListItem ) ); + listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) ); if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) { - ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); + listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) ); prvAddTaskToReadyList( pxUnblockedTCB ); #if ( configUSE_TICKLESS_IDLE != 0 ) @@ -3213,7 +3214,7 @@ BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) { /* The delayed and ready lists cannot be accessed, so hold this task * pending until the scheduler is resumed. */ - vListInsertEnd( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) ); + listINSERT_END( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) ); } if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) @@ -3252,7 +3253,7 @@ void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, * event flags. */ pxUnblockedTCB = listGET_LIST_ITEM_OWNER( pxEventListItem ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ configASSERT( pxUnblockedTCB ); - ( void ) uxListRemove( pxEventListItem ); + listREMOVE_ITEM( pxEventListItem ); #if ( configUSE_TICKLESS_IDLE != 0 ) { @@ -3271,7 +3272,7 @@ void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, /* Remove the task from the delayed list and add it to the ready list. The * scheduler is suspended so interrupts will not be accessing the ready * lists. */ - ( void ) uxListRemove( &( pxUnblockedTCB->xStateListItem ) ); + listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) ); prvAddTaskToReadyList( pxUnblockedTCB ); if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority ) @@ -4922,7 +4923,7 @@ TickType_t uxTaskResetEventItemValue( void ) * notification then unblock it now. */ if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) { - ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); /* The task should not have been on an event list. */ @@ -5069,14 +5070,14 @@ TickType_t uxTaskResetEventItemValue( void ) if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) { - ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); } else { /* The delayed and ready lists cannot be accessed, so hold * this task pending until the scheduler is resumed. */ - vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + listINSERT_END( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); } if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) @@ -5160,14 +5161,14 @@ TickType_t uxTaskResetEventItemValue( void ) if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) { - ( void ) uxListRemove( &( pxTCB->xStateListItem ) ); + listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); prvAddTaskToReadyList( pxTCB ); } else { /* The delayed and ready lists cannot be accessed, so hold * this task pending until the scheduler is resumed. */ - vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); + listINSERT_END( &( xPendingReadyList ), &( pxTCB->xEventListItem ) ); } if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) @@ -5303,7 +5304,7 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, /* Add the task to the suspended task list instead of a delayed task * list to ensure it is not woken by a timing event. It will block * indefinitely. */ - vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) ); + listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) ); } else {