1、在ucos-ii中,有这么几张表来管理任务。
A、OSTCBPrioTbl[],其结构为OS_TCB指针的数组,其元素个数为64, 每一个元素对应一个任务的优先级,ucos-ii最多可以有64个任务,所以当有任务建立的时候,其每一个元素均指向一个任务控制块(若相应的优先级,已经建立了任务的话);若相应的优先级没有建立任务,则该数组元素指向的是(OS_TCB *)0;
B、任务控制块链表,该链表的每个节点,都是OS_TCB型结构。任务控制块链表除了本身构成一个双向链表, 其还与OSTCBPrioTbl[](OSTCBPrioTbl[]存放的就是任务控制块的首地址)和任务堆栈相联系(通过OS_TCB结构的OSTCBStkPtr元素指向任务堆栈的栈顶来实现)。在新建一个任务的时候,都必须新建任务控制块置于任务控制块链表中,通过OSTCBList来实现将其放于任务控制块链表的开头即新建的任务控制块。
C、任务就绪表,为9个字节,(OSRdyGrp和OSRdyTbl[8]).
OSRdyGrp存放的优先级分组的号。若其中的有一位置1, 表明其有任务处于就绪状态,若为0表示没有任务处于就绪状态。假设OSRdyGrp的第i位为1, 则表示处于任务优先级(i-1)*8~i*8-1中,至少有一个任务的处于就绪态(其中i属于(1~8))。
OSRdyTbl[8]的每个元素为8位,每一位代表一个任务优先级。这样8*8刚好为64,所以刚好可以存放完ucos-ii的最大任务总数。在该数组中,根据每位的值为0/1来决定其对应优先级的任务是否处于就绪态。为0表示该优先级任务不处于就绪状态,为1表示处于就绪态。同时当OSRdyTbl[]有一位为1时,该位代表的优先级将OSRdyGrp中对应的为置1。
由于ucos-ii为实时系统,为了尽量缩短查找表所用的时间,其还定义了两个常数数组,一个为OSMapTbl[8]和OSUnMapTbl[256]。(我个人认为这两个数组的设计最为巧妙和最有价值),通过这两张表很方便的就可以查询是否有任务处于就绪态,处于就绪态的最高优先级是多少。并且将一个任务置于就绪状态或者进行任务的调度都需要利用这两个常数数组。
OSMapTbl[]表如图1所示:
OSUnMapTbl[]表如图2所示:
D、空任务控制块链表,用来管理空任务控制块。当新建任务时,需要从该链表获取一个OS_TCB, 并将其放于任务控制块链表中。在这过程中主要是通过两个OS_TCB指针来完成,一个是OSTCBFreelist,另一个是OSTCBList,这两个指针始终指向链表的开头。
2、任务的创建过程
通过函数OSTaskCreate()或者OSTaskCreateEXT()两个函数来创建一个任务。
A、能否创建成功取决于这么几个条件:
a) 分配给即将要创建任务的优先级是否合法,prio<63(或者为自己修改的最大任务数);
b) 分配给将要创建任务的优先级是否已经被已存任务所占用,若没有被占用,则将OSTCBPrioTbl[prio]赋值1,来占用该优先级;
c) 是否有足够的RAM来分配给任务,作为任务的私有堆栈;
d) 是否有空余的OS_TCB分配给任务,作为该任务的任务控制块;
B、任务创建完后,上面所提到的有关任务控制块的几张表的更新。
a) OSTCBPrioTbl[]表:将新创建任务的任务控制块首地址存放在相应任务优先级元素中(即OSTCBPrioTbl[prio]中)。
b) 任务控制块链表:将OSTCBList指针更新指向新建的任务控制块,另外通过OS_TCB结构中的OSTCBNext和OSTCBPrev成员,将新建任务的OS_TCB置于双向链表中。
c) 任务就绪表的更新:新建任务建完后为就绪状态,因此应该将任务优先级在任务就绪表中相应的位置1, 其实现方式通过以下两条指令实现:OSRdyGrp |=OSMapTbl[prio>>3];
OSRdyTbl[prio>>3] |=OSMapTbl[prio & 0x07];
d) 空任务控制块链表:因为新建任务必须从空任务控制块中取出,所以在取完空OS_TCB需后,要修改OSTCBFreeList指针,将其指向下一个空OS_TCB。
C) 任务新建完后,与任务相关参数的设置。
任务的OS_TCB 存放在OSTCBPrioTbl[prio]中,任务的私有堆栈信息(栈顶指针、栈底指针和堆栈大小)存放在任务的OS_TCB中。任务函数的首地址存放在任务的堆栈中。
3、任务调度
A) 任务调度发生的时间
a)系统刚启动,完成初始化和至少建立了一个任务后,通过OSStart()函数调用__OSStartHighRdy函数将OSRunning=TRUE后,通过任务切换函数OSCtxSw来启动。
b) 系统运行过程中,新建任务的时需要启动任务调度器OSSched(),进行任务调度。
c) 任务被挂起或者等待延时或者等待其他时间发生时,需要进行任务调度。
d) 任务在运行过程中,有更高优先级任务处于就绪状态时,需要进行任务的调度(通过定时器中断服务程序,查询和更新所有任务状态时发现其是否有更高优先级任务处于就绪态)。
e) 中断服务程序运行过程中(ISR中需要使用任务)或者运行完之后需要进行任务的调度。
B) 怎样找到任务并运行
第一步:通过任务调度器或其他的方式,获得任务中的最高优先级prio;
第二步:通过prio在OSTCBPrioTbl[]中查找与prio相应的任务控制块,因为OSTCBPrioTbl[prio]中存放的就是与prio对应的OS_TCB,所以很容易就知道找到该OS_TCB。
第三步:获得任务的OS_TCB后,通过任务控制块中存放的有关堆栈信息来找到任务的私有堆栈。在堆栈中,将任务私有堆栈存放的有关处理器寄存器的内容恢复,则开始运行该任务。
在这过程中,有几个地方要记住:
1) 运行任务前,应该将其优先级在任务就绪表中相应的为清零;
2) 必须保存前一任务的信息;