白话/图示 信号处理流程

我怕爱的太早我们不能终老 提交于 2020-02-05 05:05:21

信号的处理是当前进程在中断时,从内核态返回到用户态时要处理的第一件事,进程在从内核态返回用户态时,先检查进程是否有需要处理的信号(就是判断当前进程的进程控制块中的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");
 }
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!