• 信号之sigsetjmp和siglongjmp函数(转)


    在信号处理程序中经常调用longjmp函数以返回到程序的主循环中,而不是从该处理程序返回。

    但是,调用longjmp有一个问题。当捕捉到一个信号时,进入信号捕捉函数,此时当前信号被自动地加到进程的信号屏蔽字中。这阻止了后来产生的这种信号中断该信号处理程序。(仅当从信号捕捉函数返回时再将进程的信号屏蔽字复位为原先值:http://www.cnblogs.com/nufangrensheng/p/3515945.html如果用longjmp跳出信号处理程序,那么,对此进程的信号屏蔽字会发生什么呢()?(setjmp和longjmp保存和恢复信号屏蔽字,还是不保存和恢复,不同的实现各有不同。)

    为了允许两种形式的行为并存,POSIX.1并没有说明setjmp和longjmp对信号屏蔽字的作用,而是定义了两个新函数sigsetjmp和siglongjmp。在信号处理程序中进行非局部转移时使用这两个函数。

    #include <setjmp.h>
    
    int sigsetjmp(sigjmp_buf env, int savemask);
    返回值:若直接调用则返回0,若从siglongjmp调用返回则返回非0值
    
    void siglongjmp(sigjmp_buf env, int val);

    这两个函数与setjmp和longjmp之间的唯一区别是sigsetjmp增加了一个参数。如果savemask非0,则sigsetjmp在env中保存进程的当前信号屏蔽字调用siglongjmp时,如果带 非0 savemask的sigsetjmp调用已经保存了env,则siglongjmp从其中恢复保存的信号屏蔽字

    实例

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

    程序清单10-14 信号屏蔽字、sigsetjmp和siglongjmp实例

     1 #include "apue.h"
     2 #include <setjmp.h>
     3 #include <time.h>
     4 
     5 static void            sig_usr1(int), sig_alrm(int);
     6 static sigjmp_buf        jmpbuf;
     7 static volatile sig_atomic_t     canjump;
     8 
     9 int
    10 main(void)
    11 {
    12     if (signal(SIGUSR1, sig_usr1) == SIG_ERR)
    13         err_sys("signal(SIGUSR1) error");
    14 
    15     if (signal(SIGALRM, sig_alrm) == SIG_ERR)
    16         err_sys("signal(SIGALRM) error");
    17     
    18     pr_mask("starting main: ");
    19 
    20     if (sigsetjmp(jmpbuf, 1))
    21     {
    22         pr_mask("ending main: ");
    23         exit(0);
    24     }
    25     canjump = 1;    /* now sigsetjmp() is OK */
    26 
    27     for(; ;)
    28         pause();
    29 }
    30 
    31 static void
    32 sig_usr1(int signo)
    33 {    
    34     time_t starttime;
    35 
    36     if (canjump == 0)
    37         return;        /* unexpected signal, ignore */
    38 
    39     pr_mask("starting sig_usr1: ");
    40     alarm(3);        /* SIGALRM in 3 seconds */
    41     starttime = time(NULL);
    42     for(; ;)        /* busy wait for 5 seconds */
    43         if (time(NULL) > starttime + 5)
    44             break;
    45     pr_mask("finishing sig_usr1: ");
    46     
    47     canjump = 0;
    48     siglongjmp(jmpbuf, 1);    /* jump back to main, don't return */
    49 }
    50 
    51 
    52 static void 
    53 sig_alrm(int signo)
    54 {
    55     pr_mask("in sig_alrm: ");
    56 }

    pr_mask函数参见:http://www.cnblogs.com/nufangrensheng/p/3515257.html中程序清单10-10

    此程序演示了另一种技术,只要在信号处理程序中调用siglongjmp,就应使用这种技术:仅在调用sigsetjmp之后才将变量canjump设置为非0值。在信号处理程序中检测此变量,仅当它为非0值时才调用siglongjmp。这提供了一种保护机制,使得在jmpbuf(跳转缓冲)尚未由sigsetjmp初始化时,防止调用信号处理程序。在一般的C代码中(不是信号处理程序),对于longjmp并不需要这种保护措施。但是,因为信号可能在任何时候发生,所以在信号处理程序中,需要这种保护措施。

    在程序中使用了数据类型sig_atomic_t,这是由ISO C标准定义的变量类型,在写这种类型的变量时不会被中断。这种类型的变量总是包括ISO类型修饰符voaltile。

    在RedHat Linux 2.6.18版本中执行程序清单10-14并没有出现我们所预期的结果:当调用一个信号处理程序时,被捕捉到的信号加到进程的当前信号屏蔽字中。当从信号处理程序返回时,恢复原来的屏蔽字。不知为何???

    未命名

    从上面运行结果可以看出,信号屏蔽字始终都是空。本来应该是在调用一个信号处理程序时,被捕捉到的信号加到进程的当前信号屏蔽字中。为啥没有加进去呢?还是加进去了没有更新信号屏蔽字呢?

    本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

  • 相关阅读:
    011. Python中*args, **kwargs 和 pass 和self 解释
    010. windows10下安装kivy 1.9.1版
    013. MVC5过滤器
    制作ubuntu16.04 自动安装iso镜像 二
    Nexus安装
    使用docker-compose 大杀器来部署服务 上
    Docker-Compose入门
    nvidia-docker命令详解
    安装使用NVIDIA-Docker-- 可使用GPU的Docker容器
    frp实现内网穿透
  • 原文地址:https://www.cnblogs.com/jikexianfeng/p/6354275.html
Copyright © 2020-2023  润新知