4 Linux 进程管理

4.5 Linux 信号

4.5.1 信号的作用和种类

1.信号机制
2.信号种类

信号产生的三种情况:
1.进程在执行过程中发生了某种错误,标志被置位,系统内核识别到错误标志,向有关进程发送相应信号,通知进程发生了运行错误。
2.系统或用户发出的控制进程终止或暂停的信号。
3.内核需要控制进程的运行而产生的信号。

4.5.2 信号的处理

1. 在进程的任务结构体 task_struct 中有两个成员项用于处理接收的信号:

Unsigned long signal;
Unsigned long blocked;

它们都是位域(Bitmap)形式的 32 位 unsigned long 型变量,每一位(bit)对应一种信号。变量的第 0位对应信号值为 1 的 SIGHUP,第 1 位对应信号值为 2 的 SIGINT,依此类推。
1)Signal:存放进程收到且尚未处理的信号。

2) Blocked:通过将 blocked 中的某一位设置为 1,来屏蔽某种信号的处理。但是有两个不能屏蔽的信号(SIGKILL 和 SIGSTOP)是不能被屏蔽的,blocked 中它们对应的位始终为 0;

2.进程接收到信号后的两种处理方式:

1)其中 core 转储指把该进程内存中的有关信息进行转储(dump),生成 core 文件。在使用 gdb 调试工具对程序进行调试时,通常需要使用 core 文件。
2)进程接收到信号后有其自行处理成为信号的捕获,但是信号 SIGKILL 和 SIGSTOP 不能有进程捕获,他们必须由内核进行处理。
3)信号无论是由内核或是进程处理,都可以 被忽视,即不进行任何处理,但是信号 SIGKILL 和SIGSTOP 不能被忽视。

4.5.3 信号处理函数

1.数据结构

当进程接收到信号,并且该信号没有被阻塞的话,进程就执行信号处理函数完成对信号的处理,每种信号都有其对应的处理函数,进程对所有信号处理函数集中由 signal_struct 结构体来管理,进程任务结构体中成员项 sig 指向该结构体。在 include/linux/sched.h 中定义了 signal_struct 结构体:

Struct signal_struct{
Int count;
Struct sigaction action[32]};
Struct sigaction {
_sighandler_t sa_handler;
Sigset_t sa_mask;
Unsigned long sa_flags;
Void(*sa_restorer)(void);
};

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 进程管理 5》(9)-LMLPHP

2. 处理函数 signal

Linux 系统提供了用户自己设置信号处理函数的方法,它由系统调用 signal()完成。在 signal()中进一步调用内核函数 sys_signal()实现函数设置的功能。该内核函数定义在 kernal/signal.c 中:

Asmlinkage unsigned long sys_signal(int signum,_sighandler_t handler);

参数说明:

函数简要说明:

Struct sigaction tmp;/*用于暂存信号处理函数的有关信息。*/If(signum<1|| signum>32returnEINVAL; /*判断 signum 给定的信号值是否合理*/
If(signum==SIGKILL||signum==SIGSTOPreturnEINVAL; /*若为这两个信号,则不能被捕获,即用户不能为它们设定处理函数*/
If(handler!=SIG_DFL&& handler!=SIG_IGN/*若信号不是指定为缺省处理或
{ 忽视,则确认给定的处理函数使用存储空间的有效性*/
Err = verify_area(VERIFY_READ,handler,1)If(err)return err;
}

经过上面的检查确认后,开始使用 tmp 设置进程的 sigaction 结构体。

Memset&tmp,0,sizeof(tmp); /* 首先把该结构的存储空间全部清 0*/
Tmp.sa_handler =handler;/*把参数 handler 指定的信号函数处理函数首地址置入 tmp 的sa_handler*/
Tmp.sa_flags = SA_ONESHOT|SA_NOMASK; /*设置 sa_flag*/
Current->sig->action[signum-1]=tmp; /*把 tmp 的内容复制到当前进程的处理信号函数表中与指定信号对应的数组元素中。*/
Check_pending(signum); /*设置当前进程任务结构体的 signal 成员项*/
Return(unsigned long)handler; /*返回 handler 的值,即原信号处理函数的首地址*/
3.程序例
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
Int count=0;
Void ctrl_c_count(int);
Main()
{
int c;
void(*old_handler)(int);
old_handler=signal(SIGINT,ctrl_c_count);
while((c=getch()!=”\n”);
printf(Ctrl_C count=%d\n”,count);
signal(SIGINT,old_handler);
}
Void ctrl_c_count(int dump)
{
Printf(Ctrl_C\n”);
Count++;
}
11-28 08:51