目录
与优先级列表相似,在UCOS中还有另一个列表,就序列表。就序列表中存放准备好运行的TCB,方便系统调度运行。
就序列表的定义
数组定义
归根到底,就序列表是一个数组,具体定义如下
OS_EXT OS_RDY_LIST OSRdyList[OS_CFG_PRIO_MAX]; /* Table of tasks ready to run */
可以看出就绪列表在代码的层面上看是一个 OS_RDY_LIST 数据类型的数组,数组名为 OSRdyList,数组的大小由宏 OS_CFG_PRIO_MAX 决定。OS_CFG_PRIO_MAX表示优先级的最大值,也就是说有多少个优先级数组就有多大。实际上任务的优先级与 OSRdyList[] 的索引是一一对应的,也就是说优先级为2的任务的 TCB 会被放到 OSRdyList[2]中。
OS_RDY_LIST
数据类型OS_RDY_LIST定义在os.h中,具体如下
struct os_rdy_list {
OS_TCB *HeadPtr; /* Pointer to task that will run at selected priority */
OS_TCB *TailPtr; /* Pointer to last task at selected priority */
OS_OBJ_QTY NbrEntries; /* Number of entries at selected priority */
};
其中,
*HeadPtr表示头指针
*TailPtr表示为尾指针
NbrEntries表示在该索引下任务的个数
相关函数
OS_RdyListInit函数
该函数的作用是将就序列表里面的内容清零,比较简单。
void OS_RdyListInit (void)
{
OS_PRIO i;
OS_RDY_LIST *p_rdy_list;
for (i = 0u; i < OS_CFG_PRIO_MAX; i++) { /* Initialize the array of OS_RDY_LIST at each priority */
p_rdy_list = &OSRdyList[i];
p_rdy_list->NbrEntries = (OS_OBJ_QTY)0;
p_rdy_list->HeadPtr = (OS_TCB *)0;
p_rdy_list->TailPtr = (OS_TCB *)0;
}
}
OS_RdyListInsertHead函数
该函数的作用是,将一个任务插入到就序列表对应优先级索引链表的头。分两种情况,一种是该索引链表里面没有TCB,另一种就是有TCB。如果有TCB的话,就会用的p_tcb2这个指针用来中介。
void OS_RdyListInsertHead (OS_TCB *p_tcb)
{
OS_RDY_LIST *p_rdy_list;
OS_TCB *p_tcb2;
p_rdy_list = &OSRdyList[p_tcb->Prio];
if (p_rdy_list->NbrEntries == (OS_OBJ_QTY)0) { /* CASE 0: Insert when there are no entries */
p_rdy_list->NbrEntries = (OS_OBJ_QTY)1; /* This is the first entry */
p_tcb->NextPtr = (OS_TCB *)0; /* No other OS_TCBs in the list */
p_tcb->PrevPtr = (OS_TCB *)0;
p_rdy_list->HeadPtr = p_tcb; /* Both list pointers point to this OS_TCB */
p_rdy_list->TailPtr = p_tcb;
} else { /* CASE 1: Insert BEFORE the current head of list */
p_rdy_list->NbrEntries++; /* One more OS_TCB in the list */
p_tcb->NextPtr = p_rdy_list->HeadPtr; /* Adjust new OS_TCBs links */
p_tcb->PrevPtr = (OS_TCB *)0;
p_tcb2 = p_rdy_list->HeadPtr; /* Adjust old head of list's links */
p_tcb2->PrevPtr = p_tcb;
p_rdy_list->HeadPtr = p_tcb;
}
}
OS_RdyListInsertTail函数
该函数的作用是,将一个任务插入到就序列表对应优先级索引链表的尾部。和插入到头部相似,也是分两种情况。
void OS_RdyListInsertTail (OS_TCB *p_tcb)
{
OS_RDY_LIST *p_rdy_list;
OS_TCB *p_tcb2;
p_rdy_list = &OSRdyList[p_tcb->Prio];
if (p_rdy_list->NbrEntries == (OS_OBJ_QTY)0) { /* CASE 0: Insert when there are no entries */
p_rdy_list->NbrEntries = (OS_OBJ_QTY)1; /* This is the first entry */
p_tcb->NextPtr = (OS_TCB *)0; /* No other OS_TCBs in the list */
p_tcb->PrevPtr = (OS_TCB *)0;
p_rdy_list->HeadPtr = p_tcb; /* Both list pointers point to this OS_TCB */
p_rdy_list->TailPtr = p_tcb;
} else { /* CASE 1: Insert AFTER the current tail of list */
p_rdy_list->NbrEntries++; /* One more OS_TCB in the list */
p_tcb->NextPtr = (OS_TCB *)0; /* Adjust new OS_TCBs links */
p_tcb2 = p_rdy_list->TailPtr;
p_tcb->PrevPtr = p_tcb2;
p_tcb2->NextPtr = p_tcb; /* Adjust old tail of list's links */
p_rdy_list->TailPtr = p_tcb;
}
}
OS_RdyListInsert函数
这个函数的作用是添加任务到就序列表,如果要添加的任务与当前运行的任务优先级相等,就插入到链表的尾部,反之就插入到头部。
void OS_RdyListInsert (OS_TCB *p_tcb)
{
OS_PrioInsert(p_tcb->Prio);
if (p_tcb->Prio == OSPrioCur) { /* Are we readying a task at the same prio? */
OS_RdyListInsertTail(p_tcb); /* Yes, insert readied task at the end of the list */
} else {
OS_RdyListInsertHead(p_tcb); /* No, insert readied task at the beginning of the list */
}
#if (defined(TRACE_CFG_EN) && (TRACE_CFG_EN > 0u))
TRACE_OS_TASK_READY(p_tcb); /* Record the event. */
#endif
}
OS_RdyListMoveHeadToTail函数
该函数的作用是将 TCB 从就绪列表的头部移到尾部,移动的时候分四种情况,第一种是链表为空,无事可做;第二种是链表只有一个节点,也是无事可做;第三种是链表只有两个节点;第四种是链表有两个以上节点。
void OS_RdyListMoveHeadToTail (OS_RDY_LIST *p_rdy_list)
{
OS_TCB *p_tcb1;
OS_TCB *p_tcb2;
OS_TCB *p_tcb3;
switch (p_rdy_list->NbrEntries) {
case 0:
case 1:
break;
case 2: /* SWAP the TCBs */
p_tcb1 = p_rdy_list->HeadPtr; /* Point to current head */
p_tcb2 = p_rdy_list->TailPtr; /* Point to current tail */
p_tcb1->PrevPtr = p_tcb2;
p_tcb1->NextPtr = (OS_TCB *)0;
p_tcb2->PrevPtr = (OS_TCB *)0;
p_tcb2->NextPtr = p_tcb1;
p_rdy_list->HeadPtr = p_tcb2;
p_rdy_list->TailPtr = p_tcb1;
break;
default: /* Move only if there are more than 2 OS_TCBs in the list */
p_tcb1 = p_rdy_list->HeadPtr; /* Point to current head */
p_tcb2 = p_rdy_list->TailPtr; /* Point to current tail */
p_tcb3 = p_tcb1->NextPtr; /* Point to new list head */
p_tcb3->PrevPtr = (OS_TCB *)0; /* Adjust back link of new list head */
p_tcb1->NextPtr = (OS_TCB *)0; /* Adjust forward link of new list tail */
p_tcb1->PrevPtr = p_tcb2; /* Adjust back link of new list tail */
p_tcb2->NextPtr = p_tcb1; /* Adjust forward link of old list tail */
p_rdy_list->HeadPtr = p_tcb3; /* Adjust new list head and tail pointers */
p_rdy_list->TailPtr = p_tcb1;
break;
}
}
OS_RdyListRemove函数
该函数用于从链表中移除一个节点,移除的时候分为三种情况,第一种是链表 为空,无事可做;第二种是链表只有一个节点;第三种是链表有两个以上节点。
如果链表里面一个节点的前一个结点为零,说明他是第一个节点,该节点的后面的节点为零,说明他是尾节点,两个都为零说明这个链表里面只有一个节点。
如果只有一个节点,在删除该节点的同时,还有清除优先级列表的对应位。如果删除的是头结点,后面的节点自动成为头结点,删除的为节点,前一个节点自动成为尾节点。删除中间的节点的话,要把该节点的前一个节点和后一个节点联系起来。
void OS_RdyListRemove (OS_TCB *p_tcb)
{
OS_RDY_LIST *p_rdy_list;
OS_TCB *p_tcb1;
OS_TCB *p_tcb2;
p_rdy_list = &OSRdyList[p_tcb->Prio];
p_tcb1 = p_tcb->PrevPtr; /* Point to next and previous OS_TCB in the list */
p_tcb2 = p_tcb->NextPtr;
if (p_tcb1 == (OS_TCB *)0) { /* Was the OS_TCB to remove was at the head? */
if (p_tcb2 == (OS_TCB *)0) { /* Yes, was it the only OS_TCB? */
p_rdy_list->NbrEntries = (OS_OBJ_QTY)0; /* Yes, no more entries */
p_rdy_list->HeadPtr = (OS_TCB *)0;
p_rdy_list->TailPtr = (OS_TCB *)0;
OS_PrioRemove(p_tcb->Prio);
} else {
p_rdy_list->NbrEntries--; /* No, one less entry */
p_tcb2->PrevPtr = (OS_TCB *)0; /* adjust back link of new list head */
p_rdy_list->HeadPtr = p_tcb2; /* adjust OS_RDY_LIST's new head */
}
} else {
p_rdy_list->NbrEntries--; /* No, one less entry */
p_tcb1->NextPtr = p_tcb2;
if (p_tcb2 == (OS_TCB *)0) {
p_rdy_list->TailPtr = p_tcb1; /* Removing the TCB at the tail, adj the tail ptr */
} else {
p_tcb2->PrevPtr = p_tcb1;
}
}
p_tcb->PrevPtr = (OS_TCB *)0;
p_tcb->NextPtr = (OS_TCB *)0;
#if (defined(TRACE_CFG_EN) && (TRACE_CFG_EN > 0u))
TRACE_OS_TASK_SUSPEND(p_tcb); /* Record the event. */
#endif
}