操作系统--freeRTOS 双向链表解读(list)

2023-05-16

1、简介

本文依据的freeRTOS版本是V9.0.0版本,本文将分析链表文件的结构体,主要根据其list.c和list.h文件;

2、list.h文件解析

/*
 * FreeRTOS Kernel V9.0.0a
 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * http://www.FreeRTOS.org
 * http://aws.amazon.com/freertos
 *
 * 1 tab == 4 spaces!
 */

/*
 * This is the list implementation used by the scheduler.  While it is tailored
 * heavily for the schedulers needs, it is also available for use by
 * application code.
 *
 * list_ts can only store pointers to list_item_ts.  Each ListItem_t contains a
 * numeric value (xItemValue).  Most of the time the lists are sorted in
 * descending item value order.
 *
 * Lists are created already containing one list item.  The value of this
 * item is the maximum possible that can be stored, it is therefore always at
 * the end of the list and acts as a marker.  The list member pxHead always
 * points to this marker - even though it is at the tail of the list.  This
 * is because the tail contains a wrap back pointer to the true head of
 * the list.
 *
 * In addition to it's value, each list item contains a pointer to the next
 * item in the list (pxNext), a pointer to the list it is in (pxContainer)
 * and a pointer to back to the object that contains it.  These later two
 * pointers are included for efficiency of list manipulation.  There is
 * effectively a two way link between the object containing the list item and
 * the list item itself.
 *
 *
 * \page ListIntroduction List Implementation
 * \ingroup FreeRTOSIntro
 */

#ifndef INC_FREERTOS_H
	#error FreeRTOS.h must be included before list.h
#endif

#ifndef LIST_H
#define LIST_H

/*
 * The list structure members are modified from within interrupts, and therefore
 * by rights should be declared volatile.  However, they are only modified in a
 * functionally atomic way (within critical sections of with the scheduler
 * suspended) and are either passed by reference into a function or indexed via
 * a volatile variable.  Therefore, in all use cases tested so far, the volatile
 * qualifier can be omitted in order to provide a moderate performance
 * improvement without adversely affecting functional behaviour.  The assembly
 * instructions generated by the IAR, ARM and GCC compilers when the respective
 * compiler's options were set for maximum optimisation has been inspected and
 * deemed to be as intended.  That said, as compiler technology advances, and
 * especially if aggressive cross module optimisation is used (a use case that
 * has not been exercised to any great extend) then it is feasible that the
 * volatile qualifier will be needed for correct optimisation.  It is expected
 * that a compiler removing essential code because, without the volatile
 * qualifier on the list structure members and with aggressive cross module
 * optimisation, the compiler deemed the code unnecessary will result in
 * complete and obvious failure of the scheduler.  If this is ever experienced
 * then the volatile qualifier can be inserted in the relevant places within the
 * list structures by simply defining configLIST_VOLATILE to volatile in
 * FreeRTOSConfig.h (as per the example at the bottom of this comment block).
 * If configLIST_VOLATILE is not defined then the preprocessor directives below
 * will simply #define configLIST_VOLATILE away completely.
 *
 * To use volatile list structure members then add the following line to
 * FreeRTOSConfig.h (without the quotes):
 * "#define configLIST_VOLATILE volatile"
 */
#ifndef configLIST_VOLATILE
	#define configLIST_VOLATILE
#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */

#ifdef __cplusplus
extern "C" {
#endif

/* Macros that can be used to place known values within the list structures,
then check that the known values do not get corrupted during the execution of
the application.   These may catch the list data structures being overwritten in
memory.  They will not catch data errors caused by incorrect configuration or
use of FreeRTOS.*/
#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
	/* Define the macros to do nothing. */
	#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
	#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
	#define listFIRST_LIST_INTEGRITY_CHECK_VALUE
	#define listSECOND_LIST_INTEGRITY_CHECK_VALUE
	#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
	#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
	#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
	#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
	#define listTEST_LIST_ITEM_INTEGRITY( pxItem )
	#define listTEST_LIST_INTEGRITY( pxList )
#else
	/* Define macros that add new members into the list structures. */
	#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE				TickType_t xListItemIntegrityValue1;
	#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE				TickType_t xListItemIntegrityValue2;
	#define listFIRST_LIST_INTEGRITY_CHECK_VALUE					TickType_t xListIntegrityValue1;
	#define listSECOND_LIST_INTEGRITY_CHECK_VALUE					TickType_t xListIntegrityValue2;

	/* Define macros that set the new structure members to known values. */
	#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )		( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
	#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )	( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
	#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )		( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
	#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )		( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE

	/* Define macros that will assert if one of the structure members does not
	contain its expected value. */
	#define listTEST_LIST_ITEM_INTEGRITY( pxItem )		configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
	#define listTEST_LIST_INTEGRITY( pxList )			configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */


/*
 * Definition of the only type of object that a list can contain.
 */
struct xLIST_ITEM
{
	listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE			/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
	configLIST_VOLATILE TickType_t xItemValue;			/*< The value being listed.  In most cases this is used to sort the list in descending order. */
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;		/*< Pointer to the next ListItem_t in the list. */
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;	/*< Pointer to the previous ListItem_t in the list. */
	void * pvOwner;										/*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */
	void * configLIST_VOLATILE pvContainer;				/*< Pointer to the list in which this list item is placed (if any). */
	listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE			/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef struct xLIST_ITEM ListItem_t;					/* For some reason lint wants this as two separate definitions. */

struct xMINI_LIST_ITEM
{
	listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE			/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
	configLIST_VOLATILE TickType_t xItemValue;
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

/*
 * Definition of the type of queue used by the scheduler.
 */
typedef struct xLIST
{
	listFIRST_LIST_INTEGRITY_CHECK_VALUE				/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
	configLIST_VOLATILE UBaseType_t uxNumberOfItems;
	ListItem_t * configLIST_VOLATILE pxIndex;			/*< Used to walk through the list.  Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
	MiniListItem_t xListEnd;							/*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
	listSECOND_LIST_INTEGRITY_CHECK_VALUE				/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;

/*
 * Access macro to set the owner of a list item.  The owner of a list item
 * is the object (usually a TCB) that contains the list item.
 *
 * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
 * \ingroup LinkedList
 */
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )		( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )

/*
 * Access macro to get the owner of a list item.  The owner of a list item
 * is the object (usually a TCB) that contains the list item.
 *
 * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
 * \ingroup LinkedList
 */
#define listGET_LIST_ITEM_OWNER( pxListItem )	( ( pxListItem )->pvOwner )

/*
 * Access macro to set the value of the list item.  In most cases the value is
 * used to sort the list in descending order.
 *
 * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
 * \ingroup LinkedList
 */
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )	( ( pxListItem )->xItemValue = ( xValue ) )

/*
 * Access macro to retrieve the value of the list item.  The value can
 * represent anything - for example the priority of a task, or the time at
 * which a task should be unblocked.
 *
 * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
 * \ingroup LinkedList
 */
#define listGET_LIST_ITEM_VALUE( pxListItem )	( ( pxListItem )->xItemValue )

/*
 * Access macro to retrieve the value of the list item at the head of a given
 * list.
 *
 * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
 * \ingroup LinkedList
 */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext->xItemValue )

/*
 * Return the list item at the head of the list.
 *
 * \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
 * \ingroup LinkedList
 */
#define listGET_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext )

/*
 * Return the list item at the head of the list.
 *
 * \page listGET_NEXT listGET_NEXT
 * \ingroup LinkedList
 */
#define listGET_NEXT( pxListItem )	( ( pxListItem )->pxNext )

/*
 * Return the list item that marks the end of the list
 *
 * \page listGET_END_MARKER listGET_END_MARKER
 * \ingroup LinkedList
 */
#define listGET_END_MARKER( pxList )	( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )

/*
 * Access macro to determine if a list contains any items.  The macro will
 * only have the value true if the list is empty.
 *
 * \page listLIST_IS_EMPTY listLIST_IS_EMPTY
 * \ingroup LinkedList
 */
#define listLIST_IS_EMPTY( pxList )	( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) )

/*
 * Access macro to return the number of items in the list.
 */
#define listCURRENT_LIST_LENGTH( pxList )	( ( pxList )->uxNumberOfItems )

/*
 * Access function to obtain the owner of the next entry in a list.
 *
 * 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
 * and returns that entry's pxOwner parameter.  Using multiple calls to this
 * function it is therefore possible to move through every item contained in
 * a list.
 *
 * The pxOwner parameter of a list item is a pointer to the object that owns
 * the list item.  In the scheduler this is normally a task control block.
 * The pxOwner parameter effectively creates a two way link between the list
 * item and its owner.
 *
 * @param pxTCB pxTCB is set to the address of the owner of the next list item.
 * @param pxList The list from which the next item owner is to be returned.
 *
 * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
 * \ingroup LinkedList
 */
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )										\
{																							\
List_t * const pxConstList = ( pxList );													\
	/* Increment the index to the next item and return the item, ensuring */				\
	/* we don't return the marker used at the end of the list.  */							\
	( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;							\
	if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )	\
	{																						\
		( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;						\
	}																						\
	( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;											\
}


/*
 * Access function to obtain the owner of the first entry in a list.  Lists
 * are normally sorted in ascending item value order.
 *
 * This function returns the pxOwner member of the first item in the list.
 * The pxOwner parameter of a list item is a pointer to the object that owns
 * the list item.  In the scheduler this is normally a task control block.
 * The pxOwner parameter effectively creates a two way link between the list
 * item and its owner.
 *
 * @param pxList The list from which the owner of the head item is to be
 * returned.
 *
 * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
 * \ingroup LinkedList
 */
#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
 * "container" pointer that points to the list it is in.  All this macro does
 * is check to see if the container and the list match.
 *
 * @param pxList The list we want to know if the list item is within.
 * @param pxListItem The list item we want to know if is in the list.
 * @return pdTRUE if the list item is in the list, otherwise pdFALSE.
 */
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) )

/*
 * Return the list a list item is contained within (referenced from).
 *
 * @param pxListItem The list item being queried.
 * @return A pointer to the List_t object that references the pxListItem
 */
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer )

/*
 * This provides a crude means of knowing if a list has been initialised, as
 * pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise()
 * function.
 */
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )

/*
 * Must be called before a list is used!  This initialises all the members
 * of the list structure and inserts the xListEnd item into the list as a
 * marker to the back of the list.
 *
 * @param pxList Pointer to the list being initialised.
 *
 * \page vListInitialise vListInitialise
 * \ingroup LinkedList
 */
void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;

/*
 * Must be called before a list item is used.  This sets the list container to
 * null so the item does not think that it is already contained in a list.
 *
 * @param pxItem Pointer to the list item being initialised.
 *
 * \page vListInitialiseItem vListInitialiseItem
 * \ingroup LinkedList
 */
void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION;

/*
 * Insert a list item into a list.  The item will be inserted into the list in
 * a position determined by its item value (descending item value order).
 *
 * @param pxList The list into which the item is to be inserted.
 *
 * @param pxNewListItem The item that is to be placed in the list.
 *
 * \page vListInsert vListInsert
 * \ingroup LinkedList
 */
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;

/*
 * 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 vListInsertEnd vListInsertEnd
 * \ingroup LinkedList
 */
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;

/*
 * 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 uxListRemove uxListRemove
 * \ingroup LinkedList
 */
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION;

#ifdef __cplusplus
}
#endif

#endif


上面的代码是freeRTOS v9.0.0的list.h文件,上面的文件经过简化如下,下面展示的是数据结构:

struct xLIST_ITEM
{
	configLIST_VOLATILE TickType_t xItemValue;			/*< The value being listed.  In most cases this is used to sort the list in descending order. */
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;		/*< Pointer to the next ListItem_t in the list. */
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;	/*< Pointer to the previous ListItem_t in the list. */
	void * pvOwner;										/*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */
	void * configLIST_VOLATILE pvContainer;				/*< Pointer to the list in which this list item is placed (if any). */
};
typedef struct xLIST_ITEM ListItem_t;					/* For some reason lint wants this as two separate definitions. */

struct xMINI_LIST_ITEM
{
	configLIST_VOLATILE TickType_t xItemValue;
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

/*
 * Definition of the type of queue used by the scheduler.
 */
typedef struct xLIST
{
	configLIST_VOLATILE UBaseType_t uxNumberOfItems;
	ListItem_t * configLIST_VOLATILE pxIndex;			/*< Used to walk through the list.  Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
	MiniListItem_t xListEnd;							/*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
} List_t;

list文件中比较主要的几个函数如下(初始化、插入和删除):


void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;


void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION;


void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;


void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;


UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION;

根据list头文件我们可以看到其链表是双向链表,其数据结构的组织形式如下所示:
ListItem_t:
在这里插入图片描述

List_t:
在这里插入图片描述
MiniListItem_t:
在这里插入图片描述

3、list.c文件解析

list.c文件如下:

/*
 * FreeRTOS Kernel V9.0.0a
 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * http://www.FreeRTOS.org
 * http://aws.amazon.com/freertos
 *
 * 1 tab == 4 spaces!
 */


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

/*-----------------------------------------------------------
 * PUBLIC LIST API documented in list.h
 *----------------------------------------------------------*/

void vListInitialise( List_t * const pxList )
{
	/* The list structure contains a list item which is used to mark the
	end of the list.  To initialise the list the list end is inserted
	as the only list entry. */
	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );			/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */

	/* The list end value is the highest possible value in the list to
	ensure it remains at the end of the list. */
	pxList->xListEnd.xItemValue = portMAX_DELAY;

	/* The list end next and previous pointers point to itself so we know
	when the list is empty. */
	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );	/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */

	pxList->uxNumberOfItems = ( UBaseType_t ) 0U;

	/* Write known values into the list if
	configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
	listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
	listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
/*-----------------------------------------------------------*/

void vListInitialiseItem( ListItem_t * const pxItem )
{
	/* Make sure the list item is not recorded as being on a list. */
	pxItem->pvContainer = NULL;

	/* Write known values into the list item if
	configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
	listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
	listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
/*-----------------------------------------------------------*/

void vListInsertEnd( List_t * const pxList, ListItem_t * const 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;

	/* Only used during decision coverage testing. */
	mtCOVERAGE_TEST_DELAY();

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

	/* Remember which list the item is in. */
	pxNewListItem->pvContainer = ( void * ) pxList;

	( pxList->uxNumberOfItems )++;
}
/*-----------------------------------------------------------*/

void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;

	/* 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 the new list item into the list, sorted in xItemValue order.

	If the list already contains a list item with the same item value then the
	new list item should be placed after it.  This ensures that TCB's which are
	stored in ready lists (all of which have the same xItemValue value) get a
	share of the CPU.  However, if the xItemValue is the same as the back marker
	the iteration loop below will not end.  Therefore the value is checked
	first, and the algorithm slightly modified if necessary. */
	if( xValueOfInsertion == portMAX_DELAY )
	{
		pxIterator = pxList->xListEnd.pxPrevious;
	}
	else
	{
		/* *** NOTE ***********************************************************
		If you find your application is crashing here then likely causes are
		listed below.  In addition see http://www.freertos.org/FAQHelp.html for
		more tips, and ensure configASSERT() is defined!
		http://www.freertos.org/a00110.html#configASSERT

			1) Stack overflow -
			   see http://www.freertos.org/Stacks-and-stack-overflow-checking.html
			2) Incorrect interrupt priority assignment, especially on Cortex-M
			   parts where numerically high priority values denote low actual
			   interrupt priorities, which can seem counter intuitive.  See
			   http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
			   of configMAX_SYSCALL_INTERRUPT_PRIORITY on
			   http://www.freertos.org/a00110.html
			3) Calling an API function from within a critical section or when
			   the scheduler is suspended, or calling an API function that does
			   not end in "FromISR" from an interrupt.
			4) Using a queue or semaphore before it has been initialised or
			   before the scheduler has been started (are interrupts firing
			   before vTaskStartScheduler() has been called?).
		**********************************************************************/

		for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
		{
			/* There is nothing to do here, just iterating to the wanted
			insertion position. */
		}
	}

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

	/* Remember which list the item is in.  This allows fast removal of the
	item later. */
	pxNewListItem->pvContainer = ( void * ) pxList;

	( pxList->uxNumberOfItems )++;
}
/*-----------------------------------------------------------*/

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
/* The list item knows which list it is in.  Obtain the list from the list
item. */
List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;

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

	/* Only used during decision coverage testing. */
	mtCOVERAGE_TEST_DELAY();

	/* Make sure the index is left pointing to a valid item. */
	if( pxList->pxIndex == pxItemToRemove )
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	pxItemToRemove->pvContainer = NULL;
	( pxList->uxNumberOfItems )--;

	return pxList->uxNumberOfItems;
}
/*-----------------------------------------------------------*/


  • void vListInitialise( List_t * const pxList )简化如下:
void vListInitialise( List_t * const pxList )
{
	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );		
	pxList->xListEnd.xItemValue = portMAX_DELAY;

	
	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );	
	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );

	pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
}

其对应的图示:
在这里插入图片描述

  • void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
- 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; //④
	
	/* 记住该节点所在的链表 */ 
	pxNewListItem->pvContainer = ( void * ) pxList; //⑤
	/* 链表节点计数器++ */
	 ( pxList->uxNumberOfItems )++; //⑥
 }

其示意图如下所示:
在这里插入图片描述

  • void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
	
	if( xValueOfInsertion == portMAX_DELAY )
	{
		pxIterator = pxList->xListEnd.pxPrevious;
	}
	else
	{
		for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) 
		{

		}
	}

	pxNewListItem->pxNext = pxIterator->pxNext;			// 1
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;  // 2
	pxNewListItem->pxPrevious = pxIterator;				// 3
	pxIterator->pxNext = pxNewListItem;					// 4
	pxNewListItem->pvContainer = ( void * ) pxList;		//5
	( pxList->uxNumberOfItems )++;						// 6
}

其示意图如下:
在这里插入图片描述

  • UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
/* The list item knows which list it is in.  Obtain the list from the list
item. */
List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;

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

	/* Only used during decision coverage testing. */
	mtCOVERAGE_TEST_DELAY();

	/* Make sure the index is left pointing to a valid item. */
	if( pxList->pxIndex == pxItemToRemove )
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

	pxItemToRemove->pvContainer = NULL;
	( pxList->uxNumberOfItems )--;

	return pxList->uxNumberOfItems;
}

在这里插入图片描述

4、总结:

链表作为 C 语言中一种基础的数据结构,在freeRTOS系统中的作用非常重要,因此这一块内容必须要要完全掌握,以便深入阅读freeRTOS的内核代码。

参考资料:
《FreeRTOS内核实现与应用开发实战指南—基于野火 STM32 全系列(M3/4/7)开发板》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

操作系统--freeRTOS 双向链表解读(list) 的相关文章

  • Gstreamer概述

    1 什么是GStreamer GStreamer 是用来构建流媒体应用的开源多媒体框架 framework xff0c 其基本设计思想来自于俄勒冈 Oregon 研究生学院有关视频管道的创意 同时也借鉴了DirectShow的设计思想 其目
  • grbl学习之旅---serial篇

    serial c和serial h文件是实现了通过串行端口发送和接受字节的功能 首先是serial h中定义了基本函数和常量大小 xff1a ifndef RX BUFFER SIZE define RX BUFFER SIZE 128 定
  • ip rule,ip route,iptables 三者之间的关系

    以一例子来说明 xff1a 公司内网要求192 168 0 100 以内的使用 10 0 0 1 网关上网 xff08 电信 xff09 xff0c 其他IP使用 20 0 0 1 xff08 网通 xff09 上网 首先要在网关服务器上添
  • 什么是Zero-copy零拷贝

    考虑这样 种常 的情形 xff1a 你需要将静态内容 xff08 类似图 件 xff09 展 给 户 那么这个情形就意味着你需要先将静态内容从磁盘中拷贝出来放到 个内存buf中 xff0c 然后将这个buf通过socket传输给 户 xff
  • 图解协程原理

    前言 协程 Coroutines xff0c 是 Kotlin 最神奇 的特性 xff0c 没有之一 本文会以图解 43 动画的形式解释 Kotlin 协程的原理 看完本文后 xff0c 你会发现 xff0c 原来协程也没有那么难 本文要求
  • ubuntu 16.04下安裝和配置ros

    書上和網上關於ubuntu下安裝ros的文章很多 xff0c 但是很多介紹的不完整 xff0c 並且ubuntu和ros之間其實是有版本對應關系的 xff0c 並不是所有的ros都能安裝到所有的ubuntu上 xff0c xff08 很多書
  • Ubuntu 16.04安装docker详细步骤

    因需要安装opendronemap 而这个依赖于docker 所以记录了一下安装docker的步骤 比较简单 通过apt的docker官方源安装最新的Docker CE Community Edition xff0c 即Docker社区版
  • 在本地shell脚本中ssh到远程服务器并执行命令

    shell远程执行 xff1a 经常需要远程到其他节点上执行一些shell命令 xff0c 如果分别ssh到每台主机上再去执行很麻烦 xff0c 因此能有个集中管理的方式就好了 一下介绍两种shell命令远程执行的方法 前提条件 xff1a
  • Catkin_make执行过程

    这是一个比较复杂的问题 xff0c 但是有时候会有莫名其妙的编译错误 xff0c 在找错误的过程中会非常需要了解这个过程 1 模板文件 首先说一下 in文件 在catkin的目录中有许多 in文件 这些都是模板文件 xff0c 以 opt
  • Docker用yum安装步骤

    Docker用yum安装步骤 一 安装docker xff08 完整版 xff09 1 Docker 要求 CentOS 系统的内核版本高于 3 10 uname r 2 使用 root 权限登录 Centos 确保 yum 包更新到最新
  • 1024,如果全世界程序员都消失了,会怎样?

    这两天 xff0c 有一个话题引起了程序员的广泛讨论 xff1a 年薪80W程序员相亲被鄙视 某知名互联网社区 xff0c 一网友发帖 xff0c 自己年薪80W去相亲 xff0c 竟然被鄙视不如在二本学校教书的大学老师 估计令他没想到的是
  • 非线性控制1.1——稳定与跟踪问题概念

    一 非线性控制系统的两大任务 1 稳定 xff08 或称调节 xff09 问题 稳定问题是要使得闭环系统的状态稳定在一个平衡点附近 对于稳定问题 xff0c 系统的输出不一定要有具体的物理意义 xff0c 此时可以借助输入 输出状态线性化方
  • 在 linux ubuntu 18.04 上运行QQ音乐

    在 linux ubuntu 18 04 上运行QQ音乐 我使用的组合为 ubuntu 18 04 43 wine stable 3 6 43 QQ音乐17 63 xff0c 未在其它平台做过尝试 一直想在ubuntu上好好听音乐 xff0
  • 非线性控制1.0——自适应控制和鲁棒控制

    1 鲁棒控制和自适应控制的联系与区别 鲁棒控制是以目的定义的控制方法集合 xff0c 自适应控制是以手段定义的控制方法集合 xff0c 这两种控制都是为了应对 当数学模型不能精确表示实际系统的情况下 狭义的鲁棒控制是指H2 xff0c Hi
  • 非线性控制2.0——鲁棒控制之H无穷控制器设计

    一 基本概念 对于图1所示系统 xff0c u为控制输入 xff0c y为测量输出 xff0c z为被调输出 xff0c w为干扰输入 xff0c 由输入u xff0c w到输出y xff0c z的传递函数G成为增广被控对象 xff0c 控
  • 非线性控制1.0——控制理论生态及结构

    一 控制理论地图 二 控制理论发展及结构 上图应用于 xff1a https www zhihu com people xiang yi 55 49 answers
  • 四旋翼飞行器——飞行原理

    1 机械结构 旋翼对称分布在机体的前后 左右四个方向 xff0c 四个旋翼处于同一高度平面 xff0c 且四个旋翼的结构和半径都相同 xff0c 四个电机对称的安装在飞行器的支架端 xff0c 支架中间空间安放飞控板 结构形式如图 1 1所
  • 四旋翼飞行器——非线性化模型

    一 建模思路 该模型目标控制量是机体相对于地面坐标系的线速度的三个分量Vx xff0c Vy xff0c Vz xff0c 而我们能控的实质上只有四个电机的转速W1 xff0c W2 xff0c W3 xff0c W4 怎样由输入一步步推导
  • 故障诊断4—龙伯格状态观测器设计

    1 龙伯格状态观测器概念 已经线性系统模型如下 xff1a 当系统状态量难以获取 xff0c 但实际控制中又需要利用系统状态量时 xff0c 如何通过输入量和输出量重构系统状态量 xff1f 这便是龙伯格状态观测器设计初衷 xff0c 将实
  • 故障诊断5——状态观测器和输出观测器

    1 状态观测器分类 在现代控制理论中 xff0c 控制系统的基本结构和经典控制理论一样 xff0c 仍然是由受控对象和反馈控制器两部分构成的闭环系统 不过在经典理论中习惯于采用输出反馈 xff0c 而在现代控制理论中则更多地采用状态反馈 由

随机推荐

  • GPS漂移和定位不准确的解决办法

    解决GPS漂移主要从两方面入手 xff1a 一 主系统的设计主要减少在近距离内对GPS信号的干扰 二 软件处理 软件处理主要集中在导航软件处完成 xff0c 导航软件会将坐标定位在道路之内 xff0c 如果GPS接收到的信号超出道路的半径范
  • AI---是什么?可以做什么?

    1 AI的项目简单介绍 图像识别 描述 xff1a 给定图片 xff0c 识别图片中有什么 xff1f 算法 xff1a KNN CNN 情感分析 描述 xff1a 判断文本包含的情感是正面 负面还是中性 关键 xff1a 文本如何表示成向
  • realsense的安装问题

    realsense的安装问题 0 旁白1 SDK的安装2 python开发包的安装3 nodejs开发包的安装方法1 xff1a 方法2 xff1a 接手一位同事的realsense相关项目 xff0c 先配置一个环境 xff0c 出现不少
  • 二叉排序树的删除

    xff08 网上讲二叉排序树删除的资料很少 xff0c 这篇很不错 xff01 转自 xff1a http bbs csdn net topics 110010437 xff09 二叉排序树的删除 xff1a 对于一般的二叉树来说 xff0
  • 分布式锁学习

    概述 分布式锁是控制分布式系统之间同步访问共享资源的一种方式 在分布式系统中 xff0c 常常需要协调他们的动作 如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源 xff0c 那么访问这些资源的时候 xff0c 往往需要互斥来
  • 无人机飞行控制

    intro 这篇笔记记录了无人机飞控算法和px4相关 control algorithm adrc 周立功讲adrc 参数整定 xff1a Scaling and Bandwidth Parameterization
  • 168-HITL-dev-manual

    HITL todo 使用mavlink收ref和imu 可以选择发出pwm和torque 发出torque的话 xff0c 没有考虑pwm的饱和 发出pwm的话 xff0c 电机的参数也不准 参考GAAS FC 写收的imu gps xff
  • 图优化理论(1)

    简介 图优化本质上是一个优化问题 xff0c 所以我们先来看优化问题是什么 优化问题有三个最重要的因素 xff1a 目标函数 优化变量 优化约束 一个简单的优化问题可以描述如下 其中x为优化变量 xff0c 而F x 为优化函数 此问题称为
  • (动态添加select后不显示?)layui动态添加select后重新渲染

    一 问题 xff1a 利用jQuery动态添加的代码中包含select xff0c 运行后不显示 1 显示的状态 2 后台的代码 正常情况下应该像队长班级一样显示 xff0c 但是却惊奇的发现 xff0c 事与愿违 二 原因 Layui会对
  • ARM处理器的快速上下文切换技术

    5 3 1 FCSE 概述 FCSE xff08 Fast Context Switch Extension xff0c 快速上下文切换 xff09 位于 CPU 和 MMU 之间 xff0c 如果两个进程使用了同样的虚拟地址空间 xff0
  • Promise 控制并发请求数量

    Promise 控制并发请求数量 前言 xff1a 浏览器对对同一个服务器的并发数是有限制的 xff0c 参考如下表格 xff08 表格来源于网络 xff0c 未进过严谨测试 xff09 xff1a 浏览器HTTP 1 1HTTP 1 0I
  • 树莓派自动连接WiFi

    将USB无线网卡插入树莓派任一USB接口 xff0c 插上网线 xff0c 接通电源 xff1b 在个人电脑上通过ssh连接树莓派 xff0c 默认帐号是pi xff0c 默认密码是raspberry xff08 如何通过ssh连接树莓派
  • 【DragonBoard 410c】悲催的开箱体验

    这里非常感谢辉哥提供的龙板 这块板子是实验室的学长从高通公司争取过来赠送给我们实验室的 xff0c 从美国寄过来的 xff0c 遗憾的是 xff01 里面没有Android系统 xff01 xff01 以至于我开机折腾了许久 首先 xff0
  • 2017CVTE嵌入式研发岗实习生面经

    本人普通高校大三学生 xff0c 准备在暑假找一份嵌入式实习工作 xff0c 因为实验室一学长去年通过实习生通道成功拿到正式岗offer 而且CVTE在嵌入式这一行的工资福利等都是相当诱人 xff0c 所以我的目标就是首先要拿到cvte的实
  • 安装Ubuntu过程及遇到的问题

    需要的装备 xff1a 1 不小于4G的U盘或者内存卡 43 读卡器也可以 2 UltraISO xff08 使用方法http jingyan baidu com article d169e186800f02436711d87b html
  • 北邮某牛人找工作切身感受

    转自北邮人论坛 by xiaoxuanzi xff08 值得全部看完 xff09 找工作历程基本上要截止了 Offer再多也只能去一个 xff0c 也省了纠结 xff0c 顺便帮等攒人品 Offer搞定能一起happy xff0c 寝室MM
  • DNW下载文件时出现can not open /dev/secbulk0

    在学习过程中碰到了如上的问题 xff0c 在参考了不少博客之后解决了这个问题 首先到这里下载DNW安装包 xff1a http download csdn net detail david xtd 7401761 这里面有两个文件夹dnw和
  • VMware非正常关闭导致打开虚拟机时提示:未找到.vmx文件

    上次手残将VMware直接关闭 xff0c 导致第二次打开虚拟机时提示 vmx文件未找到 根据这个原理 xff0c 可能其他后缀的文件丢失也可以利用相同的原理 xff0c 就是重新建一个虚拟机 xff0c 然后就能得到相同的文件 xff0c
  • 图片合集

    HDMI接口物理地址理解
  • 操作系统--freeRTOS 双向链表解读(list)

    1 简介 本文依据的freeRTOS版本是V9 0 0版本 xff0c 本文将分析链表文件的结构体 xff0c 主要根据其list c和list h文件 2 list h文件解析 span class token comment FreeR