Signals

信号是操作系统用于异常处理和异步控制流的关键。在很多方面,信号相当于软件方面的硬件中的中断。操作系统产生的信号包括总线错误和浮点处理异常。信号也提供了API来管理和产生信号。在应用程序中,信号是最合适用来处理异常,而不是为了任务间通信。常见用法包括kill进程和任务,当定时器触发时发送事件或消息到消息队列时发送事件等。

为了兼容POSIX,VxWorks支持63种Signals,每个Signal都有独一无二的标识值和默认的处理(定义在signal.h)。值0用于表示NULL的signal。Signal可以从任务发送给任务或进程,Signal既可以被接收的任务和进程接收或忽略。是否接收或忽略依赖于signal掩码的设置。在内核里,Signal的掩码专门用于任务,如果没有任务设置接收特定的signal,那么它将被忽略。在用户空间,signal的掩码用于进程;一些信号如SIGKILL和SIGSTOP不能被忽略。

为了管理响应Signal,应用程序可以对应用程序有用的方式创建和注册signal处理函数。内核任务和ISR可以为特定任务和进程引发signal。在内核模式,signal的生成和传递运行在产生signal的任务和ISR的上下文中。为了兼容POSIX标准,发送给进程的signal被第一个可用的在进程中已经设置了处理函数的任务处理。每个内核任务都有singal掩码与之关联。signal掩码决定了哪个任务接收该signal。默认情况下,signal掩码被初始化为所有signal不阻塞(即,在内核里,掩码设置没有被继承)。掩码可以被sigorocmask函数修改。

内核里的signal处理器被注册为特定的任务。Signal在正在接收的任务的上下文中执行并使用任务执行的栈。signal处理器即使在任务被阻塞时也会被调用(挂起和搁置)。

VxWorks提供了软件Signal能力,包括POSIX函数,UNIX BSD-compatible函数和本地VxWorks函数。POSIX兼容的Signal接口包括POSIX标准1003.1中的基本Signal接口,也包括POSIX1003.1b的queued-signals扩展的接口。

此外,非POSIX的APIs提供内核和用于应用程序间的signal支持,有:taskSigqueue(),rtpSigqueue(),rtpTaskSigqueue(),taskKill(),rtpKill(),rtpTaskKill()和taskRaise()。

在VxWorks内核中--为了向前兼容--POSIX的API使用进程标识符作为参数,或者任务标识符。

注意:SIGEV_THREAD选项在内核中不支持。建议别同时使用POSIX和VxWorks的API在同一个应用程序中。POSIX的signal在内核和RTP中处理方式是不同的。内核中的处理函数总是以任务的方式,但是用户空间中,处理signal的目标可以是特定任务或整个进程。VxWorks的sigLib的实现并没有在SIGKILL,SIGCONT和SIGSTOP的操作中强加如UNIX中的特殊限制。UNIX实现的signal()不能被调用在SIGKILL和SIGSTOP。

除了Signal,VxWorks也提供了另外一种事件Event通知。当事件Event通知被完全异步发送,但同步接收时,不要求signal处理器。

VxWorks的Signal配置

默认,VxWorks包含了基本的signal组件INCLUDE_SIGNALS。该组件用sigInit()自动初始化signal。为了使用signal event能力,配置INCLUDE_SIGEVENT组件。为了包含POSIX的signal排队能力,启用INCLUDE_POSIX_SIGNALS组件。该组件在使用sigqueueInit()时自动被初始化。sigqueueInit()函数分配空间给sigqueue()使用,它要求为每一个当前入列的signal分配缓存。如果没有缓存,sigqueue将失败。

入队的最多signal数量由参数NUM_SIGNAL_QUEUES来设置。默认是16。

基本Signal函数

Signal在很多方面类似硬件中断。基本Signal能力提供了63种Signals。使用sigvec或sigaction来绑定Signal的处理函数,与ISR通过intConnect绑定ISR一样。通过kill或sigqueue来通告Signal。这类似于中断的发生。sigprocmask()函数让signal被选择性的抑制。某些Signal与硬件异常有关。如,总线错误,非法指令和浮点异常触发特殊Signal。

下面是VxWorks提供的POSIX和BSD的Signal函数的描述

POSIX 1003.1b

Compatible Routine

UNIX BSD

Compatible Routine

Description
signal() signal() 指定Signal的处理函数。
raise() N/A 发送Signal给你自己。
sigaction() sigvec() 为Signal检查或设置处理函数。
sigsuspend() pause() 挂起任务直到Signal被递交。
sigpending() N/A 返回当前pending的信号集。

sigemptyset()

sigfillset()

sigaddset()

sigdelset()

sigismember()

N/A 操纵Signal掩码。
sigprocmask() N/A 设置阻塞Signal的掩码
sigprocmask() N/A 添加一系列Signal掩码。

VxWorks也提供了类似POSIX和BSD风格的kill()函数,发送signal给任务。还提供了作为POSIX函数的别名,如rtpKill(),从内核发送signal给进程。

排队Signal函数

sigqueue()家族函数提供kill()函数家族的替代方法来发送signal。下面是两者的区别:

  • siqgueue包含了应用程序特定的值作为发送Signal的一部分。这个值提供了signal处理函数的合适的上下文。sigval的值(定义在signal.h);signal处理函数可以在它参数的si_value字段中找到它,一个结构体siginfo_t。
  • sigqueue函数为任何任务启用了多个signal的入列能力。相反,kill函数只能提交一个signal,即使在处理函数运行之前到来多个signal。

VxWorks包含了为应用程序保留的signal,连续编号从SIGRTMIN到SIGRTMAX。这些预留的signal的数量由RTSIG_MAX宏来管理(值是16),定义在POSIX 1003.1标准中。Signal值本身没有被POSIX指定。为了移植,可以为这些signal通过SIGRTMIN加偏移量来指定(如使用SIGRTMIN+2来引用3个预留的signal值)。所有signal通过sigqueue按数值的顺序来入队,低数值放在高数值的前面。

POSIX1003.1也引入了一种替代方式来接收signal。sigwaitinfo不同于sigsuspend或pause,它允许应用程序响应signal而不必使用注册signal函数的机制。当signal可用时,sigwaitinfo返回signal的值,而不调用signal处理函数,即使它被注册。sigtimedwait类似,除了它还提供了超时。

 Routine Description
 sigqueuue() 发送一个入队的signal给任务。 
 sigwaitinfo() 等待一个signal。
 sigtimedwait()  等待signa,l带有超时。

非POSIX的VxWorks排队函数,这些函数是为了帮助V5.x的移植。新开发的RTP应用程序应该使用上面的函数,而不是下面的这些函数。

 Routine  Description
 taskSigqueue()  从进程中的任务发送入队的signal给同一进程中的其它任务,或其它进程中的PUBLIC任务,或从内核任务发送到其它进程。
 rtpSigqueue()  从内核任务发送入队的signal给进程,或从进程发送到另外的进程。
 rtpTaskSigqueue()  从内核任务发送signal给内核空间中进程中特定的任务。

Signal事件

Signal事件能力允许线程或任务在特定事件发生时接收事件通知(如在消息队列中消息到达,或定时器触发等)。下面的函数用于注册时间活动相应的事件通知:mq_notify(),timer_create(),timer_open(),aio_read(),aio_write()和lio_listio()。

POSIX 1003.1-2001标准定义了3个signal事件通知类型:

SIGEV_NONE

当事件发生时,没有要求通知。这对于使用轮询的异步I/O操作的应用程序非常有用。

SIGEV_SIGNAL

当事件发生时,产生一个signal

SIGEV_THREAD

提供回调函数来完成异步通知,该函数在新线程上下文中的调用。这种方式对于多线程的进程提供了一种比signal更自然的方式。VxWorks在用户模式支持该选项,在内核模式不支持。

通知类型可以通过sigevent结构体来指定。结构体指针用于注册事件通知。要使用该功能,必须启用INCLUDE_SIGEVENT组件。

Signal处理函数

Signal比起作为任务间通信而言,更适合用于错误和异常处理。通常,Signal处理函数应该被看作类似ISRs:不应该在Signal的处理函数中调用其它能引起阻塞的函数。因为Signal是异步,很难确定当特殊Signal触发时什么资源可用。

为了安全,调用可以安全使用的函数,除非你确定不会引起死锁,否则不要违法该惯例。此外,当为signal使用C++或当以C或汇编编写的处理函数中调用C++函数时,尤其应该小心。使用C++会引入以下问题:

  • 当中断或signal发生时,intConnect和signal函数需要要执行函数的地址,但是非静态成员函数的地址不能被使用,所以必须实现静态成员函数。
  • 在Signal处理函数中,对象不能被实例化和删除。
  • 在Signal处理函数中要执行C++代码应该限制嵌入式C++。不能使用异常或RTTI。

大部分Signal是异步提交给应用程序执行。因此需要考虑非预期信号的发生,并优雅地处理。不像ISR,signal处理函数运行在中断任务的上下文中。VxWorks并没有区别普通任务和signal的上下文,它只区别普通任务和ISR的上下文。因此,系统无法区别是普通任务还是正在执行signal处理的任务,它们是一样的。

当编写信号处理函数时,确保

  • 在退出之前释放资源
  1. 释放任何分配的内存
  2. 关闭任何打开的文件
  3. 释放任何互斥的资源,如信号量
  • 任何修改过的数据结构处于健全的状态
  • 通知内核返回适当的错误值

在Signal处理函数和任务间的互斥必须小心处理。通常,用户应该在signal处理函数中避免以下活动

  • 获取可能已经被其它代码获取的互斥资源(可能导致死锁)。
  • 修改当Signal递交时已经被其他代码修改的共享数据内存。
  • 使用longjmp来修改任务执行的流程。如果longjmp用在signal处理函数去重新初始化一个正在运行的任务,必须确保当该任务正在拥有关键资源时(如内核互斥),signal没有发送到该任务。举个例子,如果signal被发送到正在执行malloc的任务,signal的处理函数调用longjmp使得内核处于不一致的状态。

这些场景对于调试非常困难,应该避免。安全的做法是同步应用程序代码,或从signal处理函数设置专用的标志和数据结构,从其它地方读取该标志和数据结构。应用程序应该周期性地检查标志是否在后台被Singal处理函数修改,然后相应的处理。volatile关键字在signal和其它代码访问内存时非常有用。

在signal处理函数中获取互斥信号量是非常糟糕的想法。互斥信号量可能被递归获取。因此,signal的处理函数能够很轻松地重新获取被其它代码占有的互斥。因为,signal处理函数是异步执行实体,因而打破了互斥应该支持的排斥性。

在signal处理函数中获取二进制信号量也是糟糕的做法。如果已经被其它元素获取,signal处理函数将引起任务的阻塞。这种死锁无法恢复。如计数信号量可用,则会有与互斥有相同的问题,如果不可用,则与二进制信号量一样引起无法恢复的死锁。

一般来说,signal应该只用于通知和处理异常或错误条件。在进程间通信或在应用程序数据流路径中的signal的使用会引起上面描述的缺点。

VxWorks 6.9 内核编程指导之读书笔记 -- Singnals的更多相关文章

  1. VxWorks 6.9 内核编程指导之读书笔记 -- ISRs和Watchdog Timer

    中断服务程序 ISR 硬件中断处理是实时系统的关键,因为它是外部时间通知系统的方式. ISR亦称为中断处理函数,是对中断的正确响应.可以使用任何ISR连接到任何没有被VxWorks使用的中断上.当关联 ...

  2. VxWorks 6.9 内核编程指导之读书笔记 -- VxWorks kernel application (一)

    #1 什么是内核应用程序? #2 开发内核应用程序注意事项 什么是内核应用程序? 内核应用程序不同于RTP程序,它允许在内核态,与操作系统使用相同的地址空间.因此,它与操作系统会相互干扰.它可以编译成 ...

  3. VxWorks 6.9 内核编程指导之读书笔记 -- 多任务

    概述 VxWork系统任务 任务调度 任务创建和管理 任务的错误状态 任务异常处理 共享代码和重入 概述 现代实时操作系统是基于多任务和任务间通信的概念的.多任务环境运行一个实时进程RTP可以被作为一 ...

  4. VxWorks 6.9 内核编程指导之读书笔记 -- VxWorks Small-Footprint Configuration

    什么是Small-footprint? Small-footprint常见关键配置? 如何配置Small-footprint? 什么是Small-footprint? Small-footprint配 ...

  5. VxWorks 6.9 内核编程指导之读书笔记 -- POSIX

    POSIX能力 VxWorks扩展了POSIX,为了移植,VxWorks提供了额外的POSIX接口作为可选组件.VxWorks实现了POSIX 1003.1(POSIX .1)一些传统接口以及POSI ...

  6. VxWorks 6.9 内核编程指导之读书笔记 -- 多任务(二)

    VxWorks的系统任务 VxWorks在引导时启动的系统任务依赖于配置,有些总是运行.任务集与VxWorks的基本配置相关,很少的任务常用于可选的组件. 注意:别挂起.删除或改变任何系统任务的优先级 ...

  7. VxWorks 6.9 内核编程指导之读书笔记 -- C++开发

    5.1 介绍 针对C++的VxWorks配置 C++头文件 使用C++启动任务 C和C++之前调用代码 C++编译器说明 在信号处理和ISR中使用C++ 下载C++编写的内核模块 C++编译器的不同 ...

  8. VxWorks 6.9 内核编程指导之读书笔记 -- VxWorks Kernel application (二)

    #1 内核对象的静态实例化 内核对象的静态实例化 任务的静态实例化 VX_TASK宏用来在编译时声明一个任务对象.该宏带有2个参数:任务名和栈大小.不像taskSpawn函数,任务名称可以是NULL. ...

  9. 《Linux/Unix系统编程手册》读书笔记9(文件属性)

    <Linux/Unix系统编程手册>读书笔记 目录 在Linux里,万物皆文件.所以文件系统在Linux系统占有重要的地位.本文主要介绍的是文件的属性,只是稍微提及一下文件系统,日后如果有 ...

随机推荐

  1. SIP入门(二):建立SIPserver

    在我的上一篇文章中已经介绍怎样通过SIP软电话直接通话,可是假设须要支持很多其它用户互相通话,同一时候基于安全考虑,须要对用户帐户登录进行验证控制,这些情况下就须要建立SIPserver. SIPse ...

  2. 即时通信(RPC)的Rtmp实现--配置篇

    http://flexman.blog.sohu.com/129838570.html http://flexman.blog.sohu.com/130007574.html step 1: 首先要确 ...

  3. iOS开发——数据持久化Swift篇&(三)SQLite3

    SQLite3 使用 //******************** 5.3 SQLite3存储和读取数据 func use_SQLite3() { //声明一个Documents下的路径 var db ...

  4. crm2011创建货币Money类型的字段

    using System;     using Microsoft.Xrm.Sdk;     using Microsoft.Xrm.Sdk.Messages;     using Microsoft ...

  5. AndroidManifest.xml 详解 (四) 之uses-permission

    The <uses-permission> Element 我们现在告别<application>元素,回到<manifest>中定义的子元素,<uses-p ...

  6. 0c-41-ARC使用特点及注意事项

    1.ARC特点总结 1)不允许调用release,retain,retainCount 2)允许重写dealloc,但是不允许调用[super dealloc] 3)@property的参数: str ...

  7. MySQL--索引条件下推优化

    http://blog.163.com/li_hx/blog/static/1839914132015782821512/ 一 什么是“索引条件下推” “索引条件下推”,称为 Index Condit ...

  8. Tcsh脚本编程

    Tcsh主要用于Free BSD等UNIX系统中. 一.输出字符串Hello的示例脚本 Tcsh脚本的基本格式.编写方法及脚本中使用的命令等,与Bash脚本完全相同,只需要直接套用即可. [root@ ...

  9. 如何在Windows Server 2003中配置FTP站点服务

    前面写过一篇文章<怎样给你的网站注册一个好域名?> ,讲到“玉米”,笔者有很深的情节,也希望与大家交流“米事”,可以站内私信我或者直接回复文章. 有了好域名只是做网站的开始.我们还要买主机 ...

  10. nie题目-游戏排行榜设计

    一个mmorpg游戏,玩家众多,需要对玩家战斗力进行排行,并且战斗力变化时需要及时刷新.需要设计一个这样的排行榜. 关于海量数据排行榜的做法,云风在他的博客里给过思路,谈谈陌陌争霸在数据库方面踩过的坑 ...