您的位置:首页 > 其它

【转载】µC/OS-II进程调度模型分析(PC移植版)

2012-04-06 14:36 417 查看



转自:http://aegiryy.net/?m=201011


µC/OS-II进程调度模型分析(PC移植版)

Posted
on November
12, 2010 by aegiryy

首先介绍一下µC/OS-II。


这是一个低功耗,基于优先级的抢占式的实时多任务操作系统内核。这个操作系统多用于嵌入式设备。


来自WIKIPEDIA

其实这也是源自嵌入式课程的作业,我有这个机会能够欣赏到µC/OS-II在windows上的移植。当我首先听到这个东西的时候,我惊讶了,一个操作系统怎么能移植到另一个操作系统上呢?操作系统应该直接面向硬件的阿,否则这玩意还有嘛意义?现在,我明白了。这个意义在于教学而非实用,可以让更多的人了解µC/OS-II的实现,而这个实现更多的是在于跟硬件无关层面的实现,包括IPC(Inter-Process Communication),进程调度,内存管理等方面。而且,这些也是操作系统最最核心的部分。

要分析这个进程调度模型,没有代码的展示和解释是不可想象的。其实很多时候,可怕的不是源代码本身,而是内心对于理解别人代码的畏惧。一份优秀的源代码,就像一本小说,有着跌宕起伏的情节,有着线索与线索之间的关联,这些都足够让人着迷。但是,µC/OS-II的代码虽然很清晰,但本身的结构并非完美,里面有着一些重复代码。这些让我产生了一个把这玩意从windows上移植到unix like的系统上,换而言之,就是对POSIX标准支持较好的系统上。


开始分析!

首先是关于临界区的,所谓临界区就是同一段时间不能有多个任务对临界区进行访问。在真实的硬件环境上往往是通过关中断的方式实现的,而在这个windows移植版上,是通过一个二元semaphore(如果童鞋们对于windows编程不甚了解,请先了解之,参看MSDN)。
µC/OS-II
抽象操作Windows
OS_ENTER_CRITICALP
WaitForSingleObject
OS_EXIT_CRITICALV
ReleaseSemaphore
OSSemaphore = CreateSemaphore( NULL, 1, 1, NULL );


初始化

OSStartHighRdy函数(主要步骤概述,下同)
代码片段描述
++OSRunning;把系统状态更改为运行态
OSCtxSwW32Event = CreateEvent(NULL, FALSE, FALSE, NULL);

OSCtxSwW32Handle = CreateThread(NULL, 0, OSCtxSwW32, 0, 0, &dwID);
新建windows事件:上下文切换事件,第二个新建出来的线程会不停的等待这个事件。换而言之,当这个事件发生之后(SetEvent),线程会进行任务调度
OSTick32Handle = CreateThread(NULL, 0, OSTickW32, 0, 0, &dwID);

OSTickEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);

OSTickTimer = timeSetEvent((1000/OS_TICKS_PER_SEC), OSTimeCap.wPeriodMin, (LPTIMECALLBACK)OSTickEventHandle, dwID, TIME_PERIODIC|TIME_CALLBACK_EVENT_SET);
该线程等待通过windows模拟出来的时钟中断,其实现是通过不断等待OSTickEventHandle事件。其中,timeSetEvent使得该事件每毫秒触发一次
SS_SP = (OS_EMU_STK*) OSTCBHighRdy->OSTCBStkPtr;

ResumeThread(SS_SP->Handle);
选出处于Ready态的且优先级最高的任务使之执行


调度函数OSCtxSw

代码片段描述
n = SuspendThread(SS_SP->Handle);暂停当前运行的任务
OSTCBCur = OSTCBHighRdy;

OSPrioCur = OSPrioHighRdy;

SS_SP = (OS_EMU_STK*) OSTCBHighRdy->OSTCBStkPtr;
上下文切换。保存被切换出去的任务,调入要被切换进来的任务。
ResumeThread(SS_SP->Handle);执行调度进来的任务


时钟中断处理过程OSTickISR

代码片段描述
OSIntEnter();统计当前进入的是第几级中断,在这个函数里会把级数+1
OSTimeTick();在这个函数中,每个处于等待态的任务会把OSTCBDly–,当有任务等待结束时,该任务会从等待态转换为就绪态
OSIntExit();该函数包含任务调度指示,下面会详述


时钟中断处理过程之OSTimeTick

代码片段描述
OSTime++;总的时间滴答数+1
while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {

if (ptcb->OSTCBDly != 0) {

if (–ptcb->OSTCBDly == 0) {

更改为Rdy态;

调整OSRdyGrp;

调整OSRdyTbl;

}

}

ptcb = ptcb->OSTCBNext;

}
遍历整个TCBList,对于每个处于等待态的任务OSTCBDly-1。如果等待完毕,则执行伪代码所表示的意思。最后在while的最下面跳到下一个TCB。


时钟中断处理过程之OSIntExit

代码片段描述
if (OSRunning == TRUE) {判断当前操作系统状态是否为运行态
if (OSIntNesting > 0) {

OSIntNesting–;

}
如果当前中断是嵌套中断,则层数-1
if (OSIntNesting == 0) {

OS_SchedNew();

OSIntCtxSw();

}

}
如果已经是最顶层的中断,则进行调度,选取新的任务并进行切换。其中省略了部分代码,这部分代码判断当前优先级最高且处于Ready态的是否和当前任务相同,如果相同则无需调度


最后一点想法…

我想把这个内核移植到Unix Like系统上,所以我最近看了一下POSIX thread模型。似乎另外还缺关于timer的一些东西,等到把这些东西弄清除了再动手不迟。

--------------------------------------------------------------------------------------------------------------------

本来想弄个传送门的,usoc任务切换之类的还是能看懂的,VC部分真心没基础。为了方便还是转了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: