收藏 分销(赏)

wind 内 核.doc

上传人:s4****5z 文档编号:8728439 上传时间:2025-02-27 格式:DOC 页数:13 大小:704.50KB
下载 相关 举报
wind 内 核.doc_第1页
第1页 / 共13页
wind 内 核.doc_第2页
第2页 / 共13页
wind 内 核.doc_第3页
第3页 / 共13页
wind 内 核.doc_第4页
第4页 / 共13页
wind 内 核.doc_第5页
第5页 / 共13页
点击查看更多>>
资源描述

1、第1章 wind 内 核1.1 内 核 概 述VxWorks操作系统内核称为wind内核,下面从实时性能、核结构、调度特点等方面初步探讨。1.1.1 实时内核“实时”表示控制系统能够及时处理系统中发生的要求控制的外部事件。从事件发生到系统产生响应的反应时间称为延迟(Latency)。对于实时系统,一个最重要的条件就是延迟有确定的上界(这样的系统属于确定性系统)。满足这个条件后,根据这个上界大小再区分不同实时系统的性能。这里,“系统”是从系统论的观点讲的一个功能完整的设计,能够独立和外部世界交互,实现预期功能,包括实时硬件系统设计、实时操作系统设计、实时多任务设计3部分。后两者可以概括为实时软件

2、系统设计。实现实时系统是这3部分有机结合的结果。从另外一个角度,即实时程度看,可以把系统分为硬实时系统和软实时系统。硬实时系统是这样一种系统,它的时间要求有一个确定的底线(Deadline),超出底线的响应属于错误的结果,系统将会崩溃,上面所说的实时系统属于硬实时系统。对于软实时系统来说,“实时性”是个程度概念,在提交诸如中断、计时和调度的操作系统服务时,系统定义一个时间范围内的延迟。在该范围内,越早给出响应越有价值,只要不超出范围,晚点给出的结果价值下降,但可以容忍。1实时硬件系统设计实时硬件系统设计是其他两部分的基础。实时硬件系统设计要求满足在软件系统充分高效的前提下,必须提供足够的处理能

3、力。例如,硬件系统提供的中断处理逻辑能同时响应的外部事件数量、硬件反应时间、内存大小、处理器计算能力、总线能力等,以保证最坏情况下所有计算仍然得以完成。多处理的硬件系统还包括内部通信速率设计。当硬件系统不能保证达到实时要求时,可以确信整个系统不是实时的。目前,各种硬件速度不断提高,先进技术大量涌现,硬件在大多数应用中已经不是实时系统的瓶颈。因而,实时系统的关键集中在实时软件系统设计,这方面也成了实时性研究的主要内容,也是最复杂的部分。许多场合甚至对实时系统和实时操作系统不加区分。2实时操作系统设计先来看实时操作系统性能评价的几个主要指标:l 中断延迟时间:从接收中断信号操作系统做出响应,并完成

4、进入中断服务程序的时间;l 任务切换时间:多任务之间进行切换所花费的时间;l 系统响应时间:系统在发出处理要求到系统给出应答信号的时间。系统响应时间从整体上评价操作系统,综合了前面两个指标。从实时性角度看,操作系统经历了前后台系统、分时操作系统和实时操作系统3个 阶段。前后台系统其实没有操作系统,系统中只运行一个无限主循环,没有多任务的概念,但是通过中断服务程序响应外部事件。在前后台系统中,对外部事件的实时响应特性从两方面看。(1)中断延迟:主循环一般保持中断开放状态,因此前后台系统中断响应非常快,并且通常允许嵌套;(2)系统响应时间:需要经历一次主循环才能对中断服务程序中采集的外部请求进行处

5、理,因此系统响应时间决定于主循环周期。分时操作系统将系统计算能力分成时间片,按照一定的策略分配给各个任务,通常在分配过程中追求某种意义上的公平。分时操作系统不保证实时性。实时操作系统(Real Time OS,RTOS)的目的是实现对外部事件的实时响应,即根据前面对实时性的定义,实时操作系统必须在确定的时间内给出响应。实时操作系统必须满足下面几个条件:l 可抢占的内核;l 可抢占的优先级调度;l 中断优先级;l 中断可嵌套;l 系统服务的优先级由请求该服务的任务的优先级确定;l 优先级保护(优先级翻转保护);l 前述实时操作系统性能评价指标具有固定上界。满足上面的必要条件后,内核内部具体的实现

6、机制就决定了其实时性的优劣。VxWorks的wind是一个真正的实时微内核,满足上述条件。同时,wind采取单一实时地址空间,任务切换开销非常低,相当于在UNIX这样的主机上切换到相同进程内的另一个线程,并且没有系统调用开销。高效的实时设计使wind在从工业现场控制到国防、航空等众多领域中表现出优秀的实时性。3实时多任务设计具备前面两个实时条件后,实时系统的最终实现就取决于实时多任务设计。这部分是最能体现系统设计者艺术的部分,也是最有挑战性的部分。这部分设计内容涵盖了一个完整的软件工程过程:需求分析(需求建模)、概要设计(设计建模)、模块设计、模块实现、调试、发布。和一般软件工程过程不同的是上

7、述每一步中都需要考虑对实时性的满足,因此更加复杂、也许需要专门通过一本书的篇幅对此进行探讨。我们只简单分析设计过程中实时多任务设计需要面临的关键问题:多任务划分、多任务分配、多任务调度。“关键”是因为它们是决定系统实时性的主要因素,具体设计时还存在其他一些问题,如任务间通信机制选择,中断服务程序设计等,都对系统实时性产生重大影响,但不属于本质的问题。对多任务划分、多任务分配和多任务调度的设计对应软件工程过程的概要设计和模块设计阶段。多任务划分即如何将整个系统功能设计为不同的任务来实现,任务之间采取怎样的耦合关系,划分的粒度如何等。这里,“任务”也包括中断,因此也包括将什么功能放在中断中实现,什

8、么功能放在常规的任务中处理。在根据数据流划分任务时,影响划分的要素包括数据流之间的并行和串行关系;根据控制流划分任务时,考虑的要素是控制的因果关系。多任务划分影响着多任务分配和多任务调度。多任务分配决定任务放在哪个处理器上完成(存在多个处理器时),以及网络环境下任务如何分配。多任务划分目的的实现需要多任务调度,多任务调度的设计目的是关键任务得到实时响应,同时整体上所有任务的设计内容都在允许的时间内完成。多任务调度的内容包括系统调度策略的选择,任务优先级的确定,以及任务间竞争和合作的设计。在划分多任务时,已经考虑了各任务所担任职责的轻重缓急,多任务调度时需要根据这种紧急程度分配合理的优先级;调度

9、还必须使不同优先级的协作任务有效地同步。多任务划分、多任务分配和多任务调度三者是有机的整体,而多任务划分则是其中决定性的部分。任何一个因素设计不合理都将影响整个系统的实时性。1.1.2 微内核传统上,一个操作系统分为核心态和用户态。内核在核心态运行,为用户态的应用程序服务。内核是操作系统的灵魂和中心,决定了操作系统的效率和应用领域。在设计操作系统时,内核包含哪些功能以及内核功能采取何种组织结构,都是由设计者决定的。我们从内核功能和结构特点看,具有整体式内核、层次式内核、微内核三种不同形式。整体式内核结构的操作系统实质上“无结构”。操作系统功能由一系列模块堆砌而成,任何模块之间可进行任意调用。整

10、体式内核结构的操作系统不进行任何的数据封装和隐藏,在具有较高效率的同时,存在着难以扩展和升级的缺点。CP/M和MS-DOS属于此类结构的操作系统。层次式内核结构的操作系统将模块功能划分为不同层次,下层模块封装内部细节,上层模块调用下层模块提供的接口。UNIX,LINUX,VAX/VMS,MULTICS等属于层次结构操作系统。层次化使操作系统结构简单,易于调试和扩展。两种操作系统的内核结构如图1-1所示。不管整体式结构,还是层次式结构,它们的操作系统都包括了许多将其用于各种可能领域时需要的功能,故被称为宏内核操作系统,以至可以认为该内核本身便是一个完整的操作系统。以UNIX为例,其内核包括了进程

11、管理、文件系统、设备管理、网络通信等功能,用户层仅仅提供一个操作系统外壳和一些实用工具程序。(a)整体式结构 (b)层次式结构图1-1 内核结构嵌入式操作系统大多采用微内核结构。微内核操作系统是近二十年新发展起来的技术,内核非常小但效率高,从数十KB到数百KB字节,适合于资源相对有限的嵌入式应用。微内核将很多通用操作的功能从内核中分离出来(如文件系统,设备驱动,网络协议栈等),只保留最基本的内容。一般认为微内核操作系统具有如下优点:l 统一的接口,在用户态和核心态之间无需进程识别;l 可伸缩性好,易于扩充,能适应硬件更新和应用变化;l 可移植性好,操作系统要移植到不同的硬件平台上,只需修改微内

12、核中极少代码即可;l 实时性好,内核响应速度快,可以方便地支持实时处理;l 安全可靠性高,微内核将安全性作为系统内部特性来进行设计,对外仅使用少量应用编程接口;l 适合分布式计算环境。内核为进程传递消息的方式天然适合RPC这一计算模式。由于操作系统核心常驻内存,而微内核结构精简了操作系统的核心功能,内核规模比较小,一些功能都移到了外存上,所以微内核结构十分适合嵌入式的专用系统,如图1-2所示的wind微内核结构。微内核的不同实现模式从宏内核系统到微内核,操作系统结构发生了根本性的变化,导致的影响是多方面的。除了上面说明的微内核的优越性外,微内核的批评者也指出了微内核的缺陷:在微内核操作系统中,

13、由于许多传统的操作系统功能改为用户任务实现,一般采取客户/服务器模型,即传统操作系统中许多系统功能作为微内核结构下的服务器任务,这样使任务间的数据交换量更大,需要在内核与任务之间进行大量的数据复制,因此影响了系统性能。有研究人员指出著名的微内核操作系统Mach性能远不如宏内核的BSD UNIX(当然这里与应用类型有关,例如用嵌入式微内核的系统实现一个文件服务器显然比UNIX效率低)。图1-2 wind微内核结构为了提高微内核效率,有两种实现模式:受保护的虚地址空间模式和无保护的单一实地址空间模式。前者在宏内核操作系统(如UNIX)和某些微内核操作系统(如QNX)中采用。这种模式的优点是显而易见

14、的:任务独立运行,不受其他任务错误影响,系统可靠性高。VxWorks的wind微内核采取单一实地址空间模式,所有任务在同一地址空间运行,不区分核心态和用户态。其优势在于:l 任务切换时不需要进行虚拟地址空间切换;l 任务间可以直接共享变量,不需要通过内核在不同的地址空间复制数据;l 系统调用时不需要在核心态和用户态之间切换,相当于直接的函数调用。k 系统调用时需要从用户态切换到核心态,以执行用户态下不能执行的操作,在许多处理器上这是通过一个trap中断处理完成的。VxWorks中不存在这样的切换,因此系统调用和一般函数调用没有什么差别。但是我们仍然沿用一般说法。对于两种模式孰优孰劣,各自的支持

15、者们进行了大量的争论。比较各有所长的东西往往非常困难。我们倾向于认为,对于嵌入式实时应用,单一实地址模式要合适一些。许多实践也证明,依靠虚地址保护来提高可靠性总存在局限性,毕竟程序运行出了错误。有时虚地址保护只是使已经出现的错误经过一个延迟、积累和放大的过程,用过Windows就会有这种感触。而经过大量关键应用检验的VxWorks操作系统,则被充分证明是高度可靠的(当然,可靠的系统由可靠的操作系统和可靠的应用系统组成)。对于从“单片机汇编语言”成长起来的开发人员,可能更喜欢单一实地址空间的系统。1.1.3 任务调度实时系统和分时系统的一个显著差异体现在调度策略上。实时系统调度关心的是对实时事件

16、的相应延迟,而传统的分时系统调度时要考虑的目标是多方面的:公平、效率、利用率、吞吐量等。因此实时系统通常采用优先级调度,即操作系统总是从就绪任务队列中选择最高优先级运行。优先级调度根据调度的时机又分为“不可抢占式调度”和“可抢占式调度”。1优先级调度如果一个线程一旦获得处理器就独占处理器运行,除非它因某种原因决定放弃处理器,系统才会调度别的线程,这种调度方式称为“不可抢占式调度”(Non-Preemptive Scheduling),也即只有任务主动让出处理器后系统才重新根据优先级调度选择任务,如图1-3所示。图1-3 不可抢占优先级调度在图1-3中,高优先级任务t2和t3就绪后(图中斜线阴影

17、部分),并没有立即被调度,而是低优先级让出处理器时,才根据优先级高低选择任务运行。高优先级任务和低优先级任务之间是紧密合作的关系,低优先级任务必须设计为不使高优先级任务长时间等待。当注重实时响应时,应该采用“可抢占式调度”(Preemptive Scheduling)。只要有更高优先级任务就绪,系统立即中断当前任务来调度高优先级任务,确保任意时刻最高优先级任务得到处理器,如图1-4所示。在图1-4中,抢占式优先级调度使任务t2和t3就绪时总能立即得到处理器,其实时响应特性优于不可抢占调度。对于区分核心态和用户态的系统,优先级调度还是微内核实现的基础。由于可抢占式内核中的核心态任务也可以随时让位

18、给比其优先级高的任务,使得系统可以把一些实时设备的操作放在内核之外,通过“任务”完成,从而简化了内核设计。在传统的操作系统(如UNIX)中,必须将所有对时间要求较高的操作放在内核中实现,导致庞大的内核。wind内核支持256 级优先级:0255。优先级0为最高优先级,优先级255为最低优先级。任务优先级在创建时确定,并允许程序运行中动态修改。但是对于内核而言,从就绪队列中选择一个任务调度时优先级是确定的,换言之,内核不会动态计算每个任务的优先级,因此这种调度策略属于静态调度策略;相对地,动态调度策略调度时需要根据某个目标(例如任务完成时间底线)动态确定任务优先级并调度。静态调度策略效率显著高于

19、动态调度策略,并且足够满足应用需要,因而被普遍采用,包括POSIX 1003.1b标准对任务调度的定义。图1-4 抢占式优先级调度2Round-Robin调度前面介绍的优先级调度存在这样的问题:如果没有被更高优先级任务抢占,或者因阻塞等原因让出处理器,任务将一直运行下去,在此情况下,同优先级任务将得不到运行。Round-Robin调度基于这样的哲学:在更高优先级任务调度依然优先运行的前提下(这一点和前面一样),同优先级任务之间调度时追求一定意义上的公平。Round-Robin调度将任务运行划分为时间片,当任务运行一个时间片后,内核将其调出处理器并放在同优先级就绪任务队列尾部;调度时选择最高优先

20、级就绪队列首部任务。Round-Robin调度的效果是将每个任务运行一个时间片后“让出”处理器给下一个任务,如轮转一样,也称轮转调度。可见,Round-Robin调度并没有改变“基于优先级”和“可抢占”这两个实时调度的特征。说在VxWorks中,Round-Robin调度是基于优先级可抢占调度的一个“附加特征”,如图1-5所示。图1-5 Round-Robin调度在POSIX 1003.1b中,基于优先级的可抢占调度定义为SCHED_FIFO;Round-Robin调度定义为SCHED_RR。3.5节“任务调度”部分深入介绍任务调度细节。3优先级翻转问题实时系统中,如果任务调度采用基于优先级的

21、方式,则传统的资源共享访问机制在系统运行时很容易造成优先级翻转问题,即当一个高优先级任务访问共享资源时,该资源已被一低优先级任务占有,而这个低优先级任务在访问共享资源时可能又被其他一些低优先级的任务抢先,因此造成高优先级任务被许多较低优先级的任务阻塞,高优先级任务在低优先级任务之后运行,看起来像低优先级任务抢占了高优先级任务,即发生了优先级翻转(Priority Inversion)。一个最为著名的优先级翻转问题的例子是“火星探路者”(Pathfinder),它采用了VxWorks实时内核设计。1997年7月4日,“探路者”弹出气囊在火星表明登陆,放出“漫游者”探测车,收集传回地球的大量数据。

22、在开始的几天里,“探路者”被誉为完美无缺的作品,引起巨大轰动。但是几天后,“探路者”开始出现系统复位、数据丢失的现象。当时解释为“软件小故障”、“同时处理的事情太多”等。为了找出故障,研究人员不断模拟“探路者”在火星上工作的条件和过程,终于在实验室中再现了系统复位的现象,并记录下来。根据分析,有如下两个任务需要互斥访问共享“信息总线”:(1)总线管理任务,具有最高优先级,运行频繁,进行总线数据I/O;(2)气象数据收集任务,优先级低,运行较少,收集数据并通过互斥信号量将数据发布到“总线”。如果数据收集任务持有信号量期间,总线管理任务就绪并且也申请获取信号量,则总线管理任务阻塞,直到收集任务释放

23、信号量。看起来工作得很好,因为收集任务很快就会完成,高优先级的总线管理任务会很快得到运行。但是,另有一个需要较长时间运行的通信任务,其优先级比总线管理任务低,但是比数据收集任务高。在很少的情况下,如果通信被中断激活,并刚好在总线管理任务等待数据收集任务完成期间就绪,它将被系统调度,从而比它优先级低的数据收集任务得不到运行,并因此使最高优先级的总线管理任务无法运行。在经历较长时间后,看门狗观测到“总线”没有活动,将此解释为严重错误并使整个系统复位。很显然需要防止优先级翻转以确保系统的实时响应。常见的解决办法之一是使用优先级继承协议(Priority Inheritance Protocol)。当

24、高优先级任务需要低优先级任务占用资源时,将低优先级任务的优先级别提高到和高优先级同样的级别,即相当于低优先级任务继承高优先级任务的优先级级别。VxWorks实现了对优先级继承的支持,但是默认情况下该功能被关闭,也就是说有可能发生优先级翻转问题,也就导致了“探路者”中问题的发生。不过,研究人员及时查出了问题并给在火星上的系统打上了补丁,使“探路者”终于成功完成使命。美国航空航天局JPL(喷气推进实验室)决定第二代火星探测器项目仍然与风河系统进行合作,被引为VxWorks功能强大和可靠性的例证。防止优先级翻转的另外一种协议是优先级天花板(Prioceiling),其设计策略是对优先级翻转采取“预防

25、而不是“补救”。也就是说:不论是否阻塞了高优先级任务,持有该协议的任务在执行期间都被赋予优先级天花板看作的优先级,以使任务尽快完成操作,因此可以把任务优先级天花板看作是更“积极”的一种保护优先级的方式。VxWorks对POSIX信号量的支持实现了该协议。我们后面将对优先级翻转问题做更具体的描述。1.2 任务属性VxWorks任务具有两个显著不同于主机操作系统的特点:(1)VxWorks任务和内核具有相同的权限,都能够执行处理器所支持的全部指令;(2)所有任务(包括内核)共享同一实地址空间(不进行虚拟内存管理),不同任务的数据没有任何保护机制。这两个特性一方面使VxWorks具有很高的效率,

26、同时,由于没有VxWorks任务执行指令和没有访问内存任何约束和保护,使得某个任务的错误容易造成更严重的影响,因而对代码质量提出了更高的要求。1.2.1 任务控制块(WIND_TCB)多任务设计能随时打断正在执行着的任务,对内部和外部发生的事件在确定的时间里作出响应。VxWorks实时Wind内核提供了基本的多任务环境。从表面上来看,多个任务正在同时执行,实际上,系统内核根据某一调度策略让它们交替运行。系统调度器使用任务控制块的数据结构(TCB)来管理任务调度功能。任务控制块用来描述一个任务,每一任务都与一个TCB关联。TCB包括了任务的当前状态、优先级、要等待的事件或资源、任务程序码的起始地

27、址、初始堆栈指针等信息。调度器在任务最初被激活时以及从休眠态重新被激活时,要用到这些信息,TCB使多个任务得以独立运行,如表1-1所示任务控制块TCB。表1-1 任务控制块TCB项 目内容和含义任务名称指针指向表示任务名称的字符串上下文程序计数器,表示任务被中止时的位置CPU状态,包括各种处理器特定的寄存器栈,用于动态变量,函数调用,信号处理等标准输入,标准输出,标准错误输出定义延迟定时器,用于任务延迟计数时间片定时器,用于Round-Robin调度 内核控制结构(Kernel Control Structures)信号处理设置信息,包括阻塞信号集,信号处理方式,信号状态等错误状态,每个任务都

28、有一个独立的全局errno的副本调试和性能监视状态任务变量(可选)浮点上下文(可选)异常信息因处理器体系不同而有差异,用于异常处理退出码exitCode作调试之用为了便于调试,每个任务都有一个独一无二的字符串表示的名称,在任务被创建时由用户程序指定或者系统默认生成。几乎所有的任务控制函数都采用任务ID(等于TCB地址)表示一个任务。VxWorks提供任务名称和任务ID之间的转换函数。TCB的一个重要内容就是任务上下文(ContExT),代表了任务运行状态。VxWorks的任务切换就是将当前任务(被换出CPU)的上下文保存到该任务的TCB,然后从调度程序(Scheduler)选择新任务(被换入C

29、PU)的TCB中恢复上下文。上下文切换分两种情况:l 同步上下文切换,引起的原因是当前运行的任务执行下列操作:(1)进行阻塞、延迟、挂起的调用;(2)使更高优先级任务就绪而发生优先级抢占;(3)降低自身优先级或者退出;l 异步上下文切换,通常由ISR使更高优先级任务就绪引起。异步上下文切换比同步上下文切换需要更多时间。调度程序开销主要取决于保存和恢复上下文需要复制的寄存器数,要求该过程非常快。对于特定体系的处理器而言,该数值是固定的。为提高调度程序效率,在默认情况下,VxWorks上下文不包括浮点寄存器(即假设任务不使用浮点寄存器,在许多情况下的确如此)。任务创建时指定浮点寄存器是否属于上下文

30、的一部分(标志VX_FP_TASK)。VxWorks中,内存地址空间不是任务上下文的一部分。所有的代码运行在同一地址空间。如每一任务需各自的内存空间,需可选产品VxVMI的支持。1.2.2 任务栈每个任务都有独立的栈空间,栈用于任务的函数调用,分配自动变量和函数返回值。任务控制块WIND_TCB记录了位置和大小等栈信息。WIND_TCB本身放在任务栈开始 部分。任务栈大小的设置必须合理,太大会浪费内存空间,太小时可能引起栈溢出。在VxWorks中,所有任务在同一地址空间运行,任务之间没有任何地址保护机制,因此栈溢出会引起连锁反应,可能导致系统崩溃,或者出现难以调试的意外结果。栈大小设置没有可以

31、套用的公式,一般凭经验设置一个较大的值,以存储空间换取可靠性。分析程序所有可能的分支和调用,从而计算出需要的栈大小的方法,从理论上给出了最佳的栈设置方案,但是目前好像还没有这样的自动化分析工具,靠程序员手工计算似乎不大可行。好在存储器越来越便宜,因此许多应用中,人们更趋向于使用大存储器解决问题。对可靠性要求高的应用,仍然需要充分分析和测试栈大小设置是否足够。栈大小在taskSpawn( )创建任务时指定。1中断只要体系和BSP支持,VxWorks支持独立的中断栈。“独立”是对任务而言,对所有的ISR使用相同的中断栈。中断栈在系统启动时根据配置参数设置位置、大小和填充。如果体系不支持,中断栈属于

32、被中断任务栈的一部分。此时任务栈必须足够大,保证最坏情况下中断嵌套也不会溢出。对独立中断栈的支持:MC680x0(MC68060除外),ARM,PPC,MIPS。VxWorks for Pentium支持程序在任务栈和专用中断栈两种方式之间动态选择,如表1-2所示。表1-2 不同处理器的中断栈处理器体系中断栈SHELL根任务WDBMC680x0100010000100000x1000COLDFIRE100010000100000x1000SPARC1000050000100000x2000I960100040000200000x2000MIPS500020000200000x2000PPC50

33、0020000240000x2000I80x86100010000100000x1000SH100010000100000x1000AM29xxx1000040000100000x2000ARM决定于BSP中断结构0x100000x40000x20002栈溢出检测当某个任务栈溢出后,系统行为将难以预料。在程序开发过程中,根据经验在可能发生较深嵌套调用的地方加入一些栈检查调用checkStack( )来检查任务栈使用情况,例如: NAME ENTRY TID SIZE CUR HIGH MARGIN - - - - - - - tShell _shell 23e1c78 9208 832 363

34、2 5576checkStack( )显示了单个指定任务或者所有任务的栈使用情况,包括:l 栈大小(SIZE);l 栈当前使用数(CUR);l 历史使用峰值(HIGH);l 最大可能空余数(MARGIN=SIZE-HIGH)。如果上述结果是程序在足够长的测试运行过程中充分考虑了边界条件以及各种可能引发最深嵌套调用的情况之后得到的输出,那么可以根据该结果调整任务栈的设置,比如设置栈大小为峰值的120%: SIZE=HIGH*1.2 如果ISR使用任务栈,则还要加上一个经验常数: SIZE=HIGH*1.2+CC根据处理器体系特点、ISR复杂程度和内存大小确定。VxWorks要求栈大小为偶数值。V

35、xWorks没有直接为checkStack()记录使用峰值,而是生成任务时将栈空间以值0xee进行填充,checkStack()据此检查栈使用情况。如果在生成任务时指定VX_NO_STACK_FILL,则任务栈不会被填充,因此用checkStack()得到的峰值是没有意义的。1.2.3 出错状态ANSI C标准定义了一个全局整型变量errno,用来使应用程序知道底层函数出错的详细情况。使用errno应该注意:errno总是定义为该任务(对其他主机操作系统而言为进程)最后一次调用出错时的错误值,任何系统调用/函数执行成功都不应该清除errno,即不应该执行errno=0。当某个函数调用返回错误的

36、结果(如返回状态值为ERROR或者返回指针为NULL)时,程序可以立即检查errno得知错误细节,该errno一直保持,直到随后某次调用中出现新的错误将其覆盖。在VxWorks中,每个任务TCB中都记录有一个全局errno副本,属于上下文的一部分,由调度程序在上下文切换时保存和恢复,因此各个任务的出错状态相互不会影响。与此类似,ISR也使用独立的errno,但是ISR没有TCB,内核为ISR在中断栈中保存和恢复errno。从编写程序角度来看,无论属于常规任务,还是属于ISR的代码,程序都可以使用不受其他任务或者ISR影响的errno。程序引用errno时实际上通过一个函数得到全局errno地址

37、errno.h):#include errno.h#define errno ( *_errno( )有经验的程序员习惯充分利用errno,这样,程序具有很好的逻辑结构和用户接口。当发生嵌套调用时,VxWorks定义的出错状态在错误最初发生的位置定义,例如:STATUS funcA ( void ) errno = S_xxx_NOT_IMPLEMENTED; return ERROR;STATUS funcB ( void ) . if ( funcA( ) != OK ) return ERROR; . return OK;函数funcA()功能尚未实现,简单的设置errno为S_xxx

38、NOT_IMPLEMENTED并返回ERROR;函数funcB()调用funcA()得到ERROR时,funcB()返回ERROR给调用者但不修改errno,因为funcA()已经定义。当然,如果错误源于funcB(),则funcB()应该设置errno。VxWorks库函数都遵循上述约定。VxWorks允许用户程序中不仅使用VxWorks库函数中对errno的定义,还允许用户代码中定义新的errno,但是应该避免和VxWorks的定义重复。VxWorks定义的errno分两 部分:bit31bit16错误产生的模块编号bit15bit0 错误编号高16位模块编号小于501的部分已经被VxW

39、orks库使用,用户程序可以使用从501开始的模块编号,低16位为错误编号可以任意指定。库errnoLib提供VxWorks库函数中定义的errno错误信息字符串。可以通过在shell执行printErrno()打印错误信息。使用库errnoLib需要定义INCLUDE_STAT_SYM_TBL。例如可以在shell下执行:- i (查看任务状态,ERRNO列出十六进制表示的错误码)NAME ENTRY TID PRI STATUS PC SP ERRNO DELAY- - - - - - - -.t16 _pRun 7641dc 100 READY 17d1c 763de4 30 0- pr

40、intErrno(0x30) S_errno_EADDRINUSE该输出结果可以极大地方便程序调试。但是一个缺点是库errnoLib以目标码形式发布,必须将其构建到执行映像中才能使用。无法直接通过文本编辑器查看。这需要消耗大约24KB代码空间。实际上,不使用库errnoLib也可以知道错误信息细节。VxWorks将模块号定义在头文件targethvwModNum.h中,可以通过得到的错误信息中的模块号找到对应的错误信息,这样可以节约代码空间。以errno为OX410001的错误为例,我们得到模块号为十进制数65(高16位),然后在vwModNum.h找到对应模块的定义: #define M_m

41、sgQLib (65 16),因此知道错误源于msgQLib模块,进而在该模块定义文件targethmsg QLib.h中了解到: #define S_msgQLib_INVALID_MSG_LENGTH (M_msgQLib | 1)从而得知errno为0x410001表示msgQLib模块由于发送消息超出长度而出错。除了各个模块定义的错误号,VxWorks还定义了一系列ANSI C标准错误,如EINTR,EINVAL,EIO,EAGAIN等,本书后面将会涉及。1.2.4 钩子函数VxWorks允许任务创建“钩子函数”,安装钩子函数后,在规定事件发生时内核自动调用。具体来说有3类钩子函数:(

42、1)任务创建钩子:在任务被创建时调用;(2)任务调度钩子:在任务被调度时调用;(3)任务删除钩子:在任务被删除时调用,任务“删除”包括以任何方式调用函数taskDelete()、taskDeleteForce()和exit()引起的系统动作。可以指定多个钩子函数,VxWorks确保钩子函数具有一致的调用顺序。当多个钩子函数之间存在某种依赖时,如下两点就显得很重要:l 任务创建钩子函数和任务调度钩子函数按照其安装的顺序调用;l 任务删除钩子函数按照与其安装顺序相反的顺序调用。1任务创建(删除)钩子任务创建钩子或任务删除钩子必须具有如下原型定义:void xxxHook ( WIND_TCB *p

43、Tcb );参数pTcb指向被创建(删除)任务的TCB,xxxHook为任务创建钩子或为任务删除钩子函数名称。钩子函数可以随时被安装/卸载,用于安装和卸载的函数为:#include taskHookLib.hSTATUS taskCreateHookAdd (FUNCPTR createHook); /* 安装任务创建钩子 */STATUS taskCreateHookDelete (FUNCPTR createHook);/* 卸载任务创建钩子 */STATUS taskDeleteHookAdd (FUNCPTR deleteHook); /* 安装任务删除钩子 */STATUS task

44、DeleteHookDelete (FUNCPTR deleteHook);/* 卸载任务删除钩子 */虽然钩子函数在某个特定任务中被创建,但是创建后的钩子却被所有任务共享:在安装钩子后创建任何任务或者删除任何任务时调用钩子函数,除非将安装的钩子函数卸载。注意,(1)任务创建钩子在任务入口函数之前被调用;(2)任务删除钩子在任务退出后被调用。即:任务创建钩子 任务入口函数 任务结束 任务删除钩子如果有多个钩子,其调用顺序前面已经说明。任务删除钩子常常用于进行任务清理工作,如释放内存和关闭打开的文件。由于每次删除任务都会引起任务删除钩子调用,因此必须注意钩子函数重入性。任务创建钩子同样需要考虑代

45、码重入。这些考虑包括使用可扩展的数据结构定义以及避免重复释放同一块内存等。2任务调度钩子任务调度钩子函数原型必须定义如下:void switchHook ( WIND_TCB *pOldTcb, WIND_TCB *pNewTcb );参数pOldTcb指向被调出处理器的任务的TCB,pNewTcb执行被调入处理器的任务的TCB。任务调度钩子函数由下列函数动态安装和卸载:#include taskHookLib.hSTATUS taskSwitchHookAdd ( FUNCPTR switchHook );STATUS taskSwitchHookDelete ( FUNCPTR switc

46、hHook );任务调度钩子函数在每次VxWorks调度程序选择新的任务运行时被调用。与任务创建(删除)钩子不同的是,任务调度钩子在内核上下文中运行,而任务创建(删除)钩子在入参pTcb所指示的任务的上下文中运行。这一差异使得任务调度钩子不能和任务创建钩子及任务删除钩子函数那样进行所有的系统调用。如表1-3所示列出了任务调度钩子所能调用的VxWorks函数。表1-3 任务调度钩子可以调用的系统函数库允许调用的函数bLib全部函数fppArchLibfppSave( ),fppRestore( )intLibintContext( ),intCount( ),intVecSet( ),intVecGet( )lstLib全部函数mathALib如果使用fppSave( )和fppRestore( ),则全部函数可以使用rngLib除rngCreate( )外的函数vxLibvxTas( )taskLibtaskIdVerify( ),taskIdDefault( ),taskIsReady( ),taskIsSuspended( ),taskTcb( )

展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传
相似文档                                   自信AI助手自信AI助手
搜索标签

当前位置:首页 > 百科休闲 > 社会民生

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服