μC/OS-II的内核结构
第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()的更详
尽的解释。
OSSched()的所有代码都属临界段代码。在寻找进入就绪态的优先级最高的任务过程
中,为防止中断服务子程序把一个或几个任务的就绪位置位,中断是被关掉的。为缩短切
换时间,OSSched()全部代码都可以用汇编语言写。为增加可读性,可移植性和将汇编语言
代码最少化,OSSched()是用C写的。
3.6 给调度器上锁和开锁(LockingandUnLockingtheScheduler)
给调度器上锁函数OSSchedlock()(程序清单L3.9)用于禁止任务调度,直到任务完
成后调用给调度器开锁函数OSSchedUnlock()为止,(程序清单L3.10)。调用
OSSchedlock()的任务保持对CPU的控制权,尽管有个优先级更高的任务进入了就绪态。然
而,此时中断是可以被识别的,中断服务也能得到(假设中断是开着的)。OSSchedlock()
和OSSchedUnlock()必须成对使用。变量OSLockNesting跟踪OSSched
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)
