μCOS-II微小内核分析_第1页
μCOS-II微小内核分析_第2页
μCOS-II微小内核分析_第3页
μCOS-II微小内核分析_第4页
μCOS-II微小内核分析_第5页
已阅读5页,还剩73页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、C/OS-II微小内核分析微小内核分析 绪论绪论 C/OS-II微小内核是为了方便初学者学习嵌入式实时操作系统的基本原理,分别由小到大将C/OS-II V2.52裁减为几个只具备基本功能的微小内核。建议:初学者学习或者教师讲授本章内容时,一定要尽量做到一边阅读源代码一边画图,事实上“过程比结论更重要” !1100行(剔除文件头和函数头后的数目) 只有418行(剔除文件头和函数头后的数目),仅包含5个最基本的服务函数的“最小内核最小内核”。 最小内核最小内核 | C/OS-II微小内核分析微小内核分析 任务级的任务调度小结任务级的任务调度小结 通过对上述内容的学习,可以看出下图就是从Task0到

2、Task1,然后再从Task1到OS_TaskIdle的切换过程。任务级的任务调度如果ticks非0,则将当前任务Task0从就绪表中删除,并将ticks延时节拍数保存到当前任务Task0的OS_TCB中,然后进行一次任务调度,并且执行下一个处于就绪态优先级最高的任务Task1。ticks非0,则将当前任务Task1从就绪表中删除,并将ticks延时节拍数保存到当前任务Task1的OS_TCB中,然后再进行一次任务调度,并且执行下一个处于就绪态优先级最高的任务OS_TaskIdle 。C/OS-II微小内核分析微小内核分析临界区与中断管理临界区与中断管理123456可重入性可重入性 案例分析案

3、例分析 禁止禁止/允许中断允许中断 时钟节拍时钟节拍 中断服务程序中断服务程序 中断管理中断管理 临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析可重入性可重入性 可重入的代码指的是一段代码可以被多个任务同时调用,而不必担心数据被破坏。即就是说,可重入型函数在任何时候都可以被中断,一段时间以后又可以继续运行,而相应数据却不会丢失。 可重入型函数或者只使用局部变量,即变量保存在CPU寄存器或堆栈中;或者使用全局变量。当使用全局变量时,则要对全局变量予以保护。代码的可重入性是保证完成多任务的基础。调用调用调用临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微

4、小内核分析案例分析案例分析 在RTOS中,有可能几个任务需要访问同一个资源。同一个资源往往不能被几个任务同时访问,否则可能会破坏资源。全局变量是最简单的资源,本例用2个全局变量模拟1个共享资源,让低优先级任务依次改变2个全局变量的值,让它们的值始终相等。而高优先级的任务则定时检查这2个变量的值是否相等,如果不相等,则让LED2闪烁。临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析案例分析案例分析void Task0(void *pdata) while (1) OS_ENTER_CRITICAL(); if (sum1 != sum2) if (i % 2) = 0)

5、 IO2CLR = LED2; else IO2SET = LED2; i+; OS_EXIT_CRITICAL(); 初始化工作允许中断 下面给出Task0任务的主要处理代码。LED1闪烁关键代码,禁止中断如果sum1与sum2不相等,则根据i % 2的值点亮或熄灭LED2临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析案例分析案例分析void Task1 (void *pdata) pdata = pdata; while (1) OS_ENTER_CRITICAL(); sum1+; sum2+; OS_EXIT_CRITICAL(); 防止编译器报警sum1和

6、sum2加1 下面给出Task1任务的主要处理代码。允许中断关键代码,禁止中断由于CPU在执行关键代码时,中断被屏蔽,因此不可能执行中断服务程序,也就不会引起中断切换。此时,只要Task0()运行,sum1和sum2就相等,因此,LED2不会闪烁。临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析案例分析案例分析void Task0(void *pdata) while (1) if (sum1 != sum2) 初始化工作当删除了禁止中断和允许中断的语句后,任务间可能出现以下情况。sum1与sum2相等,不执行括号内的代码LED1闪烁void Task1 (void

7、*pdata) pdata = pdata; while (1) sum1+; sum2+; sum1加1防止编译器报警执行任务1任务调度发生中断任务调度sum1与sum2不相等,执行括号内的代码LED2闪烁临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析禁止禁止/允许中断允许中断 和其它内核一样,C/OS-为了处理临界区代码需要禁止中断,处理完毕后再允许中断,这使得C/OS-能够避免同时有其它任务或中断服务进入临界段代码。 为了避开不同C编译器厂商选择不同的方法来处理禁止中断和允许中断 ,C/OS-定义两个宏来禁止中断和允许中断,分别是:OS_ENTER_CRITI

8、CAL()和OS_EXIT_CRITICAL()。 OS_ENTER_CRITICAL()临界区代码OS_EXIT_CRITICAL()需成对出现临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析禁止禁止/允许中断允许中断 在ARM7中,OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()是通过使用软件中断异常实现的,详细请参考SWI软件中断异常章节。ENTER_CRITICAL LDR R1, =OsEnterSum LDRB R2, R1 ADD R2, R2, #1 STRB R2, R1 MRS R0, SPSR ORR R0, R0,

9、#NoInt MSR SPSR_c, R0 MOVS PC, LR 禁止中断关中断计数器OsEnterSum加1返回OS_ENTER_CRITICAL的实现代码如下:临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析禁止禁止/允许中断允许中断OS_EXIT_CRITICAL()的实现代码如下:EXIT_CRITICAL LDR R1, =OsEnterSum LDRB R2, R1 SUB R2, R2, #1 STRB R2, R1 CMP R2, #0 MRSEQ R0, SPSR BICEQ R0, R0, #NoInt MSREQ SPSR_c, R0 MOVS

10、 PC, LR OsEnterSum为0,则允许中断关中断计数器OsEnterSum加1返回判断OsEnterSum是否为0在ARM处理器核中禁止中断和禁止中断是通过改变程序状态寄存器CPSR中的相应控制位来实现的。由于使用了软件中断,程序状态寄存器CPSR保存到程序状态保存寄存器 SPSR中,软件中断退出时会将SPSR恢复到CPSR中,所以程序只要改变程序状态保存寄存器SPSR中相应的控制位就可以了。 临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析时钟节拍时钟节拍 时钟节拍是特定的周期性中断时钟节拍是特定的周期性中断,时钟节拍源一般是由专门的硬件定时器产生的,该定

11、时器是一个周期性定时器,该定时器产生周期性的中断,这个中断可以看作是系统心脏的脉动。一般情况下,用户在第一个任务中开启时钟节拍器,以避免用户程序崩溃。 C/OS-中的时钟节拍服务是通过在中断服务程序中调用OSTimeTick()实现的,OSTimeTick()是为系统提供时钟节拍的服务程序。函数名称OSTimeTick所属文件OS_CORE.C函数原型void OSTimeTick (void) 功能描述时间节拍处理函数。减少任务的一个延时节拍数,并判断任务是否延时结束,如果延时结束,则让任务进入就绪状态函数参数无函数返回值无特殊说明由时钟节拍中断处理程序调用,用户很少使用临界区与中断管理临界

12、区与中断管理| C/OS-II微小内核分析微小内核分析时钟节拍时钟节拍使用timer0产生周期性时钟节拍,其过程如下图所示。VIC初始化定时器0初始化Timer0中断服务程序产生中断调用OSTimeTick()减少任务一个延时节拍数,并判断任务是否延时结束。如果延时结束,则任务进入就绪状态。其中,VIC初始化函数为VICInit() ,定时器0初始化函数为imer0Init() ,timer0中断服务函数为Timer0_Exception() 。 临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析时钟节拍时钟节拍 VIC初始化函数VICInit()和定时器0初始化函数T

13、imer0Init()如下。#define OS_TICKS_PER_SEC 200void VICInit (void) . 设置定时器0的中断优先级; 设置定时器0的中断服务程序入口; 使能定时器0中断; 其它中断初始化设置中断优先级为0(最高)在OS_CFG.h中定义,一秒钟200个时钟节拍设置Timer0的中断服务地址为Timer0_Exceptionvoid Timer0Init (void) T0IR = 0 xff; T0TC = 0; T0TCR = 0 x01; T0MCR = 0 x03; T0MR0 = (Fpclk/OS_TICKS_PER_SEC) 设置TC的计数值为

14、0使能Timer0 清除中断TC值匹配时产生中断,且TC值复位设定匹配值临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析时钟节拍时钟节拍void Timer0_Exception (void) T0IR = 0 x01; VICvectAddr = 0; OSTimeTick();通知中断控制器中断结束调用时钟节拍函数清除Timer0中断 当完成VIC跟Timer0的初始化后,如果此时允许中断,则CPU跳转到中断异常入口处,同时CPU切换到IRQ中断模式,“中断返回地址+4” 保存在IRQ中断模式下的LR寄存器中,再跳转到中断异常处理程序IRQ_Handler,获取T

15、imer0中断服务程序地址Timer0_Exception 。C/OS-中的函数OSTimeTick()在周期性中断的中断服务程序Timer0_Exception()中被调用,C/OS-会在中断退出时调用另一个为中断编写的调度器,让处于就绪态优先级最高的任务运行。 临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析中断服务程序中断服务程序 一般来说,C/OS-II中,中断服务程序的全部或部分用汇编语言来写。当然,部分芯片的部分编译器可能可以全部使用C语言编写,但毕竟是少数,中断服务程序的图解如下。执行用户代码(中断服务)执行用户代码(中断服务)保存全部寄存器保存全部寄存

16、器中断服务程序中断服务程序 调用调用OSIntEnter或或 OSIntNesting直接加直接加1 调用调用OSIntExit() 恢复所有恢复所有CPU寄存器寄存器执行中断返回指令执行中断返回指令 告诉C/OS-此时正在执行中断服务 OSIntNesting减1,如果OSIntNesting减到0时,则表明所有中断,包括嵌套的中断都已经完成。此时C/OS-要判定有没有优先级更高的任务被中断服务程序唤醒,如果有优先级更高的任务进入了就绪态,那么C/OS-就返回到那个更高优先级的任务。 临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析中断服务程序中断服务程序 针对AR

17、M7,当有IRQ中断产生且CPU允许相应中断时,CPU会跳转到IRQ中断异常入口处(异常向量表),同时CPU切换到IRQ中断模式,处理器会自动将“IRQ中断返回地址+4” 保存到IRQ模式下的LR寄存器中,并将用户模式下的CPSR保存到IRQ模式下的SPSR_irq中。 “IRQ中断返回地址中断返回地址+4”保存保存到到IRQ模式下的模式下的LR中中CPU跳到跳到IRQ中断异常入口中断异常入口,且且CPU切换到切换到IRQ中断模式中断模式IRQ中断中断 用户模式下的用户模式下的CPSR保存到保存到IRQ模式下的模式下的SPSR_irq临界区与中断管理临界区与中断管理| C/OS-II微小内核分

18、析微小内核分析中断服务程序中断服务程序 在针对ARM7的C/OS-中,移植代码提供了汇编接口代码,它完成了大部分必要的工作。对于LPC系列ARM,进入中断的汇编接口代码如下。 .IRQ_Handler SUB LR, LR, #4 STMFD SP!, R0-R3, R12, LR MRS R3, SPSR STMFD SP, R3, SP, LR LDR R2, =OSIntNesting LDRB R1, R2 ADD R1, R1, #1 STRB R1, R2 SUB SP, SP, #4*3 MSR CPSR_c,#(NoInt | SYS32Mode) CMP R1, #1 LDR

19、EQ SP, =StackUsr BL $IRQ_Exception_Function引入外部标号计算IRQ中断返回地址保存用户状态的R3,SP,LR,注意不能回写保存任务环境OSIntNesting+调整SP指针内容切换到系统模式跳转到中断服务程序如果当前中断是发生在任务执行时,则把SP设置为StackUsr如果不使用这两条指令,则实际的中断处理函数使用的是任务本身的堆栈,这样每个任务都需要为中断处理程序保留足够的堆栈,浪费了大量存储空间。当使用了这两条指令,那么任务就不需要为中断处理程序保留堆栈空间。对于LPC2000系列ARM,StackUsr一般就是main()函数的堆栈,与main(

20、)函数分时复用。由于调用OSStart()之后才可能产生中断,而OSStart()永远不会返回main()函数,此时main()函数的堆栈可以任意使用。 临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析中断服务程序中断服务程序退出中断的汇编接口代码如下。 MSR CPSR_c,#(NoInt | SYS32Mode) LDR R2, =OSEnterSum MOV R1, #1 STR R1, R2 BL OSInitExit LDR R2, =OSEnterSum MOV R1, #0 STR R1, R2 MSR CPSR_c,#(NoInt | IRQ32Mod

21、e) LDMFD SP, R3, SP, LR LDR R0, =OSTCBHighRdy LDR R0, R0 LDR R1, =OSTCBCur LDR R1, R1 CMP R0, R1 ADD SP, SP, #4*3 MSR SPSR_cxsf, R3 LDMEQFD SP!, R0-R3, R12, LR LDR PC, =OSIntCtxSw 切换到系统模式恢复用户状态的R3,SP,LR,注意不能回写调用OSInitExit调整SP指针内容恢复IRQ中的SPSR根据OSTCBHighRdy与OSTCBCur的值决定是否进行任务切换OsEnterSum为1,使OSIntExit退出

22、时中断关闭因为中断服务程序要退出,所以OsEnterSum=0切换回到IRQ模式比较OSTCBHighRdy指向的内容与OSTCBCur指向的内容临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析中断服务程序中断服务程序SPR12LRPCCPSRSPSRSPLRR0R1R3R4 R11R2SPR12LRPCCPSRSPSRSPLRR0R1R3R4 R11R2退出中断时的出栈关系退出中断时的出栈关系进入中断时的压栈关系进入中断时的压栈关系寄存器寄存器寄存器寄存器 用户模式 IRQ模式用户模式 IRQ模式0 x?0 x?0 x?0 x?0 x?0 x?0 x?0 x?0 x

23、?存储器存储器0 x?123 R0 LR SPSPSR_irqLR_irq R12 R3 R2 R154堆栈指针位置说明入堆指针位置出堆指针位置进入和退出中断时的堆栈动作图示如下。 执行代码 STMFD SP!,R0-R3,R12,LR保存任务环境;执行代码 STMFD SP,R3,SP,LR保存用户状态的CPSR;执行代码 SUB SP,SP,#4*3 调整SP指针内容;执行代码 LDMFD SP,R3,SP,LR恢复用户状态的R3、SP、LR;执行代码 ADD SP,SP,#4*3 调整SP指针内容;执行代码 LDMEQFD SP!,R0-R3,R12,PC 恢复任务环境。临界区与中断管理

24、临界区与中断管理| C/OS-II微小内核分析微小内核分析中断管理中断管理 由中断服务程序可知,C/OS-的中断管理实际上就是2个函数,OSIntEnter()和OSIntExit()。 函数名称OSIntEnter所属文件OS_CORE.C函数原型void OSIntEnter (void) 功能描述判断RTOS是否运行,当RTOS运行,且OSIntNesting小于255时,使OSIntNesting加1函数参数无函数返回值无特殊说明进入中断时调用函数名称OSIntExit所属文件OS_CORE.C函数原型void OSIntExit (void) 功能描述判断RTOS是否运行,当RTOS

25、运行,且OSIntNesting0时,使OSIntNesting减1,此时如果OSIntNesting等于0,则查找进入就绪态且优先级最高的任务,再把这个任务的优先级与当前任务的优先级进行比较,不相等则进行调度函数参数无函数返回值无特殊说明退出中断时调用临界区与中断管理临界区与中断管理| C/OS-II微小内核分析微小内核分析中断管理中断管理void OSIntEnter (void) if (OSRunning = TRUE) if (OSIntNesting 0) OSIntNesting-; if (OSInterNesting = 0) OSIntExitY = OSUnMapTblO

26、SRdyGrp; OSPrioHighRdy = (INT8U)(OSIntExitY OSTCBPrev = (OS_TCB*)0; if(OSTCBList != (OS_TCB*)0) OSTCBList-OSTCBPrev = ptcb;新增的代码,用于建立反向链表,加快删除任务TCB初始化任务的结束任务的结束| C/OS-II微小内核分析微小内核分析删除任务删除任务 通过调用函数OSTaskDel(),可以让处于就绪态、运行态和等待态的任务回到睡眠态,也就是说任务被删除。删除一个任务,其实际上就是将该任务从任务控制块链表中删除,并将它归还给空任务控制块链表。 函数名称OSTaskDe

27、l 所属文件OS_TASK.C 函数原型INT8U OSTaskDel (INT8U prio) 功能描述删除一个指定优先级的任务。被删除的任务将回到休眠状态,任务被删除后可以用函数OSTaskCreate()重新建立 函数参数prio :指定要删除任务的优先级,如果为OS_PRIO_SELF则删除自身 函数返回值OS_NO_ERR:函数调用成功OS_TASK_DEL_IDLE:错误,试图删除空闲任务(Idle task)OS_TASK_DEL_ ERR:错误,指定要删除的任务不存在OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIOOS_TASK_DEL_ISR:

28、错误,试图在中断处理程序中删除任务 任务的结束任务的结束| C/OS-II微小内核分析微小内核分析删除任务删除任务函数OSTaskDel()流程图如下所示。 OSTaskDel()先检查删除任务的各种条件是否成立,如果不成立,则返回相应的错误码。一旦所有条件都满足了,OS_TCB就会从所有可能的C/OS-的数据结构中移除。首先本任务从就绪表中删除,然后本任务从索引表数组OSTCBPrioTbl中删除,接着本任务从已使用的任务控制块链表中删除,最后将任务控制块加到空闲TCB链表中。这些都做完后,启动调度器运行下一个优先级最高的就绪任务,任务删除就结束了。 任务的结束任务的结束| C/OS-II微

29、小内核分析微小内核分析删除任务删除任务INT8U OSTaskDel (INT8U prio) OS_TCB *ptcb; if (OSIntNesting 0) return (OS_TASK_DEL_ISR); #if OS_ARG_CHK_EN 0 if (prio = OS_IDLE_PRIO) return (OS_TASK_DEL_IDLE); if (prio = OS_LOWEST_PRIO & prio != OS_PRIO_SELF) return (OS_PRIO_INVALID); #endif OS_ENTER_CRITICAL(); if (prio = O

30、S_PRIO_SELF) prio = OSTCBCur-OSTCBPrio; ptcb = OSTCBPrioTblprio; if (ptcb != (OS_TCB *)0) if (OSRdyTblptcb-OSTCBY &= ptcb-OSTCBBitX) = 0 x00) OSRdyGrp &= ptcb-OSTCBBitY; ptcb-OSTCBDly = 0; ptcb-OSTCBStat = OS_STAT_RDY; OSTaskDel的代码如下。不能在中断中删除任务 不能删除空闲任务 任务优先级非法 将任务从就绪表中删除 获得当前任务优先级 获得要删除任务的T

31、CB 任务的结束任务的结束| C/OS-II微小内核分析微小内核分析删除任务删除任务 OSTCBPrioTblprio = (OS_TCB *)0; if (ptcb-OSTCBPrev = (OS_TCB *)0) ptcb-OSTCBNext-OSTCBPrev = (OS_TCB *)0; OSTCBList = ptcb-OSTCBNext; else ptcb-OSTCBPrev-OSTCBNext = ptcb-OSTCBNext; ptcb-OSTCBNext-OSTCBPrev = ptcb-OSTCBPrev; ptcb-OSTCBNext = OSTCBFreeList;

32、OSTCBFreeList = ptcb; OS_EXIT_CRITICAL(); OS_Sched(); return (OS_NO_ERR); OS_EXIT_CRITICAL(); return (OS_TASK_DEL_ERR);在索引表中删除本任务从已使用的任务控制块链表中删除对应的任务控制块 加到空闲任务控制块中 任务调度 C/OS-II微小内核分析微小内核分析信号量信号量12345事件与信号量事件与信号量 事件控制块事件控制块 改进的任务控制块及任务删除函数改进的任务控制块及任务删除函数 改进的改进的OS初始化初始化 信号量管理信号量管理 6删除信号量删除信号量 信号量信号量|

33、C/OS-II微小内核分析微小内核分析事件与信号量事件与信号量 在嵌入式实时多任务系统中,为了使系统达到高效处理和快速响应的目的,于是大量采用“事件驱动”的方式来编写任务。而事件可能是外部的,比如外部设备中断;也可能是嵌入式系统内部产生的,比如一个任务给另一个任务发送信号量或消息。由此可见,用于任务同步和通信的信号量、消息邮箱、消息队列和互斥信号量都叫做“事件”。 事件信号量(Sem)消息邮箱(Mbox)消息队列(Q)互斥信号量(Mutex)信号量信号量| C/OS-II微小内核分析微小内核分析事件与信号量事件与信号量 我们知道酒店的桌子数是固定的,因此可以这样理解其最大桌子数就是计数器的初值

34、,假设一人占用一张桌子,因此每进去一人,计数器就会自动减1,而只有出去一人时计数器才会自动加1。即就是说,如果计数器大于0,就可以进去吃饭,否则只好等待有人出来才能进去,这种计数信号就是信号量。酒店酒店人计数器计数器(能容纳的人数)(能容纳的人数)3 2 1 0人人人禁止其它客人进入人没有空位,不能再容纳客人有空位,能再容纳1位客人信号量信号量| C/OS-II微小内核分析微小内核分析事件与信号量事件与信号量 信号量就像通行证,且通行证的数目是有限的,任务要运行下去就必须先拿到通行证。如果信号量已被别的任务占用,那么该任务只能被挂起,直到信号量被当前使用者释放为止。 信号量的值可以是0到255

35、、0到65535或0到4294967295,取决于信号量规约机制使用的是8位、16位还是32位。到底是几位,实际上取决于用的是哪种内核。对于C/OS-II来说,信号量使用16位,其取值范围为065535。一般地说,对信号量只能实施3种操作:建立信号量(初始化)、等待信号量(挂起)、发送信号量。注意:信号量初始化时一定要给信号量赋初值,并将等待信号量任务列表清空。操作信号量建立信号量等待信号量发送信号量OSSemPend()OSSemCreate()OSSemPost()信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块 C/OS-II将信号量、互斥信号量、消息邮箱、消息

36、队列等统称为“事件事件”,然后通过一个称为“事件控制块(ECB)”的数据结构来管理事件,也就是说,任务和中断服务程序可以通过ECB向另外的任务程序发送信号,任务也可以等待另一个任务或者中断服务程序给它发送信号。事件控制块的结构如下图所示。信号量的计数器或互斥信号量和优先级继承的计数器事件类型指向邮箱或消息队列的指针等待任务列表信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块事件控制块的定义如下所示。 typedef struct INT8U OSEventType; INT16U OSEventCnt; void *OSEventPtr; INT8U OSEventG

37、rp; INT8U OSEventTblOS_EVENT_TBL_SIZE; OS_EVENT;OSEventType定义了事件的具体类型。在C/OS-II 微小内核中只能为OS_EVENT_SEM(信号量)和OS_EVENT_TYPE_UNUSED(未分配)。当然,在完整版的C/OS-II还可以是OS_EVENT_TYPE_MBOX(消息邮箱)、OS_EVENT_TYPE_Q(消息队列)和OS_EVENT_TYPE_MUTEX(互斥信号量)。当事件控制块用于信号量时,OSEventCnt用作信号量的计数器;当事件控制块用于互斥信号量时,互斥信号量和优先级继承优先级的计数器。OSEventPt

38、r指针只有在所定义的事件是邮箱或者消息队列时才使用。当所定义的事件是邮箱时,它指向一个消息;而当所定义的事件是消息队列时,它指向消息队列控制块。当然,空闲事件控制块链表也用它做链表指针。它们共同构成事件控制块的等待任务列表。 信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块 对于等待事件任务的记录, COS-II采用了与任务就绪表类似的方法,使用一个INT8U类型的数组OSEventTbl作为记录等待事件任务的记录表,这个表叫等待任务表,如下图所示。索引表,非必须的,为加快处理速度而引入根据任务的优先级可以确定该任务在等待任务列表中的确切位置真正的等待任务列表 OSE

39、ventTbl虽然被定义为“字节数组”,但仍被看作是“位数组”,即每一位代表一个任务,其中任何一位为1表示对应的任务为事件的等待任务,否则不是等待任务。等待任务表OSEventTbl数组的大小取决于OS_LOWEST_PRIO的值确定事件的等待任务在OSEventTblOS_LOWEST_PRIO/8+1中的位置,即横坐标X确定变量OSEventGrp具体数据位,用于确定等待任务表数组元素的下标,即纵坐标Y信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块 下面将给出一个任务放到事件的等待任务列表中的代码和从等待任务列表中删除一个任务的代码,需要说明的是,OS_EVEN

40、T_TBL_SIZE被定义为(OS_LOWEST_PRIO) / 8 + 1)。1、将任务加入等待任务列表2、从等待任务列表中删除任务pevent-OSEventGrp |= OSMapTblprio 3;pevent-OSEventTblprio 3 |= OSMapTblprio & 0 x07;if (pevent-OSEventTblprio 3 &= OSMapTblprio & 0 x07) = 0) pevent-OSEventGrp &= OSMapTblprio 3;信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块IN

41、T8U const OSUnMapTbl = /0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x00 to 0 x0F*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x10 to 0 x1F*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x20 to 0 x2F*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1

42、, 0, 2, 0, 1, 0,/*0 x30 to 0 x3F*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x40 to 0 x4F*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x50 to 0 x5F*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x60 to 0 x6F*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x70 to 0 x7F*/ 7

43、, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x80 to 0 x8F*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x90 to 0 x9F*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xA0 to 0 xAF*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xB0 to 0 xBF*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2

44、, 0, 1, 0,/*0 xC0 to 0 xCF*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xD0 to 0 xDF*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xE0 to 0 xEF*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0/*0 xF0 to 0 xFF*/;若OSRdyGrp为0 x68,以此值为偏移量查表得y值为3若OSRdyTb1y为0 x30,以此值为偏移量表得x值为2就绪任务组优先级最高的就是2

45、6(3OSEventGrp;x = OSUnMapTblpevent-OSEventTbly;prio = (y 0) & (OS_MAX_EVENTS 0)#if (OS_MAX_EVENTS 1) INT16U i; OS_EVENT *pevent1; OS_EVENT *pevent2; pevent1 = &OSEventTbl0; pevent2 = &OSEventTbl1; for (i = 0; i OSEventType = OS_EVENT_TYPE_UNUSED; pevent1-OSEventPtr = pevent2; pevent1+; p

46、event2+; pevent1-OSEventType = OS_EVENT_TYPE_UNUSED; pevent1-OSEventPtr = (OS_EVENT *)0; OSEventFreeList = &OSEventTbl0;#else OSEventFreeList = &OSEventTbl0; OSEventFreeList-OSEventType = OS_EVENT_TYPE_UNUSED; OSEventFreeList-OSEventPtr = (OS_EVENT *)0;#endif#endif 空闲事件控制块链表初始化代码如下。当有多个事件时,执

47、行下面代码把所有空闲事件控制块的类型设置为“未分配”链表尾指针指向“NULL”链表头指针指向第一个空闲任务块只有一个任务控制块时的处理程序信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块使等待超时的任务进入就绪态使任务进入等待状态初始化事件控制块使等待事件的任务进入就绪态对于事件控制块有一些通用的操作,如下图所示。 为了避免代码重复和减短程序代码长度,C/OS-II将上面的操作用4个系统函数来实现,它们分别是:OS_EventWaitListInit(),OS_EventTaskRdy(),OS_EventTaskWait()和OS_EventTO(),下面将分别逐一

48、介绍。信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块1、初始化事件控制块 当建立一个信号量、互斥信号量、消息邮箱或消息队列时,需要对事件控制块中的等待任务列表进行初始化,这是通过调用函数OS_EventWaitListInit()来实现的。函数名称OS_EventWaitListInit所属文件OS_CORE.C函数原型void OS_EventWaitListInit (OS_EVENT *pevent) 功能描述初始化一个空的等待任务列表,使其中没有任何任务函数参数pevent :指向需要初始化的事件控制块 函数返回值无特殊说明在创建事件时被调用 由上面的分析可

49、知,让等待任务列表没有任何任务就是将事件控制块(ECB)的OSEventGrp成员和OSEventTbl的所有成员赋值为0。 信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块void OS_EventWaitListInit (OS_EVENT *pevent) INT8U *ptbl; pevent-OSEventGrp = 0 x00; ptbl = &pevent-OSEventTbl0;#if OS_EVENT_TBL_SIZE 0 *ptbl+ = 0 x00;#endif OS_EventWaitListInit的源代码如下。将OSEventGrp

50、赋值为0将OSEventTbl的所有成员赋值为0信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块函数名称OS_EventTaskWait所属文件OS_CORE.C函数原型void OS_EventTaskWait (OS_EVENT *pevent) 功能描述将任务从就绪任务表中删除,并放到相应事件的事件控制块的等待任务表中函数参数pevent :指向需要进入等待状态的任务的事件控制块 函数返回值无特殊说明在请求一个事件时被调用2、使任务进入等待状态 当某个任务要等待一个事件的发生时,需要将任务从就绪任务表中删除,并放到相应事件的事件控制块的等待任务表中,这些操作是通

51、过调用函数OS_EventTaskWait()来实现的。信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块void OS_EventTaskWait (OS_EVENT *pevent) OSTCBCur-OSTCBEventPtr = pevent; if (OSRdyTblOSTCBCur-OSTCBY &= OSTCBCur-OSTCBBitX) = 0 x00) OSRdyGrp &= OSTCBCur-OSTCBBitY; pevent-OSEventTblOSTCBCur-OSTCBY |= OSTCBCur-OSTCBBitX; peven

52、t-OSEventGrp |= OSTCBCur-OSTCBBitY;OS_EventTaskWait的源代码如下。指明任务等待的事件从就绪表中删除当前任务将当前任务加入到等待任务列表中信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块3、使等待事件的任务进入就绪态 当发生了某个事件时,需要将等待这个事件的任务中优先级最高的一个置于就绪态,这是通过调用函数OS_EventTaskRdy()来实现的。在C/OS-II中,TCB的成员OSTCBStat不同的位表示等待不同的事件,则不同事件处理程序调用函数OS_EventTaskRdy()时,需要清除OSTCBStat不同位

53、,则需要一个指示,就是参数msk。当然,C/OS-II微小内核只有一个事件,理论上不需要这个参数,保留它是为了使微小内核的代码最大限度与原版保持一致。 函数名称OS_EventTaskRdy所属文件OS_CORE.C函数原型INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk) 功能描述从等待任务队列中删除优先级最高的任务(简称HPT),并将该任务置于就绪态函数参数pevent :是指向事件控制块的指针 msg : 在当前版本没有使用,是预留以后升级使用的msk : 比较特别,它是用于指明清除TCB状态的哪些位函数返回值pr

54、io : HPT任务的优先级特殊说明在中断禁止的情况下调用信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块INT8U OS_EventTaskRdy(OS_EVENT *pevent, void *msg, INT8U msk) y = OSUnMapTblpevent-OSEventGrp; bity = OSMapTbly; x = OSUnMapTblpevent-OSEventTbly; bitx = OSMapTblx; prio = (INT8U)(y OSEventTbly &= bitx) = 0 x00) pevent-OSEventGrp

55、&= bity; ptcb = OSTCBPrioTblprio; ptcb-OSTCBDly = 0; ptcb-OSTCBEventPtr = (OS_EVENT *)0; ptcb-OSTCBStat &= msk; if (ptcb-OSTCBStat = OS_STAT_RDY) OSRdyGrp |= bity; OSRdyTbly |= bitx; return (prio);OS_EventTaskRdy的源代代码如下。准备公共中间变量获得任务优先级从等待任务列表中删除任务获得任务TCB将任务加入就绪表中任务不再等待事件任务不再需要等待超时指针指向NULL信号量

56、信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块函数名称OS_EventTO所属文件OS_CORE.C函数原型void OS_EventTO (OS_EVENT *pevent) 功能描述当任务等待事件超过指定超时时间,该函数从等待任务列表中删除任务,并且恢复任务控制块中的一些变量函数参数pevent :是指向事件控制块的指针 函数返回值无特殊说明无4、使等待超时的任务进入就绪态 在C/OS-II中,任务等待某个事件时可以指定超时时间,如果超时时间到了,指定的事件仍然没有到来,任务也会被时钟节拍处理函数OSTimeTick()设置为就绪态。此时,等待任务列表中仍然保存这个任

57、务,任务控制块中也仍然有一些变量没有恢复,这些未完的事情由函数OS_EventTO()处理。信号量信号量| C/OS-II微小内核分析微小内核分析事件控制块事件控制块void OS_EventTO (OS_EVENT *pevent) if (pevent-OSEventTblOSTCBCur-OSTCBY &= OSTCBCur-OSTCBBitX) = 0 x00) pevent-OSEventGrp &= OSTCBCur-OSTCBBitY; OSTCBCur-OSTCBStat = OS_STAT_RDY; OSTCBCur-OSTCBEventPtr = (OS_E

58、VENT *)0;OS_EventTO的源代码如下。任务状态设置为就绪态事件控制块指针指向NULL从等待任务列表中删除任务信号量信号量| C/OS-II微小内核分析微小内核分析改进的任务控制块及任务删除函数改进的任务控制块及任务删除函数 有了事件支持之后,删除任务时就要特别小心了。当一个任务在等待事件时可能被别的任务删除,此时尽管任务已经删除,但任务还保存在事件的等待任务列表中。当对应的事件到来之时,会将这个已经不存在(或者说睡眠态)的任务设置为就绪态,这显然是不可能的。如果在事件来临之前又建立了另一个优先级相同任务,则程序执行的结果显然是错误的。 因此,删除任务时必须将任务从它等待事件的等待

59、任务列表中删除。信号量信号量| C/OS-II微小内核分析微小内核分析改进的任务控制块及任务删除函数改进的任务控制块及任务删除函数 由于在C/OS-II中,一个任务同一时间只能等待一个事件,所以在任务控制块中增加一个指向其所等待的事件的指针,实现这个功能就很简单了。改进后的任务控制块如下所示。Typedef struct os_tcb OS_EVENT *OSTCBEventPtr;OS_TCB;增加的成员,指向任务等待的事件信号量信号量| C/OS-II微小内核分析微小内核分析改进的任务控制块及任务删除函数改进的任务控制块及任务删除函数 当使用OSTCBEventPtr这个成员后,任务的删除

60、函数也相应地得到了改进。改进的任务删除函数代码如下所示。 INT8U OSTaskDel (INT8U prio)#if OS_EVENT_EN 0 OS_EVENT *pevent;#endif #if OS_EVENT_EN 0 pevent = ptcb-OSTCBEventPtr; if (pevent != (OS_EVENT *)0) if (pevent-OSEventTblptcb-OSTCBY &= ptcb-OSTCBBitX) = 0) pevent-OSEventGrp &= ptcb-OSTCBBitY; #endif增加的代码,从事件的等待任务列表中删除任务信号量信号量| C/OS-II微小内核分析微小内核分析改进的改进的OS初始化初始化 在使用事件控制块之前,需要将所有事件控制块链接成一个空闲事件控制块链

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论