自学Linux--sigaction function

#include<signal.h>
int sigaction(int sig, struct sigaction *act , struct sigaction *oact) ;

struct sigaction{
      void     (*sa_handler)(int);
      void     (*sa_sigaction)(int, siginfo_t *, void *);
      sigset_t   sa_mask;
      int        sa_flags;
      void     (*sa_restorer)(void);
}
这个函数可以 :

1. 给一个signal安装一个handler,并且在使用sigaction修改该handler之前,不用reinstall

2. 使用sigaction结构,该结构包含handler,其中可以指定2handler,一个是使用sigiinfo_t等参数的handler,即支持给handler更多的参数,使其可以知道自己是被什么进程,那个用户,发来的什么信号,发来该信号的具体的原因是什么,当然要像这样,得给sigactionsa_flags设置SA_SIGINFO标记。

3.使用sigactionsa_flags标记还可以指定系统调用被这个信号打断后,是直接返回,还是自动restart. 一个典型就是,一般我们不让SIGALRM信号将被打断的系统调用restart,因为SIGALARM一般本来就是用来打断一个block的调用的。

4. 为了模仿老的signal函数的作用,实现unreliable 的类似signal的操作,可以通过给sa_flags设置SA_RESETHAND使handler不会自动reinstall,以及SA_NODEFER标记来使在本信号的handler内部,本信号不被自动block,当然如果你手动在sa_mask中指定要block本信号的话就可以将其block了。

5. 通过使用sigaction结构中的sa_mask,可以在该handler执行的过程中,block一些信号,注意,这个mask是与我们使用sigprocmask设置的mask不同的mask,这个mask的作用范围仅限于本handler函数,而且他不会将我们用sigprocmask设置的mask取消,而仅仅是在其基础上再次将一些信号block掉,当handler结束时,系统会自动将mask恢复成以前的样子,所以这个sigaction中的sa_mask只作用本信号的handler的执行时间。

此外,系统为了避免一个signal handler的执行的时候再次被本signal打断,就自动在本handler执行之前,将本signal加入sigactionsa_mask中,使本handler的执行过程中,不会受到本signal的嵌套打扰,单是如果本handler对应的信号的确发生了,那么该信号会在本handler执行完后执行,但只执行一次,因为只能记录一次,当然如果在这次新的执行中,又发生了这种情况,应该往复下去。下面就是一段代码,它验证了如下几点:

1).Sigaction会使handler自动将本signal给临时block

2).在一个handler执行过程中被临时block掉的信号也会被记录,等handler完成后会被delivery

下例子中, child 一开始就 pause() 等待信号来临, father 给他发送 SIGUSR1 信号,然后 father 就进入 1 秒钟的睡眠,这是为了等 child 在他的 handler 里面进入睡眠。 Child 受到 SIGUSR1 后。立即执行 handler ,它会进入 5 秒钟的睡眠。那么可见,等 father 睡了 1 秒钟后, child 还在睡眠,并且在其 handler 里面睡眠。此时 father 可以连续发送 2 SIGUSR1 child ,我们发现 child 并不响应,而是依然睡足她的剩下的时间。 5 秒钟睡眠结束后, child 醒了,它的 handler 退出,系统自动将临时 block SIGUSR1 unblock ,此时发现有 pending SIGUSR1 ,因此将他 delivery child 。于是 child 再次进入 handler ,此时 father 已经不再发送信号了,就等着孩子结束呢。所以 handler 结束后, child 就继续执行,退出,然后 father 也就退出了。

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

void nullhandler( int num )
{
       puts( "child received  signal" );
       puts( "child sleep 5 secs in handler..." );
       sleep(5);
       puts( "child wake up in handler after 5 secs" );
}

int main()
{
       setbuf( stdout, NULL );
       int pid = fork();
       if( pid == 0 )
       {
              //child
              puts("child started");
	      printf("%d",getpid());
/*          
              sigset_t maskset,oldset,oldset1;
              sigemptyset( &maskset );
              sigaddset( &maskset, SIGUSR1 );
              sigprocmask( SIG_BLOCK, &maskset, &oldset );
*/
              struct sigaction act, oldact;
              act.sa_handler = nullhandler;
              sigemptyset( &act.sa_mask );
              if( sigaction( SIGUSR1, &act,0 ) < 0 )
              {
                     puts(" child install handler failed");
                     return -1;
              }
              /*
              puts("child went to sleep ...");
              sleep(5);
              puts("child wake up...");
              sigset_t pendset;
              if( sigpending( &pendset ) < 0  )
              {
                     puts("get pending signal failed");
                     return -1;
              }
              if( sigismember( &pendset, SIGUSR1 ) )
                     puts("SIGUSR1 is pending signal");
              else
                     puts("SIGUSR1 is pending signal");
              puts("child is unblocking signal");
              if( sigprocmask(SIG_UNBLOCK, &maskset, &oldset1 ) < 0 )
                     puts("unblock signal failed");
              else
                     puts("unblock signal success");
              */
              puts("child waiting for signal...");
              /*pause函数只是简单地将进程挂起,直至进程接受到一个terminal信号,或是一个信号函数将信号捕捉,并进行调用。*/
              pause();
              puts("child returnd from signal handler");
              puts("child  is quiting");
              exit(0);
       }
       sleep(1);
       puts( " father send  SIGUSR1 once" );
       int ret = kill( pid, SIGUSR1 );
       puts("father sleep 1 sec to ensure child is now in signal handler");
       sleep(1);
       puts( " father send  SIGUSR1 twice" );
       ret = kill( pid, SIGUSR1 );
       puts( " father send  SIGUSR1 third times" );
       ret = kill( pid, SIGUSR1 );
       /*等待子进程的结束。*/
       waitpid( pid, 0, 0);
       puts("father is quiting");
       return 0;
}

输出结果:

child started

child waiting for signal...

father send  SIGUSR1 once

father sleep 1 sec to ensure child is now in signal handler

child received  signal

child sleep 5 secs in handler...

father send  SIGUSR1 twice

father send  SIGUSR1 third times

child wake up in handler after 5 secs

child received  signal

child sleep 5 secs in handler...

child wake up in handler after 5 secs

child returnd from signal handler

child  is quiting

         father is quiting

感谢大牛文章的指导:http://blog.chinaunix.net/space.php?uid=12072359&do=blog&id=2961076

你可能感兴趣的:(自学Linux--sigaction function)