Chinaunix首页 | 论坛 | 博客
  • 博客访问: 344020
  • 博文数量: 60
  • 博客积分: 1570
  • 博客等级: 上尉
  • 技术积分: 620
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-02 23:37
文章分类

全部博文(60)

文章存档

2012年(2)

2010年(2)

2009年(56)

分类: LINUX

2009-12-27 20:12:55

1.在信号处理程序中进行非局部跳转时,应该的使用的两个函数(信号处理程序中不要使用setjmp 和 longjmp函数)。(有关这四个函数:setjmp,longjmp 和 sigsetjmp,siglongjmp 的参数含义、它们如何返回和如何跳转,以及其他信号相关函数,请参看其他资料)

#include <setjmp.h>

int sigsetjmp(sigjmp_buf env, int savemask);
                      返回值:若直接调用返回0,若从siglongjmp调用返回则返回非0值
void siglongjmp(sigjmp_buf env, int val);

     说明:这两个函数需要配合使用。如果 savemask 非0, 则sigsetjmp 在 env 中保存进程的当前信号屏蔽字。调用siglongjmp时,如果前面步骤中的sigsetjmp 函数的savemask非0,则siglongjmp 函数恢复保存的信号屏蔽字。

2.实例代码
   下面的程序演示了在信号处理程序被调用时,系统所设置的信号屏蔽字如何自动地包括刚被捕捉到的信号。该程序也通过实例说明了如何使用 sigsetjmp 和 siglongjmp 函数。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <time.h>

static void sig_usr1(int), sig_alrm(int);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjump;

#include <errno.h>

void pr_mask(const char *str)
{
        sigset_t sigset;
        int errno_save;

        errno_save = errno; /* we can be called by signal handlers */
        if (sigprocmask(0, NULL, &sigset) < 0)
                perror("sigprocmask error");

        printf("%s", str);
        if (sigismember(&sigset, SIGINT)) printf("SIGINT ");
        if (sigismember(&sigset, SIGQUIT)) printf("SIGQUIT ");
        if (sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 ");
        if (sigismember(&sigset, SIGALRM)) printf("SIGALRM ");

        /* remaining signals can go here */

        /* 为了节省空间,这里没有对所有信号进行测试 */

        printf("\n");
        errno = errno_save;
}

int main(void)
{
        if (signal(SIGUSR1, sig_usr1) == SIG_ERR)
                perror("signal(SIGUSR1) error");

        if (signal(SIGALRM, sig_alrm) == SIG_ERR)
                perror("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();
}

time_t starttime;

static void sig_usr1(int signo)
{
        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;

        printf("in sig_usr1, interval = %d\n", time(NULL) - starttime);
        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: ");
        printf("in sig_alrm, interval = %d\n", time(NULL) - starttime);
}


编译后执行结果:

[liumin@localhost sigsetjmp]$ ./m &
[1] 18018
[liumin@localhost sigsetjmp]$ starting main:

[liumin@localhost sigsetjmp]$ kill -SIGUSR1 18018
[liumin@localhost sigsetjmp]$ starting sig_usr1: SIGUSR1
in sig_alrm: SIGUSR1 SIGALRM
in sig_alrm, interval = 3
in sig_usr1, interval = 6
finishing sig_usr1: SIGUSR1
ending main:

[1]+ Done ./m
[liumin@localhost sigsetjmp]$


    此程序演示了另一种技术,只要在信号处理程序中调用siglongjmp,就应使用这种技术。仅在调用 sigsetjmp 之后才将变量 canjump 设置为非0值。在信号处理程序中检测此变量,仅当它为非0值时才调用siglongjmp。这提供了一种保护机制,使得在jmpbuf尚未由sigsetjmp 初始化时,防止调用信号处理程序。另外,在本程序中,调用siglongjmp之后程序很快就结束,但是在较大的程序中,在调用siglongjmp 之后的一段较长时间内,信号处理程序可能仍旧被设置,通过检测canjump,就可以起到保护作用。
    在一般的 C 代码中(不是信号处理程序),对于longjmp并不需要这种保护措施。但是,因为信号可能在任何时候发生,所以在信号处理程序中,需要这种保护措施。
    在程序中使用了数据类型 sig_atomic_t,这是由 ISO C 标准定义的变量类型,在写这种类型的变量时不会被中断。它意味着在具有虚拟存储器的系统上这种变量不会跨越页边界,可以用一条机器指令对其进行访问。这种类型的变量总是包括 ISO 类型修饰符 volatile,其原因是:该变量将由两个不同的控制线程--main 函数和异步执行的信号处理程序访问。


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

suanmeilizhi2011-12-30 13:45:11

请问你是什么系统的???