Linux signal处理机制
- 格式:docx
- 大小:29.74 KB
- 文档页数:9
列举出 linux 系统中常用的进程通信机制,并对每种机制进行简单说明。
一、管道(Pipe)管道是最基本的进程间通信(IPC)机制之一,通常用于父子进程或对称多处理中的进程间通信。
它是一种命名管道,通过文件系统中的特殊文件实现。
使用管道,一个进程可以将数据发送到另一个进程,从而实现进程间的通信。
使用方法:1. pipe() 函数创建管道并将文件描述符返回给调用进程。
2. write() 函数从文件描述符向管道写入数据。
3. read() 函数从管道读取数据。
二、信号(Signal)信号是一种简单的进程间通信机制,用于通知接收进程某个事件的发生。
信号可以由系统生成(如操作系统的调度),也可以由其他进程发送。
信号通常用于通知接收进程发生错误、终止或需要执行某些操作。
使用方法:1. 发送信号:kill() 或 raise() 函数发送信号。
2. 接收信号:处理信号的函数(如信号处理程序)需要注册到进程中。
三、消息队列(Message Queue)消息队列是一种更为复杂的进程间通信机制,它允许不同进程之间发送和接收消息。
消息队列提供了一种高效、可靠的消息传递机制,适合于分布式系统中的进程间通信。
使用方法:1. mq_open() 函数创建或打开消息队列,并返回一个消息队列标识符。
2. mq_send() 和 mq_receive() 函数分别用于发送和接收消息。
四、共享内存(Shared Memory)共享内存是一种轻量级的进程间通信机制,允许多个进程共享同一块内存区域。
它适用于需要快速数据交换的进程间通信场景,如多线程或分布式系统中的进程间通信。
使用方法:1. mmap() 函数将一段虚拟地址空间映射到进程的地址空间中,实现进程间的共享内存。
2. 读写共享内存区域进行数据交换。
五、套接字(Socket)套接字是一种更为灵活的进程间通信机制,它提供了更为广泛的网络通信功能。
套接字可以是基于网络的,也可以是本地进程间的通信机制。
当服务器close一个连接时,若client端接着发数据。
根据TCP协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。
根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出), 所以client会退出。
若不想客户端退出可以把SIGPIPE设为SIG_IGN如: signal(SIGPIPE,SIG_IGN);这时SIGPIPE交给了系统处理。
服务器采用了fork的话,要收集垃圾进程,防止僵死进程的产生,可以这样处理:signal(SIGCHLD,SIG_IGN);交给系统init去回收。
这里子进程就不会产生僵死进程了。
signal(SIGHUP, SIG_IGN);signal信号函数,第一个参数表示需要处理的信号值(SIGHUP),第二个参数为处理函数或者是一个表示,这里,SIG_IGN表示忽略SIGHUP那个注册的信号。
SIGHUP和控制台操作有关,当控制台被关闭时系统会向拥有控制台sessionID的所有进程发送HUP信号,默认HUP信号的action是exit,如果远程登陆启动某个服务进程并在程序运行时关闭连接的话会导致服务进程退出,所以一般服务进程都会用nohup工具启动或写成一个daemon。
unix中进程组织结构为session 包含一个前台进程组及一个或多个后台进程组,一个进程组包含多个进程。
一个session可能会有一个session首进程,而一个session首进程可能会有一个控制终端。
一个进程组可能会有一个进程组首进程。
进程组首进程的进程ID与该进程组ID相等。
这儿是可能会有,在一定情况之下是没有的。
与终端交互的进程是前台进程,否则便是后台进程SIGHUP会在以下3种情况下被发送给相应的进程:1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用&符号提交的进程)2、session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程3、若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。
Linux下signal信号汇总SIGHUP 1/* Hangup (POSIX). */终⽌进程终端线路挂断SIGINT 2/* Interrupt (ANSI). */终⽌进程中断进程 Ctrl+CSIGQUIT 3/* Quit (POSIX). */建⽴CORE⽂件终⽌进程,并且⽣成core⽂件 Ctrl+\SIGILL 4/* Illegal instruction (ANSI). */建⽴CORE⽂件,⾮法指令SIGTRAP 5/* Trace trap (POSIX). */建⽴CORE⽂件,跟踪⾃陷SIGABRT 6/* Abort (ANSI). */SIGIOT 6/* IOT trap (4.2 BSD). */建⽴CORE⽂件,执⾏I/O⾃陷SIGBUS 7/* BUS error (4.2 BSD). */建⽴CORE⽂件,总线错误SIGFPE 8/* Floating-point exception (ANSI). */建⽴CORE⽂件,浮点异常SIGKILL 9/* Kill, unblockable (POSIX). */终⽌进程杀死进程SIGUSR1 10/* User-defined signal 1 (POSIX). */终⽌进程⽤户定义信号1SIGSEGV 11/* Segmentation violation (ANSI). */建⽴CORE⽂件,段⾮法错误SIGUSR2 12/* User-defined signal 2 (POSIX). */终⽌进程⽤户定义信号2SIGPIPE 13/* Broken pipe (POSIX). */终⽌进程向⼀个没有读进程的管道写数据SIGALARM 14/* Alarm clock (POSIX). */终⽌进程计时器到时SIGTERM 15/* Termination (ANSI). */终⽌进程软件终⽌信号SIGSTKFLT 16/* Stack fault. */SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */SIGCHLD 17/* Child status has changed (POSIX). */忽略信号当⼦进程停⽌或退出时通知⽗进程SIGCONT 18/* Continue (POSIX). */忽略信号继续执⾏⼀个停⽌的进程SIGSTOP 19/* Stop, unblockable (POSIX). */停⽌进程⾮终端来的停⽌信号SIGTSTP 20/* Keyboard stop (POSIX). */停⽌进程终端来的停⽌信号 Ctrl+ZSIGTTIN 21/* Background read from tty (POSIX). */停⽌进程后台进程读终端SIGTTOU 22/* Background write to tty (POSIX). */停⽌进程后台进程写终端SIGURG 23/* Urgent condition on socket (4.2 BSD). */忽略信号 I/O紧急信号SIGXCPU 24/* CPU limit exceeded (4.2 BSD). */终⽌进程 CPU时限超时SIGXFSZ 25/* File size limit exceeded (4.2 BSD). */终⽌进程⽂件长度过长SIGVTALRM 26/* Virtual alarm clock (4.2 BSD). */终⽌进程虚拟计时器到时SIGPROF 27/* Profiling alarm clock (4.2 BSD). */终⽌进程统计分布图⽤计时器到时SIGWINCH 28/* Window size change (4.3 BSD, Sun). */忽略信号窗⼝⼤⼩发⽣变化SIGPOLL SIGIO /* Pollable event occurred (System V). */SIGIO 29/* I/O now possible (4.2 BSD). */忽略信号描述符上可以进⾏I/OSIGPWR 30/* Power failure restart (System V). */SIGSYS 31/* Bad system call. */SIGUNUSED 311) SIGHUP本信号在⽤户终端连接(正常或⾮正常)结束时发出, 通常是在终端的控制进程结束时, 通知同⼀session内的各个作业, 这时它们与控制终端不再关联.2) SIGINT程序终⽌(interrupt)信号, 在⽤户键⼊INTR字符(通常是Ctrl+C)时发出3) SIGQUIT和 SIGINT类似, 但由QUIT字符(通常是Ctrl+\)来控制. 进程在因收到 SIGQUIT 退出时会产⽣core⽂件, 在这个意义上类似于⼀个程序错误信号.4) SIGILL执⾏了⾮法指令. 通常是因为可执⾏⽂件本⾝出现错误, 或者试图执⾏数据段. 堆栈溢出时也有可能产⽣这个信号.5) SIGTRAP由断点指令或其它trap指令产⽣. 由debugger使⽤.6) SIGABRT程序⾃⼰发现错误并调⽤abort时产⽣.6) SIGIOT在PDP-11上由iot指令产⽣, 在其它机器上和SIGABRT⼀样.7) SIGBUS⾮法地址, 包括内存地址对齐(alignment)出错. eg: 访问⼀个四个字长的整数, 但其地址不是4的倍数.8) SIGFPE在发⽣致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误.9) SIGKILL⽤来⽴即结束程序的运⾏. 本信号不能被阻塞, 处理和忽略.10) SIGUSR1留给⽤户使⽤11) SIGSEGV试图访问未分配给⾃⼰的内存, 或试图往没有写权限的内存地址写数据.12) SIGUSR2留给⽤户使⽤13) SIGPIPE Broken pipe14) SIGALRM时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使⽤该信号.15) SIGTERM程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理. 通常⽤来要求程序⾃⼰正常退出. shell命令kill缺省产⽣这个信号.17) SIGCHLD⼦进程结束时, ⽗进程会收到这个信号.18) SIGCONT让⼀个停⽌(stopped)的进程继续执⾏. 本信号不能被阻塞. 可以⽤⼀个handler来让程序在由stopped状态变为继续执⾏时完成特定的⼯作. 例如,重新显⽰提⽰符19) SIGSTOP停⽌(stopped)进程的执⾏. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执⾏. 本信号不能被阻塞, 处理或忽略.20) SIGTSTP停⽌进程的运⾏, 但该信号可以被处理和忽略. ⽤户键⼊SUSP字符时(通常是Ctrl+Z)发出这个信号21) SIGTTIN当后台作业要从⽤户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停⽌执⾏.22) SIGTTOU类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.23) SIGURG有"紧急"数据或out-of-band数据到达socket时产⽣.24) SIGXCPU超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变25) SIGXFSZ超过⽂件⼤⼩资源限制.26) SIGVTALRM虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占⽤的CPU时间.27) SIGPROF类似于SIGALRM/SIGVTALRM, 但包括该进程⽤的CPU时间以及系统调⽤的时间.28) SIGWINCH窗⼝⼤⼩改变时发出.29) SIGIO⽂件描述符准备就绪, 可以开始进⾏输⼊/输出操作.30) SIGPWR Power failure有两个信号可以停⽌进程:SIGTERM和SIGKILL。
linux信号处理四(sigaction参数说明)sigaction函数的功能是检查或修改与指定信号相关联的处理动作(可同时两种操作)。
他是POSIX的信号接⼝,⽽signal()是标准C的信号接⼝(如果程序必须在⾮POSIX系统上运⾏,那么就应该使⽤这个接⼝)给信号signum设置新的信号处理函数act,同时保留该信号原有的信号处理函数oldactint sigaction(int signo,const struct sigaction *restrict act,struct sigaction *restrict oact);第⼆、第三个参数为,sigaction结构类型定义如下:struct sigaction{void (*sa_handler)(int);sigset_t sa_mask;int sa_flag;void (*sa_sigaction)(int,siginfo_t *,void *);};sa_handler:字段包含⼀个信号捕捉函数的地址sa_mask:字段说明了⼀个信号集,在调⽤该信号捕捉函数之前,这⼀信号集要加进进程的信号屏蔽字中。
即执⾏信号处理函数期间,阻塞信号屏蔽字中的信号,执⾏结束后再处理这期间发⽣的信号(sa_mask集中的信号)。
注:阻塞的意思是延迟相应信号sa_flag :是⼀个选项,注意:这个选项只与sigaction函数注册的信号有关联,与sa_mask中的信号⽆任何关系。
SA_INTERRUPT 由此信号中断的系统调⽤不会⾃动重启SA_RESTART 由此信号中断的系统调⽤会⾃动重启SA_SIGINFO 提供附加信息,⼀个指向siginfo结构的指针以及⼀个指向进程上下⽂标识符的指针SA_NODEFER ⼀般情况下,当信号处理函数运⾏时,内核将阻塞(sigaction函数注册时的信号)。
但是如果设置了SA_NODEFER标记,那么在该信号处理函 数运⾏时,内核将不会阻塞该信号。
Linux信号(signal)机制分析【摘要】本⽂分析了Linux内核对于信号的实现机制和应⽤层的相关处理。
⾸先介绍了软中断信号的本质及信号的两种不同分类⽅法尤其是不可靠信号的原理。
接着分析了内核对于信号的处理流程包括信号的触发/注册/执⾏及注销等。
最后介绍了应⽤层的相关处理,主要包括信号处理函数的安装、信号的发送、屏蔽阻塞等,最后给了⼏个简单的应⽤实例。
【关键字】软中断信号,signal,sigaction,kill,sigqueue,settimer,sigmask,sigprocmask,sigset_t1 信号本质软中断信号(signal,⼜简称为信号)⽤来通知进程发⽣了异步事件。
在软件层次上是对中断机制的⼀种模拟,在原理上,⼀个进程收到⼀个信号与处理器收到⼀个中断请求可以说是⼀样的。
信号是进程间通信机制中唯⼀的异步通信机制,⼀个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
进程之间可以互相通过系统调⽤kill发送软中断信号。
内核也可以因为内部事件⽽给进程发送信号,通知进程发⽣了某个事件。
信号机制除了基本通知功能外,还可以传递附加信息。
收到信号的进程对各种信号有不同的处理⽅法。
处理⽅法可以分为三类:第⼀种是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。
第⼆种⽅法是,忽略某个信号,对该信号不做任何处理,就象未发⽣过⼀样。
第三种⽅法是,对该信号的处理保留系统的默认值,这种缺省操作,对⼤部分的信号的缺省操作是使得进程终⽌。
进程通过系统调⽤signal 来指定进程对某个信号的处理⾏为。
2 信号的种类可以从两个不同的分类⾓度对信号进⾏分类:可靠性⽅⾯:可靠信号与不可靠信号;与时间的关系上:实时信号与⾮实时信号。
2.1 可靠信号与不可靠信号Linux信号机制基本上是从Unix系统中继承过来的。
早期Unix系统中的信号机制⽐较简单和原始,信号值⼩于SIGRTMIN的信号都是不可靠信号。
linux signal代码详解-回复Linux Signal代码详解1. 介绍Linux系统中的信号是一种进程间通信机制,通过向目标进程发送信号来触发特定的操作或者通知。
信号常常用于进程间的同步、通知和异常处理等方面。
在Linux系统中,信号由整型数字表示,每个信号对应一个唯一的编号。
本文将一步一步分析Linux中关于信号的代码。
2. 信号的基本概念在Linux中,信号是一种软中断,它是指在运行时对一个进程的异步通知,通过发送信号可以中断目标进程的执行,或者触发目标进程相关的操作。
信号的发送可以由内核、系统管理员或者进程自身进行。
3. 信号的分类信号分为两类:标准信号和实时信号。
标准信号在系统中的编号比较小,其范围是1-31,而实时信号的编号比较大,范围是32-64。
常用的信号包括SIGKILL、SIGSTOP、SIGTERM等。
4. 信号处理机制Linux系统对信号的处理机制主要有三种:忽略、捕获和执行默认操作。
当一个进程收到信号时,可以根据需要选择不同的处理方式。
- 忽略信号:进程可以忽略某个信号,这样当该信号发送到进程时,不会有任何响应。
- 捕获信号:进程可以捕获某个信号,并自行处理。
捕获信号需要注册一个信号处理函数,该函数在接收到指定信号时被调用。
- 默认操作:每个信号都有一个默认的操作,当进程未捕获该信号时,会执行默认操作。
5. 信号处理函数的注册在Linux中,通过调用signal()函数可以注册一个信号处理函数。
该函数的原型如下:ctypedef void (*sighandler_t)(int);sighandler_t signal(int signum,sighandler_t handler);其中,signum是信号的编号,handler是一个信号处理函数的指针。
如果handler为SIG_IGN,则表示忽略该信号;如果handler为SIG_DFL,则表示使用默认操作;如果handler为一个函数指针,则表示使用自定义的信号处理函数。
linux 默认sigsegv处理函数在Linux中,默认的SIGSEGV(段错误)处理函数是通过信号处理机制来实现的。
当程序出现段错误时,操作系统会向进程发送SIGSEGV信号,进程会捕获该信号并执行相应的处理函数。
在Linux中,默认的SIGSEGV处理函数是`sigsegv_handler`,它会打印出有关错误的一些信息,如错误的内存地址,引起段错误的指令等。
同时,它还会终止程序的执行。
在C/C++中,可以自定义SIGSEGV处理函数。
例如,可以使用`signal`函数来注册一个自定义的SIGSEGV处理函数,如下所示:c#include <stdio.h>#include <signal.h>void sigsegv_handler(int signal){printf("Segmentation fault\n");执行一些自定义的处理逻辑...}int main(){注册SIGSEGV处理函数signal(SIGSEGV, sigsegv_handler);产生一个段错误int *p = NULL;*p = 10;return 0;}在上面的示例中,当程序产生段错误时,`sigsegv_handler`函数会被调用,并打印出"Segmentation fault"。
可以根据实际需要,在自定义的SIGSEGV处理函数中执行一些特定的逻辑。
需要注意的是,如果在SIGSEGV处理函数中通过非局部跳转(如`longjmp`)来返回到程序的主流程,可能会导致程序处于未定义的状态。
因此,一般不建议在SIGSEGV处理函数中执行非局部跳转。
最好的方式是在SIGSEGV处理函数中打印出有用的信息,并终止程序的执行。
操作系统中的信号机制信号机制是操作系统的一个重要特性,通过它,应用程序可以与操作系统进行通信,实现进程间的协调和同步。
在本文中,将详细介绍信号机制的原理、使用和实现方法,并探讨其在操作系统中应用的重要性和作用。
一、信号机制的原理信号机制的原理是在操作系统中,某个进程通过向另一个进程发送信号,来通知这个进程某些事情已发生。
在Linux和Unix系统中,每个进程都有一个唯一的进程ID,通过信号,进程可以向目标进程发送指定的信号号码,目标进程将收到这个信号,并对其进行处理。
信号可以分为两种类型:软件中断和硬件中断。
软件中断是由操作系统中断处理程序发出的,用于通知应用程序某个事件已经发生;硬件中断是由系统硬件设备发出的,例如鼠标或键盘按键、定时器等。
在Unix系统中,每个信号都有一个唯一的编号,通常在1~31之间。
其中,0号信号表示检查进程是否存在,1号信号表示终止进程,2号信号表示中断进程执行等等。
除此之外,还有一些用户自定义的信号,可以用于特定的应用程序场景。
二、信号机制的使用在Linux和Unix系统中,可以使用kill命令发送信号。
该命令的基本语法是:kill [-s ]。
其中,表示需要发送的信号号码,可以是从1开始的任意整数;表示需要发送信号的进程ID。
如果没有指定信号号码,默认发送15号信号,即终止进程。
除了kill命令,应用程序也可以使用系统调用函数来发送信号。
例如,使用kill函数和raise函数可以向指定的进程ID或当前进程发送信号,如下所示:#include <sys/types.h>#include <sys/signal.h>int kill(pid_t pid, int sig);int raise(int sig);在应用程序中,通常会使用信号处理函数来定义信号的处理方式。
应用程序使用signal函数注册信号处理函数,并在信号发生时执行预先定义好的操作。
linux sigill代码1.引言1.1 概述Linux操作系统是一种广泛使用的开源操作系统,它具有强大的性能和灵活的设计。
在Linux操作系统中,SIGILL是一个重要的代码,它代表着非法指令(illegal instruction)的意思。
SIGILL代码对于理解和分析程序的运行过程具有重要意义。
当程序执行到一个非法指令时,操作系统会发送一个SIGILL信号给程序,以通知它出现了错误。
这个信号的处理可以由程序自行定义,通常情况下,程序会终止执行并报告错误。
SIGILL代码的含义是非常灵活的。
它可以用于检测代码中的错误、优化代码执行效率,或者实现一些特定的功能。
通过对SIGILL代码的分析,我们可以发现程序中潜在的问题或者优化的空间,从而提升程序的性能和稳定性。
然而,SIGILL代码也存在一定的局限性。
首先,由于它是在程序运行过程中触发的,因此对程序的性能会有一定的影响。
其次,在某些情况下,由于代码中使用了一些特殊的指令或者不可执行的操作,导致程序产生了非法指令的情况,这可能会误判为程序存在问题。
因此,在使用SIGILL 代码时,需要谨慎处理,并结合其他方法进行综合分析。
总之,SIGILL代码在Linux操作系统中具有重要的作用。
通过对SIGILL 代码的深入理解和应用,我们可以更好地开发和优化程序,提升系统的性能和稳定性。
在本文接下来的章节中,我们将详细介绍Linux操作系统以及SIGILL代码的含义和应用。
1.2文章结构文章结构部分的内容可以包括以下内容:在本文中,将会按照以下结构展开对Linux SIGILL代码的探讨:2.正文:2.1 Linux操作系统简介:本节将从Linux操作系统的发展历程、基本特性等方面进行介绍,以帮助读者对Linux操作系统有一个基本的了解。
2.2 SIGILL代码的含义:本节将着重探讨SIGILL代码的含义及其在Linux操作系统中的作用。
将会介绍SIGILL代码的定义、产生方式以及它在操作系统中的具体应用场景。
linux 信号传递参数
在Linux中,信号是一种用于进程通信的事件机制,可以用来通
知进程发生了某个特定的事件。
信号传递参数是指在发送信号的同时,传递一些额外的数据给目标进程。
Linux支持的信号传递参数方式有两种:一种是使用信号的附加
数据(signal sigaction)结构体,另一种是使用全局变量
(volatile sig_atomic_t)。
这两种方式都可以传递一些整数类型的
数据。
对于使用信号的附加数据结构体的方式,需要先定义一个结构体
类型,例如:
```c
typedef struct {
int data1;
char data2[10];
} signal_data;
```
然后,在发送信号的时候,使用`sigqueue`函数,将结构体的地
址作为参数传递给目标进程。
接收方可以使用`sigaction`函数来注册
信号处理函数,并在处理函数中获取传递的参数。
对于使用全局变量的方式,需要定义一个全局变量,用来存储传
递的参数。
在发送信号的时候,可以通过修改全局变量的值来传递参数。
接收方可以在信号处理函数中直接访问这个全局变量来获取参数。
需要注意的是,为了保证数据的同步和正确性,需要使用原子操
作来对全局变量进行读写操作,避免出现竞态条件。
综上所述,Linux中的信号传递参数可以通过信号的附加数据结
构体或全局变量来实现。
这样,我们可以通过信号来向目标进程传递
一些额外的数据。
Linux signal处理(zz)信号是Linux编程中非常重要的部分,本文将详细介绍信号机制的基本概念、Linux对信号机制的大致实现方法、如何使用信号,以及有关信号的几个系统调用。
信号机制是进程之间相互传递消息的一种方法,信号全称为软中断信号,也有人称作软中断。
从它的命名可以看出,它的实质和使用很象中断。
所以,信号可以说是进程控制的一部分。
一、信号的基本概念本节先介绍信号的一些基本概念,然后给出一些基本的信号类型和信号对应的事件。
基本概念对于理解和使用信号,对于理解信号机制都特别重要。
下面就来看看什么是信号。
1、基本概念软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。
进程之间可以互相通过系统调用kill发送软中断信号。
内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。
注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。
收到信号的进程对各种信号有不同的处理方法。
处理方法可以分为三类:第一种是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。
第二种方法是,忽略某个信号,对该信号不做任何处理,就象未发生过一样。
第三种方法是,对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信号的缺省操作是使得进程终止。
进程通过系统调用signal来指定进程对某个信号的处理行为。
在进程表的表项中有一个软中断信号域,该域中每一位对应一个信号,当有信号发送给进程时,对应位置位。
由此可以看出,进程对不同的信号可以同时保留,但对于同一个信号,进程并不知道在处理之前来过多少个。
2、信号的类型发出信号的原因很多,这里按发出信号的原因简单分类,以了解各种信号:(1)与进程终止相关的信号。
当进程退出,或者子进程终止时,发出这类信号。
(2)与进程例外事件相关的信号。
如进程越界,或企图写一个只读的内存区域(如程序正文区),或执行一个特权指令及其他各种硬件错误。
(3)与在系统调用期间遇到不可恢复条件相关的信号。
如执行系统调用exec时,原有资源已经释放,而目前系统资源又已经耗尽。
(4)与执行系统调用时遇到非预测错误条件相关的信号。
如执行一个并不存在的系统调用。
(5)在用户态下的进程发出的信号。
如进程调用系统调用kill向其他进程发送信号。
(6)与终端交互相关的信号。
如用户关闭一个终端,或按下break键等情况。
(7)跟踪进程执行的信号。
Linux支持的信号列表如下。
很多信号是与机器的体系结构相关的,首先列出的是POSIX.1中列出的信号:信号值处理动作发出信号的原因----------------------------------------------------------------------SIGHUP 1 A 终端挂起或者控制进程终止SIGINT 2 A 键盘中断(如break键被按下)SIGQUIT 3 C 键盘的退出键被按下SIGILL 4 C 非法指令SIGABRT 6 C 由abort(3)发出的退出指令SIGFPE 8 C 浮点异常SIGKILL 9 AEF Kill信号SIGSEGV 11 C 无效的内存引用SIGPIPE 13 A 管道破裂: 写一个没有读端口的管道SIGALRM 14 A 由alarm(2)发出的信号SIGTERM 15 A 终止信号SIGUSR1 30,10,16 A 用户自定义信号1SIGUSR2 31,12,17 A 用户自定义信号2SIGCHLD 20,17,18 B 子进程结束信号SIGCONT 19,18,25 进程继续(曾被停止的进程)SIGSTOP 17,19,23 DEF 终止进程SIGTSTP 18,20,24 D 控制终端(tty)上按下停止键SIGTTIN 21,21,26 D 后台进程企图从控制终端读SIGTTOU 22,22,27 D 后台进程企图从控制终端写下面的信号没在POSIX.1中列出,而在SUSv2列出信号值处理动作发出信号的原因--------------------------------------------------------------------SIGBUS 10,7,10 C 总线错误(错误的内存访问)SIGPOLL A Sys V定义的Pollable事件,与SIGIO同义SIGPROF 27,27,29 A Profiling定时器到SIGSYS 12,-,12 C 无效的系统调用(SVID)SIGTRAP 5 C 跟踪/断点捕获SIGURG 16,23,21 B Socket出现紧急条件(4.2 BSD)SIGVTALRM 26,26,28 A 实际时间报警时钟信号(4.2 BSD)SIGXCPU 24,24,30 C 超出设定的CPU时间限制(4.2 BSD)SIGXFSZ 25,25,31 C 超出设定的文件大小限制(4.2 BSD)(对于SIGSYS,SIGXCPU,SIGXFSZ,以及某些机器体系结构下的SIGBUS,Linux 缺省的动作是A (terminate),SUSv2 是C (terminate and dump core))。
下面是其它的一些信号信号值处理动作发出信号的原因----------------------------------------------------------------------SIGIOT 6 C IO捕获指令,与SIGABRT同义SIGEMT 7,-,7SIGSTKFLT -,16,- A 协处理器堆栈错误SIGIO 23,29,22 A 某I/O操作现在可以进行了(4.2 BSD)SIGCLD -,-,18 A 与SIGCHLD同义SIGPWR 29,30,19 A 电源故障(System V)SIGINFO 29,-,- A 与SIGPWR同义SIGLOST -,-,- A 文件锁丢失SIGWINCH 28,28,20 B 窗口大小改变(4.3 BSD, Sun)SIGUNUSED -,31,- A 未使用的信号(will be SIGSYS)(在这里,- 表示信号没有实现;有三个值给出的含义为,第一个值通常在Alpha和Sparc上有效,中间的值对应i386和ppc以及sh,最后一个值对应mips。
信号29在Alpha 上为SIGINFO / SIGPWR ,在Sparc上为SIGLOST。
)处理动作一项中的字母含义如下A 缺省的动作是终止进程B 缺省的动作是忽略此信号C 缺省的动作是终止进程并进行内核映像转储(dump core)D 缺省的动作是停止进程E 信号不能被捕获F 信号不能被忽略上面介绍的信号是常见系统所支持的。
以表格的形式介绍了各种信号的名称、作用及其在默认情况下的处理动作。
各种默认处理动作的含义是:终止程序是指进程退出;忽略该信号是将该信号丢弃,不做处理;停止程序是指程序挂起,进入停止状况以后还能重新进行下去,一般是在调试的过程中(例如ptrace系统调用);内核映像转储是指将进程数据在内存的映像和进程在内核结构中的部分内容以一定格式转储到文件系统,并且进程退出执行,这样做的好处是为程序员提供了方便,使得他们可以得到进程当时执行时的数据值,允许他们确定转储的原因,并且可以调试他们的程序。
注意信号SIGKILL和SIGSTOP既不能被捕捉,也不能被忽略。
信号SIGIOT与SIGABRT 是一个信号。
可以看出,同一个信号在不同的系统中值可能不一样,所以建议最好使用为信号定义的名字,而不要直接使用信号的值。
二、信号机制上一节中介绍了信号的基本概念,在这一节中,我们将介绍内核如何实现信号机制。
即内核如何向一个进程发送信号、进程如何接收一个信号、进程怎样控制自己对信号的反应、内核在什么时机处理和怎样处理进程收到的信号。
还要介绍一下setjmp和longjmp在信号中起到的作用。
1、内核对信号的基本处理方法内核给一个进程发送软中断信号的方法,是在进程所在的进程表项的信号域设置对应于该信号的位。
这里要补充的是,如果信号发送给一个正在睡眠的进程,那么要看该进程进入睡眠的优先级,如果进程睡眠在可被中断的优先级上,则唤醒进程;否则仅设置进程表中信号域相应的位,而不唤醒进程。
这一点比较重要,因为进程检查是否收到信号的时机是:一个进程在即将从内核态返回到用户态时;或者,在一个进程要进入或离开一个适当的低调度优先级睡眠状态时。
内核处理一个进程收到的信号的时机是在一个进程从内核态返回用户态时。
所以,当一个进程在内核态下运行时,软中断信号并不立即起作用,要等到将返回用户态时才处理。
进程只有处理完信号才会返回用户态,进程在用户态下不会有未处理完的信号。
内核处理一个进程收到的软中断信号是在该进程的上下文中,因此,进程必须处于运行状态。
前面介绍概念的时候讲过,处理信号有三种类型:进程接收到信号后退出;进程忽略该信号;进程收到信号后执行用户设定用系统调用signal的函数。
当进程接收到一个它忽略的信号时,进程丢弃该信号,就象没有收到该信号似的继续运行。
如果进程收到一个要捕捉的信号,那么进程从内核态返回用户态时执行用户定义的函数。
而且执行用户定义的函数的方法很巧妙,内核是在用户栈上创建一个新的层,该层中将返回地址的值设置成用户定义的处理函数的地址,这样进程从内核返回弹出栈顶时就返回到用户定义的函数处,从函数返回再弹出栈顶时,才返回原先进入内核的地方。
这样做的原因是用户定义的处理函数不能且不允许在内核态下执行(如果用户定义的函数在内核态下运行的话,用户就可以获得任何权限)。
在信号的处理方法中有几点特别要引起注意。
第一,在一些系统中,当一个进程处理完中断信号返回用户态之前,内核清除用户区中设定的对该信号的处理例程的地址,即下一次进程对该信号的处理方法又改为默认值,除非在下一次信号到来之前再次使用signal系统调用。
这可能会使得进程在调用signal之前又得到该信号而导致退出。
在BSD中,内核不再清除该地址。
但不清除该地址可能使得进程因为过多过快的得到某个信号而导致堆栈溢出。
为了避免出现上述情况。
在BSD系统中,内核模拟了对硬件中断的处理方法,即在处理某个中断时,阻止接收新的该类中断。
第二个要引起注意的是,如果要捕捉的信号发生于进程正在一个系统调用中时,并且该进程睡眠在可中断的优先级上,这时该信号引起进程作一次longjmp,跳出睡眠状态,返回用户态并执行信号处理例程。
当从信号处理例程返回时,进程就象从系统调用返回一样,但返回了一个错误代码,指出该次系统调用曾经被中断。
这要注意的是,BSD系统中内核可以自动地重新开始系统调用。
第三个要注意的地方:若进程睡眠在可中断的优先级上,则当它收到一个要忽略的信号时,该进程被唤醒,但不做longjmp,一般是继续睡眠。