Implementation and intuitive understanding of insertion and deletion of freertos bidirectional loop chain table

Posted by allinurl on Thu, 27 Jan 2022 14:47:34 +0100

main.c

After debug, look at the observation window, and the results are as follows. The purpose of this experiment is to establish a root node, a chain table of three common nodes, and the three common nodes are sorted in ascending order according to the xitemValue value.

Main. Inside C

First, look at the type of node: the chain table root node type is xLIST, and the normal node type is xLIST_ITEM.

Then look at the main function: vListInitialise, which is the root node initialization function of the chain table, vListInitialiseItem, which is the normal node initialization function, xItemValue, which is the member variable inside the normal node, and vListInsert, which implements the function of inserting nodes into the chain table and sorting them in ascending order.

Next, explore each of these things separately.

#include "list.h"

/* Define Chain List Root Node */
struct xLIST       List_Test;

/* Define Nodes */
struct xLIST_ITEM  List_Item1;
struct xLIST_ITEM  List_Item2;
struct xLIST_ITEM  List_Item3;

int main(void)
{	
	
    /* Chain list root node initialization */
    vListInitialise( &List_Test );
    
    /* Node 1 Initialization */
    vListInitialiseItem( &List_Item1 );
    List_Item1.xItemValue = 1;
    
    /* Node 2 Initialization */    
    vListInitialiseItem( &List_Item2 );
    List_Item2.xItemValue = 2;
    
    /* Node 3 Initialization */
    vListInitialiseItem( &List_Item3 );
    List_Item3.xItemValue = 3;
    
    /* Insert nodes into the list of chains, in ascending order */
    vListInsert( &List_Test, &List_Item2 );    
    vListInsert( &List_Test, &List_Item1 );
    vListInsert( &List_Test, &List_Item3 );    
    
    for(;;)
	{
		/* Do nothing */
	}
}

list.h

Looking directly at the diagram below, you can see the member variables in the root and other node structures.

#ifndef LIST_H
#define LIST_H
#include "FreeRTOS.h"

/* Node structure definition */
struct xLIST_ITEM
{
	TickType_t xItemValue;             /* Auxiliary values to help nodes sort in order */			
	struct xLIST_ITEM *  pxNext;       /* Point to the next node in the list */		
	struct xLIST_ITEM *  pxPrevious;   /* Point to the previous node in the list of chains */	
	void * pvOwner;					   /* Points to the kernel object that owns the node, usually the TCB (used to indicate in which data structure the node is embedded)*/
	void * pvContainer;		           /* Points to the list where the node is located, usually to the root node of the list*/
};
typedef struct xLIST_ITEM ListItem_t;  /* Node data type redefinition */


/* mini Node structure definition, as the end of a two-way chain table
   Because a two-way chain table is connected from end to end, the head is the end and the end is the head */
struct xMINI_LIST_ITEM
{
	TickType_t xItemValue;                      /* Auxiliary values to help nodes sort in ascending order */
	struct xLIST_ITEM *  pxNext;                /* Point to the next node in the list */
	struct xLIST_ITEM *  pxPrevious;            /* Point to the previous node in the list of chains */
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;  /* Minimum Node Data Type Redefinition */


/* Chain List Structures Definition */
typedef struct xLIST
{
	UBaseType_t uxNumberOfItems;    /* Chain list node counter, used to indicate how many nodes are under the chain table, except for the root node*/
	ListItem_t *  pxIndex;			/* Chain list node index pointer, used to traverse nodes */
	MiniListItem_t xListEnd;		/* Last node in the list of chains */
} List_t;


/*
************************************************************************
*                                Macro Definition
************************************************************************
*/
/* Initialize the owner of the node */
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )		( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/* Get Node Owner */
#define listGET_LIST_ITEM_OWNER( pxListItem )	( ( pxListItem )->pvOwner )

/* Initialize Node Sorting Auxiliary Value */
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )	( ( pxListItem )->xItemValue = ( xValue ) )

/* Get Node Sorting Auxiliary Value */
#define listGET_LIST_ITEM_VALUE( pxListItem )	( ( pxListItem )->xItemValue )

/* Gets the value of the node counter for the root node of the chain table */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext->xItemValue )

/* Get entry node of chain list */
#define listGET_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext )

/* Get the first node of the chain table */
#define listGET_NEXT( pxListItem )	( ( pxListItem )->pxNext )

/* Get the last node of the list of chains */
#define listGET_END_MARKER( pxList )	( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )

/* Determine if the list is empty */
#define listLIST_IS_EMPTY( pxList )	( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) )

/* Get the number of nodes in the chain table */
#define listCURRENT_LIST_LENGTH( pxList )	( ( pxList )->uxNumberOfItems )

/* Gets the OWNER, or TCB, of the list node */
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )										\
{																							\
	List_t * const pxConstList = ( pxList );											    \
	/* The node index points to the first node in the chain table, adjusts the node index pointer, and points to the next node.
    If the current list has N nodes, when the function is called the Nth time, pxInedex points to the Nth node */\
	( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;							\
	/* Current list is empty */                                                                       \
	if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )	\
	{																						\
		( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;						\
	}																						\
	/* Gets the OWNER, or TCB, of the node */                                                             \
	( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;											 \
}

#define listGET_OWNER_OF_HEAD_ENTRY( pxList )  ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )

/*
************************************************************************
*                                Function declaration
************************************************************************
*/
void vListInitialise( List_t * const pxList );
void vListInitialiseItem( ListItem_t * const pxItem );
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem );
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem );
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove );

#endif /* LIST_H */


Other header files

FreeRTOS.h

#ifndef INC_FREERTOS_H
#define INC_FREERTOS_H

#include "FreeRTOSConfig.h"
#include "portable.h"

#endif /* INC_FREERTOS_H */

FreeRTOSConfig.h

Because of the next sentence,

#define configUSE_16_BIT_TICKS		0

Make the portmacro.h Do the following inside, that is, let TickType_t stands for 32 bits.

typedef uint32_t TickType_t;
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#define configUSE_16_BIT_TICKS		0

#endif /* FREERTOS_CONFIG_H */

portable.h

#ifndef PORTABLE_H
#define PORTABLE_H

#include "portmacro.h"

#endif /* PORTABLE_H */

portmacro.h

Here are some data type redefinitions in freertos.

#ifndef PORTMACRO_H
#define PORTMACRO_H

#include "stdint.h"
#include "stddef.h"


/* Data type redefinition */
#define portCHAR		char
#define portFLOAT		float
#define portDOUBLE		double
#define portLONG		long
#define portSHORT		short
#define portSTACK_TYPE	uint32_t
#define portBASE_TYPE	long

typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;

#if( configUSE_16_BIT_TICKS == 1 )
	typedef uint16_t TickType_t;
	#define portMAX_DELAY ( TickType_t ) 0xffff
#else
	typedef uint32_t TickType_t;
	#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#endif

#endif /* PORTMACRO_H */

list.c

The vListInitialise function initializes the chain table root node. The effect of initialization can be seen in the following figure.

When the root node is initialized, all the pointers inside point to one place.

Straight dot statement:

vListInsertEnd function

The vListInsertEnd function inserts a node at the end of the chain table. After inserting a node, the effect is as follows.

In diagrams:

Straighter white dots:

It is an error to write the inserted code as follows.

	pxNewListItem->pxNext = pxIndex;
	pxNewListItem->pxPrevious = pxIndex;
	pxIndex->pxNext = pxNewListItem;
	pxIndex->pxPrevious = pxNewListItem;

Just try it out. If you press this code above and insert three nodes, the result will be as follows. The consequence is that the newly inserted nodes are not connected, they are only connected to the root node.

Insert the three nodes below, and the correct variables change as follows:

It is clear here that this is a circular two-way Chain table. As a diagram, you can see:

If a new item3 is added, the graph represents when item3 is not added:

Combine the two pictures above and code. The code below takes into account the connections between nodes.

pxNewListItem->pxNext = pxIndex;//The pxNext on the right of the above image connects to the leftmost pxIndex
pxNewListItem->pxPrevious = pxIndex->pxPrevious;//Second line of code
pxIndex->pxPrevious->pxNext = pxNewListItem;//Third line of code
pxIndex->pxPrevious = pxNewListItem;//Fourth line of code

The first line of code visually represents the following green line:

PxIndex->pxPrevious starts with Item2 and adds item3, so the pxPrevious of Item3 has to point to item2, which is pxIndex->pxPrevious. So here's the second line of code. The second line of code is visually illustrated below.

The third line of code, pxIndex->pxPrevious->pxNext, equals item2's pxNext, with Item3 added, then item2's pxNext should point to item3. The third line of code is visually illustrated below.

You can see at this point that the original item2 pxNext has been completely disconnected from pxIndex. The entire list can be represented as follows.

Obviously, the fourth line of code is to give item3 to pxPrevious of pxIndex.

vListInsert function

The function inserts nodes in ascending order into the list of chains.

Starting with xListEnd is equivalent to looking for the xItemValue value of the node that pxNext points to in turn from the first root node. If the value is greater than the xItemValue value of the node currently being inserted, the node is inserted behind the current node (the pxNext of the current node points to the front of the node).

The core code is as follows.

	pxNewListItem->pxNext = pxIterator->pxNext;
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;
	pxNewListItem->pxPrevious = pxIterator;
	pxIterator->pxNext = pxNewListItem;

For example, item2 is inserted after item1. As you proceed to the third step, the visual representation is as follows.

You can now see that item3's pxPrevious has broken contact with item1. So the figure above can be represented as follows.

The last step, then, is obvious, simply point the pxNext of item1 at item2. Now Item2 is inserted.

uxListRemove function

This function deletes a node from the list. The core code is as follows.

pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

If item2 is deleted, the visual representation is as follows:

#include "FreeRTOS.h"
#include <stdlib.h>
#include "list.h"


/* Chain list root node initialization */
void vListInitialise( List_t * const pxList )
{
	/* Point the chain table index pointer to the last node */
	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );

	/* Set the value of the auxiliary sorting of the last node in the list to the maximum to ensure that the node is the last node in the list */
	pxList->xListEnd.xItemValue = portMAX_DELAY;

    /* Pointing both the pxNext and pxPrevious pointers of the last node to the node itself indicates that the chain list is empty */
	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );

	/* Initialize the chain table node counter with a value of 0, indicating that the chain table is empty */
	pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
}

/* Node Initialization */
void vListInitialiseItem( ListItem_t * const pxItem )
{
	/* The list in which the node was initialized is empty, indicating that the node has not inserted any list yet */
	pxItem->pvContainer = NULL;
}


/* Insert node at end of chain list */
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
	ListItem_t * const pxIndex = pxList->pxIndex;

	pxNewListItem->pxNext = pxIndex;
	pxNewListItem->pxPrevious = pxIndex->pxPrevious;
	pxIndex->pxPrevious->pxNext = pxNewListItem;
	pxIndex->pxPrevious = pxNewListItem;

	/* Remember the list where the node is located */
	pxNewListItem->pvContainer = ( void * ) pxList;

	/* Chain List Node Counter++. */
	( pxList->uxNumberOfItems )++;
}


/* Insert nodes into the list in ascending order */
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
	ListItem_t *pxIterator;
	
	/* Get sorting auxiliary values for nodes */
	const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;

	/* Find the location where the node will be inserted */
	if( xValueOfInsertion == portMAX_DELAY )
	{
		pxIterator = pxList->xListEnd.pxPrevious;
	}
	else
	{
		for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd );
		     pxIterator->pxNext->xItemValue <= xValueOfInsertion; 
			 pxIterator = pxIterator->pxNext )
		{
			/* There's nothing to do, iterating just to find the location where the node will be inserted */			
		}
	}

	pxNewListItem->pxNext = pxIterator->pxNext;
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;
	pxNewListItem->pxPrevious = pxIterator;
	pxIterator->pxNext = pxNewListItem;

	/* Remember the list where the node is located */
	pxNewListItem->pvContainer = ( void * ) pxList;

	/* Chain List Node Counter++. */
	( pxList->uxNumberOfItems )++;
}


/* Delete Node from Chain List */
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
	/* Get the list of links where the nodes are located */
	List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;

	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

	/* Make sure the index is left pointing to a valid item. */
    /*Adjust Node Index Pointer of Chain List*/
	if( pxList->pxIndex == pxItemToRemove )
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}

	/* The list in which the node was initialized is empty, indicating that the node has not inserted any list yet */
	pxItemToRemove->pvContainer = NULL;
	
	/* Chain List Node Counter-- */
	( pxList->uxNumberOfItems )--;

	/* Returns the number of remaining nodes in the chain table */
	return pxList->uxNumberOfItems;
}

Topics: Embedded system list FreeRTOS