第八讲2内核结构.ppt

上传人:本田雅阁 文档编号:2115184 上传时间:2019-02-17 格式:PPT 页数:45 大小:345.02KB
返回 下载 相关 举报
第八讲2内核结构.ppt_第1页
第1页 / 共45页
第八讲2内核结构.ppt_第2页
第2页 / 共45页
第八讲2内核结构.ppt_第3页
第3页 / 共45页
亲,该文档总共45页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第八讲2内核结构.ppt》由会员分享,可在线阅读,更多相关《第八讲2内核结构.ppt(45页珍藏版)》请在三一文库上搜索。

1、第八讲(2) 内核结构,授课教师:李英祥 电邮地址:,2019/2/17,,2,主要内容,1. 几个概念 2. 内核结构,2019/2/17,,3,1.几个概念,代码的临界段 共享资源 任务 关中断,2019/2/17,,4,代码的临界段,代码的临界段也称为临界区,指处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断。 为确保临界段代码的执行,在进入临界段之前要关中断,而临界段代码执行完以后要立即开中断。,2019/2/17,,5,共享资源,资源 :任何为任务所占用的实体都可称为资源。资源可以是打印机、键盘、显示器,资源也可以是一个变量,一个结构或一个数组等 共享资源:可以被一个以

2、上任务使用的资源叫做共享资源。为了防止数据被破坏,每个任务在与共享资源打交道时,必须独占该资源。这叫做互斥(mutual exclusion),2019/2/17,,6,任务,任务是一个具有独立功能的无限循环的程序段或者只执行一次的程序段的一次运行活动,是实时内核调度的单位; 任务主要包含以下内容: 代码:一段可执行的程序 数据:程序所需要的相关数据(变量、工作空间、缓冲区等) 堆栈 程序执行的上下文环境,2019/2/17,,7,High Priority Task,Low Priority Task,Task,Task,Task,Task,Task,Task,Event,Event,Eac

3、h Task,Infinite Loop,Importance,Splitting an application into Tasks,2019/2/17,,8,关中断,C/OS-为了处理临界段代码需要关中断,处理完毕后再开中断。这使得C/OS-能够避免同时有其它任务或中断服务进入临界段代码 ; C/OS-提供两个宏调用,允许用户在应用程序的C代码中关中断然后再开中断: OS_ENTER_CRITICAL() OS_EXIT_CRITICAL(),2019/2/17,,9,两个宏调用的使用法,2019/2/17,,10,2. 内核结构,基本知识: 任务参数 任务状态 任务切换 数据结构: 任务

4、控制块 空任务链表 就绪任务链表,2019/2/17,,11,系统调用: 任务调度函数OSSched() 调度器上锁和开锁函数OSSchedlock() /OSSchedUnlock() 空闲任务 OSTaskIdle() 统计任务 OSTaskStat() 中断处理 OSIntEnter() /OSIntExit() 时钟节拍 OSTickISR 获取当前C/OS-的版本号OSVersion() C/OS-初始化OSInit() C/OS-的启动 OSStart(),2019/2/17,,12,void YourTask (void *pdata) for (;) /* USER CODE

5、*/ Call one of uC/OS-IIs services: OSFlagPend(); OSMboxPend(); OSMutexPend(); OSQPend(); OSSemPend(); OSTaskDel(OS_PRIO_SELF); OSTaskSuspend(OS_PRIO_SELF); OSTimeDly(); OSTimeDlyHMSM(); /* USER CODE */ void YourTask (void *pdata) /* USER CODE */ OSTaskDel(OS_PRIO_SELF); ,任务所包含的程序通常为一个具有无限循环的程序 ; 或者一

6、次执行,例: UCOSII中的任务内容,2019/2/17,,13,任务参数,一个任务看起来像其它C的函数一样,有函数返回类型,有形式参数变量; 但是任务是绝不会返回的,故返回参数必须定义成void 形式参数变量是由用户代码在第一次执行的时候带入的。形式参数变量类型是一个指向void的指针。 这是为了允许用户应用程序传递任何类型的数据给任务,2019/2/17,,14,任务状态,C/OS-控制下的任务状态转换图。在任一给定的时刻,任务的状态一定是在这五种状态之一。,2019/2/17,,15,正在运行的任务可以通过调用两个函数之一将自身延迟一段时间,函数为OSTimeDly()或OSTimeD

7、lyHMSM(),这个任务于是进入等待状态 正在运行的任务期待某一事件的发生时也要等待,手段是调用以下3个函数之一:OSSemPend(),OSMboxPend(),或OSQPend(),调用后任务进入了等待状态(WAITING) 下一个优先级最高的、并进入了就绪态的任务立刻被赋予了CPU的控制权 当所有的任务都在等待事件发生或等待延迟时间结束,C/OS-执行空闲任务(idle task),执行OSTaskIdle()函数,2019/2/17,,16,任务切换,任务切换(context switching) 保存当前任务的上下文,并恢复需要执行的任务的上下文的过程。 当发生任务切换时: 当前正

8、在运行的任务的上下文就需要通过该任务的任务控制块保存起来; 把需要投入运行的任务的上下文从对应的任务控制块中恢复出来。,2019/2/17,,17,在时刻8即发生了任务切换,任务1的上下文需要保存到任务1的任务控制块中去。 经过调度程序的处理,在时刻10任务2投入运行,需要把任务2的任务控制块中关于上下文的内容恢复到CPU的寄存器。,2019/2/17,,18,任务1执行一段时间后,由于某种原因,需要进行任务切换,进入实时内核的调度程序。调度程序首先把当前的上下文内容保存到任务1的任务控制块TCB1中,然后又把任务2的上下文从TCB2中恢复到CPU寄存器,随后任务2得到执行。任务2执行一段时间

9、后,由于某种原因,需要进行任务切换,进入实时内核的调度程序。调度程序首先把当前的上下文内容保存到任务2的任务控制块TCB2中,然后又把任务1的上下文从TCB1中恢复到CPU寄存器,随后任务1得到执行。,2019/2/17,,19,任务控制块,任务管理是通过对任务控制块(task control block,TCB)的操作来实现的; 任务控制块是一个数据结构,当任务的CPU使用权被剥夺时,C/OS-用它来保存该任务的状态; 当任务重新得到CPU使用权时,任务控制块能确保任务从当时被中断的那一点丝毫不差地继续执行;,2019/2/17,,20,任务控制块是包含任务相关信息的数据结构 包含了任务执行

10、过程中所需要的所有信息。 任务控制块大都包括以下信息: 任务的名字 任务执行的起始地址 任务的优先级 任务的状态 任务的硬件上下文(堆栈指针、PC和寄存器等)、任务的队列指针等内容,2019/2/17,,21,TCB of ucOS,2019/2/17,,22,OSTCBStkPtr是指向当前任务栈顶的指针 ; OSTCBNext和OSTCBPrev用于任务控制块OS_TCBs的双重链接,双重连接的链表使得任一成员都能被快速插入或删除; OSTCBEventPtr是指向事件控制块的指针 ; OSTCBMsg是指向传给任务的消息的指针 ; OSTCBDly当需要把任务延时若干时钟节拍时要用到这个

11、变量,或者需要把任务挂起一段时间以等待某事件的发生 ; OSTCBStat是任务的状态字。当OSTCBStat为0,任务进入就绪态 ; OSTCBPrio是任务优先级 ; OSTCBDelReq是一个布尔量,用于表示该任务是否需要删除 ;,2019/2/17,,23,在C/OS-初始化的时候,所有任务控制块OS_TCBs被链接成单向空任务链表; 一旦建立任务,空任务控制块指针OSTCBFreeList指向的任务控制块便赋给了该任务,然后OSTCBFreeList的值调整为指向下链表中下一个空的任务控制块; 一旦任务被删除,任务控制块就还给空任务链表;,Free TCBs after OS_TC

12、BInit() in ucOS,空任务链表,2019/2/17,,24,就绪表,每个任务被赋予不同的优先级等级,从0级到最低优先级OS_LOWEST_PR1O,包括0和OS_LOWEST_PR1O在内; 每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量OSRedyGrp和OSRdyTbl ; 在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务中每一组中是否有进入就绪态的任务。任务进入就绪态时,就绪表OSRdyTbl中的相应元素的相应位也置位。 就绪表OSRdyTbl数组的大小取决于OS_LOWEST_PR1O 任务优先级的低三位用于确定任务在

13、就绪表OSRdyTbl中的所在位。接下去的三位用于确定是在OSRdyTbl数组的第几个元素。,2019/2/17,,25,2019/2/17,,26,任务调度函数OSSched(),确定哪个任务优先级最高,下面该哪个任务运行了的工作是由调度器(Scheduler)完成的; 任务级的调度是由函数OSSched()完成的,中断级的调度是由另一个函数OSIntExt()完成的 ;,2019/2/17,,27,void OS_Sched (void) INT8U y; OS_ENTER_CRITICAL(); if (OSIntNesting = 0) ,Task scheduling of ucOS

14、,2019/2/17,,28,void OSCtxSw (void) PUSH R1, R2, R3 and R4 onto the current stack; OSTCBCur-OSTCBStkPtr = SP; OSTCBCur = OSTCBHighRdy; SP = OSTCBHighRdy-OSTCBStkPtr; POP R4, R3, R2 and R1 from the new stack; Execute a return from interrupt instruction; ,OS_TASK_SW(),2019/2/17,,29,Context-switch in uc

15、OS,Data structures before context-switch,2019/2/17,,30,Context-switch in ucOS,Data structures after saving the context-switch of current task,2019/2/17,,31,Context-switch in ucOS,Data structures after restoring the context-switch of high priority task,2019/2/17,,32,调度器上锁和开锁函数OSSchedlock() /OSSchedUn

16、lock(),调用OSSchedLock()函数的任务独占CPU,不管有没有其他高优先级的就绪任务。在这种情况下,中断仍然可以被接受和执行(中断必须允许) 在调用了OSSchedLock ()函数后,OSSchedUnlock ()函数恢复任务调度 OSSchedLock ()函数和OSSchedUnlock ()函数必须配对使用 警告 任务调用了OSSchedLock()函数后,决不能再调用可能导致当前任务挂起的系统函数:OSTimeDly(),OSTimeDlyHMSM(),OSSemPend(),OSMboxPend(),OSQPend()。因为任务调度已经被禁止,其他任务不能运行,这会

17、导致系统死锁。,2019/2/17,,33,示例:,2019/2/17,,34,空闲任务 OSTaskIdle(),C/OS-总是建立一个空闲任务,这个任务在没有其它任务进入就绪态时投入运行; 空闲任务OSTaskIdle()什么也不做,只是在不停地给一个32位的名叫OSIdleCtr的计数器加1,统计任务(使用这个计数器以确定现行应用软件实际消耗的CPU时间;,2019/2/17,,35,统计任务 OSTaskStat(),提供运行时间统计的任务OSTaskStat(),如果用户将系统定义常数OS_TASK_STAT_EN设为1,这个任务就会建立; OSTaskStat()告诉用户应用程序使

18、用了多少CPU时间,用百分比表示,这个值放在一个有符号8位整数OSCPUsage中,精读度是1个百分点; 如果用户应用程序打算使用统计任务,用户必须在初始化时建立一个唯一的任务,在这个任务中调用OSStatInit();,2019/2/17,,36,中断处理 OSIntEnter() /OSIntExit(),OSIntEnter()通知C/OS-一个中断处理函数正在执行,这有助于C/OS-掌握中断嵌套的情况; void OSIntEnter (void) OS_ENTER_CRITICAL(); OSIntNesting+; OS_EXIT_CRITICAL(); OSIntExit ()通

19、知C/OS-一个中断服务已执行完毕,这有助于C/OS-掌握中断嵌套的情况; 通常OSIntExit ()和OSIntEnter ()联合使用; 当最后一层嵌套的中断执行完毕后,如果有更高优先级的任务准备就绪,C/OS-会调用任务调度函数,在这种情况下,中断返回到更高优先级的任务而不是被中断了的任务;,2019/2/17,,37,时钟节拍服务例程 OSTickISR,C/OS需要用户提供周期性信号源,用于实现时间延时和确认超时; 节拍率应在每秒10次到100次之间,或者说10到100Hz; 时钟节拍率越高,系统的额外负荷就越重; 用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用OSSt

20、art()之后,2019/2/17,,38,2019/2/17,,39,例: OSTickISR的示意代码,时钟节拍中断服务子程序必须用汇编语言编写,因为在C语言里不能直接处理CPU的寄存器;,2019/2/17,,40,获取当前C/OS-的版本号OSVersion(),应用程序调用OSVersion可以得到当前C/OS-的版本号。 OSVersion()函数返回版本号值乘以100。换言之,200表示版本号2.00。,2019/2/17,,41,C/OS-初始化 OSInit(),OSIint()初始化C/OS-所有的变量和数据结构; OSInit()建立空闲任务idle task,这个任务总

21、是处于就绪态的; OSInit()还建立统计任务OSTaskStat()并且让其进入就绪态 ; 以上两个任务的任务控制块(OS_TCBs)是用双向链表链接在一起的。OSTCBList指向这个链表的起始处 OSInit()还初始化了4个空数据结构缓冲区,如后图8所示。每个缓冲区都是单向链表,允许C/OS-从缓冲区中迅速得到或释放一个缓冲区中的元素。,2019/2/17,,42,2019/2/17,,43,2019/2/17,,44,初始化 OSInit()使用示例:,2019/2/17,,45,C/OS-的启动 OSStart(),OSStart( )启动C/OS-II的多任务。然而,启动C/OS-之前,用户至少要建立一个应用任务 ; 注意/警告 调用OSStart( )之前必须先调用OSInit ( )。在用户程序中OSStart( )只能被调用一次。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1