FreeRTOS内核调度大量使用了列表(list)和列表项(list item)数据结构。
列表被FreeRTOS调度器使用,用于跟踪任务,处于就绪、挂起、延时的任务,都会被挂接到各自的列表中。用户程序如果有需要,也可以使用列表。
FreeRTOS列表使用指针指向列表项(item)。一个列表(list)下面可能有很多个列表项(list item),每个列表项都有一个指针指向列表。
列表项有两种形式,全功能版的列表项xLIST_ITEM和迷你版的列表项xMINI_LIST_ITEM。我们来看一下它们具体的定义,先看全功能版。
全功能版的列表项 xLIST_ITEM
1 | struct xLIST_ITEM |
xItemValue是列表项值,通常是一个被跟踪的任务优先级或是一个调度事件的计数器值。
如果任务因为等待从队列取数据而进入阻塞状态,则 任务的事件列表项
的列表项值保存任务优先级
有关信息,状态列表项的列表项值保存阻塞时间
有关的信息
迷你版的列表项 xMINI_LIST_ITEM
1 | struct xMINI_LIST_ITEM |
和全功能xLIST_ITEM对比少了pvContainer
, pvOwner
列表结构体需要一个列表项成员,但又不需要列表项中的所有字段,所以才有了迷你版列表项
列表 xLIST
1 | typedef struct xLIST |
列表项类型指针 pxIndex
用于遍历列表,列表初始化后,这个指针指向&xListEnd
(表示空列表, 只有一个元素,xListEnd)。通过宏listGET_OWNER_OF_NEXT_ENTRY()
来获取列表中的下一个列表项。
看一个例子:
1 | //将TCB的事件列表项插入到 pxReadyTasksLists[prority] |
1 | void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) |
初始化列表
列表结构体中包含一个列表项成员,主要用于标记列表结束。初始化列表就是把这个列表项插入到列表中。
1 | void vListInitialise( List_t * const pxList ) |
-171341083095748.png)
初始化列表项
1 | void vListInitialiseItem( ListItem_t * const pxItem ) |
列表项插入到列表
将列表项插入到列表中,列表项所在的位置取决于列表项的列表项值(xItemValue
)
通常是一个被跟踪的任务优先级
或是一个调度事件的计数器值
。调用API函数vListInsert( List_t _ const pxList, ListItem_t _ const pxNewListItem)
可以将pxNewListItem指向的列表项插入到pxList指向的列表中
列表项在列表的位置由pxNewListItem->xItemValue决定,按照升序排列。
1 | void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) |
.png)
在此基础上,如果再将一个列表项值(xItemValue)为40的列表项插入到列表中,调用vListInsert()函数后,列表和列表项的关系如图下所示
.png)
调度相关的列表
先看一下任务的结构体的定义
1 | typedef struct tskTaskControlBlock |
TCB结构体中包括 xEventListItem
和 xStateListItem
状态列表项
大概的用途, 用于追踪任务的状态, 从ready blocked delay suspend等状态间轮转, 其xItemValue
值是调度事件的计数器值, 比如timeout等
1 | xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) ); |
前面的章节中介绍过一个例子: 将TCB的事件列表项挂入到readyTaskList中, 表示该TCB 转到就绪状态.
1 | //将TCB的事件列表项插入到 pxReadyTasksLists[prority] |
通常的用法是 状态轮转, 调用 uxListRemove
将其从之前的状态列表中删除, 然后调用vListInsert
等插入函数挂入到新的状态列表中
事件列表项
等待事件的列表? 其xItemValue
值 保存的是任务优先级.
- 任务调度器相关的操作xTaskResumeFromISR
1
2// 调度器挂起时, ready的任务挂入到xPendingReadyList下, 调度器resume后, 从ready list中取任务调度执行
PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */
xTaskGenericNotifyFromISR
xTaskResumeAll
prvTaskIsTaskSuspended
xTaskRemoveFromEventList -> 用于队列的出队队列
因等待出队而阻塞的任务会将任务的事件列表项xEventListItem
挂接到队列的等待出队列表上
要解除任务阻塞,我们需要将任务的事件列表项从**队列**
的等待出队队列
(xTasksWaitingToReceive)上删除,并且将任务移动到就绪列表中。
调用函数xTaskRemoveFromEventList()实现。xTasksWaitingToReceive
是xQUEUE
的成员1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
typedef struct QueueDefinition
{
int8_t *pcHead; /*< Points to the beginning of the queue storage area. */
int8_t *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
int8_t *pcWriteTo; /*< Points to the free next place in the storage area. */
union /* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */
{
int8_t *pcReadFrom; /*< Points to the last place that a queued item was read from when the structure is used as a queue. */
UBaseType_t uxRecursiveCallCount;/*< Maintains a count of the number of times a recursive mutex has been recursively 'taken' when the structure is used as a mutex. */
} u;
List_t xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
List_t xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
volatile UBaseType_t uxMessagesWaiting; /*< The number of items currently in the queue. */
UBaseType_t uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
UBaseType_t uxItemSize; /*< The size of each items that the queue will hold. */
volatile int8_t cRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
volatile int8_t cTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
uint8_t ucStaticallyAllocated; /* true 标识任务栈是静态分配的, 不需要free*/
} xQUEUE;