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

全部博文(200)

文章存档

2009年(12)

2008年(190)

我的朋友

分类:

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

Setlongjmplongjmp如果在signal handler里面被调用,当longjmp返回时,不会自动将handler里面系统自动block的本signalunblock。当然,如果我们用return之类的返回语句,就会自动unblock。并且为了兼容setlongjmplongjmpsigsetjmpsiglongjmp还可以提供不自动恢复signal mask的方式工作。因此我们基本上在signal handler里面摒弃对longjmpsetlongjmp的调用。

 

检查位置缓冲的合法性:

如果在signal机制里面使用这种长跳转,建议使用siglongjmp的时候,要确保sigsetjmp已经被调用,即我们可以调到一个合法的位置去。因此要使用一个标记,来表明当前位置缓冲是否合法。当sigsetjmp调用后,标记置位,位置缓冲合法,这样在signal handler里面就可以正确的跳到该位置了。我们之所以要这么做是因为,在signal 处理中,指不定什么时候来个信号,所以信号的来到并不一定完全依据我们自己的想法和设计,所以,有可能在我们用sigsetjmp来设置位置缓冲之前,该信号就到来了,所以,我们应该用一个标记来保护,如果信号来了,我们进入handler,我们检察标记,看是否被置位,如果置了位,就表明位置缓冲是合法的,这样才能跳过去。在非signal的场合,由于我们基本上可以预知程序的执行流程,因此我们可以不用检查是否位置缓冲是合法的,不过检查的话更好。

下面是例子代码:

Figure 10.20. Example of signal masks, sigsetjmp, and siglongjmp

#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中定义的一种保证对其进行写操作不会被打断的类型,可见他的空间一定不会扩越页边界(那会造成缺页中断)使其操作被打断。又由于mainsignal handler都在访问他,所以将其设置成volatile,保证对他的修改都协会内存,防止出现不一致性问题。

在我们以前使用setjmplomgjmp的时候提到过一点,即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 &

 

阅读(834) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~