uC/OS-II源码分析(六)
μC/OS-Ⅱ总是运行进入就绪态任务中优先级最高的那一个。确定哪个任务优先级最高,
下面该哪个任务运行了的工作是由调度器(Scheduler)完成的。任务级的调度是由函数
OSSched()完成的。中断级的调度是由另一个函数OSIntExt() 完成的,这个函数将在以后描
述。OSSched() 的代码如下:
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
INT8U y;
OS_ENTER_CRITICAL();
if ((OSIntNesting == 0) && (OSLockNesting == 0))
{ /* 只有ISR完成同时没有锁住调度才进行切换 */
//找最高优先级的任务
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
if (OSPrioHighRdy != OSPrioCur)
{ /*检查寻找到的优先级最高的任务是否是当前正在运行的任务,若是则不进行调度*/
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];//指向优先级最高的任务控制块
OSCtxSwCtr++; /* 切换计数器加*/
OS_TASK_SW(); /* 进行实际的任务切换*/
}
}
OS_EXIT_CRITICAL();
}
#define uCOS 0x80 /*用于任务切换的中断向量*/
#define OS_TASK_SW() asm INT uCOS
μC/OS-Ⅱ任务调度所花的时间是常数,与应用程序中建立的任务数无关。任务切换很简单,由以下两步完成,将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先级的任务的寄存器值从栈中恢复到寄存器中。在μC/OS-Ⅱ中,就绪任务的栈结构总是看起来跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。换句话说,μC/OS-Ⅱ运行就绪态的任务所要做的一切,只是恢复所有的CPU 寄存器并运行中断返回指令。为了做任务切换,运行OS_TASK_SW(), 人为模仿了一次中断。多数微处理器有软中断指令或者陷阱指令TRAP 来实现上述操作。中断服务子程序或陷阱处理(Trap hardler),也称作事故处理(exception handler),必须提供中断向量给汇编语言函数OSCtxSw() 。OSCtxSw() 除了需要OS_TCBHighRdy 指向即将被挂起的任务,还需要让当前任务控制块OSTCBCur 指向即将被挂起的任务,
OSSched()的所有代码都属临界段代码。在寻找进入就绪态的优先级最高的任务过程中,
为防止中断服务子程序把一个或几个任务的就绪位置位,中断是被关掉的。为缩短切换时间,
OSSched()全部代码都可以用汇编语言写。为增加可读性,可移植性和将汇编语言代码最少
化,OSSched() 是用C 写的。
OSCtxSw代码:
_OSCtxSw PROC FAR
PUSHA ; 保存当前任务的上下文
PUSH ES ;
PUSH DS ;
MOV AX, SEG _OSTCBCur ; Reload DS in case it was altered
MOV DS, AX ;
LES BX, DWORD PTR DS:_OSTCBCur ; OSTCBCur->OSTCBStkPtr = SS:SP
MOV ES:[BX+2], SS ;
MOV ES:[BX+0], SP ;
CALL FAR PTR _OSTaskSwHook ; Call user defined task switch hook
MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdy
MOV DX, WORD PTR DS:_OSTCBHighRdy ;
MOV WORD PTR DS:_OSTCBCur+2, AX ;
MOV WORD PTR DS:_OSTCBCur, DX ;
MOV AL, BYTE PTR DS:_OSPrioHighRdy ; OSPrioCur = OSPrioHighRdy
MOV BYTE PTR DS:_OSPrioCur, AL ;
LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr
MOV SS, ES:[BX+2] ;
MOV SP, ES:[BX] ;
POP DS ; 加载新任务的上下文
POP ES ;
POPA ;
IRET ; 返回到新任务中
_OSCtxSw ENDP
3. 给调度器上锁和开锁(Locking and UnLocking the Scheduler)
给调度器上锁函数OSSchedlock()用于禁止任务调度,直到任务完成后调用给调度器开锁函数OSSchedUnlock() 为止。调用OSSchedlock() 的任务保持对CPU 的控制权,尽管有个优先级更高的任务进入了就绪态。然而,此时中断是可以被识别的,中断服务也能得到(假设中断是开着的)。OSSchedlock() 和OSSchedUnlock() 必须成对使用。变量OSLockNesting 跟踪OSSchedLock() 函数被调用的次数,以允许嵌套的函数包含临界段代码,这段代码其它任务不得干预。μC/OS-Ⅱ允许嵌套深度达255 层。当OSLockNesting 等于零时,调度重新得到允许。函数OSSchedLock() 和OSSchedUnlock() 的使用要非常谨慎,因为它们影响μC/OS-Ⅱ对任务的正常管理。
当OSLockNesting 减到零的时候, OSSchedUnlock() 调用OSSched[L3.10(2)] 。
OSSchedUnlock() 是被某任务调用的,在调度器上锁的期间,可能有什么事件发生了并使一
个更高优先级的任务进入就绪态。
调用OSSchedLock() 以后,用户的应用程序不得使用任何能将现行任务挂起的系统调
用。也就是说,用户程序不得调用OSMboxPend() 、OSQPend() 、OSSemPend() 、
OSTaskSuspend(OS_PR1O_SELF) 、OSTimeDly() 或OSTimeDlyHMSM(), 直到OSLockNesting 回零为止。因为调度器上了锁,用户就锁住了系统,任何其它任务都不能运行。
当低优先级的任务要发消息给多任务的邮箱、消息队列、信号量时,用户不希望高优先级的任务在邮箱、队列和信号量没有得到消息之前就取得了CPU 的控制权,此时,用户可以使用禁止调度器函数。
给调度器上锁
void OSSchedLock (void)
{
if (OSRunning == TRUE)
{
OS_ENTER_CRITICAL();
OSLockNesting++;
OS_EXIT_CRITICAL();
}
}
给调度器开锁.
void OSSchedUnlock (void)
{
if (OSRunning == TRUE) {
OS_ENTER_CRITICAL();
if (OSLockNesting > 0) {
OSLockNesting--;
if ((OSLockNesting | OSIntNesting) == 0) {
OS_EXIT_CRITICAL();
OSSched();
} else {
OS_EXIT_CRITICAL();
}
} else {
OS_EXIT_CRITICAL();
}
}
}
作者:洞庭散人
出处:http://phinecos.cnblogs.com/
uC/OS-II源码分析(六)的更多相关文章
- ABP源码分析六:依赖注入的实现
ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...
- Duilib源码分析(六)整体流程
在<Duilib源码分析(一)整体框架>.<Duilib源码分析(二)控件构造器—CDialogBuilder>以及<Duilib源码分析(三)XML解析器—CMarku ...
- motan源码分析六:客户端与服务器的通信层分析
本章将分析motan的序列化和底层通信相关部分的代码. 1.在上一章中,有一个getrefers的操作,来获取所有服务器的引用,每个服务器的引用都是由DefaultRpcReferer来创建的 pub ...
- Vue.js 源码分析(六) 基础篇 计算属性 computed 属性详解
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的.在模板中放入太多的逻辑会让模板过重且难以维护,比如: <div id="example">{{ messag ...
- vuex 源码分析(六) 辅助函数 详解
对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...
- [Abp 源码分析]六、工作单元的实现
0.简介 在 Abp 框架内部实现了工作单元,在这里讲解一下,什么是工作单元? Unit Of Work(工作单元)模式用来维护一个由已经被业务事物修改(增加.删除或更新)的业务对象组成的列表.Uni ...
- MyBatis框架的使用及源码分析(六) MapperRegistry
我们先Mapper接口的调用方式,见<MyBatis框架中Mapper映射配置的使用及原理解析(一) 配置与使用>的示例: public void findUserById() { Sql ...
- docker 源码分析 六(基于1.8.2版本),Docker run启动过程
上一篇大致了解了docker 容器的创建过程,其实主要还是从文件系统的视角分析了创建一个容器时需要得建立 RootFS,建立volumes等步骤:本章来分析一下建立好一个容器后,将这个容器运行起来的过 ...
- phpcms 源码分析六:index文件
这次是逆雪寒对index.php的分析: /* [/php] [ 本帖最后由 逆雪寒 于 2007-12-25 16:12 编辑 ] 尽量每天都有新的东西每天都能进一小步 现在开始讲 index.ph ...
- Heritrix源码分析(六) Heritrix的文件结构分析(转)
本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/642618 本博客已迁移到本人独立博客: http://www.yun5u. ...
随机推荐
- nodejs初学-----helloworld
近期紧锣密鼓的学习了下nodejs(之前在学php.算入门了吧,可是时间关系,还没写文章,兴许要搞安卓和大数据,总之比較忙哈,计划上php要排到后面了,还请广大小伙伴不要着急) 先抄一句:Node.j ...
- java String概述
class StringDemo { public static void main(String[] args) { String s1 = "abc";//s1 是一个类类 ...
- 必会必知git
git必会必知 1 前言 git前身是BitKeeper,但是他不是开源软件,不符合当时开源趋势,于是就会有了开源的git,git开发只用了十天时间.目前git是公司开发必不可少的一个工具,用于多 ...
- 【BZOJ2510】弱题 期望DP+循环矩阵乘法
[BZOJ2510]弱题 Description 有M个球,一开始每个球均有一个初始标号,标号范围为1-N且为整数,标号为i的球有ai个,并保证Σai = M. 每次操作等概率取出一个球(即取出每个球 ...
- 更精炼更专注的RTMPClient客户端EasyRTMPClient,满足直播、转发、分析等各种需求
现状 EasyRTMPClient,熟悉的朋友就会联想到EasyRTSPClient项目(https://github.com/EasyDSS/EasyRTSPClient),EasyRTSPClie ...
- .net 开源框架--转载
Json.NET http://json.codeplex.com/ Json.Net 是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单.通过Li ...
- BZOJ1815: [Shoi2006]color 有色图
BZOJ1815: [Shoi2006]color 有色图 Description Input 输入三个整数N,M,P 1< = N <= 53 1< = M < = 1000 ...
- 我的Android进阶之旅------>Android资源文件string.xml中\u2026的意思
今天看了一个string.xml文件,对其中的一行代码中包含的\u2026不是很理解,后来查阅资料后发现了其中的意思. 代码如下: <resources xmlns:xliff="ur ...
- hadoop2.3安装过程及问题解决
三台serveryiprod01,02,03,当中01为namenode,02为secondarynamenode.3个均为datanode 3台server的这里提到的配置均需一样. 0.安装前提条 ...
- JS 中的面向对象
创建对象的集中常见方式 1 . 使用 Object 或 对象字面量创建对象 2 . 工厂模式创建对象 3 . 构造函数模式创建对象 4 . 原型模式创建对象 1 . 使用 Object 或 对象字面量 ...