新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > μC/OS-II的内核结构

μC/OS-II的内核结构

作者: 时间:2016-10-08 来源:网络 收藏

读者可以看出,任务优先级的低三位用于确定任务在总就绪表OSRdyTbl[]中的所在位。接下去的三位用于确定是在OSRdyTbl[]数组的第几个元素。OSMapTbl[]是在ROM中的(见文件OS_CORE.C)屏蔽字,用于限制OSRdyTbl[]数组的元素下标在0到7之间,见表3.1

本文引用地址:https://www.eepw.com.cn/article/201610/305744.htm

图3.3μC/OS-Ⅱ就绪表

如果一个任务被删除了,则用程序清单3.6中的代码做求反处理。

程序清单L3.6从就绪表中删除一个任务

if((OSRdyTbl[prio>>3]=~OSMapTbl[prio0x07])==0)

OSRdyGrp=~OSMapTbl[prio>>3];

以上代码将就绪任务表数组OSRdyTbl[]中相应元素的相应位清零,而对于OSRdyGrp,

只有当被删除任务所在任务组中全组任务一个都没有进入就绪态时,才将相应位清零。也

就是说OSRdyTbl[prio>>3]所有的位都是零时,OSRdyGrp的相应位才清零。为了找到那个

进入就绪态的优先级最高的任务,并不需要从OSRdyTbl[0]开始扫描整个就绪任务表,只

需要查另外一张表,即优先级判定表OSUnMapTbl([256])(见文件 OS_CORE.C)。OSRdyTbl[]

中每个字节的8位代表这一组的8个任务哪些进入就绪态了,低位的优先级高于高位。利用

这个字节为下标来查OSUnMapTbl这张表,返回的字节就是该组任务中就绪态任务中优先级

最高的那个任务所在的位置。这个返回值在0到7之间。确定进入就绪态的优先级最高的任

务是用以下代码完成的,如程序清单L3.7所示。

程序清单 L3.7 找出进入就绪态的优先级最高的任务

y=OSUnMapTbl[OSRdyGrp];

x=OSUnMapTbl[OSRdyTbl[y]];

prio=(y3)+x;

例如,如果OSRdyGrp的值为二进制01101000,查OSUnMapTbl[OSRdyGrp]得到的值是

3,它相应于OSRdyGrp中的第3位bit3,这里假设最右边的一位是第0位bit0。类似地,

如果OSRdyTbl[3]的值是二进制11100100,则OSUnMapTbl[OSRdyTbc[3]]的值是2,即第2

位。于是任务的优先级Prio就等于26(3*8+2)。利用这个优先级的值。查任务控制块优

先级表OSTCBPrioTbl[],得到指向相应任务的任务控制块OS_TCB的工作就完成了。

3.5 任务调度(TaskScheduling)

μC/OS-Ⅱ总是运行进入就绪态任务中优先级最高的那一个。确定哪个任务优先级最

高,下面该哪个任务运行了的工作是由调度器(Scheduler)完成的。任务级的调度是由函

数OSSched()完成的。中断级的调度是由另一个函数OSIntExt()完成的,这个函数将在以

后描述。OSSched()的代码如程序清单L3.8所示。

程序清单L3.8任务调度器(theTaskScheduler)

voidOSSched(void)

{

INT8Uy;

OS_ENTER_CRITICAL();

if((OSLockNesting|OSIntNesting)==0){(1)

y=OSUnMapTbl[OSRdyGrp];(2)

OSPrioHighRdy=(INT8U)((y3)+OSUnMapTbl[OSRdyTbl[y]]);(2)

if(OSPrioHighRdy!=OSPrioCur){(3)

OSTCBHighRdy=OSTCBPrioTbl[OSPrioHighRdy];(4)

OSCtxSwCtr++;(5)

OS_TASK_SW();(6)

}

}

OS_EXIT_CRITICAL();

}

μC/OS-Ⅱ任务调度所花的时间是常数,与应用程序中建立的任务数无关。如程序清单

中[L3.8(1)]条件语句的条件不满足,任务调度函数OSSched()将退出,不做任务调度。这

个条件是:如果在中断服务子程序中调用OSSched(),此时中断嵌套层数

OSIntNesting>0,或者由于用户至少调用了一次给任务调度上锁函数OSSchedLock(),使

OSLockNesting>0。如果不是在中断服务子程序调用OSSched(),并且任务调度是允许的,

即没有上锁,则任务调度函数将找出那个进入就绪态且优先级最高的任务[L3.8(2)],进入

就绪态的任务在就绪任务表中有相应的位置位。一旦找到那个优先级最高的任务,

OSSched()检验这个优先级最高的任务是不是当前正在运行的任务,以此来避免不必要的任

务调度[L3.8(3)]。注意,在μC/OS中曾经是先得到OSTCBHighRdy然后和OSTCBCur做比

较。因为这个比较是两个指针型变量的比较,在8位和一些16位微处理器中这种比较相对

较慢。而在μC/OS-Ⅱ中是两个整数的比较。并且,除非用户实际需要做任务切换,在查任

务控制块优先级表OSTCBPrioTbl[]时,不需要用指针变量来查OSTCBHighRdy。综合这两项

改进,即用整数比较代替指针的比较和当需要任务切换时再查表,使得μC/OS-Ⅱ比μC/OS

在8位和一些16位微处理器上要更快一些。

为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,这是

通过将以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来

实现的[L3.8(4)]。接着,统计计数器OSCtxSwCtr加1,以跟踪任务切换次数[L3.8(5)]。

最后宏调用OS_TASK_SW()来完成实际上的任务切换[L3.8(6)]。

任务切换很简单,由以下两步完成,将被挂起任务的微处理器寄存器推入堆栈,然后

将较高优先级的任务的寄存器值从栈中恢复到寄存器中。在μC/OS-Ⅱ中,就绪任务的栈结

构总是看起来跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。换句话说,

μC/OS-Ⅱ运行就绪态的任务所要做的一切,只是恢复所有的CPU寄存器并运行中断返回指

令。为了做任务切换,运行OS_TASK_SW(),人为模仿了一次中断。多数微处理器有软中断

指令或者陷阱指令TRAP来实现上述操作。中断服务子程序或陷阱处理(Traphardler),

也称作事故处理(exceptionhandler),必须提供中断向量给汇编语言函数OSCtxSw()。

OSCtxSw()除了需要OS_TCBHighRdy指向即将被挂起的任务,还需要让当前任务控制块

OSTCBCur指向即将被挂起的任务,参见第8章,移植μC/OS-Ⅱ,有关于OSCtxSw()的更详



关键词:

评论


相关推荐

技术专区

关闭