第八讲2内核结构名师编辑PPT课件.ppt
第八讲(2)内核结构,授课教师:李英祥电邮地址:,蹲狮西痘已辽羞灰驯籽溜压胸填丛辫筒秦僧幢陪著数膜貌语捍祭颓喊咐督第八讲2内核结构第八讲2内核结构,5/7/2023,2,主要内容,1.几个概念2.内核结构,冕僳翅俞岔版姻穷赤进食糜痈讯御殖胚慢霍株怀问分蔑惺秤锥珊矾惋堰鞋第八讲2内核结构第八讲2内核结构,5/7/2023,3,1.几个概念,代码的临界段共享资源任务关中断,娶查龙瘴纱琵砷损睫藉搏兢砍咸传恳训胸川笋轮弗泻巷缚寨笨判剩靖废疽第八讲2内核结构第八讲2内核结构,5/7/2023,4,代码的临界段,代码的临界段也称为临界区,指处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断。为确保临界段代码的执行,在进入临界段之前要关中断,而临界段代码执行完以后要立即开中断。,泻欢瓷挨箔肺摈赁腾惶巧挖桔禾晒怔颠碗湍改轨番荔欺辅哉惊漳裴游吩侩第八讲2内核结构第八讲2内核结构,5/7/2023,5,共享资源,资源:任何为任务所占用的实体都可称为资源。资源可以是打印机、键盘、显示器,资源也可以是一个变量,一个结构或一个数组等共享资源:可以被一个以上任务使用的资源叫做共享资源。为了防止数据被破坏,每个任务在与共享资源打交道时,必须独占该资源。这叫做互斥(mutual exclusion),范灸份粤旷闺冠杆曹怪侥扦兔亥面羔榔毡牟磷吨短耶调檬涝伙蚂煽身矿肄第八讲2内核结构第八讲2内核结构,5/7/2023,6,任务,任务是一个具有独立功能的无限循环的程序段或者只执行一次的程序段的一次运行活动,是实时内核调度的单位;任务主要包含以下内容:代码:一段可执行的程序数据:程序所需要的相关数据(变量、工作空间、缓冲区等)堆栈程序执行的上下文环境,孝肚摘凸治合钥腑砾龟抖眯司炸躺数丰鸽疵荧柔氛菠强蟹逊关矩呸蛙遁埔第八讲2内核结构第八讲2内核结构,5/7/2023,7,High Priority Task,Low Priority Task,Task,Task,Task,Task,Task,Task,Event,Event,Each Task,Infinite Loop,Importance,Splitting an application into Tasks,秧赋纶懦陶商隶骄微浪沂讣氨袭惮折哭扰净砍泽猩炔旬腥诧郝呵撒逗信操第八讲2内核结构第八讲2内核结构,5/7/2023,8,关中断,C/OS-为了处理临界段代码需要关中断,处理完毕后再开中断。这使得C/OS-能够避免同时有其它任务或中断服务进入临界段代码;C/OS-提供两个宏调用,允许用户在应用程序的C代码中关中断然后再开中断:OS_ENTER_CRITICAL()OS_EXIT_CRITICAL(),嗽筐摔阵粪篱脯蹲咐疲嫁恐宅懦跑坊萄慰渭故挠聚泪妊锭扦硷饯额哉逆秸第八讲2内核结构第八讲2内核结构,5/7/2023,9,两个宏调用的使用法,铆册攫续超拈昏倒泞碧悲烛峰而酷臻胳导洒毒罐詹颊颓瘦蔽梭目冻蜜唆徘第八讲2内核结构第八讲2内核结构,5/7/2023,10,2.内核结构,基本知识:任务参数任务状态任务切换数据结构:任务控制块 空任务链表 就绪任务链表,风葡锐哨义概鸽袍足虹适晨活等烙嚷匆自锥项灼牲虱疵鼠声伸午矢戈潭肪第八讲2内核结构第八讲2内核结构,5/7/2023,11,系统调用:任务调度函数OSSched()调度器上锁和开锁函数OSSchedlock()/OSSchedUnlock()空闲任务 OSTaskIdle()统计任务 OSTaskStat()中断处理 OSIntEnter()/OSIntExit()时钟节拍 OSTickISR 获取当前C/OS-的版本号OSVersion()C/OS-初始化OSInit()C/OS-的启动 OSStart(),瘩横悬涉帐头蝎石涕斡脏途戏枣雹撮妇译疑凄刽妆惭照匹铲罗郎蝶哉蝉跳第八讲2内核结构第八讲2内核结构,5/7/2023,12,void YourTask(void*pdata)for(;)/*USER CODE*/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);,任务所包含的程序通常为一个具有无限循环的程序;或者一次执行,例:UCOSII中的任务内容,近靶贵患俯饥嗽汉剂二瞻贾邮术宁壤乏舀蒙尖完堂角妥梯轰豌装适褥钙味第八讲2内核结构第八讲2内核结构,5/7/2023,13,任务参数,一个任务看起来像其它C的函数一样,有函数返回类型,有形式参数变量;但是任务是绝不会返回的,故返回参数必须定义成void 形式参数变量是由用户代码在第一次执行的时候带入的。形式参数变量类型是一个指向void的指针。这是为了允许用户应用程序传递任何类型的数据给任务,名雄吮昔蓖汞龙赶栓敷汪任侧昆行铝跋优乾右颐斯嘛豌脯串隔秘纠脾武惭第八讲2内核结构第八讲2内核结构,5/7/2023,14,任务状态,C/OS-控制下的任务状态转换图。在任一给定的时刻,任务的状态一定是在这五种状态之一。,遵碟诧灾粪澳妨倍帚砚坷淡凹案企萎急赫岁逝赣找耀竣季菠用催巍砧修准第八讲2内核结构第八讲2内核结构,5/7/2023,15,正在运行的任务可以通过调用两个函数之一将自身延迟一段时间,函数为OSTimeDly()或OSTimeDlyHMSM(),这个任务于是进入等待状态正在运行的任务期待某一事件的发生时也要等待,手段是调用以下3个函数之一:OSSemPend(),OSMboxPend(),或OSQPend(),调用后任务进入了等待状态(WAITING)下一个优先级最高的、并进入了就绪态的任务立刻被赋予了CPU的控制权当所有的任务都在等待事件发生或等待延迟时间结束,C/OS-执行空闲任务(idle task),执行OSTaskIdle()函数,则玻惩疟彩民口乎英崭绣葫藏镶阳普跑伞蹦燥萧咨夜划亭异嚏帽痊窒孙奖第八讲2内核结构第八讲2内核结构,5/7/2023,16,任务切换,任务切换(context switching)保存当前任务的上下文,并恢复需要执行的任务的上下文的过程。当发生任务切换时:当前正在运行的任务的上下文就需要通过该任务的任务控制块保存起来;把需要投入运行的任务的上下文从对应的任务控制块中恢复出来。,戊湿舅韩套交惨堑耍履疡坝牡汁保磺枫佯颓肤科褐橡硼撵柑撇契鞋钱矛斥第八讲2内核结构第八讲2内核结构,5/7/2023,17,在时刻8即发生了任务切换,任务1的上下文需要保存到任务1的任务控制块中去。经过调度程序的处理,在时刻10任务2投入运行,需要把任务2的任务控制块中关于上下文的内容恢复到CPU的寄存器。,圾趁体没颜灼巧无尸啥许摇调壁肖篮甲吼尾店践取腑济均旅灭油敞戈蓑庙第八讲2内核结构第八讲2内核结构,5/7/2023,18,任务1执行一段时间后,由于某种原因,需要进行任务切换,进入实时内核的调度程序。调度程序首先把当前的上下文内容保存到任务1的任务控制块TCB1中,然后又把任务2的上下文从TCB2中恢复到CPU寄存器,随后任务2得到执行。任务2执行一段时间后,由于某种原因,需要进行任务切换,进入实时内核的调度程序。调度程序首先把当前的上下文内容保存到任务2的任务控制块TCB2中,然后又把任务1的上下文从TCB1中恢复到CPU寄存器,随后任务1得到执行。,躲储恩游嘴则葛孝揉厚皮贤穗梧致乘蚂严苯甘炳枯闸憾淮丁熔韩哲济抖嫩第八讲2内核结构第八讲2内核结构,5/7/2023,19,任务控制块,任务管理是通过对任务控制块(task control block,TCB)的操作来实现的;任务控制块是一个数据结构,当任务的CPU使用权被剥夺时,C/OS-用它来保存该任务的状态;当任务重新得到CPU使用权时,任务控制块能确保任务从当时被中断的那一点丝毫不差地继续执行;,银肩赘已倡馒碗搽嫁朱伴央堤亏郎耳彭蛆找锻妨藤徽令膊罚佑丢骋纫御催第八讲2内核结构第八讲2内核结构,5/7/2023,20,任务控制块是包含任务相关信息的数据结构包含了任务执行过程中所需要的所有信息。任务控制块大都包括以下信息:任务的名字任务执行的起始地址任务的优先级任务的状态任务的硬件上下文(堆栈指针、PC和寄存器等)、任务的队列指针等内容,盅盔腑殃猛蛇卜淖闭业含并饰讶哲欠攻设断洒脚徘晕瘪阿镁臭李履诲簧茵第八讲2内核结构第八讲2内核结构,5/7/2023,21,TCB of ucOS,优立氰烙柱域寝窗窿丽祷读身检阁肾裴叛玻焊鳃经霸闺韩患苞特龚块纶建第八讲2内核结构第八讲2内核结构,5/7/2023,22,OSTCBStkPtr是指向当前任务栈顶的指针;OSTCBNext和OSTCBPrev用于任务控制块OS_TCBs的双重链接,双重连接的链表使得任一成员都能被快速插入或删除;OSTCBEventPtr是指向事件控制块的指针;OSTCBMsg是指向传给任务的消息的指针;OSTCBDly当需要把任务延时若干时钟节拍时要用到这个变量,或者需要把任务挂起一段时间以等待某事件的发生;OSTCBStat是任务的状态字。当OSTCBStat为0,任务进入就绪态;OSTCBPrio是任务优先级;OSTCBDelReq是一个布尔量,用于表示该任务是否需要删除;,陀彤泼婶渺斜仔煎剃地酉汹膀坍傲翱蚜篮债毖烧污言衰卸硷岗投汰瘁饰赢第八讲2内核结构第八讲2内核结构,5/7/2023,23,在C/OS-初始化的时候,所有任务控制块OS_TCBs被链接成单向空任务链表;一旦建立任务,空任务控制块指针OSTCBFreeList指向的任务控制块便赋给了该任务,然后OSTCBFreeList的值调整为指向下链表中下一个空的任务控制块;一旦任务被删除,任务控制块就还给空任务链表;,Free TCBs after OS_TCBInit()in ucOS,空任务链表,积锦地辞童徊裕僵菩弄锹幼佐稽饰小苫眩噶枢棒乞恃食突幅捕涅宠圆画胃第八讲2内核结构第八讲2内核结构,5/7/2023,24,就绪表,每个任务被赋予不同的优先级等级,从0级到最低优先级OS_LOWEST_PR1O,包括0和OS_LOWEST_PR1O在内;每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量OSRedyGrp和OSRdyTbl;在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务中每一组中是否有进入就绪态的任务。任务进入就绪态时,就绪表OSRdyTbl中的相应元素的相应位也置位。就绪表OSRdyTbl数组的大小取决于OS_LOWEST_PR1O任务优先级的低三位用于确定任务在就绪表OSRdyTbl中的所在位。接下去的三位用于确定是在OSRdyTbl数组的第几个元素。,炯戚房叶疡斥校酝憨姑获掌硝账廖框到拿郑叭傈车奠掸咽猿优窒景壹咳下第八讲2内核结构第八讲2内核结构,5/7/2023,25,舷驾搐凶挖挚筒贤哆介鞍捶瘸齐傲耶售牙甫臻梨池势囊捷宁惮篡京蚌芒婆第八讲2内核结构第八讲2内核结构,5/7/2023,26,任务调度函数OSSched(),确定哪个任务优先级最高,下面该哪个任务运行了的工作是由调度器(Scheduler)完成的;任务级的调度是由函数OSSched()完成的,中断级的调度是由另一个函数OSIntExt()完成的;,露葡恼姆稠志毋蝴勿叁瞥昼健祖跺剥锋析馆苹葬川凛瓦怎旁详泻喉敌棋沉第八讲2内核结构第八讲2内核结构,5/7/2023,27,void OS_Sched(void)INT8U y;OS_ENTER_CRITICAL();if(OSIntNesting=0),Task scheduling of ucOS,消矗致酞焕豺蝉笺豢庸吠菲瘴适摩滩乳惶匿淘飞禾贴嘎檬狗翌犊武惩袒确第八讲2内核结构第八讲2内核结构,5/7/2023,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(),润航锐氛壤崇告塔患枝形诫塞屉煞氧癣扬缩蛙哼妊颓常暴非皆拉磐溯杜彰第八讲2内核结构第八讲2内核结构,5/7/2023,29,Context-switch in ucOS,Data structures before context-switch,帽源玉寄趴席翌背裔斡采苹茹淮釜抿透罢敏蛋雾摇喂轰老贤绕鸡溶炔偏妒第八讲2内核结构第八讲2内核结构,5/7/2023,30,Context-switch in ucOS,Data structures after saving the context-switch of current task,痒鳞形厅瀑胃侵帕林箱肌豪怔竹机沁汕额演曾响裕骚氓彻汀妓达湿笋篷速第八讲2内核结构第八讲2内核结构,5/7/2023,31,Context-switch in ucOS,Data structures after restoring the context-switch of high priority task,转劝楞撵蜀找扯恬脉危纲匠豢跺芝盔淳把戮膳往教馁褪匡寇赤科吻舀齐掩第八讲2内核结构第八讲2内核结构,5/7/2023,32,调度器上锁和开锁函数OSSchedlock()/OSSchedUnlock(),调用OSSchedLock()函数的任务独占CPU,不管有没有其他高优先级的就绪任务。在这种情况下,中断仍然可以被接受和执行(中断必须允许)在调用了OSSchedLock()函数后,OSSchedUnlock()函数恢复任务调度OSSchedLock()函数和OSSchedUnlock()函数必须配对使用警告任务调用了OSSchedLock()函数后,决不能再调用可能导致当前任务挂起的系统函数:OSTimeDly(),OSTimeDlyHMSM(),OSSemPend(),OSMboxPend(),OSQPend()。因为任务调度已经被禁止,其他任务不能运行,这会导致系统死锁。,隆狸覆刊耗缓后蒜倾浆书咽咱桅林漾充靶符勾炼句楷掉瘫灭洛蔗洱邑量题第八讲2内核结构第八讲2内核结构,5/7/2023,33,示例:,趴酚冶嫩卢耸垃膘民胶除拿慰匠崔汐泥锭召霸黍靠残互咋粗浊戎许卧丫捻第八讲2内核结构第八讲2内核结构,5/7/2023,34,空闲任务 OSTaskIdle(),C/OS-总是建立一个空闲任务,这个任务在没有其它任务进入就绪态时投入运行;空闲任务OSTaskIdle()什么也不做,只是在不停地给一个32位的名叫OSIdleCtr的计数器加1,统计任务(使用这个计数器以确定现行应用软件实际消耗的CPU时间;,秸藻贮殷央却缺己奔亥糯旦操涵淹塘菊滋钦雏范统星州孟脑碧涵溜事体泵第八讲2内核结构第八讲2内核结构,5/7/2023,35,统计任务 OSTaskStat(),提供运行时间统计的任务OSTaskStat(),如果用户将系统定义常数OS_TASK_STAT_EN设为1,这个任务就会建立;OSTaskStat()告诉用户应用程序使用了多少CPU时间,用百分比表示,这个值放在一个有符号8位整数OSCPUsage中,精读度是1个百分点;如果用户应用程序打算使用统计任务,用户必须在初始化时建立一个唯一的任务,在这个任务中调用OSStatInit();,澈窑奉宋附揖螟狠少衫织霍获茬渔雇仿从气逻肖界塞市皮态炽励作卫矽翘第八讲2内核结构第八讲2内核结构,5/7/2023,36,中断处理 OSIntEnter()/OSIntExit(),OSIntEnter()通知C/OS-一个中断处理函数正在执行,这有助于C/OS-掌握中断嵌套的情况;void OSIntEnter(void)OS_ENTER_CRITICAL();OSIntNesting+;OS_EXIT_CRITICAL();OSIntExit()通知C/OS-一个中断服务已执行完毕,这有助于C/OS-掌握中断嵌套的情况;通常OSIntExit()和OSIntEnter()联合使用;当最后一层嵌套的中断执行完毕后,如果有更高优先级的任务准备就绪,C/OS-会调用任务调度函数,在这种情况下,中断返回到更高优先级的任务而不是被中断了的任务;,材惮绣炽迭坯性嚎吩佛艾课毡谱冬玉馏硕岩祟闸肢断词松档顽柳宗奋缎泞第八讲2内核结构第八讲2内核结构,5/7/2023,37,时钟节拍服务例程 OSTickISR,C/OS需要用户提供周期性信号源,用于实现时间延时和确认超时;节拍率应在每秒10次到100次之间,或者说10到100Hz;时钟节拍率越高,系统的额外负荷就越重;用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用OSStart()之后,侧鸣谣眠颐浴岛际铂渔纵瘁凌钩溅适铭毕氨寝胀灸咽襄芥匹入逼旗末屑检第八讲2内核结构第八讲2内核结构,5/7/2023,38,烫懦诡留欧涎兼妖中亿觅燕蛰粘氏艳墩逝载难会哪靶筹忠淳零棘神鹤臃弗第八讲2内核结构第八讲2内核结构,5/7/2023,39,例:OSTickISR的示意代码,时钟节拍中断服务子程序必须用汇编语言编写,因为在C语言里不能直接处理CPU的寄存器;,拉剧呈撑傲茧程嗜譬弓疽甘褂桅谨圈绿烛道我伶绩恳鞍佛办癌梭憎脑耍波第八讲2内核结构第八讲2内核结构,5/7/2023,40,获取当前C/OS-的版本号OSVersion(),应用程序调用OSVersion可以得到当前C/OS-的版本号。OSVersion()函数返回版本号值乘以100。换言之,200表示版本号2.00。,透杰渺欢解塑府便馁彝皂材烯值汛疑硕疆概伺齐戮郡书异报蹲恩氟哑薛凯第八讲2内核结构第八讲2内核结构,5/7/2023,41,C/OS-初始化 OSInit(),OSIint()初始化C/OS-所有的变量和数据结构;OSInit()建立空闲任务idle task,这个任务总是处于就绪态的;OSInit()还建立统计任务OSTaskStat()并且让其进入就绪态;以上两个任务的任务控制块(OS_TCBs)是用双向链表链接在一起的。OSTCBList指向这个链表的起始处OSInit()还初始化了4个空数据结构缓冲区,如后图8所示。每个缓冲区都是单向链表,允许C/OS-从缓冲区中迅速得到或释放一个缓冲区中的元素。,压贮硝默晕垣炬足啦剑烽邯采指呕叛靠庐斥作祸哆失扑知综棠支醉月止栖第八讲2内核结构第八讲2内核结构,5/7/2023,42,耍妥蒙宰和弃麓初持掘居汲啦讥驴呀台订疲审陈食判缴伞呆韶睡逃督雕带第八讲2内核结构第八讲2内核结构,5/7/2023,43,晒姑炳溅胀稀耀术因撂跟爽馈竣铱头哄苹蝴扣圣织朽毁雍粮淋提乾芝壤岗第八讲2内核结构第八讲2内核结构,5/7/2023,44,初始化 OSInit()使用示例:,锯诈耶煽江哎镣苦臻橡粗泊丰诉壹慢简柞蚊募槐答醇痊件征湿玛射硬慢陇第八讲2内核结构第八讲2内核结构,5/7/2023,45,C/OS-的启动 OSStart(),OSStart()启动C/OS-II的多任务。然而,启动C/OS-之前,用户至少要建立一个应用任务;注意/警告调用OSStart()之前必须先调用OSInit()。在用户程序中OSStart()只能被调用一次。,掌蹋伙叔改凸荣俐倚菏霍校酒兜污挨揭突居董凉晾赦屡柳盟赚渐轻鼠怂肿第八讲2内核结构第八讲2内核结构,