




全文预览已结束
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C/OS-II通信机制之内核分析摘要: 本文主要着重对C/OS-III通信机制的内核分析,研究C/OS-II内核通信机制的实现方式及实现的技巧,同时分析其中不足之处。1引言C/OS-II是一种可移植的,可植入ROM的,可裁剪的,抢占式的,实时多任务操作系统内核。它被广泛应用于微处理器、微控制器和数字信号处理器。uC/OS-II只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。没有提供输入输出管理,文件系统,网络等额外的服务。但由于uC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全可以由用户自己根据需要分别实现。C/OS-II这款操作系统内核简单易学,通过对其源代码的分析,可以加深我们对操作系统内核的理解,为学习linux等大型操作系统打下基础。2操作系统中任务间的通信机制内核中多个任务之间不可避免的存在相互协同的关系,来完成一定的内核功能。这种协同最直观的就是任务间相互通信。包括VxWorks 等所有的嵌入式操作系统一般都会提供许多任务间通信的方法,通常包括:(1)共享内存,数据的简单共享。(2)信号量,基本的互斥和同步。(3)消息队列和管道,同一CPU 内多任务间消息传递。(4) Socket 和远程调用,任务间透明的网络通信。(5)Signals,用于异常处理。在C/OS-II中设计了五种通讯机制,或者说是同步机制,分别是信号量(semaphore),互斥体(mutual exclusion semaphore),事件组(event flag),邮箱(message box)和队列(queue)。3. uC/OS-II中通信机制实现的方式分析在uC/OS-II中是如何通信机制呢?这几种通信机制有什么关系?或者说有什么共同点有什么不同点?在实现上有哪些步骤是相同的?下面将就这几个问题进行分析论述。我们知道通信机制是发生在任务之间的,换句话说任务与通信机制存在着关联。在内核又是如何处理这种关联呢?通信机制具体来说是信号量,互斥量,邮箱,队列等。通信机制协调的关系一般是针对两个以上的任务,比如说当两个任务互斥的访问共享资源,就需要一个互斥量,这个互斥量就关联着这两个任务。同样的道理,其他通信机制也是关联着两个以上的任务。那么设计内核时就要考虑如何将他们的关系有效协调地统一管理起来。在内核中是通过一个事件控制块来实现通信机制与任务的联系。这里所说的事件就是指任务间进行通信时传递信号的统称。这里其实是利用到了一种抽象的思想,即将各种通信机制的共同点抽象出来,于是内核就设计了一个事件控制块的数据结构,这个数据结构是所有通信机制都会用到的,这样的设计就节省了不少代码,因为有共同点意味着有重复代码。既然知道了事件控制块是实现通信机制代码共享的关键,那么下面我们就来分析下它的数据结构。typedef structINT8U OSEventType; /事件类型INT8U OSEventGrp; /等待任务所在的组INT16U OSEventCnt; /当事件是信号量时的计数器void *OSEventPtr; /指向消息或消息队列的指针INT8U OSEventTblOS_EVENT_TBL_SIZE; /等待任务列表 OS_EVENT; 第一个变量是事件类型,它可以是信号量,互斥型信号量,邮箱或是消息队列中的一种。OSEventPtr是一个泛型指针,只在所定义的事件是邮箱或者消息队列时才会用到,用来指向一个消息,指针类型设计成泛型的,这是一个设计技巧,因为还不知道具体的消息是什么样的数据结构类型。OSEventGrp和OSEventTblOS_EVENT_TBL_SIZE用来控制等待某事件的任务,换句话说是等待某事件的任务列表信息。通过查询这个列表信息可以知道有哪些任务在等待这个事件。OSEventCnt是计数器,当事件定义的是信号量或者是互斥型信号量时会用到。从这个事件控制块的数据结构我们可以看出,它是具有抽象性质的,即可以定义成不同的事件类型,可根据具体情况进行不同类型的定义,它具有一定的通用性,又具有一定的针对性(如OSEventPtr只对邮箱或者消息队列有用)。也就是说这样的设计抽象的程序不够,存在着一定的数据冗余,比如说当事件定义成信号量时,根本用不到OSEventPtr这个变量,它就相当是一个冗余变量,这是内核设计存在的一个缺陷。 下面分析下事件控制块是如何管理其等待的任务。首先等待一个事件的任务可能是多个,而且任务加入等待列队的时间不一样,那么又如何合理地安排它们的等待顺序呢?在内核中又是如何实现的呢?当一个事件发生后,该事件的等待事件列表中优先级最高的任务得到该任务。事件等待列表是利用OSEventGrp和OSEventTblOS_EVENT_TBL_SIZE这两个变量来控制的。在C/OS-II实时操作系统内核中最多能控制64个任务。也就是说任务列表必须能表示出64个任务的信息。在内核中,所有任务优先级被分成8组(每组8个优先级),分别对应于OSEventGrp的8位,这个变量被定义成8位的数据类型,每一位都用来指示是否有任务在等待事件发生的状态。当某组中有有任务处于等待事件的状态时,OSEventGrp对应的位就会被置1。相应地,该任务在OSEventTbl中对应位也被置1。那么实现一个任务置于等待事件的任务列表中或者从等待事件的任务列表中使任务脱离等待状态或者在等待事件列表中查找优先级最高的任务的算法又怎么样的呢?将一个任务插入到等待事件的任务列表中:pevent - OSEventGrp |= OSMapTblprio 3;pevent - OSEventTblprio3 = OSMapTblprio & 0x07;从等待事件的任务列表中使任务脱离等待状态:if (pevent - OSEventTblprio 3 &= OSMapTblprio & 0x07) = 0)pevent - OSEventGrp &= OSMapTblprio 3;在等待事件的任务列表中查找优先级最高的任务:y = OSUnMapTblpevent - OSEventGrp;x = OSUnMapTblpevent - OSEventTbly;prio = (y 3) + x;从上述代码中可以看到用到了两个数组,一个是OSMapTbl,一个是OSUnMapTbl,它们是已经定义的映射表,如OSMapTbl的内容是1,2,4,8,16,32,64,128,这个数组出现的目的是为了更方便的置位。说白点,使用OSMapTblindex的作用是更方便的把某个数值的第index位置1。从上述的代码中我们可以看出算法的原理是:任务的优先级的最低3位决定了该任务在相应的OSEventTbl中的位置,紧接着的高3位则决定了该任务优先级在OSEventTbl中的字节索引。处理事件与任务的关系时需要处理的三个共同问题:使一个任务进入就绪态,使一个任务进入等待某事件发生的状态,由于等待超时而将任务置为就绪态。分别对应于三个函数。这样的处理可以避免大量重复的代码,因为这些处理是所有通信机制所必须的,没有必要为每个通信机制就写一个独特的函数来处理。下面提出一个问题,既然事件控制块是所有通信机制的抽象,那么具体的通信机制又是如何与事件控制块进行关联呢?下面我以信号量的设计为例来进行说明。创建一个信号量时即要先创建一个事件控制块,在内核中是从事件空闲块中取出一个事件控制块,然后对这个事件控制块的数据变量进行赋值,使之成为表示一个信号量的数据结构。并将些事件控制块进行初始化,初始化的主要工作是将事件的任务等待列表清空为0。并把创建好的事件控制块指针返回。这个返回的事件控制块指针就是一个信号量,等待信号量与发送信号量都是用到这个指针的。那么某个任务发送一个创建好的信号量又是如何实现的?信号量在创建时会有个计数器,这个计数器标志着可用资源数,创建信号量时可以初始为0。当一个任务发送一个信号量时,需要考虑几个问题:发送的信号量是否真的存在?有没有任务在等待这个信号量?信号量的计数器值有没有超过范围?当发送的信号不存在时或者信号量的计数器的值超过范围要直接返回一个错误代码。如果有任务在等待这个信号量,那么就让这个任务等待列表中最高优先级的任务马上进入就绪态准备运行。计数器不用加1,因为资源已经消耗了(有任务得到信号量进入就绪态)。如果没有任务在等待这个信号量,那么计数个器值加1,表示又多一个信号量可用。而任务等待一个信号量的实现方式又是如何设计的呢?内核支持超时等待机制,即可以限定等待的时间,在限定的时间内没有收到信号量时任务会自动进入就绪态准备运行。等待一个信号量本质上就判断一个信号量的计数值是否大于0,如果大于0说明信号量可用,等待的信号量已经到达,任务可以执行后面的程序,然后还要把计数值减1,表示消耗了一个信号量。如果计数值为0(等待的信号量还没有到),那么任务要进入休眠态,实现的方法是将限定等待的时间值任务赋给任务的延时值。任务控制块的数据结构中有一个变量是延时值,用来控制休眠的时间,改变这个延时值就相当于是改变这个任务的休眠时间,一般处于就绪态的任务延时值是为0的。任务进入就绪态后就重新进行任务的调度。当这个任务从休眠态回复到运行态时有两种可能:一种是超时了,一种是在限定的时间内得到了一个信号量,那么在恢复运行态时就要进行一个判断。那现在提出一个问题是:如何区分这两种情况呢?内核是作何处理的呢?原来任务控制块中有一个变量是状态变量,这个变量标志着任务是处于何种状态,是在等待一个信号量还是在已经得到了一个信号量。任务在休眠前这个变量表示的是任务处于等待一个信号量的状态。如果等待超时后还没有得到信号量,那么这个状态变量是没有发生变化的,任务恢复运行时可以判断这个变量,如果表示处于等待一个信号量的状态,那么就意味着等待超时了,则任务就要进入就绪态准备运行。如果任务在进入休眠态期间,有其他任务释放信号量时,就会发现有任务在等待这个信号量,并将这个任务处于就绪态准备运行,同时改变这个任务的状态变量,让它表示这个任务已经得到信号量了。任务恢复运行时就会知道是得到了信号量,然后可以处理后面的内容。通过以上分析我们可以很清楚的知道事件控制块是如何与具体的通信机制进行了结合。这个有点像面向对象的思想,如果抽象类一般是父类,其子类就是具体实现的类。创建一个子类后返回的指针值可以用抽象类的指针指向它。与之类似的是,创建了一个信号量后返回的却是一个事件控制块指针,但是此指针已经不是指向单纯的事件控制块了,它具体的信息是一个信号量。其他的通信机制也是类似的用法。互斥型信号量与一般的信号量实现方式类似,不过在这个内核中互斥型信号量还可以实现优先级反转,具体情况在此不作论述。下面对消息邮箱的设计进行一个说明,进一步说明内核中是如何将事件控制块与具体通信机制进行结合的。首先要介绍的是内核是如何实现创建一个邮箱的。邮箱意味着传递的是一个消息,在这个实时操作系统中邮箱只允许存放一个消息。消息的类型可以自定义。创建邮箱函数需要传递进来一个消息指针,类型是泛型的。创建一个事件控制块(在内核中是从空闲的事件控制块的链表中取出的),然后对这个事件控制块的数据变量初始化,使之具有邮箱的特征,这与信号量的创建有点类似。传递进来的消息指针也会保存在事件控制块中,最后把这个事件控制块的指针返回。向邮箱发送一则消息的实现方式。向邮箱发送一则消息的函数要两个参数,一个是定义为邮箱的事件控制块指针,一个是要发送的消息的指针。发送要要先进行判断有没有任务在等待这个邮箱中的消息,如果有任务在等待这个邮箱里的消息,则将等待列表中优先级最高的任务置于就绪态。并重新调度任务。如果还没有任务在等待这个邮箱里的消息,那么下一步就是要判断这个邮箱里有没有存有消息,如果已经存有消息了,那么就要返回一个表示消息已满的错误代码,因为邮箱只支持存放一个消息。如果邮箱是空的,那么就将要发送的消息的指针存放在邮箱中,即赋给事件控制块里的一个表示消息的指针变量。等待邮箱里消息的实现方式。邮箱等待也支持等待超时机制,这个机制与前
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年高端会计选拔考试题库(附答案)
- 再验证培训试题及答案
- 聊城语文中考试题及答案
- 负极材料工厂管理办法
- 上海医保基金管理办法
- 严重破产风险管理办法
- 交通运输客运管理办法
- 落实社团管理办法情况
- 融资租赁管理办法修订
- 管理类培训管理办法
- GB/T 45972-2025装配式建筑用混凝土板材生产成套装备技术要求
- 电力营销稽查培训课件
- 绿色金融培训课件
- 2025安化事业单位笔试真题
- 文化创意产品设计及案例PPT完整全套教学课件
- 项目建设全过程管理经典讲义(PPT)
- 关于“成立安全领导小组”的通知
- 体育馆屋面专项施工方案(22页)
- 个人分期还款协议书的范本
- 急性重症胰腺炎诊治流程
- 质量检验员培训课件
评论
0/150
提交评论