Chinaunix首页 | 论坛 | 博客
  • 博客访问: 988539
  • 博文数量: 200
  • 博客积分: 5011
  • 博客等级: 大校
  • 技术积分: 2479
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-27 15:07
文章分类

全部博文(200)

文章存档

2009年(12)

2008年(190)

我的朋友

分类:

2008-12-08 12:15:32

10.14 sigaction function

这个函数可以:

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,此时发现有pending SIGUSR1,因此将他deliverychild。于是child再次进入handler,此时father已经不再发送信号了,就等着孩子结束呢。所以handler结束后,child就继续执行,退出,然后father也就退出了。

#include

#include

#include

#include

#include

 

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");

/*          

              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();

              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;

 

}

结果如下:

shaoting@desktopbj-LabSD:/home/shaoting/mytest> ./a.out

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

 

下面是书中的代码,实现了几个函数:

Figure 10.18实现了reliable signal函数,自动reinstall handler, handler内部自动blocksignal,并且system call自动restart,(除了SIGALRM)

Figure 10.18. An implementation of signal using sigaction
#include "apue.h"
 
/* Reliable version of signal(), using POSIX sigaction(). */
Sigfunc *
signal(int signo, Sigfunc *func)
{
    struct sigaction    act, oact;
 
    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
       act.sa_flags |= SA_INTERRUPT;
#endif
    } else {
#ifdef  SA_RESTART
        act.sa_flags |= SA_RESTART;
#endif
    }
    if (sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}
Figure 10.19. The signal_intr function
#include "apue.h"
 
Sigfunc *
signal_intr(int signo, Sigfunc *func)
{
    struct sigaction    act, oact;
 
    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
#ifdef  SA_INTERRUPT
    act.sa_flags |= SA_INTERRUPT;
#endif
    if (sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}
阅读(634) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~