需要解决的问题:
1、系统中什么是信号、有什么信号?
2、系统接收到信号,如何处理?
3、信号的作用。
一、linux内核中的信号
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGUNUSED 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
二、系统如何调用接受的信号与作用
do_signal函数是内核系统调用中断(int 0X80)中断处理子程序的预处理程序,该函数的主要作用是将信号的处理句柄插入到用户程序堆栈中,系统调用后就会执行。
sys_signal由函数库提供,用于恢复系统调用后的返回值和一些寄存器。编译链接时由libc函数库提供,用于 在信号处理程序结束后清理用户态堆栈,并恢复系统调用存放在eax中的返回值。
信号作用:信号是进程间通信的简单的消息,信号虽然不带任何信息。但是子进程结束后他会产生一个17信号给父进程,显示子进程当前的状态。信号处理函数会被压入用户堆栈 。
三、信号处理的流程
在system_call.s中,可以看到首先调用的是do_signal进行预处理,再调用sys_signal信号处理 。
call sys_call_table(,%eax,4) # 间接调用指定功能C函数
pushl %eax # 把系统调用返回值入栈
incl %ecx # 将信号调整为从1开始的数(1-32)
pushl %ecx # 信号值入栈作为调用do_signal的参数之一
call do_signal # 调用C函数信号处理程序(kernel/signal.c)
popl %eax # 弹出入栈的信号值
3: popl %eax # eax中含有上面入栈系统调用的返回值
popl %ebx
popl %ecx
popl %edx
pop %fs
pop %es
pop %ds
iret
3.1 do_signal
由于C函数是传值函数,因此给eip赋值时需要使用'*(&eip)'的形式。
3.2 sys_signal
signal()系统调用。类似于sigaction()。为指定的信号安装新的信号句柄(信号处理程序)。 信号句柄可以是用户指定的函数,也可以是SIG_DFL(默认句柄)或SIG_IGN(忽略)。参数signum --指定的信号;handler --指定的句柄;restorer --恢复函数指针,该函数由Libc库提供。用于在信号处理程序结束后恢复系统调用返回时几个寄存器的原有值以及系统 调用的返回值,就好像系统调用没有执行过信号处理程序而直接返回到用户程序一样。 函数返回原信号句柄。
int sys_signal(int signum, long handler, long restorer)
{
设置分配一个信号结构体
struct sigaction tmp;
检索信号范围要在1-32并且不是终止信号
if (signum<1 || signum>32 || signum==SIGKILL)
return -1;
指定信号处理句柄
tmp.sa_handler = (void (*)(int)) handler;
设置屏蔽码
tmp.sa_mask = 0;
设置改信号的状态为只可执行一次就恢复到默认值
tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
保存回复处理程序指针
tmp.sa_restorer = (void (*)(void)) restorer;
更新当先标识指针的信号信息
handler = (long) current->sigaction[signum-1].sa_handler;
current->sigaction[signum-1] = tmp;
return handler;
}
注意:
当一个子进程终止或结束时都给父进程发送一个标号为17的SIGCHLD信号,用来通知父进程子进程的当前状态。