信号处理函数的返回sigsetjmp/siglongjmp

来源:互联网 发布:淘宝网半身长裙 编辑:程序博客网 时间:2024/06/06 07:10

        由于在信号处理期间自动屏蔽了正在被处理的信号,而使用setjmp/longjmp跳出信号处理程序时又不会自动将

信号屏蔽码修改会原来的屏蔽码,从而引起该信号被永久屏蔽。

        可以使用sigsetjmp/siglongjmp来解决这一问题。

相关函数:longjmp, siglongjmp, setjmp 
表头文件:#include <setjmp.h> 
函数定义:int sigsetjmp(sigjmp_buf env, int savesigs) 
函数说明:sigsetjmp()会保存目前堆栈环境,然后将目前的地址作一个记号,
而在程序其他地方调用siglongjmp()时便会直接跳到这个记号位置,然后还原堆栈,继续程序的执行。 
参数env为用来保存目前堆栈环境,一般声明为全局变量 
参数savesigs若为非0则代表搁置的信号集合也会一块保存 
当sigsetjmp()返回0时代表已经做好记号上,若返回非0则代表由siglongjmp()跳转回来。 
返回:若直接调用则为0,若从siglongjmp调用返回则为非0


#include <stdio.h>#include <signal.h>#include <setjmp.h>#include <unistd.h>#include <sys/time.h>sigjmp_buf jmp_env;static void connect_alarm(int){    siglongjmp(jmp_env, 1);}int main(){    // 当超时时间sec_timeout大于等于运行时间run_time时会跳过printf("running...\n");    int sec_timeout = 3;    int run_time = 2;    printf("timeout = %d, run time = %d\n", sec_timeout, run_time);    if (sec_timeout)    {        // 超过用alarm函数设置的时间时产生此信号,调用connect_alarm函数        signal(SIGALRM, connect_alarm);        alarm(sec_timeout);        printf("set timeout\n");        if (sigsetjmp(jmp_env, 1))        {            printf("timeout\n");            goto out;        }    }    sleep(run_time);    printf("running...\n");out:    if (sec_timeout)    {        // 取消先前设置的闹钟        alarm(0);        printf("cancel timeout\n");    }    return 0;}

上面的程序,从逻辑来看,

当sec_timeout = 3, run_time = 2时:
timeout = 3, run_time = 2
set timeout
running...
cancel timeout


当sec_timeout = 3, run_time = 4时:
timeout = 3, run_time = 4
set timeout
timeout
cancel timeout


这是为什么呢?

当主进程睡眠时间大于或者等于alarm时间的话,说明

这期间由信号发生,并捕捉进入siglongjump

然后跳转道setjump里面,然后直接进入到out里面了。