分类:
2008-12-08 12:15:32
10.14 sigaction
function
这个函数可以:
1. 给一个signal安装一个handler,并且在使用sigaction修改该handler之前,不用reinstall
2. 使用sigaction结构,该结构包含handler,其中可以指定2个handler,一个是使用sigiinfo_t等参数的handler,即支持给handler更多的参数,使其可以知道自己是被什么进程,那个用户,发来的什么信号,发来该信号的具体的原因是什么,当然要像这样,得给sigaction的sa_flags设置SA_SIGINFO标记。
3.使用sigaction的sa_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加入sigaction的sa_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
#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内部自动block本signal,并且system
call自动restart,(除了SIGALRM)
#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);
}
#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);
}