Linux下的信号机制
2017-04-06
之前在看LinuxThreads线程模型的时候,看到该模型是通过信号实现线程间的同步,当时没有多想,直接当做信号量了,现在想起来真是汗颜……后来想想并不是那么回事,于是,就有了今天这篇博文!
其实关于信号的文章,网上有很多,写的也很好,而笔者仅仅是想把自己的想法记录下来,一来帮助自己捋顺思路,二来说不定还可以帮助他人理解,如有错误,还请指正!
一、总体介绍
Linux的信号在实现机制上根中断很类似,以至于有文献把linux信号作为软中断,这当然在一定程度上是说的过去,但是笔者不建议这么做,因为虽然二者的实现机制又相同之处,但是二者所处理的事务千差万别;况且软中断在Linux中是一个专有名词,比如中断处理下半部常作为软中断的方式存在,而软中断的记录根CPU相关而根某个进程无关,这里强行把信号作为软中断对于初学者的理解也有害无益,至少应该明确说明区别,想当初笔者本科时由老师提到异常就是软中断,这概念因为先入为主,在笔者后来看到真正的软中断时迟迟不能接受。至于软中断,可参考笔者另一篇博文。
当然把信号作为软中断也并非空穴来风,自然有其道理。首先,二者均是作为异步事件的处理方式。相对于操作系统来讲,中断作为异步方式存在已经众人皆知,信号也不例外。但是信号相对的,是进程,而并非操作系统。说到这里,还有文献说进程其实就是一个虚拟机,当然仅仅是广义上的。那么从这个角度,信号像是把中断扩展到更小的单元上的一个方式。
二、信号的实现方式
之前说到,信号是相对于进程存在的,在进程结构体task_struct结构中,信号相关的字段如下:
/* signal handlers */
struct signal_struct *signal;
struct sighand_struct *sighand;
/*屏蔽的信号*/
sigset_t blocked, real_blocked;
sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
/*挂起的信号*/
struct sigpending pending;
同一个进程中的所有线程共享一个signal_struct结构和sighand_struct结构,即这两个结构都是进程相关的。而之前咱们也说过,Linux中线程在内核中同样也是由task_struct代表的,下面几个字段都是针对单个线程的,blocked字段记录当前线程对信号的屏蔽情况,其类型早期是unsigned long类型,x86架构下就是32位,而现在升级成一个结构,其大小根据具体的信号数量确定,当前最大信号数量为64,以后还可能增加。
#define _NSIG 64
#define _NSIG_BPW 32
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
#define _NSIG 64
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
利用宏定义扩展位图。每位对应一个信号,当某个信号对应的位为1时,表明该信号暂时被屏蔽,但这并不意味着信号不能产生,恰恰相反,信号依然可以被传递到当前线程,只是当前线程对信号不做处理,把信号阻塞或称为挂起。待到该信号不被屏蔽了,那么该信号就可以得到处理了。挂起的信号记录在pending字段,sigpending结构如下:
struct sigpending {
struct list_head list;
sigset_t signal;
};
所有产生的信号都会被挂入这个list为表头的链表中,这样产生多个信号也不会丢失。signal还是做链表中信号标记,表明当前有哪些类型的信号未处理。链表中节点结构是sigqueue,只是需要注意,这里信号分为可靠信号和不可靠信号。二者的区别暂时不介绍,不可靠信号是早期支持的32个信号,从0-31,而可靠信号是大于31的信号。不可靠信号在投递还是采取先前的方式,这是为了和之前保持兼容,即signal位图中每个位代表一个信号,且一个信号只有一个sigqueue结构与之对应;当目前存在未处理的信号,再次受到这个信号就会忽略。而可靠信号位图中也有与之对应的位,而且每收到一个信号就生成一个sigqueue结构挂入链表,sigqueue结构如下。
struct sigqueue {
struct list_head list;
int flags;
siginfo_t info;
struct user_struct *user;
};
三、信号的处理
信号的处理时机主要由两个:
1、从内核空间返回到用户空间前夕。
2、进程位于内核空间被唤醒。
对于信号的处理主要由两种处理方式,用户可以对信号定义自己的处理函数,也可以采用系统默认的处理函数。在上述task_struct结构中有sighand_struct类型的字段 sighand,记录了信号的处理函数
struct sighand_struct {
atomic_t count;
struct k_sigaction action[_NSIG];
spinlock_t siglock;
wait_queue_head_t signalfd_wqh;
};
第一个count应该指action表项的数目,第二个action和每一个信号对应,一个表项记录一个信号的处理函数,当为0时表示采用系统默认的处理方式。注意,在signal_struct中并没有设置锁,源码注释解释为一个共享的signal_struct必定有一个sighand_struct结构与之对应,对sighand_struct加锁即可实现对signal_struct保护。
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
sigset_t sa_mask; /* mask last for extensibility */
};
sa_handler指向一个处理函数,sa_flags记录信号处理时的一些设置,可以有如下值
- SA_ONSTACK:表明要使用已经注册的新栈,而不是使用进程自身的栈。
- SA_RESTART:设置在信号被中断后重启。
- SA_NOCLDSTOP:当该位设置时,在子进程stop时不产生SIGCHLD信号。
- SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
- SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
- SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号
sa_mask就代表在处理当前信号时,可以选择性的屏蔽一些信号。相当于即时有效的。
在用户空间可以调用signal和sigaction 函数给一个信号设置处理函数,SIGKILL和SIGSTOP信号除外,这两个信号必须采用系统默认的函数。当一个信号被设置handler时,已经挂起的该类信号被丢弃。关于signal和sigaction的区别这里不做详细介绍。对于sa_handler还可以是SIG_DFL和SIG_IGN两个值,前者为0表示采取默认的处理方式。后者为1,表示忽略该信号。
参考资料:
LInux3.10.1内核源码
Linux下的信号机制的更多相关文章
- linux下 signal信号机制的透彻分析与各种实例讲解
转自:http://blog.sina.com.cn/s/blog_636a55070101vs2d.html 转自:http://blog.csdn.net/tiany524/article/det ...
- 2017-2018-1 20155222 《信息安全系统设计基础》第10周 Linux下的IPC机制
2017-2018-1 20155222 <信息安全系统设计基础>第10周 Linux下的IPC机制 IPC机制 在linux下的多个进程间的通信机制叫做IPC(Inter-Process ...
- Linux下的IPC机制
Linux下的IPC机制 IPC(Inter-Process Communication)是多个进程之间相互沟通的一种方法.在linux下有多种进程间通信的方法. 共享内存 Linux内存共享有多种, ...
- linux下epoll实现机制
linux下epoll实现机制 原作者:陶辉 链接:http://blog.csdn.net/russell_tao/article/details/7160071 先简单回顾下如何使用C库封装的se ...
- linux 下信号处理命令trap && linux下各种信号的意义
1.用途说明 trap是一个shell内建命令,它用来在脚本中指定信号如何处理.比如,按Ctrl+C会使脚本终止执行,实际上系统发送了SIGINT信号给脚本进程,SIGINT信号的默认处理方式就是退出 ...
- linux信号Linux下Signal信号太详细了,终于找到了
linux信号Linux下Signal信号太详细了,终于找到了 http://www.cppblog.com/sleepwom/archive/2010/12/27/137564.html
- linux下六大IPC机制【转】
转自http://blog.sina.com.cn/s/blog_587c016a0100nfeq.html linux下进程间通信IPC的几种主要手段简介: 管道(Pipe)及有名管道(named ...
- Linux 下的同步机制
2017-03-10 回想下最初的计算机设计,在单个CPU的情况下,同一时刻只能由一个线程(在LInux下为进程)占用CPU,且2.6之前的Linux内核并不支持内核抢占,当进程在系统地址运行时,能打 ...
- linux中的信号机制
概述 Linux信号机制是在应用软件层次上对中断机制的一种模拟,信号提供了一种处理异步事件的方法,例如,终端用户输入中断键(ctrl+c),则会通过信号机制停止一个程序[1]. 这其实就是向那个程序( ...
随机推荐
- cpython和lua源码阅读
cpython代码很多,不太容易看出来. lua代码真的短小精悍,不得不佩服.
- 原创jQuery插件之图片自适应
效果图例如以下: 功能:使图片自适应居中位于容器内 限制:容器须要给定大小 用法: 1.引入jQuery.然后引入fitimg插件 2.给须要图片自适应的容器固定宽高 3.header .accoun ...
- [基础]sizeof和strlen
转自网络 首先切记,sizeof不能用来求字符串长度 1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型.该类型保证能容纳实现所建立的最大对象的字 ...
- UCOS2系统内核讲述(三)_TCB任务控制块
Ⅰ.写在前面 学习本文之前可以参看我前面的文章: UCOS2_STM32F1移植详细过程(汇总文章) UCOS2系统内核讲述(一)_总体描述 UCOS2系统内核讲述(二)_初始化调用函数 上一篇文章讲 ...
- PHP——0128练习相关1——window.open()
Window.open()方法参数详解 1, 最基本的弹出窗口代码 window.open('page.html'); 2, 经过设置后的弹出窗口 window.open('page.html ...
- Static int data语句说明data为类变量,为一个类的共享变量,属于整个类
面向对象高级: 修饰符: static:①可修饰变量(属性):②可修饰方法:③可修饰代码块. Static int data语句说明data为类变量,为一个类的共享变量,属于整个类. Int dat ...
- 学习shader之前必须知道的东西之计算机图形学(一)渲染管线
引言 shader到底是干什么用的?shader的工作原理是什么? 其实当我们对这个问题还很懵懂的时候,就已经开始急不可耐的要四处搜寻有关shader的资料,恨不得立刻上手写一个出来.但看了一些资料甚 ...
- ActionContextCleanUp
ActionContextCleanUp作用 延长action中属性的生命周期,包括自定义属性,以便在jsp页面中进行访问,让actionContextcleanup过滤器来清除属性,不让acti ...
- 【BZOJ】1631: [Usaco2007 Feb]Cow Party(dijkstra)
http://www.lydsy.com/JudgeOnline/problem.php?id=1631 看到m<=100000果断用dij(可是好像dij比spfa还慢了在这里?)//upd: ...
- jQuery过滤HTML标签并高亮显示关键字的方法
本文实例讲述了jQuery过滤HTML标签并高亮显示关键字的方法.分享给大家供大家参考.具体如下: jQuery实现网页关键字过滤效果,将需要过滤的文字定义在JavaScript中,可定义多个,不过要 ...