/* * FreeRTOS Kernel V10.5.1 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT * * 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. * * https://www.FreeRTOS.org * https://github.com/FreeRTOS * */ /* * 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 * ascending 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 LIST_H #define LIST_H #ifndef INC_FREERTOS_H #error "FreeRTOS.h must be included before list.h" #endif /* * 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 */ /* 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 /* if ( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 ) */ /* 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; /* 双向链表节点管理结构 */ struct xLIST_ITEM { listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /* */ configLIST_VOLATILE TickType_t xItemValue; /* 有序链表的键值 */ struct xLIST_ITEM * configLIST_VOLATILE pxNext; /* 后继节点 */ struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /* 前驱节点 */ void * pvOwner; /* 保存私有数据 */ struct xLIST * configLIST_VOLATILE pxContainer; /* 节点所在的链表 */ listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /* */ }; typedef struct xLIST_ITEM ListItem_t; #if (configUSE_MINI_LIST_ITEM == 1) /* 不带有私有数据的双向链表节点 */ struct xMINI_LIST_ITEM { listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /* */ configLIST_VOLATILE TickType_t xItemValue; /* 有序链表的键值 */ struct xLIST_ITEM * configLIST_VOLATILE pxNext; /* 后继节点 */ struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /* 前驱节点 */ }; typedef struct xMINI_LIST_ITEM MiniListItem_t; #else typedef struct xLIST_ITEM MiniListItem_t; #endif /* * Definition of the type of queue used by the scheduler. */ typedef struct xLIST { listFIRST_LIST_INTEGRITY_CHECK_VALUE /**/ volatile UBaseType_t uxNumberOfItems; /* 链表中元素的个数 */ ListItem_t * configLIST_VOLATILE pxIndex; MiniListItem_t xListEnd; /* 双向链表的尾节点(哨兵) */ listSECOND_LIST_INTEGRITY_CHECK_VALUE /**/ } List_t; /* * pxListItem->pvOwner = pxOwner */ #define listSET_LIST_ITEM_OWNER(pxListItem, pxOwner) ((pxListItem)->pvOwner = (void *)(pxOwner)) /* * 返回 pxListItem->pvOwner */ #define listGET_LIST_ITEM_OWNER(pxListItem) ((pxListItem )->pvOwner) /* * pxListItem->xItemValue = xValue */ #define listSET_LIST_ITEM_VALUE(pxListItem, xValue) ((pxListItem)->xItemValue = (xValue)) /* * 返回 pxListItem->xItemValue */ #define listGET_LIST_ITEM_VALUE(pxListItem) ((pxListItem)->xItemValue) /* * 返回链表头节点的xItemValue */ #define listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxList) (((pxList)->xListEnd).pxNext->xItemValue) /* * 返回链表头结点 */ #define listGET_HEAD_ENTRY(pxList) (((pxList)->xListEnd).pxNext) /* * 返回pxListItem后继节点 */ #define listGET_NEXT(pxListItem) ((pxListItem)->pxNext) /* * 返回链表的尾部节点(哨兵节点) */ #define listGET_END_MARKER(pxList) ((ListItem_t const *) (&((pxList)->xListEnd))) /* * 链表是否为空 */ #define listLIST_IS_EMPTY(pxList) (((pxList)->uxNumberOfItems == (UBaseType_t)0) ? pdTRUE : pdFALSE) /* * 返回链表中的元素个数 */ #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; \ } /* * 删除pxItemToRemove节点 */ #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)--; \ } /* * pxNewListItem插入链表尾部 */ #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)++; \ } /* * 返回头结点的pvOwner */ #define listGET_OWNER_OF_HEAD_ENTRY(pxList) ((&((pxList)->xListEnd))->pxNext->pvOwner) /* * pxListItem节点是否在pxList链表中 */ #define listIS_CONTAINED_WITHIN(pxList, pxListItem) (((pxListItem)->pxContainer == (pxList)) ? (pdTRUE) : (pdFALSE)) /* * 返回pxListItem节点所在的链表 */ #define listLIST_ITEM_CONTAINER(pxListItem) ((pxListItem)->pxContainer) /* * pxList链表是否初始化 */ #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. * */ 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 (ascending 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; #endif /* ifndef LIST_H */