Create macro versions of uxListRemove() and vListInsertEnd() for use in xTaskIncrementTick(). This provides a minor optimisation to remove the need for a few function calls. (#241)
Co-authored-by: alfred gedeon <28123637+alfred2g@users.noreply.github.com>
Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
diff --git a/include/list.h b/include/list.h
index 6f5d15d..ce3e51c 100644
--- a/include/list.h
+++ b/include/list.h
@@ -289,6 +289,86 @@
( 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 c7be57c..9ffbc4f 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 @@
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 @@
}
/* 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 @@
* 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 @@
* 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 @@
* 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 @@
{
/* 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 @@
* 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 @@
/* 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 @@
* 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 @@
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 @@
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 @@
/* 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
{