分类:
2008-12-08 12:16:22
10.15 sigsetjmp and
siglongjmp functions
#include int sigsetjmp(sigjmp_buf env, int savemask); |
Returns: 0 if called directly, nonzero if returning from a call to
siglongjmp |
void siglongjmp(sigjmp_buf env, int val); |
这两个函数与setlongjmp 和longjmp在使用与signal
handler里面的时候的区别在于:
是否可以自动恢复signal mask:
Setlongjmp和longjmp如果在signal handler里面被调用,当longjmp返回时,不会自动将handler里面系统自动block的本signal给unblock。当然,如果我们用return之类的返回语句,就会自动unblock。并且为了兼容setlongjmp和longjmp,sigsetjmp和siglongjmp还可以提供不自动恢复signal mask的方式工作。因此我们基本上在signal handler里面摒弃对longjmp和setlongjmp的调用。
检查位置缓冲的合法性:
如果在signal机制里面使用这种长跳转,建议使用siglongjmp的时候,要确保sigsetjmp已经被调用,即我们可以调到一个合法的位置去。因此要使用一个标记,来表明当前位置缓冲是否合法。当sigsetjmp调用后,标记置位,位置缓冲合法,这样在signal handler里面就可以正确的跳到该位置了。我们之所以要这么做是因为,在signal 处理中,指不定什么时候来个信号,所以信号的来到并不一定完全依据我们自己的想法和设计,所以,有可能在我们用sigsetjmp来设置位置缓冲之前,该信号就到来了,所以,我们应该用一个标记来保护,如果信号来了,我们进入handler,我们检察标记,看是否被置位,如果置了位,就表明位置缓冲是合法的,这样才能跳过去。在非signal的场合,由于我们基本上可以预知程序的执行流程,因此我们可以不用检查是否位置缓冲是合法的,不过检查的话更好。
下面是例子代码:
#include "apue.h"
#include
#include
static void
sig_usr1(int), sig_alrm(int);
static sigjmp_buf
jmpbuf;
static volatile sig_atomic_t
canjump;
int
main(void)
{
if (signal(SIGUSR1, sig_usr1) ==
SIG_ERR)
err_sys("signal(SIGUSR1) error");
if (signal(SIGALRM, sig_alrm) ==
SIG_ERR)
err_sys("signal(SIGALRM) error");
pr_mask("starting main:
"); /* */
if (sigsetjmp(jmpbuf, 1)) {
pr_mask("ending main:
");
exit(0);
}
canjump = 1; /* now sigsetjmp() is OK */
for ( ; ; )
pause();
}
static void
sig_usr1(int signo)
{
time_t starttime;
if (canjump == 0)
return; /* unexpected signal, ignore */
pr_mask("starting sig_usr1:
");
alarm(3); /* SIGALRM in 3 seconds */
starttime = time(NULL);
for ( ; ; ) /* busy wait for 5 seconds */
if (time(NULL) >
starttime + 5)
break;
pr_mask("finishing
sig_usr1: ");
canjump = 0;
siglongjmp(jmpbuf, 1); /* jump back to main, don't return */
}
static void
sig_alrm(int signo)
{
pr_mask("in sig_alrm:
");
}
这里的pr_mask函数的作用是,打印字符串,并将此事被block的信号打印。
sig_atomic_t类型是ISO C中定义的一种保证对其进行写操作不会被打断的类型,可见他的空间一定不会扩越页边界(那会造成缺页中断)使其操作被打断。又由于main和signal handler都在访问他,所以将其设置成volatile,保证对他的修改都协会内存,防止出现不一致性问题。
在我们以前使用setjmp和lomgjmp的时候提到过一点,即volatile型的auto变量可以保证当longjmp发生后,其状态为最新的状态,不会发生rollback,这就是因为他的存储访问都是在memory进行的,而不是register。
执行结果:
$ ./a.out & start process in
background
starting main:
[1] 531 the job-control shell prints its process ID
$ kill
-USR1 531 send the process SIGUSR1
starting sig_usr1: SIGUSR1
$ in sig_alrm: SIGUSR1 SIGALRM
finishing sig_usr1: SIGUSR1
ending main:
just
press RETURN
[1] + Done ./a.out &