信号在最早的Unix系统中即被引入,用于在用户态进程间通信。内核也用信号通知进程系统所发生的事件。信号已有30多年的历史,但是只有很小的变化。
信号的作用
信号是很短的消息,可以被发送到一个进程或一组进程。发送给进程的唯一信息通常是一个数,以此来标识信号。
使用信号的两个主要目的是:
让进程知道已经发生了一个特定的事件。
强迫进程执行它自己代码中的信号处理程序。
posix信号和多线程应用
Linux内核定义了31个常规信号,如下图所示,除了下图所示的常规信号外,POSIX标准还引入了一类新的信号,叫做实时信号;在Linux中它们的编码为32~64。两者区别需要理解:
实时信号必须排队以便发送的多个信号能被接收到。
同种类型的常规信号不排队,如果一个常规信号被连续发送多次,那么,只有其中的一个发送到接收进程。
这里只需要知道信号有常规信号和实时信号的区分即可,真正用到的时候再看。
include\uapi\asm-generic\signal.h
#include <linux/types.h>
#define _NSIG 64
#define _NSIG_BPW __BITS_PER_LONG
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
/*
#define SIGLOST 29
*/
#define SIGPWR 30
#define SIGSYS 31
#define SIGUNUSED 31
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#ifndef SIGRTMAX
#define SIGRTMAX _NSIG
#endif
捕获信号
信号处理程序是用户态进程所定义的函数,并包含在用户态的代码段中。
改变信号操作
改变信号操作的封装函数signal
在用户态程序编码中,我们经常使用signal()函数来改变相应信号的默认操作。但是,我们要知道signal只是一个封装函数(wrapper function),它通过系统调用sigaction()实现改变信号默认操作的目的。
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
description:
signal() sets the disposition of the signal signum to handler, which is either SIG_IGN, SIG_DFL, or the address of a programmer-defined function (a "signal handler").
The situation on Linux is as follows:
* By default, in glibc 2 and later, the signal() **wrapper function** does not invoke the kernel system call. Instead, it calls sigaction(2) using flags that supply BSD semantics. This default behavior is provided as long as the _BSD_SOURCE feature test macro is defined. By default, _BSD_SOURCE is defined; it is also implicitly defined if one defines _GNU_SOURCE, and can of course be explicitly defined.
改变信号操作的系统调用sigaction
sigaction()系统调用允许用户 为信号指定一个操作。当然,如果没有自定义的信号操作,那么内核执行传递信号相关的缺省操作。
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
=================================glibc 2.3源码================================================
/* If ACT is not NULL, change the action for SIG to *ACT.
If OACT is not NULL, put the old action for SIG in *OACT. */
int
__sigaction (int sig, const struct sigaction *act, struct sigaction *oact);