sigaction函数的详解

来源:互联网 发布:重庆大学网络教育学校 编辑:程序博客网 时间:2024/04/28 11:25
本文主要参考《unix环境高级编程》
 
sigaction函数的功能是检查或修改与指定信号相关联的处理动作(可同时两种操作)。
 

int sigaction(int signo,const struct sigaction *restrict act,

              struct sigaction *restrict oact);

结构sigaction定义如下:

struct sigaction{
  void (*sa_handler)(int);
  sigset_t sa_mask;
  int sa_flag;
  void (*sa_sigaction)(int,siginfo_t *,void *);
};

sa_handler字段包含一个信号捕捉函数的地址

sa_mask字段说明了一个信号集,在调用该信号捕捉函数之前,这一信号集要加进进程的信号屏蔽字中。仅当从信号捕捉函数返回时再将进程的信号屏蔽字复位为原先值。

sa_flag是一个选项,主要理解两个

SA_INTERRUPT 由此信号中断的系统调用不会自动重启
SA_RESTART 由此信号中断的系统调用会自动重启

SA_SIGINFO 提供附加信息,一个指向siginfo结构的指针以及一个指向进程上下文标识符的指针

最后一个参数是一个替代的信号处理程序,当设置SA_SIGINFO时才会用他,具体有些烦,暂时用不到,不看了。

下面的代码是用sigaction实现signal函数:

 

#include "apue.h"
Sigfunc *signal(int signo,Sigfunc *func)
{
  struct sigaction act;//新的信号关联信息

  struct sigaction oact;//老的信号关联信息

  act.sa_handler = func;//新的信号处理函数

  sigemptyset(&act.sa_mask);//初始化屏蔽字

  act.sa_flags = 0;//初始化flags

  if (signo == SIGALRM) {//不会重启动
#ifdef SA_INTERRUPT
     act.sa_flags |= SA_INERRUPT;
#endif
  } else { //重启动
#ifdef SA_RESTART
     act.sa_flags |= SA_RESTART;
#endif
  }
  if (sigaction(signo, &act, &oact) < 0)//新老交换
      return(SIG_ERR);
   return (oact.sa_handler);
}



于signal 函数和  sigaction 函数的区别

注意 :
    <1> sigaction
    *一般用法:
          19
     20     phan.sa_handler = &sig_handler;
     21     sigemptyset(&phan.sa_mask);
     23     phan.sa_flags = 0;   或 //phan.sa_flags = SA_RESTART; 其效果和signal 一样
     24     sigaction(SIGALRM, &phan, NULL);



     *注意
        一般不是重启动的函数,除非把sa_flag=SA_RESTART. 也就是说当信号到来,中断其阻塞的I/O操作,或其他阻塞的操作时,
他们会自动启动这些操作,而不会中断这些操作.而这些I/O操作会保持原来的阻塞状态就好好象根本没有信号到来一样.
   
     <2>signal
       函数是重启动的,当使用该函数安装信号处理函数时,其阻塞的操作将会被中断

      实际使用例子:

    

/*
* test for alarm
*/
#include "apue.h"
void sig_handler(int signo);
void sig_handler2(int signo);
void pr_mask(const char *str);
int
main(void)
{
int i;
struct sigaction phan;
char str[100] = {'/0'};
//phan.sa_handler = &sig_handler2;
phan.sa_handler = &sig_handler;
sigemptyset(&phan.sa_mask);
//phan.sa_flags = SA_RESTART; //如果使用这一行,将会阻塞在read函数
phan.sa_flags = 0;
sigaction(SIGALRM, &phan, NULL);
//signal(SIGALRM, sig_handler2);
for(i=0;;i++){
alarm(3);
fprintf(stderr, "do something/n");
read(STDIN_FILENO, str, sizeof(str));
fprintf(stderr, "[%d] done/n", i);
//alarm(0);
//pause();
}
return(0);
}
void sig_handler(int signo)
{
struct sigaction phan;
switch(signo){
case SIGALRM:
                        //如果下面的函数将会阻塞在read函数.因为它会让阻塞的操作自动重启动  
        //signal(SIGALRM, sig_handler);
phan.sa_handler = &sig_handler;
sigemptyset(&phan.sa_mask);
phan.sa_flags = 0;
sigaction(SIGALRM, &phan, NULL);
pr_mask("sig_handler : "); //打印出信号掩码
fprintf(stderr, "time out/n");
break;
default:
fprintf(stderr, "[%d] ignores/n", signo);
}
}
void sig_handler2(int signo)
{
switch(signo){
case SIGALRM:
fprintf(stderr, "time out/n");
break;
default:
fprintf(stderr, "[%d] ignores/n", signo);
}
}
void
pr_mask(const char *str)
{
sigset_t sigset;
int errno_save;
errno_save = errno; /* we can be called by signal handlers */
if (sigprocmask(0, NULL, &sigset) < 0){
fprintf(stderr, "sigprocmask error");
exit(1);
}
printf("%s", str);
if (sigismember(&sigset, SIGINT)) printf("SIGINT ");
if (sigismember(&sigset, SIGQUIT)) printf("SIGQUIT ");
if (sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 ");
if (sigismember(&sigset, SIGALRM)) printf("SIGALRM ");
/* remaining signals can go here */
printf("/n");
errno = errno_save;