信号的处理是当前进程在中断时,从内核态返回到用户态时要处理的第一件事,进程在从内核态返回用户态时,先检查进程是否有需要处理的信号(就是判断当前进程的进程控制块中的signal信号位图,和blocked阻止位图的相与),如果信号位图与阻止位图相与后,发现有置位的位,就说明当前进程有信号需要处理。此时,先判断是32种信号中的哪种,然后内核会把这个信号的处理函数的地址,作为内核返回用户态时的EIP,因此,当返回用户态后,用户态的执行流程就从信号处理函数开始执行,当执行完了信号处理函数后,再转到发生中断时所保留的下一条语句开始执行。
而进程也许没有其他的中断,但是总会有时钟中断产生,因此,当有信号需要处理,而起进程得到执行时,都会在时钟中断返回时得到执行。
进程对信号的处理,在进程控制块中有一个struct sigaction sigaction[32]项用于记录当前进程对32种信号的处理信息,包括信号处理函数,屏蔽码,信号集改变,恢复过程4个信息。通过对不同信号的不同处理函数的赋值,让各种信息对应定义好的信号处理。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
void handler_0(int signo)
{
printf("Alarm handler 0\n");
}
void signal_rec(int signum,siginfo_t *info,void * op)
{
printf("received %d signal\n",signum);
sleep(5);
}
int main(int argc,char *argv[])
{
int i,sig;
struct sigaction act,oldact;
// while(1)
{
signal(SIGALRM,handler_0);
alarm(5);
for(i=0;i<10;i++)
{
printf("sleep %d sec\n",i);
sleep(1);
}
printf("the pid is=%d\n",getpid());
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = signal_rec;
for(i=1;i<argc;i++)
{
sig = atoi(argv[i]);
if(sigaction(sig,&act,NULL)<0)
perror("install signal \n");
}
for(;;)
{
sleep(2);
printf("wait for signal\n");
}
}
}
/*#gcc signal.c
#./a.out 20 30
记住pid号
再开一个终端
执行
#kill -s 20 pid 号
可以看对应的信号处理函数的处理流程
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
int main(int argc,char *argv[])
{
int status;
pid_t pid;
if(!(pid = fork()))
{
sleep(5);
kill(getppid(),SIGALRM);
printf("send signal to parent \n");
return;
}
else
{
printf("wait for the signal(%d) \n",pid);
pause();/*打开与屏蔽此句,可以了解pause用法*/
printf("get the signal\n");
}
}
来源:https://www.cnblogs.com/image-eye/archive/2011/07/28/2118980.html