Tornado &VxWorks 培训 深圳市微迪软件技术有限公司 培训中心 计算机操作系统原理需要掌握的知识点 一、操作系统概论

Slides:



Advertisements
Similar presentations
作者 : 陳鍾誠 單位 : 金門技術學院資管系 URL : 日期 : 2016/7/21 行程的同步 註:本章學術性較重,但考試常考。
Advertisements

考研英语复试 口语准备 考研英语口语复试. 考研英语复试 口语准备 服装 谦虚、微笑、自信 态度积极 乐观沉稳.
1 I/O 设备访问方式和类型. 2 Overview n The two main jobs of a computer: l I/O (Input/Output) l processing n The control of devices connneted to the computer is.
《互联网运营管理》系列课程 觉浅网 荣誉出品
Chapter 3: Operating-System Structures操作系统结构
Foundations of Computer Science
Memory Pool ACM Yanqing Peng.
資料庫設計 Database Design.
操作系统结构.
CHAP 2 Computer-System Structures 计算机系统结构
Chapter 2: Computer-System Structures计算机系统结构
第4章 VHDL设计初步.
Subversion (SVN) Presented by 李明璋 R /2/21
Chapter 6 同步 (Synchronization)
Operating System Process Management - 4 Monday, August 11, 2008.
Operating System CPU Scheduing - 2 Monday, August 11, 2008.
Operating System CPU Scheduing - 3 Monday, August 11, 2008.
Unit 4 I used to be afraid of the dark.
指導教授:許子衡 教授 報告學生:翁偉傑 Qiangyuan Yu , Geert Heijenk
Population proportion and sample proportion
操作系统 (并发进程) 徐锋 南京大学计算机科学与技术系 2018年9月18日3时52分.
Qtopia 编程部分要点分析 苗忠良.
Operating System Concepts 作業系統原理 Chapter 3 行程觀念 (Process Concept)
C H A P T E R 11 体系结构对操作系统的支持.
第六章 应用程序结构.
Chapter 1 用VC++撰寫程式 Text book: Ivor Horton.
Applied Operating System Concepts
第五讲 数据的分组、合并与转换.
簡易 Visual Studio 2010 C++ 使用手冊
Operating System Concepts 作業系統原理 CHAPTER 2 系統結構 (System Structures)
经典同步问题.
VxWorks基础培训.
Chapter 3 行程觀念 (Process Concept)
创建型设计模式.
ICT RTOS Research Group 胡伟平,王剑
计算机操作系统 第二章 进程管理 高校教师、高级项目经理 任铄 QQ:
第三章 进程互斥与同步 进程通信 Communication.
操作系统原理 Operating System Principles
重點 資料結構之選定會影響演算法 選擇對的資料結構讓您上天堂 程式.
李元金 计算机与信息工程学院 第 4 讲 进程管理(2) 李元金 计算机与信息工程学院 1/
第4章(1) 空间数据库 —数据库理论基础 北京建筑工程学院 王文宇.
簡易 Visual Studio 2005 C++ 使用手冊
單元11: 事件結構 主題: a. 事件結構概述 b. 如何使用事件結構 c. 使用事件結構須注意的事項.
Operating System Principles 作業系統原理
第3章 認識處理元.
服務於中國研究的網絡基礎設施 A Cyberinfrastructure for Historical China Studies
Microsoft SQL Server 2008 報表服務_設計
第2章 进程管理 2.1 进程概念 2.2 线程 2.3 进程管理 2.4 进程间通信 2.5 经典进程同步问题 2.6 管程
第2章 进程和线程 内容提要: 2.1 进 程 概 念 2.2 进程的状态和组成 2.3 进 程 管 理 2.4 线 程.
IBM SWG Overall Introduction
資料結構 Data Structures Fall 2006, 95學年第一學期 Instructor : 陳宗正.
Operation System(OS).
Speaker: Liu Yu-Jiun Date: 2009/4/29
中国科学技术大学计算机系 陈香兰 2013Fall 第七讲 存储器管理 中国科学技术大学计算机系 陈香兰 2013Fall.
虚 拟 仪 器 virtual instrument
中国科学技术大学计算机系 陈香兰 Fall 2013 第三讲 线程 中国科学技术大学计算机系 陈香兰 Fall 2013.
高考应试作文写作训练 5. 正反观点对比.
Process Description And Control
CHAPTER 6 Concurrency:deadlock And Starvation
Efficient Query Relaxation for Complex Relationship Search on Graph Data 李舒馨
Create and Use the Authorization Objects in ABAP
2012 程式設計比賽 Openfind 天使帝國 v2.0 (蓋亞的紋章).
VxWorks软硬件设计及实例分析
怎樣把同一評估 給與在不同班級的學生 How to administer the Same assessment to students from Different classes and groups.
Operating System Software School of SCU
Race Conditions and Semaphore
第6章 硬盘实用程序 GHOST 6.0 硬盘克隆(Clone)、硬盘分区拷贝工具
MGT 213 System Management Server的昨天,今天和明天
Section 1 Basic concepts of web page
When using opening and closing presentation slides, use the masterbrand logo at the correct size and in the right position. This slide meets both needs.
Presentation transcript:

Tornado &VxWorks 培训 深圳市微迪软件技术有限公司 培训中心 计算机操作系统原理需要掌握的知识点 一、操作系统概论 1、操作系统的基本概念:包括操作系统的定义、发展过程、分类以及各自的特点。 2、操作系统的五大功能。 二、进程和线程 1、掌握进程的基本概念、定义,以及它和程序的区别; 2、掌握进程基本状态和其变化的过程; 3、掌握进程挂起和解挂(以及加上这两个状态的进程之间的变化图); 4、掌握进程的描述(PCB)中应该包括的基本数据和状态; 5、了解线程的引入和基本概念; 6、掌握线程和进程之间的关系和区别; 7、评价KLT和WLT的线程实现; 三、并行性:互斥和同步 1、了解临界段、临界资源的定义; 2、了解信号量的定义和类别; 3、掌握用信号量实现进程之间的同步和互斥(主要表现为解决实际问题); 4、掌握生产者和消费者问题、阅读者(Reader)和写者(Writer)问题; 5、掌握管程的定义,以及管程和进程的区别,用管程来实现进程之间的同步和互斥; 四、多处理器和处理器管理 1、了解多处理器的优点; 2、了解作业调度算法以及其在多处理器系统中的实现问题; 3、了解几种多处理器的处理器调度和管理方法; 五、死锁 1、掌握死锁的定义和产生的原因; 2、掌握死锁产生的必要条件; 3、掌握死锁的预防和死锁的避免的区别和联系; 4、掌握(单)多资源的银行家算法; 六、存储管理 1、了解存储分区的几种方式及其特点(固定分区、可变分区、段式、页式、段页式); 2、掌握地址映射的原理,并能解决实际的问题; 3、了解伙伴系统管理的实现以及简单的计算; 4、掌握实效页面的置换算法(FIFO、OPT、LRU、NRU); 5、了解快表一致性问题; 七、设备管理 1、了解通道的工作方式及其优点; 2、掌握磁盘调度算法(FCFS、SSTF、扫描、循环扫描),并能解决实际问题; 3、了解虚拟设备和SPOOL系统的知识; 八、文件系统 1、掌握文件系统的基本概念; 2、掌握文件系统目录结构的基本概念和操作问题;; 3、了解文件系统的实现方式; 4、了解虚拟文件系统的基本概念; 九、分布式计算机系统 1、了解分布式计算机系统的基本概念(定义、优点、特点); 2、分布式系统中的互斥与同步的实现以及在此过程中可能产生的问题(巨群、唤醒丢失等); 3、了解进程迁移机制(定义、优点、评价); 十、OS结构和设计 1、了解微内核结构的优点、微内核包含的基本功能; 2、了解OS设计的目标和原则; 3、OS的结构(模块、层次、客户/服务器)等方式的特点和比较; 在上述的各个要点中,其中又以下面的几点最为重要:1、进程的互斥和同步算法;2、磁盘调度算法;3、作业调度C 深圳市微迪软件技术有限公司 培训中心

实时系统概念 实时系统是对外来事件在限定时间内能做出反应的系统。 指标 响应时间 Response Time 生存时间 Survival Time 吞吐量 Throughput

实时系统与普通系统 在实时计算中,系统的正确性不仅仅依赖于计算的逻辑结果而且依赖于结果产生的时间 对于实时系统来说最重要的要求就是实时操作系统必须有满足在一个事先定义好的时间限制中对外部或内部的事件进行响应和处理的能力 此外作为实时操作系统还需要有效的中断处理能力来处理异步事件和高效的I/O能力来处理有严格时间限制的数据收发应用

实时系统分类 根据不同的分类方法可以分为几种。 方法一是分为周期性的和非周期性的(periodic和aperiodic) 方法二是分为硬实时和软实时(hard real_time和soft real_time) 专用系统和开放系统 集中式系统和分布式系统

实时多任务操作系统与分时多任务操作系统 分时操作系统,软件的执行在时间上的要求,并不严格,时间上的错误,一般不会造成灾难性的后果。 实时操作系统,主要任务是对事件进行实时的处理,虽然事件可能在无法预知的时刻到达,但是软件上必须在事件发生时能够在严格的时限内作出响应(系统响应时间),即使是在尖峰负荷下,也应如此,系统时间响应的超时就意味着致命的失败。另外,实时操作系统的重要特点是具有系统的可确定性,即系统能对运行情况的最好和最坏等的情况能做出精确的估计。

实时操作系统中的重要概念 系统响应时间(System response time ) 系统发出处理要求到系统给出应答信号的时间。 任务换道时间(Context-switching time) 是任务之间切换而使用的时间。 中断延迟(Interrupt latency ) 是计算机接收到中断信号到操作系统作出响应,并完成换道转入中断服务程序的时间。

实时操作系统应具有如下的功能 任务管理(多任务和基于优先级的任务调度) 任务间同步和通信(信号量和共享内存等) 存储器优化管理(含ROM的管理) 实时时钟服务 中断管理服务

硬实时、软实时(一) 硬实时要求在规定的时间内必须完成操作,这是在操作系统设计时保证的 软实时则没有那么严,只要按照任务的优先级,尽可能快地完成操作即可 对于软实时系统基于优先级调度的调度算法可以满足要求,提供高速的响应和大的系统吞吐率;而对于硬实时系统则完成timely response是必须的。这两类系统的区别在于调度算法。 实时操作系统是保证在一定时间限制内完成特定功能的操作系统。例如,可以为确保生产线上的机器人能获取某个物体而设计一个操作系统。在“硬”实时操作系统中,如果不能在允许时间内完成使物体可达的计算,操作系统将因错误结束。在“软”实时操作系统中,生产线仍然能继续工作,但产品的输出会因产品不能在允许时间内到达而减慢,这使机器人有短暂的不生产现象。 实时系统与其他普通的系统之间的最大的不同之处就是要满 足处理与时间的关系。"在实时计算中,系统的正确性不仅仅 依赖于计算的逻辑结果而且依赖于结果产生的时间"(*1)。 对于实时系统来说最重要的要求就是实时操作系统必须有满足 在一个事先定义好的时间限制中对外部或内部的事件进行响应 和处理的能力。这样,实时系统可以定义为"一个能够在事先指 定或确定的时间内完成系统功能和对外部或内部、同步或异步 时间作出响应的系统"。(*2)此外作为实时操作系统还需要有 效的中断处理能力来处理异步事件和高效的I/O能力来处理有严 格时间限制的数据收发应用。就是1.系统应该有在事先定义的 时间范围内识别和处理离散的事件的能力。2.系统能够处理和存 储控制系统所需要的大量的数据。 由于实时系统在设计时与应用的关系非常强,所以有许多分类的 方法。各种分类的侧重点不同。方法一是分为周期性的和非周期 性的(periodic和aperiodic)。周期性的就是系统通过传感器 或其他设备周期性的探测外部环境的变化,在周期内对探测到的 变化作出反应。比如化工厂中的反应炉的控制。非周期性的就是 外部事件是循环性的发生的但不是有规律的或者是突发事件。 比如一架客机飞入一个空中交通管制的管制范围所产生的事件。 方法二是分为硬实时和软实时(hard real_time和soft real time)。硬实时系统就是系统必须及时的对事件作出反应,绝 对不能发生错过事件处理的deadline的情况。在硬实时系统中 一旦发生了这种情况就意味着巨大的损失和灾难。比如控制核 电站的系统,如果没有对堆芯过热作出及时的处理,后果不堪 想象。而在软实时系统中,当系统在重负载的情况下允许发生 错过deadline的情况而不会造成非常大的危害。比如在通信系 统中允许105个电话中有一个接不通。对于软实时系统基于优 先级调度的调度算法可以满足要求,提供高速的响应和大的系 统吞吐率;而对于硬实时系统则完成timely response是必须的。 这两类系统的区别在于调度算法。另外还可以分 为专用系统和开放系统;以及集中式系统和分布式系统 实时系统的设计问题 由于上述的关于实时系统的应用有关的特点,导致在实时 系统的设计时面临着与原来的通用系统所大大不同的考虑 因素。首先在实时系统中最基本的是系统应该能够提供对 时间正确性进行指定的方法。也就是在实时系统中不管是 用户还是开发人员都需要系统提供一种指定时间尺度的方 法。比如在有的实时系统中指定每隔一段时间就运行一段 程序,或者是提供指定程序必须在某个时间点之前完成的 方法等等。在实时系统中这是最最基本的要求。这时通用 系统中的功能就完全的不适用了。例如UNIX和许多类似的 通用系统中都提供一种延时的手段,但这种方法在实时系 统中就无法达到要求,因为这种延时手段无法保证应用能 够在deadline之前完成计算。 第二是实时操作系统的设计或选用。在现代的实时系统当 中一般都有实时操作系统的存在。因为操作系统使系统的 设计更加的简便,保证系统的质量以及能够提供其他通用 操作系统所提供的服务。这样实时的操作系统就面临着更 高的设计要求。本文主要论述实时操作系统,所以关于实 时操作系统的设计要点请看下文。 第三是实时系统的体系结构设计。实时系统的体系结构必 须满足1.高运算速度,2.高速的中断处理,3.高的I/O吞 吐率,4.合理的处理器和I/O设备的拓扑连接,5.高速可 靠的和有时间约束的通信,6.体系结构支持的出错处理, 7.体系结构支持的调度,8.体系结构支持的操作系统, 9.体系结构支持的实时语言特性。另外由于实时系统很多 应用于一些关键性的场合系统的稳定性和容错也非常重要 。还有实时系统很多在自然的形态上有分布式的特点,所 以还要考虑到实时的分布式应用。 此外实时的通信也是实时系统的一大要求,很显然在分布 式实时系统中实时的通信是最基本的。实时通信必须满足 1.逻辑正确2.要有确定的延迟时间(或通信延时时间的上 限)其中包括建立通信的延迟和消息传递的延时。 以上是系统设计时的要点问题。还有从计算机科学角度出 发实时系统必须解决1.时间特性的指定和确正,这点与实 际系统设计相同。2.实时的调度理论。由于实时系统应用 的特殊性以往通用系统中以大吞吐量为目标的调度算法必 须改进以适应实时应用的需要。主要要求是满足时间的正 确性,然后提供高度动态的,满足在线需求的,适应性的 实时调度。3.实时操作系统的设计和实现。在设计上首要 目标是提供保证实时性的方法,包括一系列的经典问题的 针对实时系统的解决方案。实现上要求操作系统的低开销 ,而且必须保证内核以及其他关键的可重入性。4.实时的 编程语言和设计方法。在编程语言级完成或提供实时应用 所需要的方法。比如象Ada语言,FORTH语言,QNX。5.分布 式的实时数据库。6.系统的容错。7.实时时钟的同步。 8.实时系统中的人工智能。 作为实时系统其特性决定了传统的性能衡量标准对其是不适用 的。对传统的通用系统的要求是大的系统吞吐量,合理的响应 速度,对每个系统用户相对公平的进行计算资源的分配。然而 在实时系统中,以上这些要求都不再适用或者是不再占重要位 置。再实时系统中系统的一切动作都以实时任务为中心。实时 的数据吞吐取代了以吞吐量为目标的标准。对硬实时应用的优 先响应取代了对每个用户的恰当的反应速度。系统的计算资源 和其他外设资源必须优先满足实时应用的要求。针对实时系统 新的要求,必须以实时的进程调度在实时操作系统中是一个关键性的问题。 实时操作系统的实时进程调度的根本要求是保证实时任 务的时间正确性。此外实时操作系统的进程调度算法必 须保证系统是可以事先定义的和易维护的。实时任务的 时间正确性以实时任务是否能够总是满足deadline为标准 。第一部分提到过实时系统的类型可以分为periodic和 aperiodic(周期性和非周期性),实时操作系统的调度 理论就是按照这个分类来考虑的。 §2.2.1实时进程调度算法 在控制系统的应用中,实时任务一般来说是各自独立的, 周期性的;也有一些是由外部事件来触发的。这样我们 可以设计一种最简单的调度方法:静态的周期性调度。 这种调度算法的基本思想是将处理器的时间分为"帧"。 一个帧就是一个系统内部时钟触发时钟中断的基本时间一系列不同的标准来衡量系统的性能。间隔。每个实时任务都在帧中占一段时间。仔细的设计 帧的大小可以保证系统中所有的实时任务都能在deadline 之前完成。而事件触发的实时任务则在每个帧中最后一个 周期性实时任务完成之后到帧结束这段时间内得以运行。 这种算法在系统相对简单,任务数少,又可以事先定义任 务的执行顺序的情况下很有效。还有一个更新的版本。就 是将一个大帧分为若干个级别较低的小帧。这个算法又称 为同步任务执行算法。 另外一种简单的调度算法就是FIFO。也就是将系统中所有的 任务组织成一个队列。先到先服务。在简单的和静态的实时 系统中可以事先安排好任务的执行顺序,预先组成队列。这 里要保证的是处理器执行的速度。当任务计算量一定,而处 理器的执行速度合适时,FIFO算法完全可以满足实时的需要, 而且自然的保证时间正确性。在设计队列和应用时要极力避 免关键任务长时间的阻塞。这种算法无疑是不精确的和适应 性差的。 优先级队列算法。这种算法从FIFO发展而来。给每个任务设定 优先级,然后在FIFO中按照优先级排列。这种算法保证了高优 先级的任务的完成,但是对于低优先级的任务很可能无法满足 时间的正确性。而且对低优先级的任务来说等待的时间是无法 预知的。我们无法知道在什么情况下会发生时间正确性上的错 误。而且必须在设计时仔细的检查任务优先级的设定,要保证 不会因为低优先级的任务无法按时完成而破坏整个系统的完整 性。这个算法也是与特定应用有关的。当环境或情况变化时系 统无法随之变化。 以上的调度算法都是独占的,即任务运行时,不允许别的任务 抢先。完成一个任务后才能完成下一个。下面是多任务的算法。 Rate Monatomic/Pacing算法。此算法是基于静态优先级调度 协议的方法。此算法给系统中每个任务设置一个静态的优先级。 这个优先级的设定是在计算任务的周期性和任务需要满足的 deadline的时间的长短的基础上完成的。周期越短,deadline 越紧迫,优先级越高。按周期或计算要求将任务细分成程序块, 整个任务的执行开销为P/(C/CP)( P是周期,C是计算开销,CP 是块的大小)。这样就将整个任务的执行按紧迫性要求分散在整 个周期内。这种算法允许系统以多任务方式执行。 Deadline Driven算法。Deadline Driven算法提供动态的优先级 。因为此算法根据任务满足deadline的紧迫性来修改任务的优先 级,以保证最紧迫的任务能够及时完成。当系统的负载相对较低 时,这种算法非常有效。但是当系统负载极端沉重时会引起大量 的任务发生时间错误(missing the deadline)。甚至可能导致 CPU时间大量花费在调度上,在这时系统的性能还不如FIFO方法 。根据计算当系统负载超过50%时系统性能急剧下降,所以实际 上没有哪个实时操作系统使用这种方法。 Priority Ceiling算法。这种算法用于抢先式多任务的实时操作 系统。该算法的基本思想是在系统中使用优先级驱动的可抢先的 调度算法。也就是系统首先调度高优先级的任务运行。低优先级 的任务在高优先级的任务运行时不能抢先;CPU由高优先级进程 独占。当中断发生时,正在运行的任务被中断,进入中断处理。 如果中断引起的操作是属于一个较低优先级的任务的,那么为了 保证中断被及时的处理,此低优先级进程暂时继承原来当中断发 生时正在运行的高优先级任务的优先级。当处理完关键区域后, 此低优先级任务恢复原来的优先级并被挂起,然后恢复原来高优 先级任务的运行。这种算法保证了高优先级的任务不会被低优先 级的任务所挂起,即"优先级倒挂"现象的出现。 以上主要讲述了在实时操作系统中应用的调度算法的理论。在实 际上现代实时操作系统中往往将上面提到的调度方式结合起来以 适应各种应用的不同需求。比如操作系统提供基于优先级的抢先 式多任务,也同时允许时间片机制。接下来要讨论一下实时调度 算法的正确性问题。 §2.2.2实时进程调度算法的正确性 实时调度算法的正确性主要是指理论上的调度算法能否保证实时 任务的完成。这里仅仅给出一些结论和简单说明。 1. 当C1/T1+ C2/T2+… Cn-1/Tn-1+ Cn/Tn<=n(21/n-1)=U(n)时 (Ci和Ti分别是任务执行的时间和任务的周期),使用 rate monotonic算法调度的一组相互独立的周期性任务必然能够 完成它们的时间正确性。这个定理给出了最坏情况下的系统表现。 保证了静态实时任务调度的正确性。 2. 对于一个相互独立的实时任务集合来说,如果每个任务当同时 开始运行时能够满足时间正确性的话那么不管它们开始的顺序如 何,它们也总是能够满足时间正确性。换句话说就是如果同时开始 运行时是正确的,那么这些任务的时间正确性与它们开始执行的顺 序无关。这个定理的意义在于允许了动态的实时调度。 §2.3实时系统的内存和外围设备管理 在计算机系统中内存管理主要有两个基本的任务。 第一也是基本的是为系统中运行的许多实时或非 实时任务提供共享的内存。第二是提供虚拟内存 。虚拟内存就是将系统的一部分后备的磁盘空间 作为实际物理内存的扩充。由操作系统管理,对 应用程序完全透明。应用程序所能感觉的只有系 统的物理内存变大了。这对于程序员来说是很方 便的。但是享受虚拟内存的好处的同时也是有代 价的,那就是虚拟内存将一部分最近未用的程序 代码和数据换到硬盘上,当要使用时从硬盘读出 的速度要比内存慢很多。这就引起了问题。应用 不知道什么时候会被换出物理内存,也不知道从 硬盘中换回物理内存所花的时间(也就是这个时 间是不确定的)。这样系统响应的时间就变成不 确定的了。这点在硬实时系统中是致命的。 实际上有很多实时系统是没有硬盘的。它们是嵌 入式实时操作系统。一般来说这样的系统组成规 模都尽可能的小,所以一般没有后备存储器。所 以对于实时操作系统来说内存管理必须高效率和 开销必须是可预见的。一种解决方法是预先分配 内存。就是在系统构造或编译时为每个任务指定 其使用的内存空间。这种方法对于硬实时系统来 说是很合适的。而且嵌入式实时操作系统很多都 是在ROM中运行,仅仅只有需要变化的数据才放在 RAM中。这种系统在组成上无疑是静态的。另一种 方法是系统可以有虚拟内存,但必须给实时任务 提供方法,以便将实时任务"锁"进内存,也就是系 统在管理虚拟内存时,不将"锁"住的内存块换出物 理内存。这样可以提供比较好的响应速度和操作的 可预见性。但是不适合硬实时系统。因为虚拟内存 引起的问题并没有解决。 其实实时操作系统的内核仅仅需要负责为程序分配 内存,动态的分配内存和回收内存。为程序分配内 存指当嵌入式系统从主机上下载程序或带硬盘的系 统从硬盘上获得程序代码时,操作系统内核必须为 程序代码和数据分配内存。这种分配规模比较大, 但是在系统运行时较少发生。一般只有在系统启动 或复位时发生。第二种内存管理要求就是在应用运 行时动态的分配和回收数据。一般的实时应用总是 尽量避免动态的分配内存和释放内存。因为这样一 来增加了系统的不确定性。使系统的稳定性下降。 第二种要求还用于实时任务之间的通信。系统分配 信号量,消息队列等等。第二种要求必须高效率的 实现。必须简单和高效。 实时系统的外围设备管理相对比较简单。因为对于 嵌入式实时系统来说,系统中很少有外设要管理。 即使有也是与某个特定的任务相联系,不需要操作 系统来干预。但是对于实时的事务处理来说外围设 备的管理是不可回避的问题。主要是防止实时任务 的死锁。解决死锁的经典算法是银行家算法。但是 在实际应用中这种方法却因为开销太大而很少用。 现在有很多针对某一类应用的死锁解决方法。但主 要思想还是类似的,就是破坏死锁的循环条件。大 多数系统对于死锁都是采用鸵鸟思想。因此很多商 用实时操作系统中死锁的避免是由应用设计人员完 成的。 §2.4实时系统的通信 在实时操作系统中实时的进程间通信也十分重要。特 别是多处理器的情况,通过系统总线或局域网进行 通信。这里主要讨论在分布式系统中的实时通信。 在实时分布式系统中的通信有着特殊的要求。与普通 的分布式系统不同,也与基于总线的多处理器或单处 理器不同。由于系统中没有可以用来通信的共享内存,进程之间的通信完全依靠网络协议来实现。而现有的 网络协议没有一种是为实时应用设计的。对于实时通 信来说当然是网络速度越快越好了。但光有高速的网 络通道还是不够的。必须有可预见的和有确定开销时 间的网络协议。在分布式系统或网络上实现实时应用 的关键点在于实现可预见的和有确定开销的网络协议。 首先看一下局域网。最常用的ETHERNET从本性上来说 就是一个随机的协议。载波侦听/冲突检测本身是一个随 机的协议。想发送数据的机器可能与网络上的其他机 器发生冲突。一旦发生,就放弃发送,随机等待一段时 间后再次发送。不可能给出最坏情况的上下限,这样 就造成了发送数据所需要的时间的不确定性,而这恰 恰是实时操作系统中不允许的。 另外一种局域网的协议是令牌环网。令牌环网的机制 决定了它可以得到发送数据的开销的上限。每个机器 当要发送数据时,首先要得到令牌。得到令牌的机器 可以发送数据。局域网的长度有限,令牌在网上传输 的速度是一定的,令牌环网上所能容纳的字节数也是 确定的,所以可以确定发送一个包最多所需要的时间 。这样的协议是可以被实时操作系统接受的。而且令 牌环网还可以允许带有优先级,允许优先服务高优先 级的任务的通信请求。要实现这一点,只需要在包头 上加上一个代表优先级的字段即可。当发送数据时, 只有优先级高于当前传输的包的机器才能在当前包发 送完后立即发送。这时发送一定大小的包所用的最大 开销就变成仅仅指定为最高优先级的包才能满足这个 上限。 用于局域网中的通信手段还有TDMA(时分多路复用)。 这种机制中每个机器都在网络上有自己的时间片。通信 被组织成固定大小的帧。每个帧含有n个时隙。时隙与 网络上的机器对应。这样就避免了机器发送时的冲突 。每个机器都有确定的带宽。现代的通信技术提供了 高带宽的传输能力,局域网内的实时通信基本成熟。 在广域网上的实时通信也走向应用。通常这种通信是面 向连接的。当建立连接后,实时通信的质量是得到保证 的。通信质量包括最大延迟时间,包发送速度的最大变 化率,最小带宽等等。为了保证通信质量,事先分配好 内存缓冲,表空间,CPU时间,通信信道等。一般用户 要支付占用这些资源的费用,无论他是否使用这些资源。 广域网上的实时通信的最大问题是在广域网上丢包率非 常高。通常解决这个问题的方法是发送者使用一个时钟 ,当超时时,重发数据。但这样会在系统中引起不可遇 见性。发送一个包的开销不可预见这是不允许在实时操 作系统中存在的。一个简单的解决方法是发送者每次都 将一个包发送两次或更多。这样通信的质量得到了保证 ,无非浪费一些带宽而已。 实时操作系统分为嵌入式和普通系统两种。虽然这两种系统 的规模,应用,性能及可靠性要求都不同,但是这两种实时 操作系统都一般是基于微内核的和模块化的。系统可以在最 小规模下工作时,操作系统仅仅提供一些最基本的服务,大 量的在一般系统中由操作系统完成的任务由开发商提供的作 为应用运行的系统级任务完成。所以商业化的实时操作系统 遵循前面提到的开放的系统标准,系统高度模块化。 实时操作系统的内核必须满足一系列特殊的要求。第一实时 操作系统的内核必须非常小。操作系统的内核小,可以为用 户应用留出空间。另外操作系统所占用的内存小也代表了系 统效率的提高。第二操作系统内核必须是可重入的。这一点 对于实时系统来说特别重要。因为不可重入的内核必然带来 慢速的中断响应和不可预料的操作时间。第三系统能够快速 的进行任务切换。快速的任务切换在满足高优先级的任务抢 先时,提供了完成deadline的保证。第四能够快速的响应外 部中断。正如前面所提到的操作系统的内核必须可重入。将 临界区缩到最小可以提供最大的中断响应效率。第五尽量减 少disable掉中断的时间。第六提供固定的或可变的内存管 理机制。内存管理机制在内核中的实现要求尽可能的简单。 高级的功能可以由系统级进程来完成。第七在系统级任务中 提供可高速访问的文件系统。第八系统维护一个满足应用要 求的实时时钟。因为对实时时钟的要求是随应用程序的要求 而变化的。而且实时时钟是与硬件密切相关的,所以一般是 操作系统提供一个接口,真正的管理是要求硬件提供者或用 户自己提供的。第九实时操作系统必须提供一种合适的进程 调度方法。一般商业化的实时操作系统象pSOS和QNX都是提供 的基于优先级的抢先式的进程调度算法。第十实时操作系统 必须通过使用实时时钟的接口来提供time_outs和time alarm 。 第十一实时操作系统还应该提供允许应用任务来自己修改系统 系统中所有进程的优先级的方法和延迟或挂起别的任务的方法。 这样的实时操作系统应该使用高级语言编写,而且不能带有任 何的与硬件有关的特性。操作系统可以向下定义一组接口。由 用户或硬件的提供者来提供实际操纵硬件的程序。包括系统中 设备的初始化和使用。实时时钟也必须这样管理,这样才能保 证不用为每一种嵌入式系统设计不同的内核。这样嵌入式实时操 作系统内核中需要完成的仅仅是内存管理,进程调度和定义一 系列的接口。以及使用接口的基本功能。更高级一些,可以提供 一种进程间通信的方法。这样的实时操作系统内核已经是完善的 了。操作系统内核并没有必要将所有设备都自己管理。况且在设 计内核时谁都想不到会出现什么样的设备。因此在嵌入式系统中 一般是允许应用直接访问底层的硬件设备的。 有一本RTOS的经典是"ucos,the realtime kernerl" ucos支持很多类型CPU,源代码公开,用户非常多,还有人 给它加了个TCP/IP的外壳,是朝鲜的一个家伙,其实是从linux上面改造的 另外,gnu也已经有了自己的源码公开的RTOS叫ecos,可惜现在不支持X86CPU linux现在也有realtime linux,是在linux上内核外面加一个realtime kernerl 把原来的linux kernel 作为最低级别的任务挂上去。 国外有的大学把它用作实时采集系统的应用场合。 我觉得realtime linux是很有前途的,因为linux上面有强大的网络功能 无论linux内核如何升级,都不影响实时模块。 现在又有了mini linux,很小的那种,不知道是否实现了烧在eeprom里面 启动和运行在ram里? 国外也有了基于linux的机顶盒。 建议大家加入到开发realtime linux的行列来,另外开发一个RTOS就太没必要了 开发一个RTOS内核并不困难,如果不是实现很快的响应速度,很多级别的任务调度 ,支持很多的CPU,还有很多的应用接口和网络功能,否则只有一个内核有什么用呢 就象一辆汽车,你说我们去开发一个发动机有什么困难,但是你知道吗?用户可能 是去抱怨你的汽车上的皮椅怎么那么难坐?!你说我们去开发一个dos有什么困难, 但是开发出来有什么用呢 还是乘上linux这趟快要起飞的企鹅号吧 站在前人的基础上面,增加我们自己的东西,会让自己的成果更有价值!! 嵌入式的应用开发肯定在未来很有前途,realtime linux也肯定在将来让大家大吃 一惊,pSOS,vxworks等等是很好,但是它们可能象linux那样提供一个又一个的新 的功能吗?而且也还是免费的!要买pSOS的网络OSPF路由包,要XXX万美圆,而且 他们提供的bug修复,不可能又linux那么迅速。。。 讨论半天,其实又回到关于源码公开和不公开的讨论,windows和linux的讨论上 去了:) no no RT Linux 是一个linux的扩展.并不是完完全全按照实时的要求来设计的操作 系统内核.所以它的设计中存在着trade off.我之所以要提出开发自己的RT OS.是 为了借这个计划给有兴趣的同学一个锻炼的机会.而且linux本身结构不适合做RT OS. UNIX中存在的问题,linux中都有.UNIX不是也有实时扩展吗?那要别的系统干什么? 提到pSOS昂贵的问题。的确是这样所以我们更需要自己开发这样的系统。 至于内核能干什么。这个问题我在计划中已经提过了。首先要有内核,然后再可以 讨论在内核上设计系统级任务,来实现更高级的功能。另外内核上也可以直接设计 应用就向pSOS一样,大量应用是直接在内核上完成的。其实内核的设计只是万里 长征第一步。以后还要做硬件驱动。交叉编译,调试。系统功能的完善比如增加 网络模块等等。还可以扩展到多处理器。我想作为一个学计算机的学生,参与这样 一个计划无疑是对课堂上学到的知识的综合训练。linux是好,不过她的稳定性,安全 性还值得商榷。要不然不都去用linux了?我们自己的内核,我们应该能够对系统做 出修改和保障。linux呢? 参加RT Linux的开发也是一个好主意。不过各有各的用处。 这些都是我在作论文期间查阅的资料。有兴趣的可以去看看。 1. John A.Stankovic,"Misconceptions About Real_Time computing-A Serious Problem for Next-Generation Systems",IEEE Computer,Vol.21,No.10,October 1988 2. "Real_Time UNIX Systems Design and Application Guide" 3. John A. Stankovic, krithi . Ramamritham,"Advances in Real-Time Systems", IEEE Computer Society Press,1993 4. V.Vande keere,B.Meuris,J.Vandewege,"Embedded Real-Time Intelligence in the Physical Layer of Telecommunication Networks",IEEE Computer Society Press,1993 5. Foundations of Real-Time Computing:scheduling and resource management 6. Software design for real time systems 7. Mechanisms for reliable distributed Real-Time operating system 8. Real-Time system Design Princples for Distributed Embedded Applications 9. Real-Time Systems and Programming Languages 10. Real-Time Systems 11. Lou Salkind,"UNIX for Real-Time Control Problems and Solutions",IEEE Computer ,1988 12. Paul j.Fortier and Michelle Murphy,"Simulation Analysis of Real-Time Task Scheduling",United States Naval Undersea Warfare Center,1994 13. Lui sha and Josh B.Goodenough,"Real-Time Scheduling Theory and Ada",IEEE Computer ,1990 14. Wee K.Ng and Chinya V.Ravishankar,"On-Line Detection and Resolution of communication Deadlocks",IEEE Computer,1994 15. Andrew S.Tanenbaum,"Distributed Operating Systems",Tsinghua University Press,1995

硬实时、软实时(二) 软实时的RTOS一般应用在消费类电子产品,如手持电脑、个人数字助理(PDA)和机顶盒等消费电子类。WinCE。 硬实时的RTOS一般应用于通信、控制和航空航天等实时性强和可靠性高的领域。通信行业使用PSOS、VxWorks、VRTX,航天、航空使用VRTX、VxWorks,工业PC 控制使用QNX 。

实时系统的体系结构设计 实时系统的体系结构必须满足 1.高运算速度 2.高速的中断处理 3.高的I/O吞吐率 5.高速可靠的和有时间约束的通信 6.体系结构支持的出错处理 7.体系结构支持的调度 8.体系结构支持的操作系统 9.体系结构支持的实时语言特性。 10.系统的稳定性和容错也非常重要 11.还要考虑到实时的分布式应用。

实时进程调度算法(一) 静态的周期性调度 FIFO 优先级队列算法 以上的调度算法都是独占的 这种调度算法的基本思想是将处理器的时间分为"帧"。 FIFO 也就是将系统中所有的任务组织成一个队列。先到先服务 优先级队列算法 种算法从FIFO发展而来。给每个任务设定优先级,然后在FIFO中按照优先级排列。这种算法保证了高优先级的任务的完成,但是对于低优先级的任务很可能无法满足时间的正确性。而且对低优先级的任务来说等待的时间是无法预知的。 以上的调度算法都是独占的 即任务运行时,不允许别的任务抢先。完成一个任务后才能完成下一个

实时进程调度算法(二) Rate Monatomic/Pacing算法 Deadline Driven算法 此算法是基于静态优先级调度协议的方法。此算法给系统中每个任务设置一个静态的优先级。这个优先级的设定是在计算任务的周期性和任务需要满足的deadline的时间的长短的基础上完成的。周期越短,deadline越紧迫,优先级越高。 Deadline Driven算法 Deadline Driven算法提供动态的优先级。因为此算法根据任务满足deadline的紧迫性来修改任务的优先级,以保证最紧迫的任务能够及时完成。 Priority Ceiling算法 这种算法用于抢先式多任务的实时操作系统。该算法的基本思想是在系统中使用优先级驱动的可抢先的调度算法。也就是系统首先调度高优先级的任务运行。低优先级的任务在高优先级的任务运行时不能抢先;CPU由高优先级进程独占。

嵌入式系统概述 嵌入式系统 ( Embedded Systems ) 是指以应用为中心、以计算机技术为基础、软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。是将应用程序和操作系统与计算机硬件集成在一起的系统

嵌入式硬件 嵌入式硬件包括处理器/微处理器、存储器及外设器件和I/O端口、图形控制器等 特点: 1)对实时多任务有很强的支持能力,能完成多任务并且有较短的中断响应时间,从而使内部的代码和实时内核心的执行时间减少到最低限度。 2)具有功能很强的存储区保护功能。这是由于嵌入式系统的软件结构已模块化,而为了避免在软件模块之间出现错误的交叉作用,需要设计强大的存储区保护功能,同时也有利于软件诊断。 3)可扩展的处理器结构,以能最迅速地开展出满足应用的最高性能的嵌入式微处理器。 4)嵌入式微处理器必须功耗很低,尤其是用于便携式的无线及移动的计算和通信设备中靠电池供电的嵌入式系统更是如此,如需要功耗只有mW甚至μW级。

嵌入式系统发展趋势 嵌入式应用软件的开发需要强大的开发工具和操作系统的支持。 联网成为必然趋势 支持小型电子设备实现小尺寸、微功耗和低成本 提供精巧的多媒体人机界面

实时系统内存管理 预先分配内存。 在系统构造或编译时为每个任务指定其使用的内存空间。这种方法对于硬实时系统来说是很合适的。而且嵌入式实时操作系统很多都是在ROM中运行,仅仅只有需要变化的数据才放在RAM中。这种系统在组成上无疑是静态的。 虚拟内存 但必须给实时任务提供方法,以便将实时任务“锁”进内存,也就是系统在管理虚拟内存时,不将“锁”住的内存块换出物理内存。

嵌入式系统和实时系统 嵌入式系统经常被误解为就是实时性系统。其实,多数嵌入式系统并不需要实时性 Linux是嵌入式操作系统,并非实时操作系统。 Vxwork、pSOS、Neculeus和Windowss CE 是嵌入式实时操作系统

一、实时多任务

任务状态 实时系统的一个任务可有多种状态,其中最基本的状态有四种: 就绪态:任务只等待系统分配CPU资源; 悬置态:任务需等待某些不可利用的资源而被阻塞; 休眠态:如果系统不需要某一个任务工作,则这个任务处于休眠状态; 延迟态:任务被延迟时所处状态;

任务状态迁移

任务状态迁移函数(一) 就绪态 ----> 悬置态 semTake()/msgQReceive() 就绪态 ----> 延迟态 taskDelay() 就绪态 ----> 休眠态 taskSuspend() 悬置态 ----> 就绪态 semGive()/msgQSend() 悬置态 ----> 休眠态 taskSuspend()

任务状态迁移函数(二) 延迟态 ----> 就绪态 expired delay 延迟态 ----> 休眠态 taskSuspend() 休眠态 ----> 就绪态 taskResume()/taskActivate() 休眠态 ----> 悬置态 taskResume() 休眠态 ----> 延迟态 taskResume()

多任务内核 进行任务管理 VxWorks实时内核Wind提供了基本的多任务环境,系统内核根据某一调度策略让它们交替运行。 任务是竞争系统资源的最小运行单元。任务可以使用或等待CPU、I/O设备及内存空间等系统资源,并独立于其它任务,与它们一起并发运行(宏观上如此)。VxWorks内核使任务能快速共享系统的绝大部分资源,同时有独立的上下文来控制个别线程的执行。 VxWorks实时内核Wind提供了基本的多任务环境,系统内核根据某一调度策略让它们交替运行。 系统调度器使用任务控制块的数据结构(简记为TCB)来管理任务调度功能。

任务控制快(TCB) 任务控制块用来描述一个任务,每一任务都与一个TCB关联。 任务控制块里面包含了: 当前状态、优先级、要等待的事件或资源、任务程序码的起始地址、初始堆栈指针 任务的“上下文”(context)。任务的上下文就是当一个执行中的任务被停止时,所要保存的所有信息。通常,上下文就是计算机当前的状态,也即各个寄存器的内容。 VxWorks中,内存地址空间不是任务上下文的一部分。所有的代码运行在同一地址空间。如每一任务需各自的内存空间,需可选产品VxVMI的支持。

内核管理示意图 Delayed Pended TCB TCB TCB TCB Kernel Ready Executing Suspended TCB CPU TCB TCB TCB

任务上下文切换 当前运行的任务的上下文被存入TCB 将要被执行的任务的上下文从它的TCB中取出,放入各个寄存器中。 上下文切换必须很快速的

优先级调度 基于优先级的抢占式调度法作为缺省策略 同时提供了时间片轮转调度 这种调度方法为每个任务指定不同的优先级。没有处于悬置或休眠态的最高优先级任务将一直运行下去。 当更高优先级的任务由就绪态进入运行时,系统内核立即保存当前任务的上下文,切换到更高优先级的任务。 当有内核调用或有中断到来时,内核重新调度 同时提供了时间片轮转调度 多任务调度须采用一种调度算法来分配CPU给就绪态任务。Wind内核采用基于优先级的抢占式调度法作为它的缺省策略,同时它也提供了轮转调度法。 基于优先级的抢占式调度,它具有很多优点。这种调度方法为每个任务指定不同的优先级。没有处于悬置或休眠态的最高优先级任务将一直运行下去。当更高优先级的任务由就绪态进入运行时,系统内核立即保存当前任务的上下文,切换到更高优先级的任务。

基于优先级的抢占式调度 Wind内核划分优先级为256 级(0~255)。优先级0为最高优先级,优先级255为最低。当任务被创建时,系统根据给定值分配任务优先级。然而,优先级也可以是动态的,它们能在系统运行时被用户使用系统调用taskPrioritySet()来加以改变,但不能在运行时被操作系统所改变。

(Constant - Programmable) 时间片轮转调度 Time Slice Period (Constant - Programmable) A A B B 轮转调度法分配给处于就绪态的每个同优先级的任务一个相同的执行时间片。时间片的长度可由系统调用KernelTimeSlice()通过输入参数值来指定。很明显,每个任务都有一运行时间计数器,任务运行时每一时间滴答加1。一个任务用完时间片之后,就进行任务切换,停止执行当前运行的任务,将它放入队列尾部,对运行时间计数器置零,并开始执行就绪队列中的下一个任务。当运行任务被更高优先级的任务抢占时,此任务的运行时间计数器被保存,直到该任务下次运行时。 C C D D

混合调度策略

KernelTimeSlice(ticks) 内核时间片 时间片的长度可由系统调用 KernelTimeSlice(ticks) 通过输入参数值来指定。 当 ticks为0时,时间片调度被关闭 基于优先级的抢占式调度可以发生在任何时候,时间片轮转调度只能在相同优先级的任务间每隔ticks发生一次。 在VxWorks系统中,可以调用函数kernelTimeSlice来使用时间片轮转调度。

VxWorks任务特性 所有的代码运行在同一地址空间。 任务能快速共享系统的绝大部分资源,同时有自己独立的上下文 所有的任务都运行在特权模式下

共享代码和重入(一) VxWorks提倡单个子程序或子程序库被多个不同的任务调用。例如printf。一个被多个任务调用的单个拷贝称为共享代码。 VxWorks动态链接功能很容易实现代码共享。 共享代码必须是可重入的。 VxWorks的I/O和驱动程序是可重入的。但是要求应用小心设计。对于缓冲(buffer)I/O,VxWorks推荐使用文件指针。

共享代码和重入(二) 大部分VxWorks程序使用下面的重入机制 动态堆栈变量 由信号量保护的全局或静态变量 任务变量 如果程序仅仅是纯代码,除了自己的动态堆栈变量外没有自己的数据,除了调用者以参数传进的数据外,没有其他数据。任务只在自己的堆栈内进行操作。 由信号量保护的全局或静态变量 VxWorks的一些库封装对公共数据的访问。需要借用互斥机制 任务变量 一些程序可能会被多个任务同时调用,这些任务可能要求全局变量和静态变量有不同的值。这种情况下,VxWorks提供了所谓任务变量的机制,这种机制允许在任务上下文中增加4字节的变量,因此每次上下文交换时,改变量的值被保存。 这种机制由taskVarLib库中的函数来提供。

抢占禁止 Wind内核可通过调用taskLock()和taskUnlock()来使调度器起作用和失效。当一个任务调用taskLock()使调度器失效,任务运行时没有基于优先级的抢占发生。然而,如果任务被阻塞或是悬置时,调度器从就绪队列中取出最高优先级的任务运行。当设置抢占禁止的任务解除阻塞,再次开始运行时,抢占又被禁止。这种抢占禁止防止任务的切换,但对中断处理不起作用。

POSIX调度 schedPxLib库提供了POSIX 1003.1b调度函数 POSIX和Wind调度差异 POSIX的优先级编号方案与Wind的方案相反。POSIX中,优先数越高,优先级越高;Wind方案相反。为了解决这种冲突,用户需要通过将默认的全局变量posixPriorityNumbering的设置改委FALSE。 使用POSIX调度程序,需要在配置VxWorks时,包含INCLUDE_POSIX_SCHED宏定义,系统将自动包含POSIX调度程序。

VxWorks怎样满足实时性需求 多任务特性 基于抢占式多任务调度 快速的任务上下文切换 快速确定的系统响应 高效的任务间通讯机制 任务管理(多任务和基于优先级的任务调度) 任务间同步和通信(信号量和共享内存等) 存储器优化管理(含ROM的管理) 实时时钟服务 中断管理服务 VxWorks实时内核分析 1. 实时操作系统的结构    在计算的早期开发的操作系统的最原始的结构形式是一个统一的实体(monolithic)。在这样的系统中,提供的不同功能的模块,如处理器管理、内存管理、输入输出等,通常是独立的。然而他们在执行过程中并不考虑其他正在使用中的模块,各个模块都以相同的时间粒度运行。     由于现代实时环境需要许多不同的功能,以及在这样的环境中存在的并发活动所引起的异步性和非确定性,操作系统变得更加复杂。所以早期操作系统的统一结构的组织已经被更加精确的内部结构所淘汰。 层次结构的起点----内核     操作系统的最好的内部结构模型是一个层次性的结构,最低层是内核。这些层次可以看成为一个倒置的金字塔,每一层都建立在较低层的功能之上。 内核仅包含一个操作系统执行的最重要的低层功能。正象一个统一结构的操作系统,内核提供了在高层软件与下层硬件之间的抽象层。然而,内核仅提供了构造操作系统其他部分所需的最小操作集。 对一个实时内核的要求    一个实时操作系统内核需满足许多特定的实时环境所提出的基本要求,这些包括: 多任务:由于真实世界的事件的异步性,能够运行许多并发进程或任务是很重要的。多任务提供了一个较好的对真实世界的匹配,因为它允许对应于许多外部事件的多线程执行。系统内核分配CPU给这些任务来获得并发性。     抢占调度:真实世界的事件具有继承的优先级,在分配CPU的时候要注意到这些优先级。基于优先级的抢占调度,任务都被指定了优先级, 在能够执行的任务(没有被挂起或正在等待资源)中,优先级最高的任务被分配CPU资源。换句话说,当一个高优先级的任务变为可执行态,它会立即抢占当前正在运行的较低优先级的任务。     快速灵活的任务间的通信与同步:在一个实时系统中,可能有许多任务作为一个应用的一部分执行。系统必须提供这些任务间的快速且功能强大的通信机制。内核也要提供为了有效地共享不可抢占的资源或临界区所需的同步机制。     方便的任务与中断之间的通信:尽管真实世界的事件通常作为中断方式到来,但为了提供有效的排队、优先化和减少中断延时,我们通常希望在任务级处理相应的工作。所以需要杂任务级和中断级之间存在通信。     性能边界:一个实时内核必须提供最坏情况的性能优化,而非针对吞吐量的性能优化。我们更期望一个系统能够始终以50微妙执行一个函数,而不期望系统平均以10微妙执行该函数,但偶尔会以75微妙执行它。     特殊考虑:由于对实时内核的要求的增加,必须考虑对内核支持不断增加的复杂功能的要求。这包括多进程处理,Ada和对更新的、功能更强的处理器结构如RISC的支持。 拥有其它名字的内核     许多商用化的内核支持的功能远强于上面所列的要求。在这方面,他们不是真正的内核,而更象一个小的统一结构的操作系统。因为他们包含简单的内存分配、时钟管理、甚至一些输入输出系统调用的功能。     这种分类不仅仅是在语义上的争论,在这篇文章的后面章节将说明限制内核功能和油画这些功能的重要性。 2. VxWorks内核:Wind    VxWorks操作系统是一种功能最全的现在可以获得的独立于处理器的实时系统。然而,VxWorks是带有一个相当小的真正微内核的层次结构。内核仅提供多任务环境、进程间通信和同步功能。这些功能模块足够支持VxWorks在较高层次所提供的丰富的性能的要求。 通常内核操作对于用户是不可见的。应用程序为了实现需要内核参与的任务管理和同步使用一些系统调用,但这些调用的处理对于调用任务是不可见的。应用程序仅链接恰当的VxWorks例程(通常使用VxWorks的动态链接功能),就象调用子程序一样发出系统调用。这种接口不象有些系统需要一个笨拙的跳转表接口,用户需要通过一个整数来指定一个内核功能调用。 多任务     内核的基本功能是提供一个多任务环境。多任务使得许多程序在表面上表现为并发执行,而事实上内核是根据基本的调度算法使他们分段执行。每个明显独立的程序被成为一个任务。每个任务拥有自己的上下文,其中包含在内核调度使该任务执行的时候它所看到的CPU环境和系统资源。 任务状态    内核维护系统中的每个任务的当前状态。状态迁移发生在应用程序调用内核功能服务的时候。下面定义了wind内核状态:     就绪态----一个任务当前除了CPU不等待任何资源     阻塞态----一个任务由于某些资源不可获得而被阻塞    延迟态----一个任务睡眠一段时间     挂起态----主要用于调试的一个辅助状态,挂起禁止任务的执行     任务被创建以后进入挂起态,需要通过特定的操作使被创建的任务进入就绪态,这一操作执行速度很快,使应用程序能够提前创建任务,并以一种快捷的方式激活该任务。 调度控制     多任务需要一个调度算法分配CPU给就绪的任务。在VxWorks中默认的调度算法是基于优先级的抢占调度,但应用程序也可以选择使用时间片轮转调度。     基于优先级抢占调度:基于优先级的抢占调度,每个任务被指定一个优先级,内核分配CPU给处于就绪态的优先级最高的任务。调度采用抢占的方式,是因为当一个优先级高于当前任务的任务变为就绪态时,内核将立即保存当前任务的上文,并切换到高优先级任务的上文。VxWorks有从0到255共256个优先级。在创建的时候任务被指定一个优先级,在任务运行的过程中可以动态地修改优先级以便跟踪真实世界的事件优先级。外部中断被指定优先于任何任务的优先级,这样能够在任何时候抢占一个任务。     时间片轮转:基于优先级抢占调度可以扩充时间片轮转调度。时间片轮转调度允许在相同优先级的处于就绪态的任务公平地共享CPU。没有时间片轮转调度,当有多个任务在同一优先级共享处理器时,一个任务可能独占CPU,不会被阻塞直到被一个更高优先级的任务抢占,而不给同一优先级的其他任务运行的机会。如果时间片轮转被使能,执行任务的时间计数器在每个时钟滴答递增。当指定的时间片耗尽,计数器会被清零,该任务被放在同一优先级任务队列的队尾。加入特定优先级组的新任务被放在该组任务的队尾,并将运行计数器初始化为零。 基本的任务函数     用于状态控制的基本任务函数包括一个任务的创建、删除、挂起和唤醒。一个任务也可以使自己睡眠一个特定的时间间隔不去运行。     许多其他任务例程提供由任务上下文获得的状态信息。这些例程包括访问一个任务当前处理器寄存器控制。 任务删除问题     wind内核提供防止任务被意外删除的机制。通常,一个执行在临界区或访问临界资源的任务要被特别保护。我们设想下面的情况:一个任务获得一些数据结构的互斥访问权,当它正在临界区内执行时被另一个任务删除。由于任务无法完成对临界区的操作,该数据结构可能还处于被破坏或不一致的状态。而且,假想任务没有机会释放该资源,那麽现在其他任何任务现在就不能获得该资源,资源被冻结了。    任何要删除或终止一个设定了删除保护的任务的任务将被阻塞。当被保护的任务完成临界区操作以后,它将取消删除保护以使自己可以被删除,从而解阻塞删除任务。     正如上面所展示的,任务删除保护通常伴有互斥操作。     这样,为了方便性和效率,互斥信号量包含了删除保护选项。(参见“互斥信号量”) 任务间通信     为了提供完整的多任务系统的功能,wind内核提供了一套丰富的任务间通信与同步的机制。这些通信功能使一个应用中各个独立的任务协调他们的活动。 共享地址空间     wind内核的任务间通信机制的基础是所有任务所在的共享地址空间。通过共享地址空间,任务能够使用共享数据结构的指针自由地通信。管道不需要映射一块内存区到两个互相通信任务的寻址空间。    不幸的是,共享地址空间具有上述优点的同时,带来了未被保护内存的重入访问的危险。UNIX操作系统通过隔离进程提供这样的保护,但同时带来了对于实时操作系统来说巨大的性能损失。 互斥操作    当一个共享地址空间简化了数据交换,通过互斥访问避免资源竞争就变为必要的了。用来获得一个资源的互斥访问的许多机制仅在这些互斥所作用的范围上存在差别。实现互斥的方法包括禁止中断、禁止任务抢占和通过信号量进行资源锁定。  中断禁止:最强的互斥方法是屏蔽中断。这样的锁定保证了对CPU的互斥访问。这种方法当然能够解决互斥的问题,但它对于实时是不恰当的,因为它在锁定期间阻止系统响应外部事件。长的中断延时对于要求有确定的响应时间的应用来说是不可接受。      抢占禁止:禁止抢占提供了强制性较弱的互斥方式。 当前任务运行的过程中不允许其他任务抢占,而中断服务程序可以执行。这也可能引起较差的实时响应,就象被禁止中断一样,被阻塞的任务会有相当长时间的抢占延时,就绪态的高优先级的任务可能会在能够执行前被强制等待一段不可接受的时间。为避免这种情况,在可能的情况下尽量使用信号量实现互斥。     互斥信号量:信号量是用于锁定共享资源访问的基本方式。不象禁止中断或抢占,信号量限制了互斥操作仅作用于相关的资源。一个信号量被创建来保护资源。VxWorks的信号量遵循Dijkstra的P()和V()操作模式。     当一个任务请求信号量,P(), 根据在发出调用时信号量的置位或清零的状态, 会发生两种情况。如果信号量处于置位态, 信号量会被清零,并且任务立即继续执行。如果信号量处于清零态,任务会被阻塞来等待信号量。     当一个任务释放信号量,V(),会发生几种情况。如果信号量已经处于置位态,释放信号量不会产生任何影响。如果信号量处于清零态且没有任务等待该信号量,信号量只是被简单地置位。如果信号量处于清零态且有一个或多个任务等待该信号量,最高优先级的任务被解阻塞,信号量仍为清零态。     通过将一些资源与信号量关联,能够实现互斥操作。当一个任务要操作资源,它必须首先获得信号量。只要任务拥有信号量,所有其他的任务由于请求该信号量而被阻塞。当一个任务使用完该资源,它释放信号量,允许等待该信号量的另一个任务访问该资源。     Wind内核提供了二值信号量来解决互斥操作所引起的问题。 这些问题包括资源拥有者的删除保护,由资源竞争引起的优先级逆转。     删除保护----互斥引起的一个问题会涉及到任务删除。在由信号量保护的临界区中,需要防止执行任务被意外地删除。删除一个在临界区执行的任务是灾难性的。资源会被破坏,保护资源的信号量会变为不可获得,从而该资源不可被访问。通常删除保护是与互斥操作共同提供的。由于这个原因,互斥信号量通常提供选项来隐含地提供前面提到的任务删除保护的机制。     优先级逆转/优先级继承----优先级逆转发生在一个高优先级的任务被强制等待一段不确定的时间以便一个较低优先级的任务完成执行。考虑下面的假设:     T1,T2和T3分别是高、中、低优先级的任务。T3通过拥有信号量而获得相关的资源。当T1抢占T3,为竞争使用该资源而请求相同的信号量的时候,它被阻塞。如果我们假设T1仅被阻塞到T3使用完该资源为止,情况并不是很糟。毕竟资源是不可被抢占的。然而,低优先级的任务并不能避免被中优先级的任务抢占,一个抢占的任务如T2将阻止T3完成对资源的操作。这种情况可能会持续阻塞T1等待一段不可确定的时间。这种情况成为优先级逆转,因为尽管系统是基于优先级的调度,但却使一个高优先级的任务等待一个低优先级的任务完成执行。     互斥信号量有一个选项允许实现优先级继承的算法。优先级继承通过在T1被阻塞期间提升T3的优先级到T1解决了优先级逆转引起的问题。这防止了T3,间接地防止T1,被T2抢占。通俗地说,优先级继承协议使一个拥有资源的任务以等待该资源的任务中优先级最高的任务的优先级执行。当执行完成,任务释放该资源并返回到它正常的或标准的优先级。因此,继承优先级的任务避免了被任何中间优先级的任务抢占。 同步     信号量另一种通常的用法是用于任务间的同步机制。在这种情况下,信号量代表一个任务所等待的条件或事件。最初,信号量是在清零态。一个任务或中断通过置位该信号量来指示一个事件的发生。等待该信号量的任务将被阻塞直到事件发生、该信号量被置位。一旦被解阻塞,任务就执行恰当的事件处理程序。信号量在任务同步中的应用对于将中断服务程序从冗长的事件处理中解放出来以缩短中断响应时间是很有用的。 消息队列    消息队列提供了在任务与中断服务程序或其他任务间交换变长消息的一种较低层的机制。这种机制在功能上类似于管道,但有较少的开销。 管道、套接字、远程过程调用和更多     许多高层的VxWorks机制提供任务间通信的更高层的抽象,包括管道、TCP/IP套接字、远程过程调用和更多。为了保持裁减内核为仅包含足够支持高层功能的一个最小函数集的设计目标,这些特性都是基于上面描述的内核同步方式的。 3. 内核设计的优点     wind内核的一个重要的设计特性是最小的抢占延时。其他的主要设计的优点包括史无前例的可配置性,对不可预见的应用需求的可扩展性,在各种微处理器应用开发中的移植性。 最小的抢占延时     正如前面所讨论的,禁止抢占是获得代码临界资源互斥操作的通常手段。这种技巧的不期望的负面影响是高的抢占延时,这可以通过尽量使用信号量实现互斥和保持临界区尽量紧凑被减小。但即使广泛地使用信号量也不能解决所有的可能导致抢占延时的根源。内核本身就是一个导致抢占延时的根源。为了理解其原因,我们必须更好地理解内核所需的互斥操作。 内核级和任务级     在任何多任务系统中,大量的应用是发生在一个或多个任务的上下文。然而,有些CPU时间片不在任何任务的上下文。这些时间片发生在内核改变内部队列或决定任务调度。在这些时间片中,CPU在内核级执行,而非任务级。     为了内核安全地操作它的内部的数据结构,必须有互斥操作。内核级没有相关的任务上下文,内核不能使用信号量保护内部链表。内核使用工作延期作为实现互斥的方式。当有内核参与时,中断服务程序调用的函数不是被直接激活,而是被放在内核的工作队列中。内核完成这些请求的执行而清空内核工作队列。     当内核正在执行已经被请求服务时系统将不响应到达内核的函数调用。可以简单地认为内核状态类似于禁止抢占。如前面所讨论的,抢占延时在实时系统中是不期望有的,因为它增加了对于会引起应用任务重新调度的事件的响应时间.     管操作系统在内核级(此时禁止抢占)完全避免消耗时间是不可能的,但减少这些时间是很重要的。这是减少由内核执行的函数的数量的主要原因, 也是不采用统一结构的系统设计方式的原因。例如,有一种流行的实时操作系统的每个函数都是在内核级执行。这意味着当一个低优先级的任务在执行分配内存、获得任务信息的函数时所有高优先级的任务被禁止抢占。 一个最小的内核     已经说明了一个最小内核的优点和构造高层操作系统功能的必要功能,我们使用这些操作原语来执行一个传统的内核级功能,而在VxWorks中作为任务级功能执行,内存管理。 在这个例子中,考虑用户可调用的子例程malloc, 用于分配所请求大小的内存区并返回一个指向该内存区的指针。假定空闲内存区是通过搜索一个空闲内存块的队列找到的,一个信号量必须被用来保护这个非抢占多用户资源。分配内存的操作如下:     获得互斥信号量     搜索空闲内存块链表     释放互斥信号量     值得注意的是搜索一个足够大的空闲内存块的可能的冗长的时间是发生在调用任务的上下文中。这是可以被高优先级的任务抢占的(除了信号量调用的这段执行时间)。     在一个标准的统一结构的实时内核中,内存分配例程操作如下:     进入内核     搜索空闲内存块链表     退出内核     整个内存分配发生在内核级,任务抢占被禁止如果高优先级的任务在此时变为就绪态,它必须等待直到内核为低优先级的任务完成内存分配。有些操作系统甚至在这段市时间禁止中断。 任务级操作系统服务     Wind River System的实时操作系统,VxWorks,显示了这样设计的一个最小内核是能够满足需求的。VxWorks是现在能够获得的独立于任何处理器的、拥有相当小内核的、功能完全的层次结构的实时操作系统。     VxWorks在内核之上提供了大量的功能。它包括内存管理,一个完整的BSD4.3网络包,TCP/IP,网络文件系统(NFS),远程过程调用(RPC),UNIX兼容的链接加载模块,C语言的解释界面,各种类型的定时器,性能监测组件,调试工具,额外的通信工具如管道、信号和套接字,I/O和文件系统,和许多功能例程。这些都不是运行在内核级,所以不会禁止中断或任务抢占。 可配置性     实时应用有多种内核需求。没有哪个内核有一个用来满足每种需求的很好的设计折衷。然而,一个内核可以通过配置来调整特定的性能特性,裁减实时系统来最好地适应一个应用的要求。不可预见的内核配置性以用户可选择的内核排队算法的形式提供给应用。 排队策略     VxWorks中的排队库是独立于使用他们的内核队列功能而执行的,这样提供了将来增加新的排队方式的灵活性。     在VxWorks中有各种内核队列。就绪队列是一个按优先级索引的所有等待调度的任务队列。滴答队列用于定时功能。信号量是一个等待信号量的被阻塞任务的链表。活动队列是一个系统中所有任务的一个先进先出(FIFO)的链表。这些队列中的每个队列都需要一个不同的排队算法。这些算法不是被内嵌在内核中,而是被抽取到一个自治的、可转换的排队库中。这种灵活的组织形式是满足特殊的配置需求的基础。可扩展性    支持不可预见的内核扩展的能力与以有功能的可配置性是同样重要的。简单的内核接口和互斥方法使内核级功能扩展相当容易; 在某些情况下,应用可以仅利用内核钩子函数来实现特定的扩展。 内部钩子函数     为了不修改内核而能够向系统增加额外的任务相关的功能,VxWorks提供了任务创建、切换和删除的钩子函数。这些允许在任务被创建、 上下文切换和任务被删除的时候额外的例程被调用执行。这些钩子函数可以利用任务上下文中的空闲区创建wind内核的任务特性。 未来考虑     有许多系统函数现在变得越来越重要,而且会影响到内核设计时的抢占延时。尽管涉及这些问题一个完整的讨论超出了本文的范围,但值得简单地提一下。 RISC/CISC    设计一个独立于CPU的操作系统一直是一个挑战。随着新的RSIC(精简指令集)处理器变得很流行,这些难度也加大了。为了在RISC环境下有效地执行,内核和操作系统需要有执行不同策略的灵活性。     例如,考虑在任务切换时内核执行的例程。在CISC(复杂指令集,如680x0或80x86)CPU,内核为每个任务存储一套完整的寄存器,在运行任务的时候将这些寄存器换入换出。在一个RISC机器上,这样是不合理的,因为涉及到太多的寄存器。所以内核需要一个更精密复杂的策略,如为任务缓存寄存器,允许应用指定一些寄存器给特殊的任务。移植性    为了使wind内核在他们出现的结构上能够运行,需要有一个可移植的内核版本。这使移植是可行的,但不是最优化的。 多处理     支持紧耦合的多处理需求要求实时内核的内部功能包含,在理想情况下,在远端请求内核调用,如从一个处理器到另一个处理器。这就要涉及到信号量调用(为处理器间同步)和任务调用(为了控制另一个CPU上的任务)。这种复杂性无疑会增加内核级功能调用的开销,但是许多服务如对象标识可以在任务级执行。在多处理系统中保持一个最小内核的优点是处理器之间的互锁可以有较好的时间粒度。大的内核将在内核级消耗额外的时间,仅能获得粗糙的互锁时间粒度。 Ada    Ada语言为实时系统设计者提供了象聚会机制这样的任务原语。异常处理、任务终止、终止替换和聚会都将潜在地影响内核设计。这些操作可以由前面讨论的任务和同步机制构造,为了保持减小抢占延时的设计目标,许多工作能够在任务级执行。 4. 实时内核的重要尺度     许多性能特性被用来比较以有的实时内核,这些包括:    快速的任务上下文切换----由于实时系统的多任务的特性,系统能够快速地从一个任务切换到另一个任务是很重要的。在分时系统中,如UNIX,上下文切换是在ms级。Wind内核执行原始上下文切换只用17us。     最小的同步开销----因为同步是实现资源互斥访问的基本方法,这些操作所引起的开销最小化是很重要的。在VxWorks中,请求和释放二值信号量仅用8us。     最小的中断延时----因为外部世界来的事件通常以中断的形式到来,操作系统快速的处理这些中断是很重要的。内核在操作一些临界数据结构的时候必须禁止中断。为了减小中断延时,必须使这些时间最小化。Wind内核的中断延时小于10us。 抢占延时对性能指标的影响     当许多的实时解决方案被提交给应用工程师时, 性能指标对于评估供应商的产品变得越来越重要。不象上下文切换和中断延时,抢占延时很难测量。所以它很少在说明中被提及。但是考虑到当内核通常禁止上下文切换会长达数百微妙,而声称一个50us的固定长度(与任务个数无关)的上下文切换时间是毫无意义的。除了很难测量外,抢占延时可能会削弱许多性能指标的有效性。     Wind内核通过减小内核的大小来尽量减小抢占延时。 包含繁多功能的内核必将引起长的抢占延时。 5. 结论     为了满足对实时内核日益增加的要求,如新的调度算法、多处理、Ada和RISC结构,wind内核始终以灵活性和可配置性为设计目标。它所提供的优秀的运行性能将成为实时应用需求新标准。

Real-Time Multitasking Introduction Task Basics Task Control Error Status System Tasks

Overview Low level routines to create and manipulate tasks are found in taskLib. A VxWorks task consists of: A stack (for local storage of automatic variables and parameters passed to routines). A TCB (for OS control) Do not confuse executable code with the task(s) which execute it. Code is downloaded before tasks are spawned. Several tasks can execute the same code (e.g., printf()).

Creating a Task taskSpawn Stack TCB PC foo () { ... }

Creating a Task int taskSpawn (name, priority, options, stackSize, entryPt, arg1, ..., arg10) name Task name, if NULL gives a default name. priority Task priority, 0-255. options Task options e.g. VX_UNBREAKABLE. stackSize Size of stack to be allocated in bytes. entryPt Address of code to start executing (initial PC) arg1, ..., arg10 Up to 10 arguments to entry point routine. Returns a task id or ERROR if unsuccessful.

Task ID’s Assigned by kernel when task is created. Unique to each task. Efficient 32-bit handle for task. May be reused after task exists. A task id of zero refers to task making call (self). Relevant taskLib routines: taskIdSelf() Get ID of calling task. taskIdListGet() Fill array with ID’s of all existing tasks. taskIdVerify() Verify a task ID is valid.

Task Names Provided for human convenience. Typically used only from the shell (during development). Within programs, use task Ids. By convention, start with a t. Promotes interpretation as a task name. Default is an ascending integer following a t. Doesn’t have to be unique (but usually is). Relevant taskLib routines. taskName() Get name from tid. taskNameToId() Get tid from task name.

Task Priorities Range from 0 (highest) to 255 (lowest). No hard rules on how to set priorities. There are two (often contradictory) “rules of thumb”: More important = higher priority. Shorter deadline = higher priority. Can manipulate priorities dynamically with: taskPriorityGet (tid, &priority) taskPrioritySet (tid, priority)

Task Stacks Allocated from memory pool when task is created. Fixed size after creation. The kernel reserves some space from the stack, making the stack space actually available slightly less than the stack space requested. Exceeding stack size (“stack crash”) causes unpredictable system behavior.

Stack Overflows To check for a stack overflow use the Browser. Press the check-stack button: Examine the high-water mark indicator in the stack display window. High-water Mark Indicator (UNIX) Note: In the PC Browser Stack Check Window, the high water makr triangles are not present. Instead, the number displayed inside each stack bar is that stack’s high water mark. The filled portion of the bar indicates the current stack usage graphically.

Task Options Can be bitwise or’ed together when the task is created. VX_FP_TASK Add floating point support. VX_NO_STACK_FILL Don’t fill stack with 0xee’s. VX_UNBREAKABE Disable breakpoints. VX_DEALLOC_STACK Deallocate stack and TCB when task exists (automatically set for you). Use taskOptionsGet() to inquire about a task’s options. Use taskOptionsSet() to unset VX_DEALLOC_STACK.

Task Creation During time critical code, task creation can be unacceptably time consuming. To reduce creation time, a task can be spawned with the VX_NO_STACK_FILL option bit set. Alternatively, spawn a task at system start-up, which blocks immediately, and waits to be made ready when needed.

Task Deletion taskDelete(tid) exit (code) Deletes the specified task. Deallocates the TCB and stack. exit (code) Analogous to a taskDelete() of self. code parameter gets stored in the TCB field exitCode. TCB may be examined for post-mortem debugging by Unsetting the VX_DEALLOC_STACK option or, Using a delete hook.

Resource Reclamation Contrary to the philosophy of sharing system resources among all tasks. Can be an expensive process, which must be the application’s responsibility. TCB and stack are the only resources automatically reclaimed. Tasks are responsible for cleaning up after themselves. Deallocating memory. Releasing locks to system resources. Closing files which are open. Deleting child / client tasks when parent / server exits.

Real-Time Multitasking Introduction Task Basics Task Control Error Status System Tasks

Task Restart taskRestart (tid) Task is terminated and respawned with original arguments and tid. Usually used for error recovery.

Task Suspend / Resume taskSuspend (tid) Makes task ineligible to execute. Can be added to pended or delayed state. taskResume (tid) Removes suspension. Usually used for debugging and development purposes.

Task Delay To delay a task for a specified number of system clock ticks. STATUS taskDelay (ticks) To poll every 1/7 second: FOREVER { taskDelay (sysClkRateGet() / 7); ... } Accurate only if clock rate is a multiple of seven ticks / seconds. Can suffer from “drift.” Use sysClkRateSet() to change the clock rate.

Reentrancy and Task Variables If tasks access the same global or static variables, the resource can become corrupted (called a race condition). Possible Solutions: Use only stack variables in applications. Protect the resource with a semaphore. Use task variables to make the variable private to a task Task Variables cause a 32-bit value to be saved and restored on context switchs, like a register. Caveat: task variables increase context switch times. See the taskVarLib manual pages for details.

Task Hooks User-defined code can be executed on every context switch, at task creation, or at task deletion: taskSwitchHookAdd () taskCreateHookAdd () taskDeleteHookAdd () VxWorks uses a switch hook to implement task variables. See manual pages on taskHookLib for details.

Task Information ti (taskNameOrId) Like i(), but also displays: Stack information Task options CPU registers FPU registers (if the VX_FP_TASK option bit is set) Can also use show (): -> show (tNetTask, 1)

Task Browser To obtain information about a specific task, click on the task’s summary line in the main target browser.

What is POSIX ? Originally, an IEEE committee convened to create a standard interface to UNIX for: Increased portability. Convenience. VxWors supports almost all of the 1003.1b POSIX Real-time Extensions. The POSIX real-time extensions are based on implicit assumptions about the UNIX process model which do not always hold in VxWorks. In VxWorks, Context switch times are very fast. Text, data, and bss are stored in a common, global address space.

What does VxWorks support ? Library Description aioPxLib Asynchornous I/O semPxLib POSIX Semaphores mqPxLib POSIX Message Queues mmanPxLib POSIX Memory Management schedPxLib POSIX Scheduler Interface sigLib POSIX Signals timerLib, clockLib POSIX Timer/Clock Interface dirLib File/Directory Information

Real-Time Multitasking Introduction Task Basics Task Control Error Status System Tasks

VxWorks里使用一个全局整型变量errno来描述错误信息 Error Status VxWorks里使用一个全局整型变量errno来描述错误信息 程序执行过程中我们可以设置并调用一些函数例程来检测错误信息,并针对错误信息设置相应的错误号 然后调用一些函数例程检测错误号,当程序执行异常时可以根据错误号发现相应的错误 VxWorks中的errno由两种不同的方式同时定义。在ANSI C中有一个潜在的命名为errno的全局变量,它可以在Tornado 开发工具中显示;errno同时作为一个宏也定义在errno.h中。对VxWorks而言,除一个函数外,其他所有的的部分均可操作errno宏。 #define errno (*__errno()) __errno()函数返回全局变量errno的地址(这个函数不能调用使用自身的宏errno)。 不要使用与errno名字相同的局部变量。

Errno and Context Switches At each context switch, the kernel saves and restores the value of errno. errno TCB errorStatus VxWorks把errno作为每个任务的上下文,在每次任务上下文交换时,errno将同时被保存与恢复。

Setting Errno Lowest level routine to detect an error sets errno and returns ERROR: STATUS myRoutine () { ... if (myNumFlurbishes >= MAX_FLURBISH) errno = s_myLib_TOO_MANY_FLURBISHES; return (ERROR); } … pMem=malloc(sizeof(myStruct)); if ( pMem== NULL) /* malloc() sets errno - don’t redefine it */ 在大多数情况下,函数在返回一个错误指示时,也将设置errno值来指明发生的是哪种特定错误。VxWorks程序从不会清除全局变量errno,因此它的值总是由最后发生的错误状态设置。如果一个VxWorks子程序在调用其他程序时得到一个错误,它通常返回自己的错误指示,而不去修改errno。因此在底层程序设置的errno值作为一个错误类型的指示仍然有效。 例如: 中断连结函数intConnect(),它将一个硬件中断与某一用户程序相联系,调用malloc()来分配内存,在所分配的内存中建立中断处理程序。如果系统没有足够内存,调用malloc()会失败,它设置errno来指明内存分配库memLib遇到这种没有足够内存(“insufficient memory”)用于分配上的错误。Malloc()然后返回NULL来表示分配失败。intConnect()函数接受由mallo()返回的NULL,返回它自己的错误指示ERROR。然而,它没有改变errno,errno仍然是由malloc()设置的“insufficient memory” if ((pNew=malloc(CHUNK_SIZE))==NULL) return(ERROR); 推荐用户在自己的子程序中使用这种机制。

Examining Errno Examine errno to find out why a routine failed. if (reactorOk() == ERROR) { switch (errno) case S_rctorLib_TEMP_DANGER_ZONE: startShutDown (); break; case S_rctorLib_TEMP_CRITICAL_ZONE: logMsg (“Run!”); case S_rctorLib_LEAK_POSSIBLE: checkVessel (); default: startEmergProc (); } errno is only valid after an error occurs.

Interpreting Errno VxWorks uses the 32-bit value errno as follows: 31 15 0 module error number Module numbers are defined in vwModNum.h. Each module defines its own error numbers in its header file. For example, an errno of 0x110001 would be: Module number 0x11 (define in vwModNum.h to be memLib) and Error number 0x01 (defined in memLib.h to be “not enough memory”).

Error Messages VxWorks uses an error symbol table (statSymTbl) to convert error numbers to error messages. To print the error message for the current task’s error status to STD_ERR: -> perror (“darn”) darn: S_netDrv_NO_SUCH_FILE_OR_DIR To print the error message associated with an error number to the WindSh console : -> printErrno (0x110001) S_memLib_NOT_ENOUGH_MEMORY

User-Defined Error Codes To get perror() to print your error messages: 1. Modify vwModNum.h to reserve a module number: #define M_myLib (501 << 16) 2. Define error macros in your header file (which must be in the wind/target/h directory): #define S_myLib_BAD_STUFF (M_myLib | 1) 3. Rebuild the system error table: Go to the wind/target/src/usr directory. remove statTbl.c Execute the makefile. 4. Rebuild VxWorks with the new error table built in.

Real-Time Multitasking Introduction Task Basics Task Control Error Status System Tasks

System Tasks Task Name Priority Function tUsrRoot 0 Initial task. Configures the system, spawns the shell, then exits. tLogTask 0 Message logging. tExecTask 0 Exeption handling. tWdbTask 3 WDB running agent. tNetTask 50 Task-level network functions. tFtpdTask 55 FTP server. 根任务 日志任务 异常处理任务 网络任务 目标代理任务

Summary Real-time multitasking requirements: Preemptive priority-based scheduler. Low overhead. Task properties stored in task’s TCB. OS control information (priority, stack size, options, state, ...). CPU context (PC, SP, CPU registers, ...). taskSpawn() lets you specify intrinsic properties : Priority Stack size Options

Summary Task manipulation routines in taskLib: taskSpawn / taskDelete taskDelay taskSuspend / taskResume Task information ti / show Task Browser Additional task context : errno Task variables Task hooks

Semaphores

概述 信号量是最早出现的用来解决进程同步与互斥问题的机制,包括一个称为信号量的变量及对它进行的两个原语操作。 信号量作为任务间同步和互斥的机制,是快速和高效的,它们除了被应用在开发设计过程中外,还被广泛地应用在 VxWorks 高层应用系统中。 二进制信号量 计数信号量 互斥信号量 POSIX 信号量 二进制信号量: 用于同步或互斥 互斥信号量:为解决具有内在的互斥问题、优先级继承、删除安全和递归等情况的特殊的二进制信号量 计数器信号量:类似于二进制信号量,但是随信号量释放的次数改变而改变。适合于一个资源的多个实例需要保护的情形 等待一个信号量的任务可以按优先级(SEM_Q_PRIORITY)或先进先出(SEM_Q_FIFO)的顺序排队

信号量的类型定义 每个信号量至少须记录两个信息:信号量的值和等待该信号量的进程队列。它的类型定义如下:(用类PASCAL语言表述)     semaphore = record          value: integer;          queue: ^PCB;        end;   其中PCB是进程控制块,是操作系统为每个进程建立的数据结构。 s.value>=0时,s.queue为空; s.value<0时,s.value的绝对值为s.queue中等待进程的个数; 1. 生产者-消费者问题(有buffer) 问题描述: 一个仓库可以存放K件物品。生产者每生产一件产品,将产品放入仓库,仓库满了就停止生产。消费者每次从仓库中去一件物品,然后进行消费,仓库空时就停止消费。 解答: 进程:Producer - 生产者进程,Consumer - 消费者进程 共有的数据结构: buffer: array [0..k-1] of integer; in,out: 0..k-1; — in记录第一个空缓冲区,out记录第一个不空的缓冲区 s1,s2,mutex: semaphore; — s1控制缓冲区不满,s2控制缓冲区不空,mutex保护临界区; 初始化s1=k,s2=0,mutex=1 producer(生产者进程): Item_Type item; { while (true) produce(&item); p(s1); p(mutex); buffer[in]:=item; in:=(in+1) mod k; v(mutex); v(s2); } consumer(消费者进程): p(s2); item:=buffer[out]; out:=(out+1) mod k; v(s1); consume(&item);

PV原语(一) 对一个信号量变量可以进行两种原语操作:p操作和v操作,定义如下:  procedure p(var s:samephore);      {        s.value=s.value-1;        if (s.value<0) asleep(s.queue);      }   procedure v(var s:samephore);      {        s.value=s.value+1;        if (s.value<=0) wakeup(s.queue);      } 3. 哲学家问题 问题描述: 一个房间内有5个哲学家,他们的生活就是思考和进食。房间里有一张圆桌,中间放着一盘通心粉(假定通心粉无限多)。桌子周围放有五把椅子,分别属于五位哲学家每两位哲学家之间有一把叉子,哲学家进食时必须同时使用左右两把叉子。 解答: 进程:philosopher - 哲学家 共有的数据结构&过程: state: array [0..4] of (think,hungry,eat); ph: array [0..4] of semaphore; — 每个哲学家有一个信号量,初值为0 mutex: semaphore; — mutex保护临界区,初值=1 procedure test(i:0..4); { if ((state[i]=hungry) and (state[(i+1)mod 5]<>eating) and (state[(i-1)mod 5]<>eating)) { state[i]=eating; V(ph[i]); } philosopher(i:0..4): while (true) think(); p(mutex); state[i]=hungry; test(i); v(mutex); p(ph[i]); eat(); state[i]=think; test((i-1) mod 5); test((i+1) mod 5);

PV原语(二) 其中用到两个标准过程:   asleep(s.queue);执行此操作的进程的PCB进入s.queue尾部,进程变成等待状态   wakeup(s.queue);将s.queue头进程唤醒插入就绪队列 s.value初值为1时,可以用来实现进程的互斥。 p操作和v操作是不可中断的程序段,称为原语。如果将信号量看作共享变量,则pv操作为其临界区,多个进程不能同时执行,一般用硬件方法保证。一个信号量只能置一次初值,以后只能对之进行p操作或v操作。 信号量机制必须有公共内存,不能用于分布式操作系统,这是它最大的弱点。 2. 第一类读-写者问题 问题描述: 一些读者和一些写者对同一个黑板进行读写。多个读者可同时读黑板,但一个时刻只能有一个写者,读者写者不能同时使用黑板。对使用黑板优先级的不同规定使读者-写者问题又可分为几类。第一类问题规定读者优先级较高,仅当无读者时允许写者使用黑板。 解答: 进程:writer - 写者进程,reader - 读者进程 共有的数据结构: read_account:integer; r_w,mutex: semaphore; — r_w控制谁使用黑板,mutex保护临界区,初值都为1 reader - (读者进程): { while (true) p(mutex); read_account++; if(read_account=1) p(r_w); v(mutex); read(); read_account--; if(read_account=0) v(r_w);; } writer - (写者进程): write();

Binary Semaphores and Synchronization Overview Binary Semaphores and Synchronization Mutual Exclusion B:二值信号量,count取值范围是0和1;        C:多值信号量,count取值范围是整数;        M:是操作上受限的二值信号量,任务对该信号量有拥有关系,          可以实现删除安全和优先级继承安全的机制

The synchronization Problem myGetData () { requestData (); waitForData (); getData (); } Task 编程过程中的同步问题 Task may need to wait for an event to occur. Busy waiting (I.e., polling) is inefficient. Pending until the event occurs is better.

The Synchronization Solution Create a binary semaphore for the event. Binary semaphores exist in one of two states: Full (event has occurred). Empty (event has not occurred). Task waiting for the event calls semTake(), and blocks until semaphore is given. Task or interrupt service routine detecting the event calls semGive(), which unblocks the waiting task.

Binary Semaphores SEM_ID semBCreate (options, intialState) options Sepcify queue type (SEM_Q_PRIORITY or SEM_Q_FIFO) for tasks pended on this semaphore. initialState Initialize semaphore to be available (SEM_FULL) or unavailable (SEM_EMPTY). Semaphores used for synchronization are typically initialized to SEM_EMPTY (event has not occurred). Returns a SEM_ID, or NULL on error.

Taking a Semaphore STATUS semTake (semId, timeout) semId The SEM_ID returned from semBCreate(). timeout Maximum time to wait for semaphore. Value can be clock ticks, WAIT_FOREVER, or NO_WAIT. Can pend the task until either Semaphore is given or Timeout expires. Semaphore left unavaiable. Returns OK if successful, ERROR on timeout (or invalid semId).

Taking a Binary Semaphore available ? task pends until sem is given or timeout task unpends semTake() returns ERROR no timeout semaphore given yes task continues semTake() returns OK task unpends, semTake() returns OK

Giving a Semaphores STATUS semGive (semId) Unblocks a task waiting for semId. If no task is waiting, make semId available. Returns OK, or ERROR if semId is invalid.

Giving a Binary Semaphore tasks pended ? semaphore made available no yes task at front of queue made ready semaphore remains unavailable 当任务调用semGive()释放一个二进制信号量,其结果依赖于在调用时该信号量是否可用。如果此时信号量已经可用,释放信号量不产生任何影响。如果信号量不可用并且没有任务在等待它,那么信号量变为可用。如果信号量不可用并且有任务在等待它,那么阻塞在该信号量队列中的第一个任务解除阻塞,信号量仍不可用。

Information Leakage Fast event occurrences can cause lost information. Suppose a VxWorks task (priority=100) is executing the following code, with semId initially unavailable: FOREVER { semTake (semId, WAIT_FOREVER); printf (“Got the semaphore\n”); } What would happen in the scenarios below ? 1. -> repeat (1, semGive, semId); 2. -> repeat (2, semGive, semId); 3. -> repeat (3, semGive, semId); 一个例子

释放信号量图示 信号量可用? 有任务阻塞? 任务继续 信号量变为可用 No No Yes Yes 任务继续 信号量保持不变 等待该信号量的 任务队列的任务 就绪,信号量不 可用

Synchronizing Multiple Tasks STATUS semFlush (semId) Unblocks all tasks waiting for semaphore. Does not affect the state of a semaphore. Useful for synchronizing actions of multiple tasks. 广播同步,允许所有阻塞在同一个信号量上的任务集合全部自动解除阻塞。

Binary Semaphores and Synchronization Overview Binary Semaphores and Synchronization Mutual Exclusion

Mutual Exclusion Problem Some resources may be left inconsistently if accessed by more than one task simultaneously. Shared data structures. Shared files. Shared hardware devices. Must obtain exclusive access to such a resource before using it. If exclusive access is not obtained, then the order in which tasks execute affects correctness. 当两个或多个任务共享使用诸如同一块内存缓冲或同一个I/O设备之类的资源时,可能会发生竞争状态。 二进制信号量可以通过对共享资源上锁,实现高效的互斥访问。不象禁止中断或禁止抢占,二进制信号量将互斥仅仅限于对与之联系的资源的访问。使用这种技术时,创建用于保护资源的二进制信号量,初始时信号量时可用的。 semTake(semMutex,WAIT_FOREVER); … ..临界区,某一时刻仅能有一个任务来访问 semGive(semMutex); We say a race condition exists. Very difficult to detect during testing. Mutual exclusion cannot be compromised by priority.

Race Condition Example tTask1 tTask2 1 char myBuf(BU_SIZE); /* store data here */ 2 int myBufIndex = -1; /* Index of last data */ 3 4 myBufPut (char ch) 5 { 6 myBufIndex++; 7 myBuf [myBufIndex] = ch; 8 } Multiple tasks calling myBufPut( ) may disrupt each other: Suppose tTask1 wants to add ‘b’ to the buffer, and tTask2 wants to add ‘a’ to the buffer. If the events happen as above, then ‘a’ will be overwritten in its buffer slot, and the previous slot will contain invalid data. myBufIndex++ myBufIndex++ myBuf [myBufIndex] = ‘a’ myBuf [myBufIndex] = ‘b’ …….

Solution Overview Create a mutual exclusion semaphore to guard the resource. Call semTake() before accessing the resource; call semGive() when done. semTake() will block until the semaphore (and hence the resource) becomes available. semGive() releases the semaphore (and hence access to the resource).

Creating Mutual Exclusion Semaphores SEM_ID semMCreate (options) options can be : queue specification SEM_Q_FIFO or SEM_Q_PRIORITY deletion safety SEM_DELETE_SAFE priority inheritance SEM_INVERSION_SAFE Symbolic constants defined in semLib.h. Queue specification determines the order in which tasks waiting for the semaphore should unblock. Deletion safety and priority inheritance will be discussed later. Initial state of semaphore is available.

Mutex Ownership A task which takes a mutex semaphore “owns” it, so that no other task can give this semaphore. Mutex semaphores can be taken recursively. The task which owns the semaphore may take it more than once. Must be given same number of times as taken before it will be released. A mutex may be given regardless of ownership by calling the semMGiveForce( ) function. This is primarily intended as a debugging aid, but the function might be used in a recovery task if the task owning the mutex dies, and the resource guarded by the mutex can be reset to a consistent state. Mutual exclusion semaphores cannot be used in an interrupt service routine.

Taking a Mutex Semaphore owner of Semaphore? task pends until sem is given or timeout another task this task no one task continues semTake() returns OK task ownership count incremented task continues semTake() returns OK Task becomes owner Difference from binary semaphores: Can be taken more than once by a task without blocking.

Giving a Mutex Semaphore made available ownership count? tasks pended? one no greater than one yes not owner task at head of queue is made ready, becomes owner semGive() returns ERROR decrement ownership count Difference from binary semaphore: Only the owner of a semaphore can give it. The owner may take the semaphore more than once, but must give it as many times as it was taken in order to release it.

Code Example - Solution 1 #include ”vxWorks.h” 2 #include ” semLib.h” 3 4 LOCAL char myBuf[BUF_SIZE]; /* Store data here */ 5 LOCAL int myBufIndex = -1; /* Index of last data */ 6 LOCAL SEM_ID mySemId; 7 8 void myBufInit ( ) 9 { 10 mySemID = semNCreate (SEM_Q_PRIORITY | 11 SEM_INVERSION_SAFE | 12 SEM_DELETE_SAFE ); 13 } 14 15 void myBufPut (char ch) 16 { 17 semTake(mySemId, WAIT_OREVER); 18 myBufIndex++; 19 myBuf[myBufIndex] = ch; 20 semGIve (mySemId); 21 } /* mutexSemDemo.c - Demonstrate the usage of the mutual exclusion semaphore * for intertask synchronization and obtaining exclusive * access to a data structure shared among multiple tasks. */ /* Copyright 1984-1997 Wind River Systems, Inc. */ /* modification history -------------------- 01c,06nov97,mm added copyright. 01b,16sep97,ram included logLib.h, sysLib.h, stdio.h The arguments to logMsg are required arguments(6) Since there were fewer than 6 arguments the remaining have been filled up with zeros. 01a,14jan94,ms written. #include "vxWorks.h" #include "semLib.h" #include "taskLib.h" #include "mutexSemDemo.h" #include "logLib.h" #include "sysLib.h" #include "stdio.h" LOCAL STATUS protectSharedResource (); /* protect shared data structure */ LOCAL STATUS releaseProtectedSharedResource (); /* release protected access */ LOCAL STATUS producerTask (); /* producer task */ LOCAL STATUS consumerTask (); /* consumer task */ LOCAL struct shMem shMemResource; /* shared memory structure */ LOCAL SEM_ID mutexSemId; /* mutual exclusion semaphore id*/ LOCAL BOOL notFinished; /* Flag that indicates the * completion */ /***************************************************************************** * mutexSemDemo - Demonstrate the usage of the mutual exclusion semaphore * for intertask synchronization and obtaining exclusive * access to a data structure shared among multiple tasks. * * DESCRIPTION * Creates a mutual exclusion semaphore for intertask syncronization * between the producerTask and the consumerTask. Both producerTask and * consumerTask access and manipulate the global shared memory data * structure simultaneously. To avoid corruption of the global shared * memory data structure mutual exclusion semaphores are used. * Spawns the producerTask that produces the message and puts the message * in the global shared data structure. Spawns the consumerTask that * consumes the message from the global shared data structure and * updates the status field to CONSUMED so that producerTask can put * the next produced message in the global shared data structure. * After consumerTask has consumed all the messages, the mutual exclusion * semaphore is deleted. * RETURNS: OK or ERROR * EXAMPLE * -> sp mutexSemDemo STATUS mutexSemDemo() { notFinished = TRUE; /* initialize the global flag */ /* Create the mutual exclusion semaphore*/ if ((mutexSemId = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE)) == NULL) perror ("Error in creating mutual exclusion semaphore"); return (ERROR); } /* Spwan the consumerTask task */ if (taskSpawn ("tConsumerTask", CONSUMER_TASK_PRI, 0, TASK_STACK_SIZE, (FUNCPTR) consumerTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR) perror ("consumerTask: Error in spawning demoTask"); /* Spwan the producerTask task */ if (taskSpawn ("tProducerTask", PRODUCER_TASK_PRI, 0, TASK_STACK_SIZE, (FUNCPTR) producerTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) perror ("producerTask: Error in spawning demoTask"); /* Polling is not recommended. But used for making this demonstration * simple */ while (notFinished) taskDelay (sysClkRateGet ()); /* When done delete the mutual exclusion semaphore*/ if (semDelete (mutexSemId) == ERROR) perror ("Error in deleting mutual exclusion semaphore"); return (OK); * producerTask - produce the message, and write the message to the global * shared data structure by obtaining exclusive access to * that structure which is shared with the consumerTask. STATUS producerTask () int count = 0; int notDone = TRUE; while (notDone) /* Produce NUM_ITEMS, write each of these items to the shared * global data structure. if (count < NUM_ITEMS) /* Obtain exclusive access to the global shared data structure */ if (protectSharedResource() == ERROR) /* Access and manipulate the global shared data structure */ if (shMemResource.status == CONSUMED) count++; shMemResource.tid = taskIdSelf (); shMemResource.count = count; shMemResource.status = PRODUCED; /* Release exclusive access to the global shared data structure */ if (releaseProtectedSharedResource () == ERROR) logMsg ("ProducerTask: tid = %#x, producing item = %d\n", taskIdSelf (), count,0,0,0,0); taskDelay (sysClkRateGet()/6); /* relingiush the CPU so that * consumerTask can access the * global shared data structure. else notDone = FALSE; * consumerTask - consumes the message from the global shared data * structure and updates the status filled to CONSUMED * so that producerTask can put the next produced message * in the global shared data structure. STATUS consumerTask () /* Initialize to consumed status */ shMemResource.status = CONSUMED; taskDelay (sysClkRateGet()/6); /* relingiush the CPU so that * producerTask can access the if ((shMemResource.status == PRODUCED) && (shMemResource.count > 0)) logMsg ("ConsumerTask: Consuming item = %d from tid = %#x\n\n", shMemResource.count, shMemResource.tid,0,0,0,0); if (shMemResource.count >= NUM_ITEMS) notFinished = FALSE; * protectSharedResource - Protect access to the shared data structure with * the mutual exclusion semaphore. LOCAL STATUS protectSharedResource () if (semTake (mutexSemId, WAIT_FOREVER) == ERROR) perror ("protectSharedResource: Error in semTake"); * releaseProtectedSharedResource - Release the protected access to the * shared data structure using the mutual * exclusion semaphore LOCAL STATUS releaseProtectedSharedResource () if (semGive (mutexSemId) == ERROR)

Deletion Safety Deleting a task which owns a semaphore can be catastrophic. data structures left inconsistent. semaphore left permanently unavailable. The deletion safety option prevents a task from being deleted while it owns the semaphore. Enabled for mutex semaphores by specifying the SEM_DELETE_SAFE option during semMCreate( ).

安全删除 wind内核提供防止任务被意外删除的机制。通常,一个执行在临界区或访问临界资源的任务要被特别保护。 我们设想下面的情况:一个任务获得一些数据结构的互斥访问权,当它正在临界区内执行时被另一个任务删除。由于任务无法完成对临界区的操作,该数据结构可能还处于被破坏或不一致的状态。而且,假想任务没有机会释放该资源,那麽现在其他任何任务现在就不能获得该资源,资源被冻结了。 任何要删除或终止一个设定了删除保护的任务的任务将被阻塞。当被保护的任务完成临界区操作以后,它将取消删除保护以使自己可以被删除,从而解阻塞删除任务。

Priority Inversion tHigh unblocks tMediumunblocks semTake( ) High Priority Pended Pended Medium Priority Pended Ready semTake( ) Critical Region Low Priority Ready time

优先级逆转/优先级继承 优先级逆转发生在一个高优先级的任务被强制等待一段不确定的时间以便一个较低优先级的任务完成执行。 T1,T2和T3分别是高、中、低优先级的任务。T3通过拥有信号量而获得相关的资源。当T1抢占T3,为竞争使用该资源而请求相同的信号量的时候,它被阻塞。如果我们假设T1仅被阻塞到T3使用完该资源为止,情况并不是很糟。毕竟资源是不可被抢占的。然而,低优先级的任务并不能避免被中优先级的任务抢占,一个抢占的任务如T2将阻止T3完成对资源的操作。这种情况可能会持续阻塞T1等待一段不可确定的时间。这种情况成为优先级逆转,因为尽管系统是基于优先级的调度,但却使一个高优先级的任务等待一个低优先级的任务完成执行。     互斥信号量有一个选项允许实现优先级继承的算法。优先级继承通过在T1被阻塞期间提升T3的优先级到T1解决了优先级逆转引起的问题。这防止了T3,间接地防止T1,被T2抢占。通俗地说,优先级继承协议使一个拥有资源的任务以等待该资源的任务中优先级最高的任务的优先级执行。当执行完成,任务释放该资源并返回到它正常的或标准的优先级。因此,继承优先级的任务避免了被任何中间优先级的任务抢占。   优先级逆转/优先级继承 优先级逆转发生在一个高优先级的任务被强制等待一段不确定的时间以便一个较低优先级的任务完成执行。 T1,T2和T3分别是高、中、低优先级的任务。T3通过拥有信号量而获得相关的资源。当T1抢占T3,为竞争使用该资源而请求相同的信号量的时候,它被阻塞。如果我们假设T1仅被阻塞到T3使用完该资源为止,情况并不是很糟。毕竟资源是不可被抢占的。然而,低优先级的任务并不能避免被中优先级的任务抢占,一个抢占的任务如T2将阻止T3完成对资源的操作。这种情况可能会持续阻塞T1等待一段不可确定的时间。这种情况成为优先级逆转,因为尽管系统是基于优先级的调度,但却使一个高优先级的任务等待一个低优先级的任务完成执行。     互斥信号量有一个选项允许实现优先级继承的算法。优先级继承通过在T1被阻塞期间提升T3的优先级到T1解决了优先级逆转引起的问题。这防止了T3,间接地防止T1,被T2抢占。通俗地说,优先级继承协议使一个拥有资源的任务以等待该资源的任务中优先级最高的任务的优先级执行。当执行完成,任务释放该资源并返回到它正常的或标准的优先级。因此,继承优先级的任务避免了被任何中间优先级的任务抢占。  

Priority Inheritance Priority inheritance algorithm solves priority inversion problem. Task owning a mutex semaphore is elevated to priority of highest priority task waiting for that semaphore. Enabled on mutex semaphore by specifying the SEM_INVERSION_SAFE option during semMCreat( ). Must also specify SEM_Q_PRIORITY (SEM_Q_FIFO is incompatible with SEM_INVERSION_SAFE).

Priority Inversion Safety tHigh unblocks tMediumunblocks semTake( ) High Priority Pended Pend Medium Priority Pended Ready semTake( ) semGive( ) Critical Region Low Priority Ready time

Avoiding Mistakes It is easy to miuse mutex semaphores, since you must protect all accesses to the resource. To prevent such a mistake Write a library of routines to access the resource. Initialization routine creates the semaphore. Routines in this library obtain exclusive access by calling semGIve( ) and semTake( ). All uses of the resource are through this library.

Caveat - Deadlocks INT 6 INT 3 tExcTask tLogTask semTake(semId2,-1) tEvtTask semTake(semId1,-1) tWdbTask semTake(semId2,-1) semTake(semId1,-1) tNetTask tTaskHi tTaskLow tPortmapd tWvSvc u0 idle A deadlock is a race condition associated with the taking of multiple mutex semaphores. Very difficult to detect during testing.

Other Caveats Mutual exclusion semaphores can not be used at interrupt time. This issue will be discussed later in the chapter. Keep the critical region (code between semTake( ) and semGive( )) short.

Common Routines Additional semaphore routines : semDelete( ) Destroy the semaphore.semTake( ) calls for all tasks pended on the semaphore return ERROR. show( ) Display semaphoreinformation.

Semaphore Browser To inspect the properties of a specific semaphore insert the semaphore ID in the Browser’s Show box, and click on Show. Attributes Blocked Tasks

Locking out Preemption When doing something quick frequently, it is preferable to lock the scheduler instead of using a Mutex semaphore. Call taskLock( ) to disable scheduler. Call taskUnLock( ) to reenable scheduler. Does not disable interrupts. 抢占禁止:禁止抢占提供了强制性较弱的互斥方式。 当前任务运行的过程中不允许其他任务抢占,而中断服务程序可以执行。这也可能引起较差的实时响应,就象被禁止中断一样,被阻塞的任务会有相当长时间的抢占延时,就绪态的高优先级的任务可能会在能够执行前被强制等待一段不可接受的时间。为避免这种情况,在可能的情况下尽量使用信号量实现互斥。 If the task blocks, the scheduler is reenabled. Prevents all other tasks from running, not just the tasks contending for the resource.

ISR’s and Mutual Exclusion ISR’s can’t use Mutex semaphores. Task sharing a resource with an ISR may need to disable interrupts. To disable / re-enable interrupts : int intLock( ) void intUnLock(lockKey) lockKey is return value from intLock( ). 中断禁止:最强的互斥方法是屏蔽中断。这样的锁定保证了对CPU的互斥访问。这种方法当然能够解决互斥的问题,但它对于实时是不恰当的,因为它在锁定期间阻止系统响应外部事件。长的中断延时对于要求有确定的响应时间的应用来说是不可接受的。 当涉及到中断需要互斥时,中断禁止是必要的。 Keep interrupt lock-out time short (e.g., long enough to set a flag) ! Does not disable scheduler.

计数器信号量 计数器信号量是实现任务同步的和互斥的另一种方法。计数器信号量出了象二进制信号量那样工作外,他还保持了对信号量释放次数的跟踪。信号量每次释放,计数器加一,每次获取,计数器减一。当计数器减到0,试图获取该信号量的任务被阻塞。 正如二进制信号量,当信号量释放时,如果有任务阻塞在该信号量阻塞队列上,那么任务解除阻塞。然而,不象二进制信号量,如果信号量释放时,没有任务阻塞在该信号量阻塞队列上,那么计数器加一。 计数器信号量适用于保护拥有多个拷贝的资源。

Summary Binary Mutual Exclusion semBCreate semMCreate semTake, semGive show semDelete

Summary Binary semaphores allow tasks to pend until some event occurs. Create a binary semaphore for the given event. Tasks waiting for the event blocks on a semTake( ). Task or ISR detecting the event calls semGive( ) or semFlush( ). Caveat : if the event repeats too quickly, information may be lost

Summary Mutual Exclusion Semaphores are appropriate for obtaining access to a resource. Create a mutual exclusion semaphore to guard the resource. Before accessing the resource, call semTake( ). To release the resource, call semGive( ). Mutex semaphores have owners. Caveats : Keep critical regions short. Make all accesses to the resource through a library of routines. Can’t be used at interrupt time. Deadlocks.

Summary taskLock( ) / taskUnLock( ) : Prevents other tasks from running. Use when doing something quick frequently. Caveat : keep critical region short. intLock( ) / intUnLock( ) : Disable interrupts. Use to protect resources used by tasks and interrupt service routines. Caveat : keep critical region short.

Now Have a rest

Intertask Communication Chapter 7 Intertask Communication

Intertask Communication Introduction Shared Memory Message Queues VxWork中,单CPU任务间主要的通讯机制时消息队列。作为一个可选产品,VxMP提供了处理器间任务通讯的全局消息队列 Pipes

Overview Multitasking systems need communication between tasks. Intertask communication made up of three components : Data / information being shared. Mechanism to inform task that data is available to read or write. Mechanism to prevent tasks from interfering with each other (e.g., if there are two writers). Two common methods : Shared memory. Message passing.

Shared Memory fooLib.c tTaskA tTaskB LOCAL SEM_ID fooSem; LOCAL FOO_BUF fooBuffer; fooSet ( ) …… fooGet ( ) …...

Message Passing Queues VxWorks pipes and message queues are used for passing messages between tasks. Both pipes and message queues provide : taskA taskB FIFO buffer of messages Synchronization Mutual Exclusion More robust than shared data. Can be used from task to task, or from ISR to task.

Intertask Communication Introduction Shared Memory Message Queues Pipes

Overview All tasks reside in a common address space. User-defined data structures may be used for Intertask communication : Write a library of routines to access these global or static data-structures. All tasks which use these routines manipulate the same physical memory. Semaphores may be used to provide mutual exlusion and synchronization. VxWorks provides libraries to manipulate common data structures such as linked lists and ring buffers.

Linked Lists lstLib contains routines to manipulate doubly linked lists. List Descriptor User node 1 User node 2 head NODE NODE tail User specific data User specific data count = 2 NULL NULL Mutual exclusion and synchronization are not built-in.

Ring Buffers rngLib contains routines to manipulate ring buffers (FIFO data streams) reader writer Mutual exclusion is not required if there is only one reader and one writer. Otherwise, user must provide. Synchronization is not built-in.

Intertask Communication Introduction Shared Memory Message Queues Pipes

Message Queues Used for intertask communication within one CPU. FIFO buffer of variable length messages. Task control is built-in : Synchronization. Mutual Exclusion.

Creating a Message Queue MSG_Q_ID msgQCreate (maxMsgs, maxMsgLength, options) maxMsgs Maximum number of messages on the queue. maxMsgLength Maximum size in bytes of a message on the queue. options Queue type for pended tasks (MSG_Q_FIFO or MSG_Q_PRIORITY) Returns an id used to reference this message queue or NULL on error.

Sending Messages STATUS msgQSend (msgQId, buffer, nBytes, timeout, priority) msgQId MSG_Q_ID returned by msgQCreate( ). buffer Address of data to put on queue. nBytes Number of bytes to put on queue. timeout Maximum time to wait (if queue is full). Values can be tick count, WAIT_FOREVER or NO_WAIT. priority “Priority“ of message to put on queue. If MSG_PRI_URGENT, message put at head of queue. If MSG_PRI_NORMAL message put at end of queue.

Message Sending Examples char buf[BUFSIZE]; status = msgQSend (msgQId, buf, sizeof(buf), WAIT_FOREVER, MSG_PRI_NORMAL); status = msgQSend (msgQId, buf, sizeof(buf), NO_WAIT, MSG_PRI_URGENT);

Receiving Messages int msgQReceive (msgQId, buffer, maxNBytes,timeout) msgQId Returned from msgQCreate( ). buffer Address to store message. MaxNBytes Maximum size of message to read from queue. timeout Maximum time to wait (if no message available). Values can be clock ticks, WAIT_FOREVER or NO_WAIT. Returns number of bytes read on success, ERROR on timeout or invalid msgQId. Unread bytes in a message are lost.

Deleting a Message Queue STATUS msgQDelete (msgQId) Deletes message queue. Tasks pended on queue will be unpended; their msgQSend( ) or msgQReceive( ) calls return ERROR. These tasks’ errno values will be set to S_objLib_OBJ_DELETED.

Gathering Data with Message Queues Input device poll task or ISR devic data device data devic data device data consumer To capture data quickly for future examination : 任务或ISR可以向消息队列发送消息 Have a poll task or ISR place device data in a message queue. Have a lower priority task read data from this queue for processing. GO TO APPENDIX A3

Client-Server model with Message Queues Task this is a mes this is a mess this is a mes this is a message Client

Client-Server Variations How would the previous code example change if : The client needs a reply from the server ? We wish to simultaneously service several requests ? (we may wish to do this if there are multiple clients, and this service requires blocking while I / O completes).

Message - Queue Browser To examine a message queue, enter the message queue ID in the Browser’s Show box, and click on Show. mv152-external@mekong: Mempart Ox3ff988 Attributes options = PRIORITY maxMsgs = 10 maxLength = 100 sendTimeouts = 0 recvTimeouts = 0 Receivers Blocked Senders Blocked Messages Queued address = 0x3ffdb4 length = 0x7 value = 68 65 66 6f 0a *hello.. 1 address = 0x3ffd48 length = 0x4 value = 68 69 0a 0d *hi..

POSIX消息队列 POSIX消息对列由mqPxLib库提供,除了POSIX消息队列提供命名队列和消息具有一定范围的优先级之外,提供的这些函数与Wind消息队列类似。 在使用POSIX消息队列前,系统初始化代码必须调用mqPxLibInit()进行初始化。也可以在配置VxWorks时进行配置。 通知任务一个消息队列在等待 任务可以调用mq_notify()函数要求系统当有一个消息进入一个空的消息队列时通知它。这样可以避免任务阻塞或轮询等待一个消息。 mq_notify()以消息进入空队列时系统发给任务的信号(signal)作为参数。这种机制只对当前状态为空的消息队列有效,如果消息队列中已有可用消息,当有更多消息到达时,通知不会发生。

POSIX和Wind消息队列比较 特征 Wind消息 POSIX消息对列 消息优先级 1 32 阻塞的任务队列 FIFO或基于优先级 不带超时的接收 可选 不可用 任务通知 关闭/解链语法 无 有

Intertask Communication Introduction Shared Memory Message Queues Pipes

Pipes Virtual I/O device managed by pipeDrv. Built on top of message queues. Standard I/O system interface (read / write). Similar to named pipes in UNIX. (UNIX Host) 管道使用VxWorks I/O系统,可提供能与消息队列互换的功能。管道是一种由pipeDrv驱动程序管理的虚拟I/O设备。想对消息队列的操作一样。ISRs能够向管道写,但是不能从管道读,象I/O设备。管道提供消息队列不能提供的一个重要特征,可以使用select()函数,它允许任务等待一个I/O设备集合之一的数据可用。使用select(),任务能够同时等待几个管道、套接字和串行设备集合上的数据。 this is a mes this is a mess this is a mes this is a message

Creating a Pipe STATUS pipeDevCreate (name, nMessages, nBytes) name Name of pipe device, by convention use “/pipe/yourName”. nMessages Maximum number of messages in the pipe. nBytes Maximum size in bytes of each message. Returns OK on success, otherwise ERROR.

Example Pipe Creation -->pipeDevCreate (“/pipe/myPipe”,10,100) value = 0 = 0x0 -->devs drv name 0 /null 1 /tyCo/0 1 /tyCo/1 4 columbia: 2 /pipe/myPipe

Reading and Writing to a Pipe To access an existing pipe, first open it with open( ). To read from the pipe use read( ). To write to the pipe use write( ). fd = open (“/pipe/myPipe”, O_RDWR, 0); write (fd, msg, len); this is a mes this is a mess this is a mes this is a message read (fd, msg, len);

Message Queues vs. Pipes Message Queue advantages : Timeouts capability. Message prioritization. Faster. show( ). Can be deleted. Pipe advantages : Use standard I / O interface i.e., open ( ), close ( ), read ( ), write( ), etc. Can perform redirection via ioTaskStdSet( ) (see I/O chapter) File descriptor can be used in select ( ).

Summary Shared Memory Often used in conjunction with semaphores. lstLib and rngLib can help. Message queues : msgQCreate( ) msgQSend( ) msgQReceive( ) Pipes pipeDevCreate( ) Access pipe via file descriptor returned from open( ). Use write( ) / read( ) to send / receive messages from a pipe.

Chapter 8 Memory

Memory Layout VxWorks LOCAL_MEM_LOCAL_ADRS RAM_LOW-ADRS FREE_RAM_ADRS WDB_POOL_SIZE SYSTEM MEMORY POOL sysMemTop( ) USER_RESERVED_MEM sysPhysMemTop( )

Target Server Memory Pool A pool of memory on the target reserved for use by the Tornado tools : Dynamic loading of object modules. Spawning task from WindSh or CrossWind. Creation of variables from WindSh. The target server manages the pool, keeping overhead such as block lists on the host. The initial size of the target server memory pool is configured by WDB_POOL_SIZE. The default is 1 / 16 of sysMemTop( ) - FREE_RAM_ADRS. Additional memory is silently allocated from the system memory pool, if needed.

System Memory Pool Used for dynamic memory allocation in programs : malloc( ). Creating tasks (stack and TCB). VxWorks memory requests. Initialized at system startup. Can modify USER_RESERVED_MEM to reserve memory for application-specific use. May need to modify sysPhysMemTop( ) (or just LOCAL_MEM_SIZE) when adding memory to your board. To add off board memory : void memAddToPool (pPool, poolSize) pPool must be the local address of the memory.

Allocating / Releasing Memory To dynamically allocate memory : void *malloc (nBytes) Returns a pointer to the newly allocated memory or NULL on error. Uses first-fit algorithm. Free memory is stored in a linked list. Some (small) overhead for each malloc( ). To release allocated memory : void free (ptr) Adjacent blocks are coalesced.

Debugging Options Default malloc( ) debugging : If request too large, log an error message. Default free( ) debugging : Check block for consistency. If corrupted: suspend task, log error message. Can change default debugging options with : void memOptionsSet (options) Options can be : + MEM_ALLOC_ERROR_LOG_FLAG - MEM_ALLOC_ERROR_SUSPEND_FLAG + MEM_BLOCK_CHECK + MEM_BLOCK_ERROR_LOG_FLAG + MEM_BLOCK_ERROR_SUSPEND_FLAG

mv152-external@mekong: Mempart Ox Examining Memory Use the browser. Enter the memory partition ID in the Show box. mv152-external@mekong: Mempart Ox Total bytes = 3870840 Allocated blocks = 86 bytes = 467224 Free blocks = 7 bytes = 3403584 Cummulative blocks = 88 bytes = 467832 Free List addr = 0x3fd8f8 size = 9604 1 addr = 0x4ef90 size = 3355432 Free List

Additional System Memory Management Routines void *calloc(nElems, size ) Allocate zeroed memory for an array. void *realloc(ptr,newSize) Resize an allocated block. The block may be moved. int memFindMax( ) Returns the size of the largest free block in system memory.

Fine Tuning For fast, deterministic allocation of fixed size buffers, use message queues instead of malloc( ). message queue ptr ptr . . . . ptr bufGet( ) bufReturn( ) . . . . buffers

Generic Partition Manager VxWorks provides low level routines to create and manipulate alternate memory pools. High level routines like malloc( ) and free( ) call these lower level routines, specifying the system memory pool. Application may use alternate memory partitions to reduce fragmentation. Applications may use alternate memory partitions to manage memory with different properties.

Creating a memory Partition PART_ID memPartCreate (pPool, size) pPool Pointer to memory for this partition size Size of memory partition in bytes. Returns a partition id (PART_ID) or NULL or error. The memory for this partition (pPool) may be taken from : A separate memory board. A block allocated from the system memory partition. The top of the CPU board’s RAM.

Managing Memory Partitions System partition management routines call routines listed below, specifying the PART_ID as memSysPartId. Generic System Memory Pool memPartAlloc( ) malloc( ) memPartFree( ) free( ) memPartShow( ) memShow( ) memPartAddToPool( ) memAddToPool( ) memPartOptionsSet( ) memOptionsSet( ) memPartRealloc( ) realloc( ) memPartFindMax( ) memFindMax( )

Example Creating a Memory Partition -->partId=memPartCreate(pMemory, 100000) new symbol “partId” added to symbl table. partId = 0x23ff318 : value = 37745448 = 0x23ff328 = partId + 0x10 -->ptr=memPartAlloc(partId, 200) new symbol “ptr” added to symbl table. ptr = 0x23ff2ec : value = 37652632 = 0x23e8898 -->show partId status bytes blocks ave block max block current free 99776 1 99776 99776 alloc 208 1 208 - cumulative

Summary Standard C routines used for dynamic memory allocation. To configure the system memory pool : Modify sysPhysMemTop( ) Modify USER_RESERVED_RAM Modify memAddToPool( ) For fast, deterministic allocation of fixed size buffers, use message queues instead of malloc( ). Create separate memory partition for off-board memory, or to help reduce fragmentation.

Exceptions, Interrupts and Timers Chapter 9 Exceptions, Interrupts and Timers

Exceptions, Interrupts and Timers Exception Handling and Signals Interrupt Service Routines Timers

信号(Signals)(一) VxWorks支持软件信号功能。信号可以异步改变任务控制流。任何任务和ISR都可以向指定的任务发信号。获得信号的任务立即挂起当前的执行,在下次调度它运行时转而执行指定的信号处理程序。 信号处理程序在信号接收任务的 上下文中执行,使用该任务的堆栈。在任务阻塞时,信号处理程序仍可被唤醒 信号机制适合于错误和异常处理。 通常,信号处理程序可以作为中断处理程序看待。任何可能导致调用程序阻塞的函数均不能在信号处理程序中调用。 Wind内核支持两种类型的信号接口 UNIX BSD风格的信号 POSIX兼容的信号

信号(Signals)(二) 信号在很多方面跟硬件中断相似。基本信号接口提供了31个不同的信号。调用sigvec()或sigaction()可为信号指定一个信号处理程序。这与调用intConnect()为中断指定一个中断处理程序(ISR)相似。可以调用kill()将信号发送给任务,这类似于于中断发生。函数sigsetmask()和sigblock或sigprocmask()可以用来象屏蔽中断那样屏蔽信号。 使用sigInit()初始化信号函数库,使得基本信号函数可用

基本信号接口函数 POSIX 1003.1b兼容调用 UNIX BSD兼容调用 说明 signal() 指定信号的处理程序 kill() 向任务发送一个信号 raise() N/A 发信号给自身 sigaction() sigvec() 检测或设置信号处理程序 sigsuspend() pause() 挂起任务直到信号提交 sigpending() 取回一组提交阻塞的信号 .. 设置信号屏蔽

几个函数原型 int sigvec 检测或设置信号处理程序 ( int sig, /*于处理程序相联系的信号*/ const struct sigvec *pVec, /*新的处理程序信息*/ struct sigvec *pOvec /*旧的处理程序信息*/ ) int kill 向任务发送一个信号 ( int tid, /*接收信号的任务号*/ int signo /*发送给任务的信号*/ sigqueue 提供与kill()等价的功能 ( int tid, /*接收信号的任务*/ int signo, /*发送给任务的信号*/ const union sigval value /*隋信号发送的值*/

Signals normalCode() mySignalHandler() { . } { . } mySignal

UNIX: UNIX vs. VxWorks SIgnals Signal is ignored if no handler is installed ‘‘Automatic function restarting ‘‘ Ready Q Pend Q  semTake(....OrgDelay) Ž Run signal- handler Œ Signal  Can install a handler to catch SIGKILL. No SIGCHLD, SIGPIPE, or SIGURG. taskDelay() sets errno = EINTR and returns ERROR if interrupted by a signal.

Caveats Signals are not recommended for general intertask communication. A signal : May be handled at too high a priority if it arrives during a priority inheritence. Disrupts a task’s normal execution order.(It is better to create two tasks, than multiplex processing in one task via signals.) Can cause reentrancy problems between a task running its signal handler and the same task running its normal code. Can be used to tell a task to shut itself down. SIgLib contains both POSIX and BSD UNIX interfaces. Do not mix them.

Registering a Signal Handler signal ( signo.handler) To register a signal handler signal ( signo.handler) signo Signal number. handler Routine to invoke when signal arrives (or SIG_IGN to ignore signal). Returns the previously installed signal handler,or SIG_ERR. The signal handler should be declared as : void sigHandler (int sig) ; /* signal number */:

Signals and Exceptions Hardware exceptions include bus error, address error, divide by zero, floating point overflow, etc. Some signals correspond to exceptions (e.g., SIGSEGV corresponds to a bus error on a 68K; SIGFPE correponds to various arithmetic exceptions). myCode() { . } Task has SIGSEGV signal handler installed ? bus error raise signal Suspend task Log error message

The Signal Handler If an exception signal handler returns : The offending task will be suspended. A message will be logged to the console. Exception signal handlers typically call : exit( ) to terminate the task, or taskRestart( ) to restart the task, or longjmp( ) to resume execution at location saved by setjmp( )

Exceptions, Interrupts and Timers Exception Handling and Signals Interrupt Service Routines Timers

中断 硬件中断处理是实时系统设计的最重要、最关键的问题。为了获得尽可能快的中断响应时间,VxWorks的中断处理程序运行在特定的上下文中(在所有任务上下文之外)。因此,中断处理不会涉及任何任务上下文的交换。 VxWorks提供函数intConnect(),该函数允许将指定的C函数与任意中断相联系。 STATUS intConnect ( VOIDFUNCPTR *vector, /*要联系的中断向量*/ VOIDFUNCPTR *routine, /*中断发生时要调用的函数*/ int parameter /*传递给中断处理函数的参数*/ ) 该函数将指定的C函数routine与指定的中断向量vector相联系,函数的地址存储在这个中断向量里。

中断函数 调用 描述 intConnect() 设置中断处理程序 intContext() 如果是在中断级调用,返回真 intCount() 得到当前的中断嵌套深度 intLevelSet() 设置处理器中断屏蔽级 intLock() 禁止中断 intUnlock() 重新允许中断 intVecBaseSet() 设置向量基地址 intVecBaseGet() 得到向量基地址 intVecSet() 设置一个异常向量 intVecGet() 得到一个异常向量

中断处理过程 中断 中断向量表 执行顺序 事件 1 切换到中断堆栈、保存 程序计数器和寄存器 调用inConnect指定 的中断处理程序 处理该中断 恢复寄存器、返回 255

中断堆栈 如果体系结构允许,所有的ISRs使用的中断堆栈。堆栈的定位和初始化由系统在启动时根据指定的配置参数完成。堆栈必须足够大,以保证能够处理系统最坏情形下的中断嵌套。 体系结构不允许使用一个特定的堆栈。在这种结构中,ISRs使用中断任务的堆栈。对于这种结构的目标机,应用必须创建足够大的堆栈空间。 开发过程中,可以调用checkStack()函数察看一个任务堆栈的使用或整个系统堆栈的使用情况。

ISR的特殊限制 基本约束:必须不能调用可能引起调用阻塞的函数。 在中断服务程序中不能试图获取一个信号量,因为信号量可能不可用。 中断服务程序里面不能使用malloc和free,因为他们都需要获取一个信号量。 中断服务程序也不能通过VxWorks驱动执行I/O操作。多数设备驱动由于可能需要等待设备而引起调用者阻塞,因此需要任务上下文交换。 VxWorks支持纪录功能,任务可以向系统输出平台打印文本信息。 logMsg()

Interrupts Interrupts allow devices to notify the CPU that some event has occured. An user-defined routine can be installed to execute when an interrupt arrives. This routine runs at interrupt time. It is not a task. On-board timers are a common source of interrupts. Using them requires understanding interrupts.

Device Drivers Use interrupts for asynchronous I/O Are beyond the scope of this course For more information: intArchLib To install user defined ISR’s. Board Support Package Board specific interrupt handling. Programmers Guide Architecture specific interrupt info. Tornado User’s Guide System mode debugging info. BSP Porting Kit Optional product for writing BSP’s. VxWorks Device Driver Workshop Write VMEbus and VxWorks standard device drivers.

Handling an interrupt Interrupt Vector Table Interrupt Service Routine(ISR) User ISR handler : myISR() { . } save registers call routine Vector number hander restore registers hardware RET

Interrupts and Priorities Absolute system -Wide Priority Interrupt Level (Hard Wired) interrupt interrupt interrupt Execution Order Controlled by Hardware Absolute system -Wide Priority Execution Order Controlled by Kernel Task Task Task Priority (Programmable) . Task

Interrupt Stack Most architectures use a single dedicated interrupt stack Interrupt stack is allocated at system start-up. The Interrupt stack size is contolled by the macro INT_STACK_SIZE in config All.h Must be large enough for worst-case nesting Interrupt Stack int level 2 int level 3 int level 5

ISR Restrictions No tasks can run until ISR has completed ISRs are restricted from using some VxWorks facilities. In particular they can’t block : Can’t call semTake( ). Can’t call malloc( ) (uses semaphores). Can’t call I/O system routines (e.g.,printf( ) ). The Programmer’s guide gives a list of routines which are callable at interrupt time

ISR Guidelines Keep your ISRs short, because ISRs : Delay lower and equal priority interrupts. Delay all tasks Can be hard to debug Avoid using floating-point operations in an ISR. They may be slow. User must call fppSave( ) and fppRestore( ). Try to off-load as much work as possible to some task: Work which is longer in duration. Work which is less critical.

Typical ISR Read and writes memory-mapped I/O registers. Communicates information to a task by : Writing to memory Making non-blocking writes to a message queue. Giving a binary semaphore.

logMsg(‘‘foo = %d\n’’, foo, 0, 0, 0, 0, 0, 0); Debugging ISR’s To log diagnostic information to the console at interrupt time. logMsg(‘‘foo = %d\n’’, foo, 0, 0, 0, 0, 0, 0); Sends a request to tLogTask to do a printf( ) for us Similar to printf( ), with the following caveats : Arguments must be 4 bytes. Format string plus 6 additional arguments. Use a debugging strategy which provides system level debugging. WDB agent Emulator

Exceptions at Interrupts Time Causes a trap to the boot ROMs. Logged messages will not be printed. Boot ROM program will display an exception description on reboot. An exception occuring in an ISR will generate a warm reboot. Can use sprintf( ) to print diagnostic information to memory not overwritten on reboot, if necessary.

Exceptions, Interrupts and Timers Exception Handling and Signals Interrupt Service Routines Timers

Timers On board timers interrupts the CPU periodically. Allows user-defined routines to be executed at periodic intervals which is useful for : Polling hardware. checking for system errors. Aborting an untimely operation. VxWorks supplies a generic interface to manipulate two timers : System clock. Auxiliary clock ( if available).

System Clock System clock ISR performs book-keeping: Increments the tick count (use tickGet() to examine the count ). Updates the delatys and timeouts. Checks for round robin rescheduling. These operations may cause a reschedule. Default clock rate is 60Hz. sysClkRateSet (freq) Sets the clock rate . int sysClkRateGet() Returns the clock rate sysClkRateSet( ) should only be called at systems startup.

Watchdog Timers User interface to the system clock. Allows a C rioutine to be connected to a specified time delay. Upon expiration of delay, connected routine runs. As part of system clock ISR Subject to ISR restriction.

Creating watchdog Timers To ceate a watchdog timer : WDOG_ID wdCreate() Returns watchdog id, or NULL on error. To start (or restart) a watchdog timer : Status wdSDtart (wdId,delay,pRoutine,parameter) wdId Watchdog id, returned from wdCreate(). delay Number of ticks to delay pRoutine Routine to call when delay has expired parameter Argument to pass to routine

Using Watchdog To use watchdogs for periodic code execution : wdId = wdCreate(); wdStart ( wdId, DELAY_PERIOD, myWdTsr, 0 ) void myWdIsr ( int param) { doit(param); wdStart ( wdId, DELAY_PERIOD, mywdIsr, 0); } The doit( ) routine might : Poll some hardware device. Unblock some task. Check if system errors are present.

Missed Deadlines To recover from a missed deadline : WDOG_ID wdId; void foo(void) { wdId = wdCreate( ); /* Must finish each cycle in under 10 seconds */ FOREVER wdStart ( wdId, Delay_10_SEC, fooISR, 0); fooDoWork () ; } void fooISR (int param) /* Handle missed deadline */ ......

STATUS wdCancel ( wdId) STATUS wdDelete ( wdId) Stopping Watchdogs To cancel a previously started watchdog : STATUS wdCancel ( wdId) To deallocate a watchdog timer ( and cancel any previous start) : STATUS wdDelete ( wdId)

Watchdog Browser After creating, but prior to activating the watchdog, the Browser provides minimal information : After activating the watchdog, more useful information is provided :

Polling Issues Can poll at task time or interrupt time. Interrupt time polling is more reliable . Task time polling has a smaller impact on the rst of the system. To poll at task time, two options : taskDelay( ) - fastest, but may ‘‘drift’’. wdStart( ) + semGive( ) - more robust.

Polling Caveats The following code is accurate only if the system clock rate is a multiple of 15hz : void myWdISR () { pollMyDevice() ; wdStart (myWdId, sysClkRateGet )/15, 0) ; } Do not set the system clock rate too hiogh because there is OS overhead in each clock tick. Use auxillary clock to poll at high speeds.

Auxillary Clock For high speed polling, use the auxillary clock. Precludes using spy, which also uses the auxillary clock. Some routines to manipulate auxillary clock : sysAuxClkConnect( ) Connect ISR to Aux clock sysAuxClkRateSet( ) Set Aux clock rate. sysAuxClkEnable( ) Start Aux clock . sysAuxClkDIsable( ) Stop Aux clock

Summary Using signals for exception handling : signal( ) exit( ) taskRestart( ) longjmp() Interrupt Service routines have a limited context : No blocking. No I/O system calls

Summary Polling with timers : low speed high speed Interrupt time wd timer aux clock task time taskDelay, or wd timer + semGive

Chapter 10 I/O System

Chapter 10 I/O System

I/O System Introduction Basic I/O Select( ) Standard I/O

I/O System Interface I/O System xxDriver creat( ) xxCreat( ) open( ) xxOpen( ) close( ) xxClose( ) Application Device read( ) xxread( ) write( ) xxWrite( ) ioctl( ) xxIoctl( )

I/O System Benefits Simple interface Standard (portable) interface Select( ) I/O redirection

Driver Installation A device driver must be installed in the I/O system. Then VxWorks can call driver-specific routines when generic routines are called: e.g. calling xxRead( ) when read( ) is called on an XX device. Installation done automatically for VxWorks drivers included in VxWorks image. ttyDrv( ). pipeDrv( ). Must call drivers’s xxDrv( ) routine before using a third party driver.

Device Creation Each device driver has a device creation routine: Pipes Created at your request with pipeDevCreate( ). Serial devices Created automatically at system start up (via ttyDevCreate( )). Remote file systems See Network Basics Chapter Local file systems See Local file Systems chapter. Third-party devices xxDevCreate( ). These routines each initialize instances of a particular device type.

Devices -> devs drv name 0 /null 1 /tyCo/0 1 /tyCo/1 4 columbia: 2 /pipe/dream 2 /pipe/cleaner 5 /vio

I/O System Introduction Basic I/O Select( ) Standard I/O

File Descriptors Integer that identifies a file (file or device). Assigned by open( ) or creat( ) . Used by read( ), write( ), ioctl( ) and close( ) to speify file. File descriptor table is global Table size defined by the symbolic constant NUM_FILES (default of 50 is specified in configAll.h).

Standard Input, Standard Output, and Standard Error The first three file descriptors are predefined by the system and are never reassigned by the system. 0 STD_IN reserved file descriptors 1 STD_OUT File Descriptor Table 2 STD_ERR 3 4 : . n These three file descriptors (0-2) are never returned by creat( ) or open().

Standard Input, Output, and Error By default, these are directed to the console at system startup. Global assignments may be changed using: Void ioGlobalStdSet(stdFd, newFd) Example: fd = open (“columbia:/vx/errLog”, O_RDWR, 0); ioGlobalStdSet ( STD_ERR, fd); Redirect I / O on a per task basis with : void iotaskStdSet (taskId, stdFd, newFd)

Accessing Files int open (name, flags, mode) name Name of file to open. flags Specifies type of access: O_RDONLY Open file for reading only. O_WRONLY Open file for writing only. O_RDWR Open for reading and writing. O_TRUNC Truncate file on open. O_CREAT Create file if it doesn’t exist mode Permissions used when creating a file in an NFS system. Returns file descriptor on success, otherwise ERROR creat( ) routine similar to open( ), but for new files on a file system device.

Examining the File Descriptor Table -> iosFdShow fd name drv 3 /tyCo/0 1 4 (socket) 3 10 /pipe/dream 2 12 /pipe/cleaner 2

Closing Files STATUS close(fd) fd File descriptor returned from open( ) or creat( ) Flushes buffers. Frees up resources associated with file descriptor. Tasks must explicitly close files when they are no longer needed. File descriptor table is fixed size. VxWorks does not close files on task deletion.

Read / Write int read (fd, buffer, nBytes) int write (fd, buffer, nBytes) File descriptor returned by open( ) or creat( ). fd Address of buffer. Will be filled on a read, copied to device on write. buffer nBytes Maximum number of bytes to read / write. Returns the number of bytes read / written or ERROR if unsuccessful.

Ioctl int ioctl (fd, command, arg) fd File descriptor returned from open( ) or creat( ). command Integer identifying some driver specific command. Symbolic constants typically used. arg Type and value depends on command. Driver manual pages lists valid ioctl commands for that driver.

ioctl() Examples To set the baud rate of a serial device: status = ioctl (fd, FIOBAUDRATE, baudRate); To find the number of messages in a pipe: status = ioctl (fd, FIONMSGS, &nMsgs); To get / set your current file offset: status = ioctl ( fd, FIOSEEK, newOffset); position = ioctl ( fd, FIOWHERE, 0);

Setting Options for a Serial Device status = ioctl (fd, FIOSETOPTIONS, option); Symbolic constants for options may be OR’ed: 1 OPT_ECHO Echo of input. 2 OPT_CRMOD Convert \n to CR-LF on output. 4 OPT_TANDEM Implement ^S / ^Q flow control. 8 OPT_7_BIT Strip parity bit from 8 bit input. 16 OPT_MON_TRAP Reboot on ^X. 32 OPT_ABORT Restart target shell on ^C. 64 OPT_LINE Allow line editing before \n. ------------------------------------------------------------------------- 0 OPT_RAW All options off ( raw mode). 127 OPT_TERMINAL All options on.

I/O System Introduction Basic I/O Select( ) Standard I/O

Overview select( ) pipe, socket, or serial port Server select( ) allows a task to wait for activity on set of file descriptors. Requires driver support: VxWorks pipes, sockets and serial device drivers support select( ). Third party drivers may also support select( ). Also used to pend with a timeout.

select() select调用及宏FD_CLR、FD_ISSET、FD_SET、FD_ZERO用于I/O多路复用。 int select( int width, /*number of bits to examine from 0*/ fd_set *pReadFds, /*read fds*/ fd_set *pWriteFds, /*write fds*/ fd_set *pExceptFds, /*exception fds unsupported*/ struct timeval *pTimeout /*max time to wait ,NULL=forever*/ ) pReadFds监测是否有字符可以从某个描述符读入 pWriteFds监测是否某个描述符准备好了可以立即写入 pExceptFds监测是否某个描述符有异常出现 FD_SET(fd,&fdset) 从一个集合中添加一个描述符 FD_CLR(fd,&fdset) 从一个集合中删除一个描述符 FD_ZERO(&fdset) 清空一个集合

struct fd_set used by select( ) to specify file descriptors. Conceptually an array of bits, with bit N corresponding to file descriptor N. Manipulated via a collection of macros: FD_SET(fd, &fdSet) Sets the bit which corresponds to fd. FD_CLR(fd, &fdSet) Clears the bit which corresponds to fd. FD_ISSET(fd, &fdSet) Returns TRUE if the fd bit is set, else FALSE. FD_ZERO(&fdSet) Clears all bits.

Select int select(width, pReadFds, pWriteFds, pExceptFds, pTimeOut) width Number of bits to examine in pReadFds and pWriteFds. pReadFds struct fd_set pointer for the file descriptor we wish to read. pWriteFds struct fd_set pointer for the file descriptor we wish to write. pExceptFds Not implemented. pTimeOut. Pointer to a struct timeval, or NULL to wait forever. Returns number of active devices, or ERROR.

I/O System Introduction Basic I/O Select( ) Standard I/O

Standard I/O Application Buffered I/O: ANSI stdio fioLib fread( ) fwrite( ) fioLib fioRead( ) printf( ) sprintf( ) Basic I/O Routines (device independent) read( ), write( ) Driver Routines xxRead( ) xxwrite( ) Hardware Devices Network Disk Drive Serial Device

Standard I/O Functions ansiStdio functions include: fopen( ) opens a stream to a device or file. fclose( ) closes a stream. fread( ) reads data into an array. fwrite( ) writes data to a stream. getc( ) gets next character from a stream. putc( ) puts a character to a stream. ungetc( ) returns character to input stream.

File Pointers ansiStdio routines use file pointers (pointers to FILE data structure) instead of file descriptors. The FILE data structure, typedef’ed in stdio.h, contains : The underlying file descriptor. Pointers, etc., for managing the file buffers. stdin, stdout, and stderr are file pointers created using file descriptors 0,1, and 2. File Descriptors File Pointers (stdio.h) (vxWorks.h) STD_IN stdin stdout STD_OUT STD_ERR stderr

Standard I/O Buffers Private buffers minimize driver access: device driver myBuf stdio buffer buffer size driver dependent default 1024 bytes fp fread(. . ., fp)

Standard I/O Library Caveats Stdio buffers not protected with semaphores. Two tasks should not use the same fp at the same time. stdio library contains routines and macros. Breakpoints cannot be set on macros. Routines useful for access from the shell. Macros override routines when including stdio.h. Symbolic constants in configAll.h (default): INCLUDE_STDIO Initialize library. INCLUDE_ANSI_STDIO Link all ansiStdio routines into VxWorks.

Other ANSI Libraries Manual Page Header File Description Examples ansiCtype ctype.h Character testing and conversion. isdigit( ) isalpha( ) toupper( ) ansiString string.h String manipulation strlen( ) strcat( ) strcpy( ) ansiStdarg stdarg.h Variable number of arguments va_start( ) var_arg( ) va_end( ) ansiStdlib stdlib.h Standard conversion routines atoi( ) atof( ) rand( )

Formatted I/O Application Buffered I/O: ANSI stdio fioLib fread( ) fwrite( ) fioLib fioRead( ) printf( ) sprintf( ) Basic I/O Routines (device independent) read( ), write( ) Driver Routines xxRead( ) xxwrite( ) Hardware Devices Network Disk Drive Serial Device

Formatted I/O fioLib contains routines for non-bufferd formatted I/O. Includes printf() and sprintf() which are normally part of stdio. fioLib allows ansiStdio to be excluded without losing functionality.

Buffered Vs. Non Buffered I/O (ansiStdio) Unbuffered I/O (fioLib) Destination stdout fprintf(stdout, …) printf(…) stderr printErr(…) fprintf(stderr, …) other fprintf(fp, …) fdprintf(fd, …)

UNIX and VxWorks - I/O Comparison Similarities: Source code compatible.. Devices haave names like files. Concept of current directory. Concept of stdin, stdout, stderr. Differences: Speed. File descriptors in UNIX are local to a process; in VxWorks they are global. VxWorks uses only a subset of UNIX open( ) flags. printf( ) is not buffered.

Summary Basic I/O routines: open( ) close( ) read( ) write( ) ioctl( ) creat( ) Buffered I/O (ansiStdio) built on top of basic I/O using file pointers: fopen( ) fclose( ) fread( ) fwrite( ) fprintf( ) Formatted Non-buffered I/O (fioLib): printf( ) sprintf( ) fdprintf( )

Now Have a rest

Chapter 11 Local File Systems

Local File systems Overview DOS File System Raw File System SCSI Devices

(devicen independent) File Systems Application fioLib fioRead( ) printf( ) sprintf( ) Buffered I/O: stdio fread( ) fwrite( ) Basic I/O Routines (devicen independent) read( ) write( ) File System Routines xxRead( ) xxWrite( ) Driver Routines xxRead( ) xxWrite( ) Hardware Devices Network Disk Drive Serial Device

Local File Systems Available block device drivers : ramDrv Makes memory look like a disk scsiLib Supports SCSI random-access devices. xxDrv Third Party block drivers. Available file system libraries : dosFsLib MS-DOS compatible. rawFsLib Supports disk as a single file. rt11FsLib For backward compatibility.

Initialization and Use Block device creation routines ramDevCreate( ) scsiBlkDevCreate( ) xxDevCreate( ) BLK_DEV Local file system initialization routines dosFsDevInit( ) rawFsDevInit( ) local file systems ioLib / dirLib / usrLib routines open / close stat / fstat creat / remove read / write mkdir / rmdir

Creating a RAM Disk BLK_DEV * ramDevCreate ( ramAddr , bytesPerBlk , bytesPerTrack , nBlocks , blkOffset ) ramAddr Memory location of ram disk ( 0 = malloc( ) ). bytesPerBlk Number of bytes per block. blksPerTrack Number of blocks per track. nBlocks Size of disk in blocks. blkOffset Number of blocks to skip. Typically zero. Returns a pointer to a BLK_DEV structure describing the RAM disk, or NULL on error. Define INCLUDE_RAMDRV to include ramDrv in your vxWorks image.

A Simple Example /* Create and write to a file. Flush to RAM disk */ -> pBlkDev = ramDevCreate(0,512,400,400,0) -> dosFsMkfs (“/RAM1” , pBlkDev) /* Create and write to a file. Flush to RAM disk */ -> fd = creat(“/RAM1/myfile”,2) -> writeBuf = “This is a string.\n” -> write(fd,writeBuf,strlen(writeBuf)+1) -> close(fd) /* Open file and read contents. */ -> readBuf = (char *) malloc(100) -> fd = open(“/RAM1/myfile”,2) -> read(fd , readBuf , 100) -> printf readBuf This is a string.

Local File systems Overview DOS File System Raw File System SCSI Devices

DOS File System Hierarchical file system Restrictive file names. Compatible with MS-DOS file systems up to release 6.2. Disks are interchangeable with those created on PCs using MS-DOS ( if configured properly).

Configuring dosFs Define INCLUDE_DOSFS, in configAll.h , ( excluded by default ). Maximum number of dosFs files that can be open at a time with NUM_DOSFS_FILES ( default of 20 defined in configAll.h ). Specify Volume Configuration information in a DOS_VOL_CONFIG data structure : Disk layout. VxWorks options.

Caveat : Data Integrity To improve performance, FAT and directory changes are not flushed to disk immediately. To flush FAT and directory changes (before removing media) , use dosFsVolUnmount( ). Alternatively , set options in the dosvc_options field of a partition’s DOS_VOL_CONFIG structure : DOS_OPT_AUTOSYNC Flush FAT and directory changes. DOS_OPT_CHANGENOWARN Remount dosFs on open( ) or creat( ). Setting these options will degrade performance. Flush file changes with, ioct(fd, FIOSYNC, 0).

Caveat : DOS file names By default, standard 8 + 3 DOS file names are used. Enable UNIX - style file names by setting DOS_OPT_LONGNAMES option bit in DOS_VOL_CONFIG data structure. UNIX - style file names are not PC compatible.

Caveat : PC Compatibility A disk initialized on a PC will work with VxWorks. For PC compatibility, a disk initialized with VxWorks Must use correct media byte. Do not enable UNIX - style file names enabled with DOS_OPT_LONGNAMES.

Configuration : New File System To create a new DOS filesystem with custom configuration parameters : 1. pBlkDev = xxDevCreate(...); 2. Initialize DOS_VOL_CONFIG structure. 3. dosFsDevInit( “/DOS”, pBlkDev , pConfig); 4. fd = open( “/DOS” , O_WRONLY , 0 ); 5. ioctl ( fd , FIODISKFORMAT , 0); /* if necessary */ 6. ioctl ( fd , FIODISKINIT , 0); 7. close( fd );

Configuration : New Filesystem To create a new DOS filesystem with default configuration parameters : 1. pBlkDev = xxDevCreate(...); 2. dosFsMkfs( “/DOS”, pBlkDev);

Configuration : Using an Existing File System To remount an existing file system : 1. pBlkDev = xxDevCreate(...); 2. pDesc = dosFsDevInit( “/DOS”, pBlkDev , NULL ); 3. dosFsVolOptionsSet (pDesc , options); /* if needed */ Typically , file system are configured in startup code.

Contiguous File Support To pre-allocate contiguous disk space for a file : ioctl (fd , FIOCONTIG,numBytes ) Must be called before anything is written to file. Example : fd = creat(“/dos1/myDir/myFile”, O_RDWR ); ioctl ( fd , FIOCONTIG , 0x10000 ); To obtain the largest contiguous block available , set numBytes to CONTIG_MAX. Pre-allocated space may be reclaimed with : ioctl (fd , FIOTRUNC , newLength)

Local File systems Overview DOS File System Raw File System SCSI Devices

Introduction to the Raw File System Wind River Systems defined. Fastest , least structured file system. Handles device (partition) as one file. Analogous to the UNIX raw interface to a block device. No Directories or other structure on disk.

Configuring the Raw File System Define INCLUDE_RAWFS in configAll.h (excluded by default ). Maximum number of rawFs files that can be open at a time controlled by NUM_RAWFS_FILES ( default of 5 is defined in configAll.h.)

Raw FS Initialization raw FsDevInit ( devName , pBlkDev ) To initialize a raw device : raw FsDevInit ( devName , pBlkDev ) devName Name of raw file system device being created. pBlkDev Pointer to the BLK_DEV returned from xxDevCreate( ). Returns NULL on error. To low-level format the disk : Open a file descriptor on the rawFs device. Call the FIODISKFORMAT ioctl. With no structure on the disk to initialize, there is no diskInit( ) routine.

Local File systems Overview DOS File System Raw File System SCSI Devices

SCSI Overview SCSI - Small Computer System Interface. ANSI standard providing device independence. All devices “speak the same language.” Less driver writing is required. Support for SCSI-1 and SCSI-2 devices. Support for general and block drives is supplied by scsiLib. Support for sequential devices is provided by scsiSeqLib.

SCSI Bus Controller SCSI Bus VxWorks Tape Drive Bus Id = 6 LUN = 3 Initiator Bus Id = 7

SCSI -1 Restrictions VxWorks must be the sole initiator. Only SCSI I random-access block devices conforming to the Common Command Set is supported. Disconnect / reconnect is not supported. Synchronous transfers are not supported. Drivers for non-random-access devices ( e.g., a tape drivse ) must be written by the user : scsiLib provides routines to put commonly used SCSI commands on the bus.. scsiIoctl ( ) allows arbitrary SCSI commands to be put on the bus.

SCSI -1 Support configuration To configure VxWorks for SCSI-1 support , selectively define the appropriate macro(s) by moving them outside the # if FALSE block in wind/target/config/bspName/config.h : # if FALSE # define INCLUDE_SCSI # define INCLUDE_SCSI_BOOT # define INCLUDE_SCSI_DMA /* if supported by BSP */ # define INCLUDE_DOSFS # define INCLUDE_TAPEFS /* SCSI -2 only */ # define SYS_SCSI_CONFIG # endif . . .

SCSI -2 Features Supports all mandatory features of the SCSI-2 protocol , and many optional features. SCSI - 2 features not supported by SCSI-1 : Multiple Initiators. Disconnect / reconnect. Mandatory direct access commands. Mandatory sequential access commands. Identify message. Synchronous data transfer. Fast SCSI Wide SCSI Tagged command queuing.

SCSI -2 Support configuration To include SCSI-2 support , the macro INCLUDE_SCSI2 (as well as INCLUDE_SCSI) must be defined in wind/target/config/target/config.h INCLUDE_SCSI2 must be defined before the include control line for the BSP header file bspName.h # define INCLUDE_SCSI2 # include “configAll.h” # include “bspName.h” Access to SCSI-2 devices : DOS or RAW file systems on direct-access devices. Tape File System on sequential-access devices.

Initializing SCSI Block Devices Include SCSI-2 Support in VxWorks #define INCLUDE_SCSI2 pSysScsiCtrl Initialization of SCSI Peripheral scsiPhysDevcreate(pSysScsiCtrl,busId,LUN,...) pScsiPhysDev Initialize Logical Partition scsiBlkDevcreate( ) pBlkDev Initialize File System dosFsDevInit( )

Configuration of SCSI Devices When support for SCSI is enabled, the system initialization code will : Initialize SCSI controller. Configure SCSI peripherals. Peripheral configuration call chain : usrRoot( ) => usrScsiConfig( ) => sysScsiConfig( ) sysScsiConfig( ) is called only if SYS_SCSI_CONFIG is defined. Configuring specific peripherals requires writing the sysScsiConfig( ) function. The sysScsiConfig( ) function should be placed in sysScsi.c (preferably) or sysLib.c in the BSP directory. Do not modify wind/target/src/config/usrScsi.c

Configuration : Hard Disks Bus Id 0 /* configure Winchester at busId=2 , LUN=0 */ 1 if((pSpd20= 2 scsiPhysDevCreate(pSysScsiCtrl,2,0,0,NONE,0,0,0)) 3 == (SCSI_PHYS_DEV *) NULL) 4 { 5 SCSI_DEBUG_MSG(“usrScsiConfig:”\ 6 “scsiPhysDevCreate failed. \n”); 7 return ERROR; 8 } 9 /* create block devices */ 10 if(((pSbd0=scsiBlkDevcreate (pSpd20,0x10000,0))== 11 NULL)|| 12 ((pSbd1=scsiBlkDevcreate (pSpd20,0x10000,0x10000)) 13 == NULL) 14 return (ERROR); 15 /* Configure file systems on partitions */ 16 if((dosFsDevInit (“/sd0/”,pSbd0,NULL)== NULL)|| 17 (rawFsDevInit (“/sd1/”,pSbd1)==NULL) 18 return (ERROR); 19 /* Continue with other devices… */ LUN Size Offset

Initializing SCSI Sequential Devices Include SCSI-2 Support in VxWorks #define INCLUDE_SCSI2 pSysScsiCtrl Initialization of SCSI Peripheral scsiPhysDevcreate(pSysScsiCtrl,busId,LUN,...) pScsiPhysDev Initialize Logical Partition scsiSeqDevcreate( ) pSeqDev Initialize File System tapeFsDevInit( )

Sequential Devices SEQ_DEV * scsiSeqDevCreate (pScsiPhysDev) pScsiPhysDev pointer to a SCSI_PHYS_DEV structure returned by scsiPhysDevCreate( ) Returns a pointer to a SEQ_DEV structure describing the sequential device , or NULL on error. Only need to define INCLUDE_SCSI and INCLUDE_SCSI2 in config.h. Sequential devices allow blocks of data to be read and written sequentially.

The Tape File System To access a sequential device create a tape file system. Can be configured for fixed block size transfers or variable size block transfers. No directory structure. No file names used. The Sequential device is accessed through the standard I/O interface. Define INCLUDE_TAPEFS in config.h.

Tape File System Initialization TAPE_VOL_DESC * tapeFsDevInit (devName, pSeqDev , pTapeConfig ) devName Volume name of tape file system device being created. pSeqDev Pointer to a SEQ_DEV returned from sequential device creation routine. pTapeConfig Pointer to a tape configuration structure TAPE_CONFIG. TAPE_VOL_DESC used to reference the file system.

Configuration : Sequential Devices 1 /* configure Exabyte 8mm tape drive at busId=4 , LUN=0 */ 2 if((pSpd40=scsiPhysDevCreate 3 (pSysScsiCtrl,4,0,0,NONE,0,0,0)) 4 == (SCSI_PHYS_DEV *) NULL) 5 { 6 SCSI_DEBUG_MSG(“usrScsiConfig:\” 7 ”scsiPhysDevCreate failed. \n”); 8 return (ERROR); 9 } 10 /* configure the sequential device for this physical device */ 11 if(((pSd0=scsiSeqDevcreate (pSpd40)) 12 == (SEQ_DEV *)NULL) 13 { 14 SCSI_DEBUG_MSG(“usrScsiConfig:\” 15 ”scsiSeqDevCreate failed. \n”); 16 return (ERROR); 17 } 18 /* initialize a tapeFs device */ 19 .... 20 if(tapeFsDevInit (“/tape1/”,pSd0,pTapeConfig)== NULL) 21 return (ERROR);

Debugging Tools -> scsiShow ID LUN VendorId ProductId Rev. Type Blocks BlkSize scsiPhysDev -- --- -------- --------- --------- ---- ------ ------- ----------- 5 0 ARCHIVE VIPER 150 21247-005 1R 0 0 0X003CF654 When first starting out , define SCSI_AUTO_CONFIG in wind/target/config/target/config.h. Calls scsiPhysDevCreate( ) for each bus Id and LUN. Calls scsiShow( ) when done. If you don’t see all your peripherals attached : Check cable connections. Check SCSI bus terminations. Make sure your peripheral supports the SCSI protocol being used. In sysScsiConfig( ), set the global scsiDebug = TRUE.

Summary DOS and RAW file systems for : RAM disk. SCSI devices. Custom block devices. SCSI-1 device support for : Direct-access devices. SCSI-2 device support for : Direct-access devices. Sequential-access devices. Tape file system.

Chapter 12 Network Basics

Network Basics Introduction Configuring The Network Remote Login Remote Command Execution Remote File Access

Network Protocols Machines on a network must agree to exchange data in some standard way. Internet protocol suite (also called TCP / IP) provides system independent protocols. VxWorks implementation of TCP / IP protocol suite is based on 4.3BSD “Tahoe release”.

(VMEbus and serial line are also supported) Simple Network UNIX Fileserver VxWorks Target ethernet PC Host (VMEbus and serial line are also supported)

Terminology Each node on the network is a “host”. Not to be confused with VxWorks host / target relationship. Internet is an ambiguous word : Internet Protocol Suite : A collection of protocols for system independent network communication. An Internet : A collection of connected networks. The Internet : The global internet.

Complex Network (Internet) routers

Shared Memory Network Overview VMEbus Network 100.0.0.0 100.0.0.1 100.0.0.2 90.0.0.2 90.0.0.30 VxWorks CPU0 VxWorks CPU1 UNIX ETHERNET Network 90.0.0.0 Details in appendix and Programmers Guide.

Network Services VxWorks network services include : Remote file access Remote login Remote command execution User can build other network services as needed. Writing network applications will be discussed in the next chapter.

Network Non-Determinism TCP / IP is non-deterministic because of : Ethernet collisions VMEbus spin locks Dropped packets Timeouts and retransmissions

Networking Introduction Configuring The Network Remote Login Remote Command Execution Remote File Access

Routing If client and server are on different networks, data passing between them must be routed. Internet routing algorithm : if (destination on a directly attached network) send data to destination else use routing table to find correct router and send data to router.

Internet Addresses Internet addresses written in “dot” notation 90.0.0.70 Internally stored as 4 byte integer 0x5a000046 This value encodes both a network number and a host number. Analogous to a phone number having an area code and a local portion. Two nodes are on the same network if they have the same network number. Makes routing easier.

Internet Address Classes network 7 bits host 24 bits B network 14 bits host 16 bits 1 C network 21 bits host 8 bits 1 1

Internet Address Examples CLASS A 90.0.0.0 Network 90.1.2.4 90.3.6.8 CLASS B 128.11.0.0 Network 128.11.3.21 128.11.5.19 CLASS C 192.15.2.0 Network 192.15.2.10 192.15.2.45

Assigning Internet Addresses Network Prefixes Must be unique for each network on an internet. Assigned by adminstrator of that internet. In an isolated environment, there is no restriction on network prefix. If connected to the Internet, network prefix must be assigned by the InterNIC (Internet Network Information Center) Host Numbers Must be unique for each host on a network Assigned by administrator of that network.

Subnets At a large site, many physical networks are needed : To improve network performance To make administration easier. Adding a new network normally requires obtaining a new network prefix. A new network number may not be available. Subnetting allows a site to add new networks transparently to the rest of the internet.

router to outside world Subnet Example 130.10.2.0 subnet 130.10.2.5 130.10.2.6 130.10.0.0 network router to outside world subnet mask : 0xffffff00 130.10.1.20 130.10.1.37 130.10.1.0 subnet VxWorks target on 130.10.1.0/24 subnet must specify: inet on ethernet (e) : 130.10.1.20:ffffff00

Routines for manipulating internet addresses : inetLib Routines for manipulating internet addresses : inet_addr( ) Converts dot notation internet address to an integer. inet_lnaof( ) Returns the host portion of an internet address. inet_netof( ) Returns the network portion of an internet address. inet_netof_string( ) Obtains network portion of address as a string. Knows about interface subnet masks. inet_ntoa_b( ) Converts internet address to ASCII dot notation.

hostAdd (hostName, hostAddr) Host Names To associate a name with an internet address : hostAdd (hostName, hostAddr) To display host name table use : hostShow ()

Example -->hostAdd “styx”, “147.11.1.80” value = 0 = 0x0 -->hostAdd “nelson”, “147.11.1.80” -->hostShow hostname inet address aliases localhost 127.0.0.1 ohio 147.11.1.81 styx 147.11.1.80 nelson

Routing Tables 192.15.2.0 network 192.15.2.1 192.15.2.22 epimetheus janus mimas 65.0.0.1 65.0.0.3 65.0.0.0 network Host A Routing Table Host C Routing Table Network Gateway Network Gateway 192.15.2.0 65.0.0.3 65.0.0.0 192.15.2.1

Adding Routes in VxWorks To add a route use : route (destination, gateway) Can use a host name or an internet address. Destination can be : A specific host : routeAdd (“65.0.0.4”,”192.15.2.7”) A network : routeAdd (“65.0.0.0”,”gateHost”) Anywhere else ( default route ): routeAdd (“0”,“192.15.2.1”)

A Debugging Tool -->routeAdd “150.39.0.0”, “147.11.54.254” value = 0 = 0x0 -->routeShow ROUTE NET TABLE destination gateway flags Refcnt Use Interface 150.39.0.0 147.11.54.254 3 0 0 enp0 147.11.54.0 147.11.54.170 1 1 52 enp0 ROUTE HOST TABLE 127.0.0.1 127.0.0.1 5 0 0 lo0 value = 73 = 0x49 = ‘I’

Testing Routes To check if a host is reachable : STATUS ping (host, nPackets, options) -->ping “columbia”, 1 columbia is alive value = 0 = 0x0 -->ping “90.0.0.70”, 1 no answer from 90.0.0.70 value = -1 = 0xffffffff = _end + 0xfff91c4f If ping( ) fails, check : Routing information. Hardware connections.

Host Configuration Associate host names with internet addresses in host table. Set up routing tables so that packets will be routed correctly. Speak with your network administrator! For more information, see : TCP / IP Network Administration, O’Reilly & Associates. (UNIX Host) Networking personal Computers with TCP / IP, O’Reilly & Associates. (PC Host) Managing NFS and NIS, O’Reilly & Associates. (UNIX Host) Your network software’s documentation.

Network Services Introduction Configuring The Network Remote Login Remote Command Execution Remote File Access

Remote Login and VxWorks Two protocols : rlogin (UNIX Host) telnet (internet protocol) Gives access paths to VxWorks applications for sites without Tornado interface. Security can be installed. Restricts access to VxWorks by user name and password: Define INCLUDE_SECURITY Modify LOGIN_USER_NAME and LOGIN _PASSWORD Add additional users with loginUserAdd( )

Remote Login and Support Facilities Support routines must be linked into VxWorks. INCLUDE_RLOGIN rlogin server and client. INCLUDE_TELNET telnet server. Remote login also requires the target resident shell. INCLUDE_SHELL Additional tools to be used in conjunction with remote login facilities can also be linked into VxWorks : Target resident symbol table. Target resident show routines. Target resident module loader / unloader.

Network Basics Introduction Configuring The Network Remote Login Remote Command Execution Remote File Access

Executing Remote Commands UNIX RSH server VxWorks shell RSH client shell cmd socket VxWorks programs can invoke remote shell (RSH) commands on a UNIX host A file descriptor called a socket is created. Can read( ) from this socket to get command output.

UNIX : Remote Command Execution int rcmd (host, remotePort, localUser, remoteUser, cmd, pFd2) host Host name or inet number. remotePort Remote port number to connect to, typically 514(shell). localUser Name of local user. remoteUser User name on remote host. cmd Shell command string to execute. pFd2 If non-zero, a socket for STD_ERR is returned through this pointer. Returns a socket file descriptor or ERROR.

UNIX : rcmd Example -->unixDate = calloc (300,1) unixDate = 0x23ff264 : value = 37744912 = 0x23ff110 -->aFd = rcmd(“ohio”,514,”debbie”,”debbie”,”date”,0) newsymbol “aFd” added to symbol table. aFd = 0x23fefa0 : value = 4 = 0x4 -->read (aFd, unixDate, 300) value = 29 = 0x1d -->printf (“%s \n”, unixDate) Mon Nov 18 12:25:45 PST 1991 value = 30 = 0x1e -->close (aFd)

Network Basics Introduction Configuring The Network Remote Login Remote Command Execution Remote File Access

Remote File Access VxWorks comes with two drivers which allow access to files on remote machines. nfsDrv netDrv

NFS Network File System (NFS) was developed by Sun Microsystems Allows efficient access to files. NFS transfers and buffers files in pieces (usually 8 Kbytes). Remote file systems are mounted; then accessed as if they were local file systems. VxWorks provides NFS client and server. NFS client excluded by default. To include, define INCLUDE_NFS in ConfigAll.h

To access files on a remote machine using NFS : NFS Overview To access files on a remote machine using NFS : . Export server’s file system : Make a local file system available to remote host with appropriate access permissions. . Mount the file system on the client. . Set the client’s authentication parameters.

1. Exporting the File System NFS servers only export local file system %mount /dev/sd0a on / type 4.2 /dev/sd0g on / dino type 4.2 styx : /usr on /usr type nfs VxWorks Target / /dino File server styx /usr Workstation Columbia

2. Mounting NFS Filesystems STATUS nfsMount (host, fileSystem, localName) host Name of remote host. fileSystem Name of remote file system to mount (must be exported by remote host). localName Local device name for file system. If NULL, uses fileSystem. Example : -->nfsMount (“columbia”, “/dino”, “/dinoNfs”) -->fd = open (“/dinoNfs/comics/myFile”, 2)

Examining NFS Filesystems To display al mounted NFS file systems : -->nfsDevShow device name file system /usrNfs styx : /usr /dinoNfs columbia : / dino value = 0 = 0x0

UNIX : 3. NFS Authentication For UNIX NFS servers, once file system is mounted client can access files as if they were local after authentications are set. File access depends on : User id. Group id. Default id’s specified in configAll.h : #define NFS_USER_ID 2001 #define NFS_GRUOP_ID 100 To find your user and group ids on UNIX host : %id uid = 219(marc) gid=700(training)

UNIX : NFS Authentication void nfsAuthUnixSet (hostName, uid, gid, ngids, aup_gids) hostName Remote host name. uid User id on hostName. gid Group id on hostName. ngids Number of gids listed in aup_gids. aup_gids Array of additional group id’s. Sets authentication programmatically. To see current authentication parameters, use : void nfsAuthUnixShow( )

netDrv netDrv allows access to remote files : Entire file read into target memory on open( ). read( ) / write( ) act on copy of file in memory. File not written to remote host until close( ). Can’t access large files (constrained by available memory). ioctl (fd, FIOSYNC, 0) is not supported dirLib routines opendir / readdir do not work on netDrv directories. stat / fstat only partially implemented.

Creating network Devices STATUS netDevCreate (devName, host, protocol) devName Local name of device to create. By convention, ends with ‘:’. host Name of remote machine (from previous hostAdd( )). protocol Protocol to transfer files to / from VxWorks (0=RSH or 1=FTP). Example : -->netDevCreate (“ohio:”, “ohio”, 1) -->fd = open (“ohio:/u/teamN”, 2)

Permissions FTP file access requires a name and a password : --> iam “team8” , “team8Password“ RSH file access permission requires : (UNIX host) A user name to be sent on the target. --> iam “team8” Target must be trusted to verify user name without a password. ~team8/.rhosts vx8 rcmd and rlogin to UNIX also use the RSH protocol. (UNIX host)

UNIX : netDrv Protocol Comparison Advantages of FTP over RSH : FTP is part of the TCP / IP protocol suite, so is available on all networked hosts. FTP is faster on open / close; since there is no shell delay. FTP server supplied with VxWorks. Advantages of RSH over FTP : FTP clear text password goes over the network on each open( ) and close( ).

netDrv vs. nfsDrv Advantages of nfsDrv over netDrv : Reads and writes only needed parts of the file. Can access arbitrarily large files. open( ) and close( ) much faster. Can use dirLib routines. Can flush file changes with FIOSYNC. Advantages of netDrv over nfsDrv : All networked hosts have an FTP server. Easier to configure. read( ) / write( ) slightly faster.

Accessing Files on VxWorks Requires a file server : VxWorks supplies FTP and NFS servers. VxWorks does not supply RSH server.

NFS Server Overview Allows remote hosts to access a target’s file system using NFS protocol. Only DOS file system is supported. Define INCLUDE_NFS_SERVER in configAll.h NFS server configuration : 1. Initialize DOS file system with NFS server support. 2. Inform NFS server that the file system is exportable. 3. Mount file system on remote host.

1. Creating A Mountable File System Enable the DOS_OPT_EXPORT configuration option, before initializing a DOS file system to support remote access. Example : /* Configure Block Device */ pBlkDev = xxDevCreate(….); /* Configure File System with NFS Support */ dosFsDevInitOptionsSet (DOS_OPT_EXPOT); dosFsDevInit (“/fsName, pBlkDev, NULL);

2. Exporting A File System To allow remote systems access to local file system : nfsExport (name, fsId, rdOnly, notUsed) name File system name. fsId NFS export Id number - Use 0 for NFS to create an ID. rdOnly TRUE = mountable read only. FALSE = mountable read write. notUsed Set to zero - reserved for future use. Example : nfsExport (“/fsName“, 0, FALSE, 0);

3. Accessing File System From A Remote Host To mount the VxWorks file system on a remote host, use : mount -F nfs node:fileSystem directory Typically, superuser (root) privilege is required on UNIX systems to mount a file system. (UNIX host) Example : mount -F nfs vxtarget: /fsName /mountPoint Once mounted, files may be accessed as if they were on a local file system.

Caveats By default, no authentication is performed Only DOS file system supported. Standard DOS limitations apply: File naming restrictions. No symbolic links. No directory renaming.

VxWorks FTP Server Define the macro INCLUDE_FTP_SERVER in configAll.h or config.h. When target is rebooted, should see tFtpdTask (server daemon) running.

FTP Example - VxWorks to VxWorks VxServer VxClient -->pBlkDev = ramDevCreate (0, 512, 0, 400, 0) -->dosFsMkfs = (“/RAM1”, pBlkDev) -->fd = creat(“RAM1/dataFile”,2) -->wirte (fd, dataPtr, nBytes) -->close (fd) -->netDevCreate (“VxServer :”, “VxServer”, 1) -->fd = open(“VxServer:” “/RAM1/dataFile”,2) -->getData (fd, dataBuf, maxSize) -->close (fd) Can also use FTP to boot one VxWorks target from another.

FTP Example - VxWorks to UNIX VxServer UNIX Client -->pBlkDev = ramDevCreate (0, 512, 0, 400, 0) -->dosFsMkfs = (“/RAM1”, pBlkDev) -->fd = creat(“RAM1/aFile”,2) -->wirte (fd, dataPtr, nBytes) -->close (fd) % FTP VxServer connected to VxServer. Name (VxServer : debbie) : Password : ftp> cd /RAM1 ftp> get dataFile local : dataFile remote : dataFile 137 bytes received in 0.02 seconds (6.7Kbytes /s) ftp> quit % ls dataFile

NFS vs. FTP Server NFS advantages : Efficient file access. Configurable number of servers pre-spawned. FTP advantages : Can access file systems other than DOS. All network hosts have FTP client.

Summary Internet Protocol for node-to-node routing. Configuring the network : VxWorks : routeAdd( ), hostAdd( ). Configure host’s host routing tables. rlogin (UNIX host) and telnet support. rcmd ( ) (UNIX host) nfsDrv mounts remote file systems with nfsMount( ) Reads and writes portion of remote file. File system must be exported by remote host. File access requires uid and gid.

Summary netDrv devices created with netDevCreate( ). Entire file is read into VxWorks on open( ), and not updated until close( ). Uses either RSH (UNIX host) or FTP for file transfer. RSH requires name and entry in .rhosts. (UNIX Host) FTP requires name and password. FTP and NFS servers allows local VxWorks files to be accessed by a remote machine.

Chapter 13 Network Programming

Network Programming Introduction Sockets UDP Sockets Programming TCP Sockets Programming RPC

VxWorks Networking Network programming allows users to : Build services Create distributed applications VxWorks network programming tools : Berkeley sockets zbuf socket API Sun RPC ( Remote Procedure Call )

Network Components Sockets Shared Memory Network Driver Tornado tgtsvr rlogin telnet NFS rsh ftp RPC zbuf API Sockets TCP UDP IP Ethernet Shared Memory Slip / PPP

Network Components Sockets Shared Memory Network Driver Tornado tgtsvr rlogin telnet NFS rsh ftp RPC zbuf API Sockets TCP UDP IP IP Ethernet Shared Memory Slip / PPP

Network Components Sockets Shared Memory Network Driver Tornado tgtsvr rlogin telnet NFS rsh ftp RPC zbuf API Sockets TCP UDP IP Ethernet Shared Memory Slip / PPP

Ports UDP IP Abstract destination point within a node. 90.0.0.1 90.0.0.2 TCP/ UDP intertask communication. Data is sent by writing to a remote port. Data is rceived by reading from a local port.

Network Components Sockets Shared Memory Network Driver Tornado tgtsvr rlogin telnet NFS rsh ftp RPC zbuf API zbuf API Sockets TCP UDP IP Ethernet Shared Memory Slip / PPP

Network Components Sockets Shared Memory Network Driver Tornado tgtsvr rlogin telnet NFS rsh ftp RPC zbuf API Sockets TCP UDP IP Ethernet Shared Memory Slip / PPP

Packet Encapsulation data data Application Application UDP / TCP header UDP / TCP header data data UDP / TCP UDP / TCP IP header IP header UDP / TCP header UDP / TCP header IP IP data data ethernet header ethernet header IP header Ethernet Ethernet IP header UDP / TCP header UDP / TCP header data data

Network Programming Introduction Sockets UDP Socket Programming TCP Socket Programming RPC

Socket Overview Programmatic interface to internet protocols. Protocol specified when socket created ( e.g.,UDP or TCP ). Server binds its socket to a well known port. Client’s port number dynamically assigned by the system.

Ports Socket address consists of : An internet address ( node socket is on ). A port number ( destination within that node ) Port identified by a short integer : 0-1023 Reserved for system services (e.g.,rlogin,telnet, etc). 1024-5000 Dynamically allocated >5000 User defined Unique to each machine and protocol

VxWorks supports only internet sockets. Socket Address Generic socket address : struct sockaddr { u_short sa_family ; /* address family */ char sa_data[14] ; /*protocol specific address data */ } ; Generic address structure used by Internet Protocol : struct sockaddr_in { short sin_family ; /* AF_INET */ u_short sin_port ; /* port number */ struct in_addr sin_addr ; /*internet address */ char sin_zero[8] ; /* padding, must be zeroed out */ } ; VxWorks supports only internet sockets.

Network Byte Ordering Fields in the struct sockaddr_in must be put in network byte order ( big - endian) Macros to convert long / short integers between the host and and the network byte ordering : hotnl( ) host to network long hotns( ) host to network short ntohl( ) network to host long ntohs( ) network to host short

Caveat - User Data To send data in a system independent way : 1.Sender converts data from its system-dependent format to some standard format. 2. Receiver converts data from the standard format to its system- dependent format. The standard format used must handle : Any standard data types used ( e.g.,int, short, float, etc.). Data structure alignement. One such facility, XDR, will be discussed in the RPC section of this chapter.

int socket ( domain , type , protocol) Creating a Socket int socket ( domain , type , protocol) domain Must be PF_INET type Typically SOCK_DGRAM (UDP) or SOCK_STREAM (TCP) protocol Socket protocol ( typically 0 ). Opens a socket ( analogous to open() for files) Returns a socket file descriptor or ERROR

STATUS bind ( sockFd , pAdrs , adsLen) Binding a Socket To bind a socket to a well known address : STATUS bind ( sockFd , pAdrs , adsLen) sockFd Socket descriptor returned from socket( ) pAdrs Pointer to a struct sockaddr to which to bind this socket adrsLen sizeof ( struct sockaddr ). Typically only called by server.

Example Server Stub 1 #define PORT_NUM ( USHORT ) 5001 2 struct sockaddr_in myAddr; 3 int mySocket ; 4 ... 5 mySocket = socket ( PF_INET, SOCK_DGRAM,0 ); 6 if ( mySocket == ERROR) 7 return (ERROR) ; 8 9 bzero (&myAddr, sizeof (struct sockaddr_in)); 10 myAddr.sin_family = AF_INET; 11 myAddr.sin_port = htons (PORT_NUM) ; 12 myAddr.sin_addr.s_addr = INADDR_ANY ; 13 14 if ( bind ( mySocket, (struct sockaddr *) &myAddr, 15 sizeof (myAddr)) == ERROR ) 16 { 17 close (mySocket) ; 18 return (ERROR); 19 }

Network Programming Introduction Sockets UDP Socket Programming TCP Socket Programming RPC

UDP Socket Overview Server Client socket fds at saddr socket fdc fds = socket ( PF_INET, SOCK_DGRAM, 0 ) bind ( fds , (struct sockaddr *)&saddr, sizeof(saddr)) loop recvfrom(fds , ...) /* wait for request */ ...... /* perform service */ sendto (...) /* Send reply */ fds = socket ( PF_INET, SOCK_DGRAM, 0 ) sendto (...) /* Send request to server */ select(...) /* wait for reply with timeout */

Sending Data on UDP Sockets int sendto ( sockFd , pBuf , bufLen , flags , pDestAdrs , destLen) sockFd Socket to send data from. pBuf Address of data to send. bufLen Length of data in bytes. flags Special actions to be taken. pDestAdrs Pointer to struct sockaddr containing destination address. destLen sizeof (struct sockaddr). Returns the number of bytes sent or ERROR.

Receiving Data on UDP Sockets int recvfrom (sockFd, pBuf, buflen, flags, pFromAdrs, pFromLen) sockFd Socket to received data from. pBuf Buffor to hold incoming data. buflen Maximum number of bytes to read. flags Flags for special handling of data. pFromAdrs Pointer to struct sockaddr. Routine supplies internet address of sender. pFromLen Pointer to integer. Must be initialized to sizeof (struct sockaddr). Blocks until data available to receive. Returns number of bytes received or ERROR.

Network Programming Introduction Sockets UDP Socket Programming TCP Socket Programming RPC

TCP Socket Overview TCP is connection based (like making a phone call) Concurrent servers are often implemented. SERVER Master Slave Slave Clients send connection requests to Master’s socket New socket created dynamically for each connection, serviced by work task.

TCP Server Overview 1 2 3 4 5 6 7 8 9 10 / * master server * / masterFd = socket (PF_INET, SOCK_STREAM, 0) / * fill in server’s sockaddr struct * / bind (...) / * bind to well-known port * / listen (...) / * configure request queue * / FOREVER { clientFd = accept (masterFd, ...) taskSpawn (..., slaveSrv, clientFd, ...) } / * slave server * / slaveSrv (clientFd, ...) read (clientFd, ...) / * read request * / serviceClient ( ) write (clientFd, ...) / * send reply * / close (clientFd)

TCP Client Overview 1 2 3 4 5 6 7 8 9 10 11 / * TCP Client * / fd = socket (PF_INET, SOCK_STREAM, 0) / * fill in sockaddr with server’s address * / connect (fd, ...) / * request service * / write (fd, ...) / * send request * / read (fd, ...) / * read reply * / close (fd) / * terminate connection * /

Server Initialization Before accepting connections, server must : Create a socket (socket( )) Bind the socket to a well known address (bind( )) Establish a connection request queue : STATUS listen (sockFd , queueLen) SockFd Socket descriptor returned from socket( ). queueLen Nominal length of connection request queue.

Accepting Conncetions int accept (sockFd , pAdrs , pAdrsLen) sockFd Servers socket (returned from socket( )). pAdrs Pointer to a struct sockaddr through which the client’s address is returned. pAdrsLen Pointer to length of address. Blocks until connection request occurs. Returns new socket file descriptor (connected to the client) or ERROR. Original socket, sockFd, is unconnected and ready to accept other connection requests.

Requesting Connections To connect to the server, the client calls: STATUS connect (sockFd, pAdrs, adsLen) sockFd Client’s socket descriptor. pAdrs Pointer to server’s socket address. adrsLen sizeof (struct sockaddr) Blocks until connection is established or timeout. Returns ERROR on timeout or if no server is bound to pAdrs

Exchanging Data Master read( ) / write( ) may be used to exchange data: Server Master Slave Slave read( ) write( ) Caveat : TCP is stream oriented. write( ) may write only part of message if I / O is nonblocking. read( ) may read more or less than one message.

Cleaning up a Stream Socket When done using a socket, close( ) it : Frees resources associated with socket. Attempts to deliver any remaining data. Next read( ) from peer socket will return 0. Can also use shutdown( ) to terminate output, while still reveiving data from peer socket.

Setting Socket Options Options can be enabled on a per socket basis, including : Don’t delay write( )’s to coalesce small TCP packets. Enable UDP broadcasts. Linger on close( ) until data is sent. bind( ) to an address already in use. Change the size of the send / receive buffers. Consult UNIX man pages on setsockopt( ) for details. To make a socket non-blocking : int val = 1; /* Set to 0 for blocking I / O */ ioctl (sock, FIONBIO, &val);

zbuf Socket API Improves application performance by minimizing data copies through buffer loaning. Application must manage buffers. zbuf application can communicate with a standard socket application. Supports TCP and UDP protocols. See zbufLib and zbufSockLib for details. Proprietary API.

Network Programming Introduction Sockets UDP Socket Programming TCP Socket Programming RPC

Overview RPC (Remote Procedure Call) provides a standard way to invoke procedures on a remote machine. For more information about RPC : Appendix TCP / IP Illustrated Volume I (Stevens). Power Programming with RPC (O’Reilly & Associates). Documentation and source code can be found in wind/target/unsupported/rpc4.0

RPC Client - Server Model client routines server routines client stub server stub network routines network routines

VxWorks and rpcgen STATUS rpcTaskInit( ) rpcgen is a RPC protocol compiler. From a specification of the remote procedures, rpcgen creates : A client stub. A server stub. The XDR routines for packing / unpacking data structures. Not created if all parameters / return_values are standard data types. A header file for inclusion by client and server. Each VxWorks task accessing RPC calls using code produced by rpcgen must first initialize access. STATUS rpcTaskInit( )

Summary Transport layer network Protocols: TCP Stream oriented, reliable port-to-port communication. UDP Packet oriented, non-reliable port-to-port communication. Sockets as the interface to network protocols: UDP transport protocol. TCP transport protocol. Configurable socket options. zbuf socket API. Client / server programming strategies for distributed applications.

Reconfiguring VxWorks Chapter 14 Reconfiguring VxWorks Introduction Components Getting Help Custom Hardware

Reconfiguring VxWorks Chapter 14 Reconfiguring VxWorks

Overview After development is completed, you may need to: Exclude unneeded VxWorks facilities. Link application code into VxWorks. Modify VxWorks’s start-up code to spawn application tasks. Final application may be: Downloaded from host over a network. Linked with VxWorks and put into ROM. Loaded from a local disk.

Typical Steps 1. Exclude unneeded facilities from VxWorks. 2. Modify system start up code to spawn a task to initialize your application. 3. Modify the target’s Makefile to link your application code with VxWorks. 4. Run make to produce either a downloadable or a ROM- able application.

1. Scaling VxWorks To build a VxWorks image which includes a facility, the facility’s corresponding macro(s) must be defined in either: wind/target/config/all/configAll.h (generic base configuration - avoid modifying this file if possible). wind/target/config/bspName/config.h (target specific configuration). Alternatively, WindConfig can be used to select or unselect VxWorks facilities. When the new VxWorks image is built and booted, it will initialize the facilities selected.

Configuration Dependencies Some optional facilities depend on others (e.g., the NFS facility requires RPC). wind/target/src/config/usrDepend.c checks these dependencies and includes all required facilities. As a result of dependency checking, some facilities which apparently were excluded may actually be included in the final system image.

2. Modifying System Start-up Code usrRoot( ) in usrConfig.c: Executed by first VxWorks task. Initializes system facilities. Start user application if macros defined appropriately : void usrRoot( ..... ) { ............. #ifdef INCLUDE_USER_APPL /* Start the user’s application. */ USER_APPL_INIT; /* must be valid C statement */ /* or block. */ #endif }

Example USER_APPL_INIT Define INCLUDE_USER_APPL Define USER_APPL_INIT to be a statement or block which starts your application. You may make necessary declarations within the block : /* mv162/config.h - Motorola MVME162 header */ ............. #define INCLUDE_USER_APPL #define USER_APPL_INIT {\ extern void myApp( void ); \ taskSpawn (“tMyApp”, 60, 0, 30000,\ (FUNCPTR) myApp, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\ }

3. Linking An Application with VxWorks Modify the Makefile in the target directory: MACH_EXTRA = myCode.o . . . myCode.o: . . . $(make) -f Makefile_myCode Alternatively, specify your application’s modules on the command line with ADDED_MODULES. % make -f Makefile_mycode % make ADDED_MODULES = muCode.o vxWorks_rom

4. Building VxWorks Use makefile in target directory to rebuild VxWorks or boot ROMs: Go to the target directory. make object Common makefile objects: vxWorks VxWorks image (default). vxWorks_rom .hex ROM-able VxWorks image vxWorks_res_rom_nosym ROM-resident standalone version of VxWorks without symbol table.Starts fast, uses little RAM bootrom .hex Boot ROM code.

ROMable Objects ROMable objects copy themselves into RAM before running. Most of the ROMable VxWorks objects are compressed. An exception to this is vxWorks_rom If using large capacity ROM’s, may need to modify the constant ROM_SIZE in both: wind/target/config/target/config.h . wind/target/config/target/Makefile. Make will fail if the object is larger than the ROM_SIZE

Downloadable Objects ROM boot code copied into RAM at RAM_LOW_ADRS, bootstrap part decompresses rest to RAM_HIGH_ADDRS. VxWorks system image loaded at RAM_LOW_ADRS (typically 0x1000). ROM RAM BootStrap Program RAM_LOW_ADRS Boot ROM Program VxWorks FREE_RAM_ADRS RAM_HIGH_ADRS Boot ROM Program

Rebuilding Boot ROM’s If system image is large (>570 Kbytes, typically), downloading will overwrite the booting code, failing while printing: Loading . . . 400316 + 28744 + 23852 May need change RAM_HIGH_ADRS in: wind/target/config/target/config.h . wind/target/config/target/Makefile. New ROM’s are also required to boot off of a local disk

Standard make Targets TYPES OF IMAGES VxWorks Tornado VxWorks Standalone Boot Program ROMable compressed vxWorks.st_rom bootrom ROMable uncompressed vxWorks_rom bootrom_uncmp ROM resident vxWorks.res_rom_nosym vxWorks.res_rom bootrom_res Downloadable uncompressed vxWorks vxWorks.st Not all BSP’s will support all of these images. Some BSP’s support additional images Standalone VxWorks has a target shell built-in symbol table. target/make/rules.bsp has the make rules for these images.

Additional Configuration Many other configuration changes are possible : Change the default boot line in config.h Change boot code in bootConfig.c. Modify I/O system parameters in ConfigAll.h For details, see the Configuration chapter in the Programmer’s Guide.

ROM-based VxWorks Start-up 1. _romInit in config/bspName/romInit.s Minimal initialization : mask interrupts, disable caches, set initial initial stack, initialize DRAM access. 2. romStart( ) in config/all/bootnit.c Copy text / data segment(s) to RAM, clear other RAM. Decompress if necessary. 3. usrInit( ) in bootconfig.c or usrConfig.c Do pre-kernel hardware & software initialization; start kernel by calling kernelInit( ). 4. usrRoot( ) in bootconfig.c or usrConfig.c Initialize facilities configured into VxWorks; start boot program or user application 5. Boot program or user application.

Downloaded VxWorks Start-up 1. Boot program loads VxWorks over network, from local disk, etc. Call : Minimal initialization : mask interrupts, disable caches, set initial initial stack, initialize DRAM access. 2. _sysInit( ) in config/bspName/sysALib.s Similar to _romInit: mask interrupts, disable caches, set initial stack pointer. Then call: 3. usrInit( ) in config/all/usrConfig.c 4. usrRoot( ) in config/all/usrConfig.c 5. User application.

Summary 1. Modify config.h to exclude unneeded facilities. 2. Define INCLUDE_USER_APPL and USER_APPL_INIT to make usrRoot() spawn your tasks. 3. Modify the Makefile to link your application into the VxWorks system image MACH_EXTRA = myCode.o . . . 4. Remake the system image. New image can be booted or ROM-ed. % make vxWorks % make vxWorks_rom.hex % make bootrom.hex

OVER Thank you very much Good luck