Linux信号
信号的产生
一.通过终端按键产生信号
1.通过键盘Ctrl+C 产生SIGINT信号,对当前前台进程,和他的所在的进程组的每个进程都发送 SIGINT 信号
2.通过键盘Ctrl+\ 产生SIGQUIT信号,默认处理动作是终止进程并且Core Dump.
3.关于Core Dump,当进程发生错误或收到“信号”(signal) 而终止执行时,系统会将核心映像写入一个文件,以作为调试之用,这就是所谓的核心转储(core dump)。
开启核心转储:Linux 默认没有打开core文件生成功能,可通过ulimit -c unlimited不限制 core 的大小。
这只会在当前终端有效,退出终端或者打开一个新的终端时是无效的。因此可以在将上述配置加入到 /etc/profile 中。
使用GDB调试core文件:编译时加上-g选项,产生core文件后使用gdb <程序> <core文件>命令查看错误。
二.调用系统函数向进程发信号
1.调用kill函数int kill(pid_t pid, int signo)给指定进程发送信号,kill命令也是调用kill函数实现的。
2.同样还有int raise(int signo)函数和void abort(void)函数
三.由软件条件产生信号
1.SIGPIPE信号,我们在管道的读写中,如果读端关闭写端会收到SIGPIPE信号直接终止,在sock通信中,如果尝试send到一个disconnected socket上,也会让底层抛出一个SIGPIPE信号,终止进程。
2.SIGALRM信号,unsigned int alarm(unsigned int seconds);调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。
3.SIGCHLD信号,子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略。父进程调 用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略 通常是没有区别的,但这是一个特例。
四.硬件异常产生信号
硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。
信号的相关常见概念
一.概念
实际执行信号的处理动作称为信号递达(Delivery)
信号从产生到递达之间的状态,称为信号未决(Pending)。
进程可以选择阻塞 (Block )某个信号。
被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
二.信号的处理方式
1.默认
2.忽略
3.自定义
三、Pending位图、Handler表和Block位图
信号发送本质就是操作系统修改目标进程pcb内32位的unisgned int字段的pending位图
处理信号时调用handler表中的函数方法,如果该信号被阻塞则不会调用直到解除阻塞。
信号的自定义捕捉
一.signal函数
函数sighandler_t signal(int signum, sighandler_t handler),handler的函数声明为void (*sighandler_t)(int);
二.sigaction函数
1.了解sigset_t类型
每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。
因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号
的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有
效”和“无效”的含义是该信号是否处于未决状态。阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask)
2.了解struct sigaction
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
sa_handler:对捕获的信号进行处理的函数,函数参数为sigaction函数的参数1信号(概念上等同于单独使用signal函数)
sa_sigaction:如果设置了SA_SIGINFO标志位,则会使用sa_sigaction处理函数,否则使用sa_handler处理函数。
sa_mask:定义一组信号,在调用由sa_handler所定义的处理器程序时将阻塞该组信号,不允许它们中断此处理器程序的执行。
sa_flags:位掩码,指定用于控制信号处理过程的各种选项。
sa_restorer:已被弃用。
3.了解信号集操作函数
sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_ t变量
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
4.sigaction函数自定义捕捉
先设置struct sigaction的各项成员,再调用函数实现自定义捕捉指定信号。
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact)函数
信号的阻塞
sigprocmask函数
信号屏蔽字规定了当前阻塞而给该进程的信号集。调用函数sigprocmask可以检测或更改其信号屏蔽字。
int sigprocmask( int how, const sigset_t *restrict set, sigset_t *restrict oset );
how参数:
sigset_t使用上述的信号操作函数进行设置。