VX编程手册
更新时间:2024-06-03 02:51:01 阅读量: 综合文库 文档下载
VxWorks编程手册
编程手册
赵洪策
2003年3月7日
第 1 页 共 35 页
VxWorks编程手册
目录
编程手册 .......................................................................................................................................... 1
1.VxWorks任务 .................................................................................................................... 3
1.1VxWorks中的多任务 ................................................................................................. 3 1.2任务状态转换 ............................................................................................................. 3 1.3 任务的调度程序 ........................................................................................................ 4 1.4任务控制 ..................................................................................................................... 7 1.5任务扩展 ................................................................................................................... 10 1.6任务错误状态: ....................................................................................................... 11 1.7任务异常的处理 ....................................................................................................... 11 1.8共享代码和重载入 ................................................................................................... 11 1.9VxWorks系统任务 ................................................................................................... 13 1.10任务堆栈 ................................................................................................................. 13 2任务间通讯 .......................................................................................................................... 14
2.1共享内存结构 ........................................................................................................... 14 2.2互斥变量 ................................................................................................................... 14 2.3Semaphores信号量 ................................................................................................... 15 2.4消息队列 ................................................................................................................... 20 3、中断 ................................................................................................................................... 23 4、I/O系统 ............................................................................................................................ 25
4.1介绍 ........................................................................................................................... 25 4.2文件、设备和驱动 ................................................................................................... 26 4.3基本I/O .................................................................................................................... 26 4.4 Buffered I/O—Stdio .................................................................................................. 28 4.6异步输入、输出(AIO) ........................................................................................ 29 4.7 VxWorks中的设备 .................................................................................................. 30
4.7.1串口I/O设备(终端和伪终端设备) ......................................................... 30 4.7.2 PIPE设备 .................................................................................................... 31 4.7.3 伪内存设备 ................................................................................................. 32 4.7.4 网络文件系统设备 ..................................................................................... 32 4.7.5 非NFS设备 ................................................................................................ 32 4.7.6 block设备 ................................................................................................... 33 4.7.7 SOCKET...................................................................................................... 33 4.7.8 VxWorks与Host系统I/O的区别 ............................................................ 33
5. 本地文件系统 .................................................................................................................... 33
5.1介绍 ........................................................................................................................... 33 5.1dosFs .......................................................................................................................... 33 5.2 Raw File System: rawFs ............................................................................................ 33 5.3 CD-ROM File System: cdromFs ............................................................................... 34 5.4 目标服务器文件系统-TSFS ................................................................................... 35
第 2 页 共 35 页
VxWorks编程手册
前言 本手册主要描述VxWorks系统,VxWorks是高性能实时操作系统Tornado的组件。也描述了如何使用VxWorks工具开发实时应用程序。目前流行的实时系统都基于多任务和任务间通讯。多任务环境允许时实应用程序作为独立的任务构建,每个任务都有自己的执行程序和系统资源。任务间通讯允许这些任务为完成某一行为而同步和相互通讯。在VxWorks中,从信号量到消息队列,从管道到socket,都涉及任务间通讯。 在实时系统中,另一个重要工具是硬件中断处理,因为中断是通知外部事件系统的常用机制,为了得到对中断的更快响应,在VxWorks 中,interrupt service routines (ISRs)是一个独立的部分,不在任务之列。主要涉及如下几个主题:
1、 多任务 2、 任务间通讯 3、 中断处理 4、 I/O系统 5、 文件系统 1.VxWorks任务
在VxWorks中,任务,同调度程序一样,是工作的基本单元,与其他系统中的线程等同(threads)。所有的调度程序都发生在任务层。VxWorks的任务是相关联的,共享的大部分相同的系统资源。
1.1VxWorks中的多任务
多任务为应用程序提供了一个基本的机制,以控制和响应多个、离散的事件。每个任务都有自己的内容,包括CPU环境和系统资源,由内核按照一定的调度算法运行。在发生任务切换时,与任务相关的内容保存到task control block (TCB)中。任务的内容包括: -内存地址空间 -执行线程,即任务的程序计数器 -CPU寄存器和浮点寄存器 -动态变量和函数调用的堆栈 -标准输入、输出和错误的I/O分配 -延时定时器 -时间片定时器 -内核控制结构 -信号处理器
1.2任务状态转换
系统内核维护了当前每个任务的状态,应用程序调用内核函数,导致一个任务从一种状态转换到另一种状态。表1-1列出了任务的所有状态: 3 状态 READY PEND 描述 此任务状态只等待CPU资源,其他资源除外 此任务状态是由于一些资源不可用而被阻塞 第 3 页 共 35 页
VxWorks编程手册
DELAY SUSPEND 此任务状态是休眠一段时间 此任务状态是执行程序不可用,此状态主要用来调试,SUSPEND状态不影响状态的转换,只影响程序的执行。因此,pended-suspended任务一直不阻塞,而delayed-suspended tasks任务能够一直唤醒。 此任务状态是停止(暂停),当一个任务被debugger停止,通常是在任务中设置了断点。此状态不影响状态的转换,只影响程序的执行。 此任务状态是both delayed and suspended 此任务状态是 both pended and suspended 此任务状态是阻塞一段时间值 此任务状态是 both pended and stopped 此任务状态是 stopped with a timeout value 此任务状态是 both stopped and suspended 此任务状态是 both pended with a timeout value and suspended 此任务状态是 pended, stopped and suspended 此任务状态是 both stopped with a timeout value, and suspended. 此任务状态是 pended with a timeout value, stopped, and suspended 此任务状态是:状态由state指定,加上继承的优先级 BREAK DELAY + S PEND + S PEND + T PEND + BRK DLY + BRK BREAK + S PEND + S + T PEND + B + S BRK + S + T P + B + S +T state + I
PEND + B + T 此任务状态是 both pended with a timeout value, and stopped 任务可以在一到两步内创建并且激活,也可以调用函数taskSpawn( )一步生成(spawned,即创建又激活)。某些情况下,使用taskCreate( )和 taskActivate( )函数两个步骤是有用的,这允许应用程序在使用任务之前先创建(因为任务的创建要花费一部分taskSpawn( )时间),然后采用快速激活机制激活任务。在创建任务之后,激活之前,任务在suspended状态,激活时转换到ready状态。可以在任何状态下删除任务。
1.3 任务的调度程序
多任务需要一种调度机制,用来为ready状态的任务分配CPU。在wind中,缺省模式是基于优先级的抢占模式算法,但是你可以选择轮询模式。
1.3.1抢占式优先级模式
采用抢占式优先级算法,每个任务都有一个优先级,内核决定分配CPU给具有最高优先级的ready状态的任务。此方法既为抢占式,既当一个比当前任务有更高优先级的任务准备运行时,内核立即保存当前任务的相关内容,并切换到有更高优先级的任务。图1-2中,任务1被拥有更高优先级的任务2抢占,依次,又被任务3抢占。
第 4 页 共 35 页
VxWorks编程手册
ready——pend:semTake( ) / msgQReceive( ) ready——delay:taskDelay( )
ready——suspend:taskSuspend( )
pend——ready:semGive( ) / msgQSend( ) pend——suspend:taskSuspend( ) delay——ready:expired delay delay——suspend:taskSuspend( ) suspend——ready:taskActivate( ) suspend——pend:taskResume( ) suspend——delay:taskResume( ) 当任务3完成时,任务2继续执行,当任务2完成后,任务1继续执行。 表1-2,任务排列控制例程: Call kernelTimeSlice( ) taskPrioritySet( ) taskLock( ) taskUnlock( ) Description 控制轮询式调度程序 改变任务优先级 取消任务的再调度 允许任务的再调度 第 5 页 共 35 页
VxWorks编程手册
图1-2——优先级的抢占 wind内核有256个优先级级别,从0到255,优先级0最高,255最低。当创建任务式,需要设置其优先级,当任务在运行时,可以调用函数taskPrioritySet( )来改变优先级。
1.3.2轮询模式
抢占式的优先级模式可以通过增加轮询式进行扩充。轮询模式是所有具有相同优先级的ready任务平均分配CPU。如果不用轮询式,当多个具有相同优先级的任务共享CPU时,某个任务由于没有被阻塞可能独占整个CPU,因此其他等优先级的任务没有机会运行。 通过时间分片的方式,轮询模式可以实现为具有相同优先级的任务公平的分配CPU。每个任务(一个优先级组)运行一定的时间或时间片,然后另一个任务执行相同的时间。轮询模式可以通过调用函数kernelTimeSlice( )来触发,它的一个参数是时间片,再将处理器交给另一个等优先级任务之前的运行时间。 详细说来,每个任务都有一个运行时间计数器对应,每个时钟加1。当指定的时间片间隔完成时,计数器清0,当前任务被放到等优先级任务队列的最后,新的任务被执行,计数器被初始化为零。 如果一个任务在运行时被告优先级的任务抢占,那么运行时间计数器被保存,当此任务再次被运行时,时间计数被恢复。图1-3显示了具有相同优先级的任务t1、t2和t3的调度程序。
图1-3——轮询模式
任务2被任务4抢占,当任务4完成时,任务2从中断点恢复。
第 6 页 共 35 页
VxWorks编程手册
1.3.2抢占锁(Preemption Locks )
wind调度程序可以调用函数taskLock( )和taskUnlock( )来取消和使能每个任务的抢占模式。当调用函数taskLock( )取消某个任务的调度程序时,这个任务不会被抢占。然而,如果此任务已被阻塞或悬挂,调度程序就选择高优先级的适合的任务运行。当被锁定的任务解锁,并再次运行时,抢占模式再次被取消。(When the preemption-locked task unblocks and begins running again, preemption is again disabled.)
注意,抢占锁阻止任务内容被切换,但不能锁定中断处理。抢占锁也能用来实现互斥操作。
1.4任务控制
下面粗略浏览一下VxWorks的任务程序,在VxWorks的库taskLib中可以找到。这个程序提供了任务创建和控制的方法。
任务创建:
下表的函数用来创建任务: Call taskSpawn( ) taskCreate( ) taskActivate( ) Description 生成(创建和激活)一个新任务 创建一个新任务,但不激活它。 激活一个已经创建的任务 函数taskSpawn( )的参数有:新建任务名(ASCII字符串)、优先级、选项字、堆栈大小、主程序地址及10个参数(作为启动参数传给主函数): id = taskSpawn ( name, priority, options, stacksize, main, arg1, …arg10 );
此函数生成任务内容,包括分配堆栈、配置任务环境,新任务在制定程序的入口开始执行。另外,此函数包括底层的创建和激活步骤(taskCreate( )和 taskActivate( ))。
任务名称和IDs: 当创建任务时,你可以制定任意长度的ASCII字符串作为任务名称。VxWorks返回任务Ids,ID是4字节长度,多数VxWorks任务都把任务ID作为任务的唯一标示。VxWorks用0任务ID表示正在调用的任务。VxWorks不需要任务名称是唯一的,但是推荐使用唯一任务名,以免混淆。而且,为了更好的利用Tornado开发环境,任务名称不应与全局函数和变量名称发生冲突。为了避免名字冲突,VxWorks是用约定前缀pdt开头。你可能不想为你的任务命名,如果它是NULL,taskSpawn( )函数的name参数就用指针替代,VxWorks为其分配唯一的名称,形式为pdtN,N为十进制整数。 通常,任务名可以转化为对应的任务Ids,以简化任务间的交互。 taskLib中的例程管理任务IDs和任务名称: 函数: Call taskName( ) taskNameToId( ) taskIdSelf( ) taskIdVerify( ) Description 得到任务id对应的任务名称 得到任务名称对应的任务id 得到调用任务的id(正在运行的) 验证一个指定任务是否存在 第 7 页 共 35 页
VxWorks编程手册
下表的函数也用于任务名称和任务Ids: Description 找到与名称字符串和类型相匹配的对象 得到对象名称 设置对象名称 显示已知名称的对象的相关信息 Routine objNameToId( ) objNameGet( ) objNameSet( ) objNameShow( ) objNameToId( ) 函数是VxWorks的缺省函数,为了包括objNameShow( )函数,配置INCLUDE_OBJECT_NAME_SHOW组件。
任务和对象的所有权: 同其他的wind对象一样,任务也有所有者。但是同其他对象相比,任务的缺省所有者是任务所生成的保护域(protection domain)。在创建任务时,可以指定参数,以使这些任务成为他们所创建的其他对象的所有者,但是,与其他对象不同,任务的所有者不可以被改变。 使用函数objOwnerGet( )可以得到对象拥有者的id。函数objShowAll( )可以用来得到对象所有权的层次关系。
任务选项:
当生成任务时,可以根据需要,执行与操作,来指明选项参数,如下表所示(如果任务执行浮点操作,VX_FP_TASK选项必须被设置): 选项 VX_USER_MODE VX_SUPERVISOR_MODE VX_UNBREAKABLE VX_FP_TASK VX_PRIVATE_ENV VX_NO_STACK_FILL VX_STDIO_INHERIT 值(hex) 描述 0x0000 0x0001 0x0002 0x0008 0x0080 0x0100 0x0200 在用户模式下执行,这是所有任务的缺省模式(除了内河任务), 等同于VX_SUPERVISOR_MODE选项设置为not。 在超级用户模式下运行。这是内核任务的缺省模式。 不允许在调试时对任务设置断点 执行浮点计算 包括私有环境支持,见envLib. 调用函数checkStack() 时努允许填充0xee 当任务用此选项创建时,任务继承VX_STDIO_INHERIT选项以及标准I/O文件描述符。当不使用此选项时,被创建的任务使用标准I/O文件描述符,可以用函数pdStdIoSet( )来改变。 被任务创建的对象直接由此任务所有,而不是任务的主保护域。例外是任务本身,他一直都由保护域所有。 取消任务的堆栈溢出保护 VX_TASK_OBJ_OWNER 0x0400 VX_NO_STACK_OVERFLOW 0x0800 例子:
为了创建浮点操作的任务,如下:
tid = taskSpawn (\2387, 0, 0, 0, 0, 0, 0, 0, 0, 0);
第 8 页 共 35 页
VxWorks编程手册
任务选项值可以在任务创建之后进行检测和修改,可以使用如下函数(目前,只有VX_UNBREAKABLE、VX_TASK_OBJ_OWNER和VX_STDIO_INHERIT选项可以被改变): 函数 taskOptionsGet( ) taskOptionsSet( ) 描述 检测任务参数 设置任务选项
任务信息:
任务的信息可以通过调用下列函数得到,任务的状态信息是动态的,信息可能不是当前的,除非此任务是在休眠状态: 函数 taskIdListGet( ) taskInfoGet( ) taskPriorityGet( ) taskRegsGet( ) taskRegsSet( ) taskIsSuspended( ) taskIsReady( ) taskTcb( ) 描述 将所有活动状态的任务id填写到个数组中 得到一个任务的信息 检查任务的优先级 检查一个任务的寄存器(但是不能被当前任务使用) 设置一个任务的寄存器(但是不能被当前任务使用) 检查一个任务是否在悬挂状态(suspended.) 检查一个任务是否准备运行就绪 得到一个任务的控制块的指针,此函数只用于内核保护域。 任务的删除、资源回收和安全删除: 任务可以从系统中动态删除,下列函数用于对任务的删除: 函数 exit( ) taskDelete( ) taskSafe() taskUnsafe( ) 描述 结束正在运行任务,释放内存* 结束制定的任务,释放内存* 保护当前任务,防止被删除 取消taskSafe( )操作,即能够删除当前任务 说明:*当任务结束时,此任务所分配的内存并不释放;但是,当主保护域删除时,内存才被释放。
警告:不要在不恰当的时候删除任务。在应用程序删除一个任务时,此任务应该释放所有资源。 当入口函数(创建任务时指定的)返回时,意味着已经隐式的调用了函数exit( )。一个任务可以调用函数taskDelete( )来杀死本身或其他任务。因此,一个任务可以通过调用exit(),或调用taskDelete( )函数,或在入口函数中返回,来删除任务本身。 当一个任务被删除时,其他任务不会知道,函数taskSafe( ) 和taskUnsafe( )防止任务的意外删除。taskSafe( )函数防止一个任务被其他任务删除,例子: 当一个任务获得信号量,并正访问某些数据结构,当执行到某个关键域,此任务被删除了,那么数据结构可能处于一种混乱状态,信号量也没有被任务释放,关键的资源对其他任务是不可用的。
第 9 页 共 35 页
VxWorks编程手册
当一个任务试图删除另一个被保护的任务时会处于阻塞状态,当另一个任务完成操作后会调用taskUnsafe( )函数解除保护,那么此任务就可以被删除了。为了支持嵌入式的安全删除,一个计数器纪录taskSafe( )和taskUnsafe( )函数被调用的次数,只有当计数器为0时(即unsafes和safes次数一样多),才允许删除。保护操作只用于当前任务。 下面是一个例子: taskSafe ();
semTake (semId, WAIT_FOREVER); /* Block until semaphore available */ .
. critical region .
semGive (semId); /* Release semaphore */ taskUnsafe ();
如上例所示,安全删除通常与互斥量成对出现。
任务控制: 任务控制函数如下: 函数 taskSuspend( ) taskResume( ) taskRestart( ) taskDelay( ) nanosleep( ) 描述 Suspend a task. Resume a task. Restart a task. Delay a task; delay units are ticks, resolution in ticks. Delay a task; delay units are nanoseconds, resolution in ticks. VxWorks调试工具需要程序悬挂、恢复任务,用来冻结任务的状态以便检测。 当任务在执行过程中可能遇到灾难性的徐徐错误,因此任务必须能够重新启动。taskRestart( )函数的重启机制是重新创建任务,其参数与第一次创建任务的参数相同。 Delay操作是任务能够休眠一段时间,常用来检测(polling)应用程序,例如,让任务休眠半个时钟周期:taskDelay (sysClkRateGet ( ) / 2); sysClkRateGet( )函数返回系统时钟的速率,每秒的ticks数。你也可以用nanosleep()函数(POSIX)实现同样的功能,只是时间单位不同,nanosleep()函数以秒为单位。Delay操作的另一个影响是此任务被排到同优先级任务序列之后。因此,你能把CPU给另一个同优先级任务,只要你延迟0个ticks: taskDelay (NO_WAIT); /* allow other tasks of same priority to run */ 0延迟只能用于taskDelay( )函数; nanosleep( )函数会出错。
1.5任务扩展
VxWorks提供一些钩子函数,可以在任务创建、任务切换及任务删除时调用。(任何被钩子函数调用的用户程序必须是在内核域),当调用钩子函数时,应注意一点:
1、 Task switch hook routines must not assume any VM context is current other than the
kernel context (as with ISRs).
2、 Task switch and swap hooks must not rely on knowledge of the current task or invoke
any function that relies on this information; for example, taskIdSelf( ). 3、 A switch or swap hook must not rely on the TASK_ID_VERIFY(pOldTcb) mechanism
to determine if the delete hook, if any, has already executed for the self-destructing task
第 10 页 共 35 页
VxWorks编程手册
case. Instead some other state information needs to be changed; for example, using a NULL pointer in the delete hook to be detected by the switch hook.
任务创建、状态转换和删除的钩子函数如下: 描述 Add a routine to be called at every task create. Delete a previously added task create routine. Add a routine to be called at every task switch. Delete a previously added task switch routine. Add a routine to be called at every task delete. Delete a previously added task delete routine. 函数 taskCreateHookAdd( ) taskCreateHookDelete( ) taskSwitchHookAdd( ) taskSwitchHookDelete( ) taskDeleteHookAdd( ) taskDeleteHookDelete( )
1.6任务错误状态:
VxWorks中的errno变量是针对任务的,而不是系统范围的。当一个函数遇到错误时,会将errno变量设为合适的值,注意:在VxWorks中,errno变量不是全局变量,它包含在error.h中,要用rxtern int errno定义。 全局变量errno从来不会被VxWorks函数清除,它一直表示最后被设置的错误状态,它只表示底层函数(被调用函数)的错误值,而不是调用函数的值。推荐使用这种机制以便于调试。用函数printErrno( )可以显示与errno对应的字符串常量。
1.7任务异常的处理
程序中错误的代码和数据可能引起硬件异常,如非法指令、总线或地址错误、被零除等。在VxWorks中缺省的异常处理方法是悬挂此任务,在异常点保存任务状态,内核和其他任务继续运行。通过signal工具,对于某些特定的硬件异常,任务可以有自己的处理方式,此时系统缺省的异常处理方法不起作用。常用的函数是setjmp( )和longjmp( )。软件的异常处理同样如此。
1.8共享代码和重载入
在VxWorks中,一段代码或程序被多个任务调用是很常见的,即共享代码。多个任务调用共享代码的一个冲突是修改全局或静态变量,因此需要重载入,VxWorks得动态连接工具使其尤其简单。
第 11 页 共 35 页
VxWorks编程手册
在VxWorks中,大部分程序是可重载的。但是,如果程序someName( )有一个对应的函数someName_r( ),那么,你应该认为someName( )是不可重载的,而someName_r( )是可重载的。VxWorks的I/O和驱动程序是可重载的,但需要仔细设计。对于I/O,推荐用文件指针缓存。 多数VxWorks程序是用下面的重载技术:
1、 动态堆栈变量
2、 被信号量监护的全局或静态变量 3、 任务变量
在编写应用程序代码时,如果可能被多个任务调用,推荐采用相同的技术。
动态堆栈变量: 许多程序都是纯代码的,除了动态堆栈变量之外没有其他自己的数据,它所需要的数据由调用者的参数传递。
图——堆栈变量和共享代码
全局变量和静态变量: 为了避免多个任务对全局或静态变量的同时访问,通常采用互斥机制,即由semMLib库提供的mutex semaphore工具。
任务变量: 有些被多个任务同时调用的程序,在使用某个全局变量或静态变量时,每个任务需要有不同的值。为了实现这一点,VxWorks提供了一个叫任务变量的技术,它允许增加4字节的变量到任务内容中,以使任务进行切换时变量值也被切换,通常,几个任务声明同样的变量(4字节的内存域)作为任务变量,这样每个任务都可以像对待自己私有变量一样对待内存域。VxWorks提供以下几个函数:taskVarAdd( ),taskVarDelete( ), taskVarSet( ), 和 taskVarGet( ),参见taskVarLib库。
多任务有同一个主程序: 在VxWorks中,可能会遇到如下情况:当生成任务时,几个任务有同一个主程序,每个新任务都有自己的堆栈和内容,也为主程序传递不同的参数,这是很有用的。例子:
第 12 页 共 35 页
VxWorks编程手册
机械手的多个节点都是用同一段代码,任务调用函数操纵节点,节点数标示手臂上哪个节点被操纵。
1.9VxWorks系统任务
VxWorks包括许多系统任务:
BOOT任务:
ROOT任务时内核执行的第一个任务,其入口函数是usrRoot(),它初始化大部分VxWorks设备它有生成日志任务、异常任务、网络任务和tRlogind daemon等。通常,root任务初始化完成之后将被删除。注意:小心修改usrRoot()函数,要注意初始化的顺序。
Logging任务:tLogTask 此任务被VxWorks模块记录系统消息,而不用在当前任务中执行I/O。可以配置INCLUDE_LOGGING选项来加入日至任务。 异常任务:tExcTask 此函数支持VxWorks的异常处理,只用函数而不用中断,也用来处理当前任务不能处理的异常,如任务的自删除。此任务必须有最高的优先级,并且悬挂、删除,也不能改变它的优先级,可以配置INCLUDE_EXC_HANDLING选项来加入异常处理任务。详见exclib库。 网络任务:tNetTask 此任务处理VxWorks网络所需要的任务层函数。 Target Agent任务: tWdbTask 如果目标代理被设置成在任务模式下运行,就需要创建此任务。它对来自Tornado target server的请求作处理和响应。可以配置INCLUDE_WDB选项来加入目标代理任务。 Target Shell任务:tShell 如果在VxWorks配置中加入了目标命令行任务,此任务就被创建,任何程序或任务都由命令行调用。可以配置INCLUDE_SHELL选项来加入命令行任务。 rlogin任务:tRlogind 如果在VxWorks配置中加入了目标命令行和rlogin任务,后台程序就允许远端用户登陆到VxWorks.系统,它接受远端的登陆请求,并生成tRlogInTask和tRlogOutTask.任务。只要用户一直在登陆状态,任务就一直存在。在此会话过程中,命令行的输入、输出都被定向到远端用户。可以配置INCLUDE_RLOGIN选项来加入rlogin任务。 telnet 任务: tTelnetd 类似rlogin。
RPC Server 任务: tPortmapd 略
1.10任务堆栈
在VxWorks中有一个任务堆栈,每个任务有一个异常堆栈,同时,系统还有一个中断堆栈。
VxWorks提供了堆栈溢出检测,为了检测堆栈溢出,系统增加了附加的page到堆栈结尾,它标记为用户模式的任务不可访问。如果试图对page写操作,就发生堆栈溢出异常,但这并不会一定发生。为了取消堆栈溢出保护,创建任务时选项VX_NO_STACK_OVERFLOW必须被设置。
第 13 页 共 35 页
VxWorks编程手册
任务堆栈: 所有任务函数都会用到任务堆栈,其堆栈大小由创建任务时的stackSize参数制定,其值参考如下:
1、 It will be rounded up to a page boundary.
2、An additional mapped, but inaccessible, page will be added if stack overflow detection is requested.
堆栈从保护域内存资源分配。
任务异常堆栈: 每个任务都有异常堆栈,堆栈大小取决于系统的配置参数TASK_EXC_STACK_SIZE.。从内核内存分配,并保存发生异常或系统调用时的重要信息。在系统调用中,系统的关键数据保存到任务异常堆栈后,就切换到任务堆栈。 异常堆栈没有溢出检测保护。 中断堆栈: VxWorks有一个单独的中断堆栈,与异常堆栈类似,只是它应用于整个系统。
2任务间通讯
VxWorks提供丰富的任务间通讯机制,包括:
1、 共享内存(Shared memory):简单的数据共享;
2、 信号量(Semaphores):基本的互斥信号量和同步信号
3、 消息队列和管道(Message queues and pipes):在一个CPU内的任务间消息传递; 4、 Sockets和远程过程调用(RPC):任务间通讯的网络透传; 5、 信号(Signals):异常处理;
可选产品VxMP和VxFusion提供了多个CPU的任务间通讯功能。
2.1共享内存结构
对于任务间通讯,最直接的方法是访问共享数据结构。
图——共享数据结构
2.2互斥变量
虽然共享地址空间简化了数据的交换,但是,为了防止对共享数据的抢占,连锁访问内存是十分重要的。方法包括取消中断、取消抢占,用信号量锁定资源等。
第 14 页 共 35 页
VxWorks编程手册
中断的锁定和等待时间:
最强有力的互斥方式是取消中断,这种锁保证独占访问CPU。 funcA () {
int lock = intLock(); .
. critical region that cannot be interrupted .
intUnlock (lock); } 但是,终端锁可能会带来一些问题,如它阻止系统立即对外部事件做出反应(ISR)。因此,锁定时间要尽量的短。
抢占锁和等待时间: 取消抢占可能会减少一些对互斥操作的一些限制,当一个任务正在执行时,不允许其他任务抢占,但ISR可以运行: funcA () {
taskLock (); .
. critical region that cannot be interrupted .
taskUnlock (); } 但是,这种方法也会导致过长的实时响应,例如,当任务没有执行完锁定域的程序,其他高优先级的任务是不允许执行的。因此,应用这种方法时,要使锁定时间尽量的短。
2.3Semaphores信号量
信号量为VxWorks提供了更快的任务间通讯机制。Semaphores are the primary means for addressing the requirements of both mutual exclusion and task synchronization:
? 对于互斥操作,信号量对共享资源实现互锁访问,相对于取消中断或抢占锁,它为
互斥操作提供了更高的粒度;
? 对于同步,信号量配合任务执行与外部事件交互。 这有三种信号量,以解决不同问题: binary:
最快捷、最通用的信号量,用以优化同步信号或互斥信号; mutual exclusion: 一个特殊的二进制信号量,优化互斥信号量内部问题:优先级继承、安全删除和递归; counting: 与二进制信号量相似,但是要记录信号量的使用次数,能够优化对一个资源的多个实例的保护。
VxWorks不仅提供了Wind信号量,同时也提供了POSIX信号量。
第 15 页 共 35 页
VxWorks编程手册
信号量的控制: Wind信号量提供了统一的信号量控制接口,不分类型,只有创建函数需要指明类型。 函数 semBCreate( ) semMCreate( ) semCCreate( ) semDelete( ) semTake( ) semGive( ) semFlush( ) 描述 分配和初始化一个二进制信号量 分配和初始化一个互斥信号量 分配和初始化一个计数信号量 删除并释放信号量 启动信号量 停止信号量 Unblock all tasks that are waiting for a semaphore. 函数semBCreate( ), semMCreate( ), 和 semCCreate()返回信号量ID,当创建信号量时,需要指定队列类型,信号量可以按照优先级顺序或先入先出顺序加入队列中。 当删除信号量时,即调用函数semDelete( ) 时,一定要注意不要删除另一个任务一直正在请求的信号量。
二进制信号量: 获取一个信号量的流程:
二进制信号量可以被看作一个标志位(可用-FULL,不可用-empty),当一个任务起用一个二进制信号量,其结果取决于次信号量当前是否可用,如果可用(full),信号量立即变为不可用(empty),任务继续运行;如果不可用,任务被加入到阻塞任务队列中,并等待信号量可用。
当任务停止信号量(调用函数semGive( )),其结果也取决于次信号量当前是否可用,如果信号量已经可用,停止信号量,结果没什么影响;如果信号量不可用,也没有任务等待获取它,那么信号量变为可用;如果信号量不可用,并且有多个任务正等待获取它,那么阻塞任务队列中的第一个任务变为非阻塞,信号量变为不可用。
释放一个信号量的流程:
第 16 页 共 35 页
VxWorks编程手册
互斥: 二进制信号量对共享资源的互锁访问是十分有效的,它将互斥操作的范围限制到只与它相关的资源。当一个任务想访问某些资源时,它必须首先获得信号量,只要一个任务保持此信号量,其他试图访问此资源的任务被阻塞;当任务完成了资源访问,并释放了信号量,才允许其他任务访问此资源。 因此,所有对资源的互斥访问都是使用semTake( )和semGive( )对。 3 semTake (semMutex, WAIT_FOREVER); .
. critical region, only accessible by a single task at a time .
semGive (semMutex);
同步信号: 当用于任务同步时,信号量可以代表一个任务正在等待的条件或事件。初始化时,信号量是不可用的,一个任务或ISR通过释放信号量代表事件的发生,另一个任务调用函数semTake( )等待信号量。等待的任务阻塞,直到事件发生和信号量被释放。 互斥信号和同步信号的区别是他们的顺序:对于互斥信号,信号量在初始化时是可用的,每个任务必须首先获取它,然后再释放他;对于同步信号,信号量在初始化时是不可用的,一个任务等待获取另一个任务释放的信号量。
互斥信号量: 互斥信号量的行为与二进制信号量基本相同,以定位互斥操作的内部问题,如优先级转换、安全删除、递归访问等:
1、 他只能用于互斥操作;
2、 他只能有获取它的任务释放; 3、 他不能从ISR处释放; 4、 semFlush()操作无效。
优先级反转: 当一个高优先级的任务被迫等待一个低优先级任务不确定的完成时间时,优先级发生了倒置问题。例子:
第 17 页 共 35 页
VxWorks编程手册
T1、T2、T3分别代表优先级为高、中、低的三个任务。任务T3获得了二进制信号量,并可以访问一些资源。当T1(也需要获得同一个信号量)抢占T3,以访问资源时,任务T1就会阻塞。如果T3正常完成资源的访问,T1不会有问题。但是,当中优先级的任务T2抢占了T3任务,这将妨碍T3放弃资源的访问,这种情况一直僵持着,T1将无限期的阻塞。
图——优先级倒置问题
互斥信号量有一选项——SEM_INVERSION_SAFE,它使用priority-inheritance算法,此协议保证访问某一资源的任务以最高优先级任务(也阻塞在这一资源)的优先级别执行。一旦此任务的优先级被提升,它就保持此优先级,直到此任务获取的所有互斥信号量被释放,然后此任务又恢复到正常的或标准的优先级。这样就防止了中优先级的任务的抢占。此选项必须与优先级队列一起使用(SEM_Q_PRIORITY)。 此方法不一定都可行。如果一个任务获取了几个不同的互斥信号量,其中的一个时任务的优先级别提升了,那么任务优先级将一直保持着,直到所有的信号量被释放。
图——优先级继承
在上图中,当T1阻塞在信号量时,通过把T3的优先级提升到与T1相同的优先级,就解决了优先级倒置问题,这种方法叫做优先级继承。他保护了T3,也就间接的保护了T1不被任务T2抢占。
下面是使用优先级继承算法创建互斥信号量的例子: semId = semMCreate (SEM_Q_PRIORITY | SEM_INVERSION_SAFE);
安全删除: 互斥信号量解决的另一个问题是任务删除。当信号量保护着关键域时,删除一个运行在关键域的任务是灾难性的。函数taskSafe( ) 和 taskUnsafe( )为任务删除提供了安全的解决方
第 18 页 共 35 页
VxWorks编程手册
案。而互斥信号量提供SEM_DELETE_SAFE选项,即每个semTake( )函数暗含着调用
taskSafe( )函数,每个semGive( )函数暗含着调用taskUnsafe( )函数。这样,拥有信号量的任务不能被删除。
例子:semId = semMCreate (SEM_Q_FIFO | SEM_DELETE_SAFE);
回归资源访问: 互斥信号量能够被回归的获取,即一个任务在施放信号量之前,可以多次获取信号量。但是,在释放回归获取的互斥信号量之前,信号量也必须获取同样次数,即semTake( )和semGive( )函数必须成对出现。 据个例子:
#include \#include \SEM_ID mySem;
/* Create a mutual-exclusion semaphore. */ init () {
mySem = semMCreate (SEM_Q_PRIORITY); }
funcA () {
semTake (mySem, WAIT_FOREVER);
printf (\...
funcB (); ...
semGive (mySem);
printf (\}
funcB () {
semTake (mySem, WAIT_FOREVER);
printf (\...
semGive (mySem);
printf (\}
计数信号量: 计数信号量是实现任务同步和互斥操作的另一种方式。与二进制信号量相似,只是多了一个计数器,记录信号量被释放的次数。信号量被释放一次,计数器加1;被获取一次,减1;当计数为0时,企图获取此信号量的任务将阻塞。 下表是一个例子: 信号量调用函数 调用后的计数 第 19 页 共 35 页
VxWorks编程手册
semCCreate( ) semTake( ) semTake( ) semTake( ) semTake( ) semGive( ) semGive( ) 3 2 1 0 0 0 1 Semaphore initialized with initial count of 3. Semaphore taken. Semaphore taken. Semaphore taken. Task blocks waiting for semaphore to be available. Task waiting is given semaphore. No task waiting for semaphore; count incremented. 特殊信号量选项: wind信号量接口包括两个特殊的选项,对于POSIX兼容的信号量则没有: 1、超时时间: 当一个任务阻塞等待信号量可用时,信号量获取操作可能需要限制到一定时间内,如果在这段时间内没有信号量被获取,则此操作失败。这个操作由函数semTake( )的一个参数控制,这个参数指明等待时间。如果在指定时间内获得了信号量,返回OK,否则返回ERROR,同时rrno被设置。参数NO_WAIT (0)表示不需要等待,WAIT_FOREVER (-1)表示一直等待。 2、队列: wind信号量为阻塞任务提供了信号量队列选择机制,包括基于先进先出(FIFO)和优先级两种机制。在创建信号量时就选择了队列类型。如使用了优先级继承选项(SEM_INVERSION_SAFE),就必须选择优先级机制。
POSIX信号量: POSIX定义有名字和无名字两种信号量,他们有相同的属性,但接口的使用稍微有些不同(见semPxLib)。POSIX中的术语wait(或lock)和post(或unlock)分别对应于VxWorks中的take和give。POSIX信号量是计数信号量。
2.4消息队列
当前的实时应用都是由一组相互独立又相互协作的任务组成。信号量为任务间同步和互锁提供了高效的机制,而在VxWorks中,消息队列是单处理器中主要的任务间通讯机制。消息队列允许不定数量、不定长度的消息排队等待。任何任务或ISR都能发送消息到消息队列,任何任务也能从消息队列中接受消息。多个任务可以从一个消息队列中接受或发送消息。两个任务间的全双工通讯通常需要两个队列,一个用于发,一个用于收。
第 20 页 共 35 页
VxWorks编程手册
在VxWorks中,两个消息队列子程序库,一个是msgQLib,提供WIND消息队列,为VxWorks设计的;另一个是mqPxLib,与POSIX标准兼容的,用于实时性的扩展。下面主要说明WIND消息队列。 WIND消息队列由下表的函数创建和删除,它提供了先入先出机制的消息排队方法,只有一个例外:当有两个优先级别时,标志有高优先级别的消息被加入到队列的前面。 msgQCreate( ) msgQDelete( ) msgQSend( ) Allocate and initialize a message queue. Terminate and free a message queue. Send a message to a message queue. msgQReceive( ) Receive a message from a message queue. 函数msgQCreate( )用来创建消息,它的参数指明最大的排队消息数和每个消息的最大长度。
任务或ISR用函数msgQSend( )发送消息,如果没有等待队列中的消息,那么消息被加入到消息缓存中;如果有任务正在等待队列中的消息,那么此消息被立即传到第一个等待任务。 任务接收消息用函数msgQReceive( )。如果队列中有消息,那么第一个消息立即从队列中取出并返回到调用者;如果没有可用消息,那么调用任务阻塞,并被加入到消息等待任务队列。任务等待队列可能是基于任务优先级或先入先出(FIFO)机制,取决于任务创建时的选项参数。
超时: 函数msgQSend( )和 msgQReceive( )都有超时参数,当发送消息时,如果消息队列没有空间可用,超时参数指明等待缓存空间可用的ticks数;当接受消息时,如果队列没有消息,超时参数指明等待消息可用的ticks数。NO_WAIT (0)表示不等待;WAIT_FOREVER (-1)表示永远等待。 紧急消息: 函数msgQSend( )可以指明消息的优先级,(MSG_PRI_NORMAL)或(MSG_PRI_URGENT)。正常消息被加到队列尾,紧急消息被加到队列头。
POSIX与Wind消息队列的比较: 特点 消息优先级别 等待任务队列 接受超时 任务通知 Wind消息队列 1 FIFO或基于优先级 可选 无 POSIX消息队列 32 基于优先级 无 可选(只针对一个任务) 第 21 页 共 35 页
VxWorks编程手册
Close/Unlink Semantics 无 有 显示消息队列属性: 在VxWorks中,show()函数可以显示消息队列的属性信息。 服务器和客户端的消息队列: 实时系统通常是由客户/服务器任务组成,服务器任务接收客户端的请求,并提供一些服务,通常是返回应答,请求和应答通常采用任务间消息的形式,在VxWorks中,消息队列或管道是实现它的常用方法。
每个服务器创建一个消息队列用来接受客户端的请求,每个客户端也创建一个队列用来接收应答。
管道(pipes): 管道通过I/O系统为消息队列工具提供另一种接口。管道是虚拟的I/O设备,由驱动pipeDrv管理。函数pipeDevCreate( )创建一个管道设备,它与下面的消息队列相对应。调用者指明管道名称、最大消息数、消息的最大长度:
status = pipeDevCreate (\/pipe/name\max_msgs, max_length); 管道可以看作是命名的I/O设备,任务可以调用标准的I/O函数对管道进行打开、读、写操作。当从一个空的管道读数据时,任务发生阻塞,直到有数据可用;当像一个已经满的管道写时,任务也发生阻塞,直到有内存空间可用。与消息队列一样,ISR也可以向管道写,但不能读。 管道提供了一个队列没有的功能——它能够进行SELECT,即允许任务等待任何可用I/O设备上的数据,包括管道、SOCKET和串口设备。
网络上的任务间通讯: sockets: 在VxWorks中,基本的网络上的任务间通讯是使用sockets。VxWorks支持TCP/UDP,其源码与BSD4.4 UNIX兼容。 RPC: RPC使用sockets在为底层通讯机制,它允许一台机器上的程序调用此台机器的另一个进程或远程机器上的进程的一个程序。RPC为客户/服务器模式中的请求和应答的传递提供了标准协议。
信号(Signals): VxWorks支持软件信号通知,异步的信号可以改变任务的控制流,任何任务或ISR都可以为特殊任务生成信号通知。被通知的任务立即悬挂当前执行的线程,执行指定的处理程序(一被安排运行的)。信号更适合于错误或异常情况的处理,通常信号处理被看作ISR,它不调用任何其他程序,因为这可能会引起阻塞。由于信号通知是异步的,当有一个特殊的信号通知时,很难判断那些资源不可用,出于安全考虑,只调用ISR能够调用的函数。只有当你确认你的信号处理程序不会发生死锁时,才可以违背这个原则。 WIND内核支持两种类型的信号通知接口:UNIX BSD类型的和POSIX类型的。 下表是基本的信号通知程序, POSIX signal( ) kill( ) UNIX BSD signal( ) kill( ) Description Specify the handler associated with a signal. Send a signal to a task. 第 22 页 共 35 页
VxWorks编程手册
raise( ) sigaction( ) sigsuspend( ) sigpending( ) sigemptyset( ) sigfillset( ) sigaddset( ) sigdelset( ) sigismember( ) sigprocmask( ) sigprocmask( ) N/A sigvec( ) pause( ) N/A sigsetmask( ) Send a signal to yourself. Examine or set the signal handler for a signal. Suspend a task until a signal is delivered. Retrieve a set of pending signals blocked from delivery. Manipulate a signal mask. sigsetmask( ) sigblock( ) Set the mask of blocked signals. Add to a set of blocked signals. 为了能够使用信号通知,信号库初始化程序sigInit( )必须被调用,通常在usrInit( )函数中,启动中断之前。通常,信号通知类似于硬件的中断,每个信号处理程序对应于一种特殊的信号,即使用函数sigvec( )或 sigaction( ),某些信号与硬件的异常相关联,如总线错误、非法指令、浮点异常等,都会产生信号通知。 在VxWorks中可以选择INCLUDE_SIGNALS组件来包含信号功能。在你的应用程序能够使用POSIX信号通知之前,你必须分别对他们进行初始化,即调用函数sigqueueInit( ),同sigInit( )函数,通常在函数sysInit( )运行之后在函数usrInit( )中调用。 3、中断
硬件中断处理在实时系统中是非常重要的,因为系统接收外部事件完全通过中断实现的。为了对中断做出最快地反映,中断服务程序ISR运行在任务内容之外的特殊内容内,因此,中断处理不涉及任务切换。 在intLib和 intArchLib库内提供了如下中断函数: Call intConnect( ) intContext( ) intCount( ) intLevelSet( ) intLock( ) intUnlock( ) intVecBaseSet( ) intVecSet( ) intVecGet( ) Description Connect a C routine to an interrupt vector. Return TRUE if called from interrupt level. Get the current interrupt nesting depth. Set the processor interrupt mask level. Disable interrupts. Re-enable interrupts. Set the vector base address. Set an exception vector. Get an exception vector. intVecBaseGet( ) Get the vector base address.
将程序连接到中断: VxWorks提供了函数intConnect(),它允许C函数连接到任何中断,其参数是要连接中断的字节偏移量,将被连接的C函数地址,及传递给函数的参数。当用这种方式建立的矢量中断发生时,在中断层调用被连接的C函数。当中断处理完成时,被连接的函数也完成操作。用这种方式连接到中的程序叫做ISR。
第 23 页 共 35 页
VxWorks编程手册
实际上,中断不能直接引导到C函数。intConnect( )函数建立一部分代码,保存必要的寄存器内容,用传递的参数建立堆栈实体(可以是一个特殊的中断堆栈,也可以是当前的任务堆栈),然后调用被连接的函数。完成返回时,他保存寄存器和堆栈,退出中断。
中断堆栈: 一般情况,所有的ISR都使用同一个堆栈,在系统启动时,根据配置参数分配和初始化此堆栈,堆栈要足够大,使其能够处理最坏情况下的堆栈嵌套。在开发过程中可以使用checkStack( )函数观察如何关闭任务以及ISR如何耗尽可用的堆栈空间。
ISR的特殊限制: ISR有些限制,因为ISR不能运行在REGULAR任务中,他没有任务控制域,并且所有的ISR都共享一个堆栈。 能够被ISR调用的函数: LIBRARY bLib errnoLib 函数 All routines errnoGet( ), errnoSet() 等等,建P123。 因此,ISR的基本限制是:ISR不能调用可能引起阻塞的函数。例如,ISR不能试图获取信号量,因为如果信号量刚好不可用,内核将把调用任务切换到悬挂状态。然而,ISR可以释放信号量。 因为内存操作函数malloc( )和 free( )需要获取信号量,因此ISR不能调用他们,同时,ISR也不能地调用任何创建和删除函数,因为这些函数可能要调用malloc( )和 free( )。 ISR也不能执行I/O驱动操作,因为大部分设备驱动器都可能需要任务上下文,这些任务可能阻塞以等待设备可用。一个例外是VxWorks pipe驱动器,它允许被ISR写。 VxWorks提供了日志功能,它将文本消息打印到console口,这是从ISR打印消息的常用方式。ISR也不能调用浮点处理器的函数,因此ISR不能处理浮点指令,为了使ISR能够处理浮点指令,必须用fppArchLib库中的函数保存浮点寄存器的内容。ISR可以使用链表和环形缓存。
中断层的异常: 当任务引起硬件中断时,如非法指令或总线错误,那么任务被悬挂,系统其他的部分继续运行。在VxWorks中,会将异常的描述信息保存在内存的特殊位置,然后重新启动系统。VxWorks的启动程序(ROM)检测内存中异常描述信息的存在,如果信息被删除了,就将异常信息显示到console口。ROM中的e命令可以重新显示异常信息。
第 24 页 共 35 页
VxWorks编程手册
当在中断层高频率的使用内核调用时,会经常发生异常。通常表现为清除中断信号或类似的驱动问题。 在某些情况下,低级中断可能需要系统失败响应等事件,因此,需要RESERVE最高级别的中断,以保证对这些事件的零延迟。为了实现至一点,VxWorks提供了函数
intLockLevelSet( ),他设置中断级别到指定级别。如果你没有指定,缺省为最高级别。
中断到任务的通讯: VxWorks中的许多函数不能访问中断层的代码,包括I/O到任何设备(除了PIPE),但下面的技术能够实现ISR到任务的通讯:
1、 共享内存和环形缓存:ISR能够和任务层代码共享变量、缓存和环形缓存; 2、 信号量:ISR能够释放任务获取的或等待的信号量(除了互操作信号量);
3、 消息队列:ISR能够将消息发送到任务的消息队列中,如果队列已满,则消息被丢
弃;
4、 PIPES:ISR能够将消息写到pipes中,然后任务可以从中读取。任务和ISR能够向同
一个PIPE写。然而,如果PIPE已满,消息将被丢弃,因为ISR不能阻塞。除了写操作,ISR不能调用其他I./O函数对PIPE进行操作;
5、 信号通知:ISR能够通知任务,实现信号处理的异步调度
4、I/O系统 4.1介绍
VxWorks的I/O系统为各种设备提供一个简单、统一的与设备无关的接口,包括: 1、 面向字节的设备,如终端 2、 可自由访问的设备,如硬盘 3、 虚拟设备,如pipes或sockets
4、 显示器和控制设备,如数字I/O设备 5、 可以访问远端设备的网络设备
VxWorks为基本的I/O和基于缓存的I/O提供了标准C库。下图显示了VxWorks中I/O系统各单元的关系:
第 25 页 共 35 页
VxWorks编程手册
4.2文件、设备和驱动
在VxWorks中,应用程序都是通过打开已命名的文件(files)访问I/O设备的。如: /usr/myfile /pipe/mypipe /tyCo/0 第一个表示是磁盘设备/USR上的文件myfile;第二个是因命名的PIPE;第三个是物理串口通道。但是I/O系统同样对待他们。在VxWorks中,他们都被叫做文件(files),虽然他们是不同的物理对象。被程序模块处理的设备叫驱动(drivers)。所有的I/O都被镜像到命名文件上,这有两种方式:基本的(basic)和缓存的(buffered)。
文件名和缺省设备: 文件名就是一个字符串,一个unstructured设备由设备名标示。在文件系统的设备中,设备名之后跟着文件名,如:DEV1:/file1。 当在I/O函数中指定了一个文件名,I/O系统首先查找设备,其名字与文件名的首部字符串匹配。然后I/O函数被引导到这个设备。如果没有找到匹配的设备名,那么I/O系统就被引导到缺省设备上。缺省设备可以是系统中的任何设备,包括根本没有设备。 非阻塞设备在他们被加入到I/O系统时命名,这通常发生在系统初始化时;而阻塞设备在使用指定的文件系统时进行初始化和命名。 对于设备和文件,这有一些命名规则,通常设备名以“/”开头(除了non-NFS网络设备和VxWorks DOS设备dosFs),如:/usr。Non-NFS网络设备命名采用远端机器名+:,如:host:,剩下的部分是远端文件夹。 使用dosFs的文件系统命名是大写字母+/(或数字)+:,如:DEV1:。
4.3基本I/O
基本I/O是VxWorks中I/O的最底层,其接口与标准C库是兼容的,下面是7个基本I/O函数:
函数 creat( ) remove( ) open( ) close( ) read( ) write( ) ioctl( ) 描述 Create a file. Remove a file. Open a file. (Optionally, create a file.) Close a file. Read a previously created or opened file. Write a previously created or opened file. Perform special control functions on files or devices.
文件描述符: 在基本I/O层,通过文件描述符(file descriptor或fd)来表示一个文件,fd是函数open( )或creat( )返回的一个整数,其它的函数调用都是根据参数得到fd,以指明对应的文件。当文件被打开时,分配fd并返回;当文件被关闭时,fd被释放。在VxWorks中,fd的数量是有限的,它在i/o系统初始化时指定。 文件和资源回收:
第 26 页 共 35 页
VxWorks编程手册
文件描述符和其他对象一样,也需要回收,即当文件描述符的拥有者被删除时,需要关闭文件,删除相关的内核对象。
标准输入、输出和错误: 下面的三个文件描述符被系统保留: 0 = standard input
1 = standard output
2 = standard error output 他们可以被间接映射到任何文件或设备。 全局重定向: 当VxWorks系统初始化时,这三个文件描述符缺省的映射到系统控制台(console),在任务被创建时,他们没有分配任务自己的文件描述符,任务就使用全局描述符。 函数ioGlobalStdSet( )用来实现全局重定向,其参数是被重定向的全局描述符和目的文文件描述符。例子:将全局标准输出(fd=1)映射到描述符为fileFd的文件(需要首先被打开): ioGlobalStdSet (1, fileFd); 指定任务的重定向: ioTaskStdSet( )函数用来实现指定任务的描述符的映射。其参数包括:目的任务的id,将被映射的标准描述符,和目的描述符,例子:一个任务将标准输出映射到任务自己的文件描述符fileFd: ioTaskStdSet (0, 1, fileFd);
打开和关闭: 在I/O能够对设备进行操作之前,fd必须要先打开。函数open( )有如下参数:文件名、访问类型和模式: fd = open (\name\flags, mode); 访问类型入下表所示: Flag O_RDONLY O_WRONLY O_RDWR O_CREAT O_TRUNC Hex Value 0 1 2 200 400 Description Open for reading only. Open for writing only. Open for reading and writing. Create a new file. Truncate the file. 模式参数的一些特殊用法: 1、通常,你只能用函数open()打开一个已经存在的设备或文件。对于NFS网络和dosFs设备,你可以使用O_CREAT访问类型创建一个文件,在NFS设备中,需要指定模式参数:
fd = open (\name\ 2、对于NFS网络和dosFs设备,你可以使用访问类型O_CREAT和模式FSTAT_DIR来创建子目录。 函数open()执行成功,返回文件描述符fd,fd是全局的,一个任务打开他,其他任务可以使用它,直到调用close()函数。当一个任务退出或被删除,被此任务打开的文件描述不会自动关闭。
创建和删除:
第 27 页 共 35 页
VxWorks编程手册
ceate()函数映射到一个面向文件的设备上,创建一个新的文件,返回文件描述符,其参数与open()类似,但文件名是新创建的而不是已经存在的: fd = creat (\name\flag); remove()函数删除一个文件,但是当一个文件正在打开时,不要删除: remove (\name\ 对于非文件系统的设备,create()与open()一样,但remove()无效。
读和写: 当文件被打开后,任务可以对文件进行读、写操作。Read()函数的参数是:文件描述符、接受缓存地址、要读取的最大字节数: nBytes = read (fd, &buffer, maxBytes); 此函数返回实际读到的字节树。
函数write()的参数是:文件描述符、需要输出的缓存地址、要写的最大字节数: actualBytes = write (fd, &buffer, nBytes); 此函数返回实际写的字节数。如果返回的字节数与请求的字节数不等,就返回错误。 文件截断(Truncation): 在一个文件打开后,可以使用函数ftruncate( )将文件截取指定的长度,其参数是文件描述符和希望的文件长度:
status = ftruncate (fd, length); 如果成功,返回OK;如果指定的文件长度比实际长度大,或文件不能被截取,返回ERROR,同时设置errno为EINVAL。
I/O控制: 函数ioctl( ) 对于执行任何I/O函数都是open-ended机制,包括:决定当前可用的字节数,设置设备选项,获得文件系统的信息,指定访问位置等。其参数为:fd,控制函数的地址,和一个与函数相关的可选参数:
result = ioctl (fd, function, arg); 例如,使用下面的函数设置tty设备的波特率为9600: status = ioctl (fd, FIOBAUDRATE, 9600);
多文件描述符的处理——SELECT功能: 库提供了任务层的支持,即允许任务等待多个设备就绪;同时,也支持设备驱动层,即驱动有能力探测任务正在等待设备的I/O。为了使用这个功能,头文件selectLib.h必须包含在程序中。 任务级的支持不仅允许任务同时等待多个任务的I/O,它也允许任务指明最大的等待时间。
4.4 Buffered I/O—Stdio
在VxWorks中,可以配置INCLUDE_ANSI_STDIO组件以提供buffered I/O的支持。 使用Stdio: 为了使VxWorks的I/O更有效,stdio实现了缓存方案,即可以读写和缓存大块数据,而不是一个字节一个字节的读写。 fp = fopen (\ 此函数返回一个文件指针(或fp),指向对应的FILE类型的数据结构。
第 28 页 共 35 页
VxWorks编程手册
通过调用fdopen( )函数,一个已经打开的fd可以关联到一个FILE缓存中: fp = fdopen (fd, \ 之后,可以通过fread()函数读数据,如果一次读一字节;用函数getc( ),通过fwrite()函数写数据,如果一次写一字节;用函数putc( )。 注意:多个任务不能同时对同一个stdioFILE指针进行I/O操作。 当调用fclose()函数时,FILE缓存被删除。
标准输入、输出和错误: 当任务使用标准的文件描述符时,系统会自动创建对应的三个stdio FILE缓存。每个任务在使用标准描述符时都有他自己的stdio FILE缓存。
4.5其他各式的I/O
printf( ) ,sprintf( ) 和sscanf( ): 此三个函数通常被认为是stdio包的一部分,而在VxWorks中,虽然功能相同,但是却不使用stdio包。实际上,它使用fioLib库中的自包含的、格式化的、非缓存的接口。 printErr( )和fdprintf( ): fioLib库提供了附加的格式化的但没有缓存的输出函数,函数printErr( )与printf( )函数类似,但将格式化字符串输出到标准错误描述符2。函数 fdprintf( ) 将格式化字符串输出到指定的文件描述符。
消息日志: logLib库对格式化的消息提供日志功能,而不需要当前任务执行i/o操作。消息格式和参数被发送到日志任务的队列中。
4.6异步输入、输出(AIO)
异步输入输出可以在一般的内部进程间并行的执行输入、输出操作,其优点是大大提高处理效率:因为当资源可用,它就可以执行I/O操作,可以消除不必要的任务阻塞,因而不必在内部进程和输入输出之间争夺资源。 POSIX AIO函数: AioPxLib库提供了POSIX AIO函数。为了异步的访问文件,首先需要调用函数open()打开文件,然后根据返回的文件描述符调用其他函数。下表为POSIX AIO函数: aioPxLibInit( ) ——Initialize the AIO library (non-POSIX).
aioShow( ) ——Display the outstanding AIO requests (non-POSIX).* aio_read( ) ——Initiate an asynchronous read operation. aio_write( ) ——Initiate an asynchronous write operation.
aio_listio( ) ——Initiate a list of up to LIO_MAX asynchronous I/O requests. aio_error( ) ——Retrieve the error status of an AIO operation.
aio_return( ) ——Retrieve the return status of a completed AIO operation. aio_cancel( ) ——Cancel a previously submitted AIO operation.
aio_suspend( ) ——Wait until an AIO operation is done, interrupted, or timed out.
AIO 控制块:
第 29 页 共 35 页
VxWorks编程手册
每个AIO的调用者都把AIO控制块作为描述AIO操作的依据,调用程序为控制块分配空间。两个同时发生的AIO操作不能使用同一个控制块。在你请求AIO操作之后,调用
aio_return( )函数之前,千万不要修改相应的AIO控制块。aio_return( )函数释放AIO控制块。 AIOcb数据结构被定义在aio.h文件中。 使用AIO: 函数aio_read( ), aio_write( ), or lio_listio( )触发AIO操作。lio_listio( )函数允许你一次执行多个异步请求(读或写),通常,在执行AIO请求之后,实际的I/O操作不一定立即发生,因此,函数的返回值也不会影响实际I/O操作的结果,唯一的影响是:请求是否成功,即AIO函数是否已经把操作加到执行队列中了。I/O操作执行之后,也有返回值。有两个函数可以得到I/O操作是否成功或失败的信息:aio_error( ) 和aio_return( )。aio_error( )函数得到AIO操作的状态(成功,失败或在进行中),aio_return( )函数或的单个I/O操作的返回值。在AIO操作完成之前,它的错误状态是EINPROGRESS。为了取消AIO操作,调用函数aio_cancel( )。 可以使用aio_error( )函数检查读或写AIO操作是否完成。 检查AIO请求是否完成可以使用如下方式:
1、 周期的检查aio_error( )函数的结果,直到AIO请求状态不是EINPROGRESS为止; 2、 aio_suspend()函数将任务悬挂起来,直到AIO请求完成; 3、 当AIO完成时采用信号通知
4.7 VxWorks中的设备
所有的VxWorks设备驱动都遵循上面描述的基本规定,但有各自不同,本章详细说明。
Module ttyDrv ptyDrv pipeDrv memDrv nfsDrv netDrv ramDrv scsiLib -
4.7.1串口I/O设备(终端和伪终端设备)
VxWorks提供了终端和伪终端设备驱动(tty和pty),tty驱动是针对实际终端,pty驱动是针对仿真终端。VxWorks串口I/O设备是缓存的连续字节流,每个设备都有一个环形缓存区,用于输入和输出,在系统初始化时,创建设备时,指定环形缓存区的大小。 Tty选项: Tty设备有一套选项,以影响设备的行为。可以调用ioctl( )函数,通过设置位设置这些选项。例子:status = ioctl (fd, FIOSETOPTIONS, OPT_TERMINAL & ~OPT_MON_TRAP); 下面是选项的总结:
OPT_LINE—— Select line mode. (See Raw Mode and Line Mode, p.176.) OPT_ECHO ——Echo input characters to the output of the same channel.
Driver Description Terminal driver Pseudo-terminal driver Pipe driver Pseudo memory device driver NFS client driver Network driver for remote file access RAM driver for creating a RAM disk SCSI interface library Other hardware-specific drivers 第 30 页 共 35 页
VxWorks编程手册
OPT_CRMOD ——Translate input RETURN characters into NEWLINE (\\n); translate output NEWLINE into RETURN-LINEFEED.
OPT_TANDEM ——Respond to X-on/X-off protocol (CTRL+Q and CTRL+S). OPT_7_BIT ——Strip the most significant bit from all input bytes.
OPT_MON_TRAP—— Enable the special ROM monitor trap character, CTRL+X by default. OPT_ABORT ——Enable the special target shell abort character, CTRL+C by default. (Only useful if the target shell is configured into the system;.) OPT_TERMINAL ——Set all of the above option bits. OPT_RAW ——Set none of the above option bits.
Raw模式和line模式: Tty设备由两种操作模式:Raw模式(不缓存)和line模式。Raw模式是缺省的,line模式可以通过OPT_LINE选项进行设置。在raw模式,从设备输入的每个字节都是可读的;在line模式,直到NEWLINE字节被输入,字节才被保存,整个行字符,包括NEWLINE,在环形缓存区中都是可用的(一次操作)。 Tty的特殊字节: 如果tty设备执行在line模式下,下列的字符很特殊:
1、 退格字符;ctrl+H 2、 行删除字符:ctrl+U
3、 文件结束字符(EOF),ctrl+D
I/O控制函数: TyLib库支持的I/O控制函数如下:
FIOBAUDRATE ——Set the baud rate to the specified argument. FIOCANCEL ——Cancel a read or write.
FIOFLUSH—— Discard all bytes in the input and output buffers. FIOGETNAME ——Get the file name of the fd.
FIOGETOPTIONS ——Return the current device option word. FIONREAD—— Get the number of unread bytes in the input buffer. FIONWRITE—— Get the number of bytes in the output buffer. FIOSETOPTIONS—— Set the device option word.
4.7.2 PIPE设备
PIPE是虚拟的设备,通过它,任务可以通过I/O系统进行通讯。任务将消息写到PIPE,这些消息可以被其他任务读取。 创建PIPE: status = pipeDevCreate (\maxMsgs, maxLength); 如果任务试图向已满的PIPE中写消息,那么任务将等待,直到有消息出列;超出最大消息长度的血操作将导致错误。 从ISR向PIPE写: ISR可以使用PIPE同任务通讯,ISR可以调用函数write( )向PIPE写消息,任务和ISR可以向同一个PIPE写操作。如果PIPE已满,消息将被丢弃,因为ISR不能等待,除了write( )之外,ISR不能调用其他的I/O函数。 I/O控制函数:
第 31 页 共 35 页
VxWorks编程手册
被pipeDrv库支持的I/O控制函数如下(通过ioctl()函数): FIOFLUSH ——Discard all messages in the pipe. FIOGETNAME ——Get the pipe name of the fd.
FIONMSGS ——Get the number of messages remaining in the pipe. FIONREAD ——Get the size in bytes of the first message in the pipe. 4.7.3 伪内存设备
memDrv驱动允许I/O系统直接访问内存,当设备被创建时,指定内存的位置和大小。 安装内存驱动: 此驱动器首先被初始化,然后设备被创建: STATUS memDrv(void)
STATUS memDevCreate(char * name, char * base, int length) 设备的内存是以base开始的绝对内存位置,长度指明内存大小。 I/O控制函数: 被memDrv库支持的I/O控制函数如下(通过ioctl()函数):
FIOSEEK ——Set the current byte offset in the file.
FIOWHERE—— Return the current byte position in the file.
4.7.4 网络文件系统设备
通过镜像本地的文件系统,用函数创建I/O设备,可以访问远程的NFS文件系统,它的参数是:NFS服务器的主机名,主机文件系统名和本地文件系统名,例子: nfsMount (\
这样就创建了指定本地名的(/vxusr)I/O设备。如果本地名为空,则与远端名相同。通过这样的镜像,访问远端文件系统就想访问本地一样。
对NFS客户端的I/O控制函数: 被nfsDrv库支持的I/O控制函数如下(通过ioctl()函数):
FIOFSTATGET ——Get file status information (directory entry data). FIOGETNAME ——Get the file name of the fd.
FIONREAD ——Get the number of unread bytes in the file. FIOREADDIR ——Read the next directory entry. FIOSEEK ——Set the current byte offset in the file. FIOSYNC ——Flush data to a remote NFS file.
FIOWHERE ——Return the current byte position in the file.
4.7.5 非NFS设备
通过Remote Shell protocol (RSH)或FTP,VxWorks也支持访问远端主机上的文件。(用驱动netDrv)实现方式是:将远端主机上的整个文件拷贝到本地内存,读写操作都在本地内存内进行,当关闭时,文件被拷贝回远端主机,覆盖源文件。 创建网络设备: 为了能够用RSH或FTP访问远端主机,必须首先调用函数netDevCreate( )创建网络设备,函数参数是:设备名称,主机名称,使用的协议(0:RSH或1:FTP),例子:
netDevCreate (\
第 32 页 共 35 页
VxWorks编程手册
注意:创建网络设备允许访问远端系统上的任何文件或设备;而镜像NFS文件系统只能访问指定的文件系统。 I/O控制函数: 同NFS设备。
4.7.6 block设备
Block 设备是一系列可访问的数据块。最通常的block设备是磁盘,在VxWorks中,术语block指设备上最小的有地址的单元。与其他I/O略微不同,他并不是直接与I/O系统交互,他通过底层驱动与文件系统交互,文件系统再与I/O系统交互。为了使用BLOCK设备,VxWorks提供了与MS-DOS相同的文件系统。这也有简单的RAW磁盘文件系统,他们针对于:SCSI磁带设备、CD-ROM设备,FLASH内存设备。
4.7.7 SOCKET
一个套接字是任务间通讯的终端,数据从一个SOCKET发送到另一端。VxWorks SOCKET函数与BSD 4.4 UNIX SOCKET函数及WINDOWS SOCKET1.1兼容。
4.7.8 VxWorks与Host系统I/O的区别
1、设备配置(Device Configuration):在VxWorks中,设备驱动可以动态装配和卸载; 2、文件描述符:在UNIX和Windows中,fds在每个进程中是唯一的;在VxWorks中,fds是全局的,可以被每个任务访问(除了标准输入、标准输出和错误); 3、I/O控制:传到ioctl( )函数的参数可能不同;
4、 驱动程序:UNIX中,驱动在系统模式下执行,是不可抢占的;在VxWorks中,驱
动程序实际上是抢占的,因为他们运行在任务中。
5. 本地文件系统 5.1介绍
本章主要介绍VxWorks文件系统的组织、配置和使用。VxWorks文件系统主要包括block、磁带、CD-ROM及flash内存设备。本地文件系统是:
1、 dosFs文件系统,针对实时使用block设备而设计,与MS-DOS兼容; 2、 rawFS文件系统,将整个硬盘作为一个大的文件处理;
3、 tapeFS文件系统,专为磁带设备设计的,不使用标准的文件或目录结构; 4、 cdromFS文件系统,允许应用程序从CD-ROM读数据; 5、 TrueFFS文件系统,为flash内存设备提供了接口。 5.1dosFs
看文件the dosFs for Tornado 2.0 Release Notes and Supplement, 2.0.
5.2 Raw File System: rawFs
rawFs文件系统是最小的文件系统,只需要最基本的硬盘I/O函数。由于此文件系统将整
第 33 页 共 35 页
VxWorks编程手册
个磁盘的内容作为一个大的文件,因此,此设备上的所有OPEN()操作只指明设备名,不需要文件名。在执行其他应用之前,rawFs库,rawFsLib,必须初始化,可以用函数rawFsInit(),参数只有一个:可一次打开的rawFs文件描述符的最大值。rawFsInit()函数通常在系统启动之后被usrRoot()任务调用。 rawFs文件系统初始化之后,下一步是创建一个或多个设备。驱动程序的创建函数xxDevCreate()创建一个BLOCK设备,此时设备既没有名称也没有对应的文件系统。因此需要调用函数rawFsDevInit()进行初始化,它为设备制定名称,分配和初始化系统卷描述符;返回指向卷描述符的指针。 当可移动磁盘被改变时,必须通知rawFs文件系统,例如交换软盘。这有两种方法:(1):rawFsVolUnmount( )(2)ready-change 机制。 第一个方法是:在拿走磁盘之前调用函数rawFsVolUnmount( ),此函数清除所有的被修改的文件描述符缓存,并将已经打开的文件描述符标记为“旧的”,下一个I/O操作重新镜像磁盘。ISR不能直接调用rawFsVolUnmount( )函数。 第二个方法是:采用ready-change机制。磁盘就绪状态变化表明在下一个I/O调用之前必须重镜像。有三种方式:
1、 直接调用rawFsReadyChange()函数; 2、 调用函数ioctl( )用FIODISKCHANGE;
3、 在BLK_DEV结构中将bd_readyChanged域设置为TRUE;
ready-change通知不会引起将缓存数据写到磁盘,它只是将卷标记为需要重定向。
Ready-change可以被ISR使用。如果不能使用ready-change,则在改变磁盘之前关闭所有的文件描述符。
RawFsLib支持的I/O控制函数: RawFs文件系统支持ioctl( )函数功能,下列函数定义在ioLib.h文件中。 Function Decimal Description Value Announce a media change. Format the disk (device driver function). Initialize a rawFs file system on a disk volume (not required). Same as FIOSYNC. Get the file name of the fd. Get the number of unread bytes on the device. Set the current byte offset on the device. Write out all modified file descriptor buffers. Unmount a disk volume. Return the current byte position on the device. FIODISKCHANGE 13 FIODISKFORMAT 5 FIODISKINIT FIOFLUSH FIOGETNAME FIONREAD FIOSEEK FIOSYNC FIOUNMOUNT FIOWHERE
5.3 CD-ROM File System: cdromFs
6 2 18 1 7 21 39 8 CdromFs库cdromFsLib可以让应用程序读取任何CD-ROM(其格式符合ISO9660文件系统标准)。在对CD-ROM设备进行初始化和镜像之后,你可以用标准的POSIX I/O函数:open( ), close( ),read( ), ioctl( ), readdir( ), and stat( )访问设备上的数据。
第 34 页 共 35 页
VxWorks编程手册
CdromFs支持多个驱动、多个打开的文件和并行文件访问。通过使用标准的BLK_DEV结构,CdromFs支持对CD-ROM文件系统的访问。其基本的初始化顺序与在SCSI设备上安装dosFs文件系统类似。
5.4 目标服务器文件系统-TSFS
TSFS使用WDB驱动将请求从I/O系统传到目标服务器,目标服务器度请求并用主机文件系统执行请求,因此,当你用TSFS打开一个文件,被打开的文件实际是在主机上。他能自由访问主机上的文件,不需要将整个文件拷贝到目标服务器上。考虑读操作,驱动器将文件ID、接收数据的缓存地址和要接收的数据长度传到目标服务器,目标服务器在主机上执行读操作,将读出的数据传给目标程序,返回值和可能发生的ERRNO也传给目标。这样,文件就像在本地一样。
第 35 页 共 35 页
正在阅读:
VX编程手册06-03
一次惊心动魄的尝试作文800字07-01
英语学考重点词汇及句型06-30
写台风的高中英语作文07-17
我爱家乡的太阳岛作文500字06-26
兰大《急救护理学》17春平时作业309-19
戈波乡城乡一体党员动态管理制度03-26
巴蜀中学初2017届16-17学年(下)半期试题——物理05-01
监理细则04-09
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 编程
- 手册
- 小兵张嘎阅读检测题一
- 2017破产法练习题 - 答案在后
- 高中生物《染色体变异及其应用》学案2 苏教版必修2
- 票据法测试题及参考答案
- 学习机升级版慧学苑 - 图文
- 2011年高考数学一轮复习精品学案(人教版A版) - 空间向量及应用
- 玩好股票最关心的几个问题
- 给顾家北老师的反馈&自己的一点点经验
- 2016送礼物给客户 都很文艺范儿 - 图文
- 土整项目验收记录资料库
- 南粤杯技能竞赛试题库第(5)(6)(8)章 93-153
- 井控手册(J部分)
- 特种作业操作证 国家题库 熔化焊接与热切割作业
- 北京市西城区2012届高三第一次模拟考试理科数学试题及答案
- 2017年5月三级理论真题(校对版)
- 人际关系的基础在于价值的潜在交换,一个没有价值的人,不要谈人
- 公司社会治安综合治理工作计划
- 护本免疫学复习题
- 2004年中国电梯市场分析报告
- 三台市场调查计划