主机环境:Windows
开发环境:MDK4.7.2
FreeRTOS版本:FreeRTOS8.1.2
目标环境:STM32F030C8T6
最近打算学习一下FreeRTOS的知识,在此作下笔记以便帮助自己理解,FreeRTOS与uCos-ii不同,在查询最高优先级时不是采用查表法来得知,而是通过链表来获取,因此链表在FreeRTOS中是比较重要的一个数据结构,因此先学习下FreeRTOS中有关链表的操作,查看源代码发现链表的代码貌似很精简,有三个结构分别是xLIST_ITEM、xMINI_LIST_ITEM、xLIST,其中xLIST_ITEM和xMINI_LIST_ITEM类似可以归为一类
/* * Definition of the only type of object that a list can contain. */ struct xLIST_ITEM { configLIST_VOLATILE TickType_t xItemValue; struct xLIST_ITEM * configLIST_VOLATILE pxNext; struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; void * pvOwner; void * configLIST_VOLATILE pvContainer; }; typedef struct xLIST_ITEM ListItem_t; 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; MiniListItem_t xListEnd; } List_t;
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) ) #define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner ) #define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) ) #define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue ) #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue ) #define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext ) #define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext ) #define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) ) #define listLIST_IS_EMPTY( pxList ) ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ) #define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems ) #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; \ } #define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner ) #define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) ) #define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer ) #define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY ) void vListInitialise( List_t * const pxList ); void vListInitialiseItem( ListItem_t * const pxItem ); void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ); void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ); UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove );
在list.c中还有五个链表的操作函数
1.链表初始化函数
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 ); /* 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 ); pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); pxList->uxNumberOfItems = ( UBaseType_t ) 0U; }
2. 初始化队列中的元素
void vListInitialiseItem( ListItem_t * const pxItem ) { /* Make sure the list item is not recorded as being on a list. */ pxItem->pvContainer = NULL; }
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) { ListItem_t * const pxIndex = pxList->pxIndex; /* 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->pvContainer = ( void * ) pxList; ( pxList->uxNumberOfItems )++; }该函数在队列当前指针pxIndex之前插入了一个元素,同时设置了新元素的pvContainer属性指向所插入的链表pxList,同时更新链表中的元素数
4. 插入元素2
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 ) { /* There is nothing to do here, we are 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 )++; }
5.移除元素
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; /* 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; }
/* Lists for ready and blocked tasks. --------------------*/ PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ]; PRIVILEGED_DATA static List_t xDelayedTaskList1; PRIVILEGED_DATA static List_t xDelayedTaskList2; PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList; PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList; PRIVILEGED_DATA static List_t xPendingReadyList;
一个就绪链表数组,两个延时任务链表(一个用于正常延时,一个用于延时溢出),一个挂起的就绪任务链表,现在还不清楚两个延时任务链表的用法,关于就绪链表数组需要说明的是FreeRTOS的调度算法是机遇任务优先级调度的,总是运行就绪任务中优先级最高的任务,因此在FreeRTOS中按照优先级区分,为每一个优先级都建立了一个就绪链表,以便于查找就绪任务中优先级最高的任务。有关链表的知识先记录到此,有新东西再说吧。。。
PS:关于两个延时链表,FreeRTOS是有一个时钟计数器的,当任务需要延时,任务就会从就绪链表中移除转而进入延时链表中,由于任务延时完毕后还需要唤醒 ,因此需要一个唤醒时间,如果唤醒时间没有溢出那么任务就会插入pxDelayedTaskList指针指向的链表即xDelayedTaskList1链表,而如果唤醒时间溢出的话,那么任务就会插入pxOverflowDelayedTaskList指针指向的链表即xDelayedTaskList2,这个会在vTaskDelay()函数中提到。