ucos-II任务调度-随记

    这两天项目有点多,其中一个是在ucos上实现数据采集功能,以前看过ucos的代码,但是断断续续的,也没有记录,现在基本忘的差不多了,所以把看代码后的一些思考和经验总结出来,供自己以后阅读。因为是循序渐进的,有很多不足,以后为修正,也希望网络上的大牛能指出不足。微笑

    看了ucos部分内核代码后,感觉相对于linux这些航母级的操作系统来说,ucos整个内核还是比较轻量级的。并且没有有复杂的文件系统和内存管理后,整个内核看起来就更加爽。但是“麻雀虽小五脏俱全”(这句话老听别人说,咱也用用),实时操作系统该有的ucos都有。

    关于内核调度这块,不会记录与平台相关的部分,也就是任务切换时arm寄存器保存和恢复的过程,这部分只知道大致的原理,没有细研究过,因为暂时不用,所以也懒得去查arm芯片手册。


     ucos的任务调度:

    上课时,老师在说ucos时讲,ucos唯一值得说的就是它的任务调度算法,现在回想起来还是有道理的,我看过一些实时内核的代码,关于调度算法不一样外,其它的像什么event, messge, mailbox, 还有mutex之类的实现机制,都非常相似,跟我们打大学学的操作系统原理上讲的查不多。所以就记录下ucos任务调度算法:

    整个算法比较重要的就是四个数组:

    unsigend char OSRdyGrp;                    辅助表,它长8bits,每个比特指示OSRdyTbl一行的状体,eg: bit0->OSRdyTbl[0]; bit1->OSRdyTbl[1]......bit7->OSRdyTbl[7].当后者任何一位为一时,前者bit位为1.

    unsigend char OSRdyTbl[8];                 8*8 = 64  按优先级排列task,每个bit代表一个task, bit位唯一表示相应的task, ready to run;


    unsigned char OSMapTbl[8];                     辅助表  算法中用到,当任务进入/脱离就绪表时都会用到它。

    unsigned char OSUnMapTbl[256];           辅助表  当需要在任务就绪表中找出最高优先级的任务时,就需要用到这个表,这个表比较怪异,它的成员记录的是二进制数据末尾为1的位置。

    详细的算法可以查看代码OS_SchedNew(), OS_Sched();   


    发生任务调度的地方:

     当初始化时,会建立两个任务,一个是idle task,还有一个是stat task,这两个任务是ucos默认建立的,stat task是用于统计cpu的使用情况, idle task是优先级最低的task,它存在的意义是,当所有任务都没事做时,就跳到它里面,它只是让一个变量自加,这个变量给stat task用。处此之外就可以建立自己的task。

     在建立task的时候,有OSTaskCreate()函数,这个函数在建立后会有条件的选择是否立即调度,这个条件是OSRunning == 1, 但是在初始化的时候这个值给的是0,在所有任务建立后才在OSStart()函数里面赋值为1。也就是在OSStart之后才会允许调度。

那些地方会执行任务调度:

    每个task都会运行一段时间后执行任务调度,将执行权转移(idle task例外,下面有讲)到其它的task,目前看到的转移方式是在task里面执行OSTimeDly()函数,这个函数会将要delay的tick数,放入到当前task tcb的OSTCBDly变量里面,然后就会执行OS_Sched()执行调度。

    疑问,当系统运行到idle task之后,怎么从idle task里面跳出来,因为idle task没有执行任务调度的代码,--------中断,没有中断打扰他,他是不会让出执行权的。在运行idle task的时候中断是开着的,这个时候能够产生调度的中断,目前只看到SysTick_Handler(),这个中断,也许还有其它的中断发生后会有可能产生调度。

SysTick_Handler()是system tick发生后运行的ISR,(system tick 类似于ucos的脉搏,一般设置为1秒100个ticks, 也就是每个tick占10ms, 每10ms都会导致system tick中断),这个中断函数做了两件事:1.  中断发生后会遍历当前所有task的tcb->OSTCBDly变量,并逐个自减1,自减的同时判断OSTCBDly是否为零,如果为零就将任务放入就绪表。2.在退出中断函数时,回产生任务调度。  这就解释了为什么在idle task里面会跳出来了。

   所以从现在来看,任务调度发生的地方就这些了,后面看到了还会补充。

发生任务调度的地方:

   1. 等待mailbox消息,sys_mbox_fetch()

   2.等待信号量,sys_sem_wait()


任务切换的过程:

    这点开始说了只是知道一个大致的原理,现在就记录下来这个原理,给以后做个参考。

    任务切换(单核),主要的思想就是,保存和恢复task在某个时刻的状态,这个状体包括很多东西,与平台有关,以x86和arm比较为例,x86芯片有任务状态寄存器,任务描述符,这些在任务切换的时候都需要保存,而arm里面没有这些东西。但是无非就是那些记录当前芯片运行状态的东西,例如: x86的pc指针,状态寄存器flags, ax,bx,cx,dx,ds,es,ss等,arm的r0-r15(pc),cpsr等等这些寄存器的内容等等,这些在task切换的时候都会保存到对应task的stack里面,同时,新task里面的stack保存的内容会放入对应的芯片寄存器里面,然后产生一个中断或exception之类的动作,芯片就会在新task上接着运行。反之同样的道理。-------------这是自己的理解。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值