自学Linux--sigaction function

来源:互联网 发布:linux 硬盘的dd命令 编辑:程序博客网 时间:2024/05/16 05:48

#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可以连续发送2SIGUSR1child,我们发现child并不响应,而是依然睡足她的剩下的时间。5秒钟睡眠结束后,child醒了,它的handler退出,系统自动将临时blockSIGUSR1 unblock,此时发现有pendingSIGUSR1,因此将他deliverychild。于是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

原创粉丝点击