- 浏览: 140326 次
文章分类
最新评论
在非局部跳转函数 setjmp 和 longjmp 介绍一节中曾提到用于在普通函数中进行非局部转移的 setjmp 和 longjmp 函数,POSIX.1 没有指定指定这两个函数对信号屏蔽字的作用,而是定义了两个新函数 sigsetjmp 和 siglongjmp。在信号处理程序中进行非局部转移时应当使用这两个函数。
这两个函数与 setjmp、longjmp 之间的唯一区别是 sigsetjmp 增加了一个参数:如果 savemask 非 0,则 sigsetjmp 在 env 中保存进程的当前信号屏蔽字,以便调用 siglongjmp 时从其中恢复保存的信号屏蔽字。
下面这个程序演示了在信号处理程序被调用时,系统所设置的信号屏蔽字如何自动地包括被捕捉到的信号。
此程序中演示了另一种只要在信号处理程序中调用 siglongjmp 就应使用的技术:仅在调用 sigsetjmp 之后才将变量 canjump 设置为非 0,在信号处理程序中检测此变量,仅当它为非 0 时才调用 siglongjmp。这提供了一种保护机制,以免 jmpbuf 还未初始化时就调用信号处理程序,因为信号可能在任何时候发生。
另外,程序中使用了数据类型 sig_atomic_t,在写这种类型的变量时不会被中断。这意味着这种变量在具有虚拟存储器的系统上不会跨越页边界,可以用一条机器指令对其进行访问。这种类型的变量总是包括类型修饰符 volatile,其原因是:该变量将由两个不同的控制线程 main 函数和异步执行的信号处理程序访问。
下图显示了此程序的执行时间顺序。在进程执行左面部分时(对应 main),信号屏蔽字是 0(无信号被阻塞);执行中间部分是(对应 sig_usr1),其信号屏蔽字是 SIGUSR1;执行右面部分时(对应 sig_alrm),其信号屏蔽字是 SIGUSR1 和 SIGALRM。
运行该程序的结果如下。
可见该输出与所期望的相同:当调用一个信号处理程序时,被捕捉到的信号会自动加到进程的当前信号屏蔽字中。当从信号处理程序返回时,siglongjmp 恢复了 sigsetjmp 所保存的信号屏蔽字。
如果在 Linux 中将该程序中的 sigsetjmp 和 siglongjmp 分别替换成 setjmp 和 longjmp,则最后一行输出将变成:
ending main: SIGUSR1
这意味着在调用 setjmp 之后执行 main 函数时,其 SIGUSR1 是阻塞的,这多半不是所期望的。
#include <setjmp.h> int sigsetjmp(sigjmp_buf, int savemask); /* 返回值:若直接调用,返回 0;若从 siglongjmp 调用返回,则返回非 0 */ void siglongjmp(sigjmp_buf env, int val);
这两个函数与 setjmp、longjmp 之间的唯一区别是 sigsetjmp 增加了一个参数:如果 savemask 非 0,则 sigsetjmp 在 env 中保存进程的当前信号屏蔽字,以便调用 siglongjmp 时从其中恢复保存的信号屏蔽字。
下面这个程序演示了在信号处理程序被调用时,系统所设置的信号屏蔽字如何自动地包括被捕捉到的信号。
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <time.h> #include <setjmp.h> #include <errno.h> // extern void pr_mask(const char *); 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){ printf("sigprocmask error\n"); }else{ 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; // restroe errno } static sigjmp_buf jmpbuf; static volatile sig_atomic_t canjump; static void sig_usr1(int signo){ if(canjump == 0) return; // unexpected signal, ignore pr_mask("starting sig_usr1:"); alarm(3); // SIGALRM in 3 seconds time_t 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:"); } int main(void){ if(signal(SIGUSR1, sig_usr1) == SIG_ERR) printf("signal(SIGUSR1) error\n"); if(signal(SIGALRM, sig_alrm) == SIG_ERR) printf("signal(SIGALRM) error\n"); pr_mask("starting main:"); if(sigsetjmp(jmpbuf, 1)){ pr_mask("ending main:"); exit(0); } canjump = 1; // now sigsetjmp() is OK for(;;) pause(); }
此程序中演示了另一种只要在信号处理程序中调用 siglongjmp 就应使用的技术:仅在调用 sigsetjmp 之后才将变量 canjump 设置为非 0,在信号处理程序中检测此变量,仅当它为非 0 时才调用 siglongjmp。这提供了一种保护机制,以免 jmpbuf 还未初始化时就调用信号处理程序,因为信号可能在任何时候发生。
另外,程序中使用了数据类型 sig_atomic_t,在写这种类型的变量时不会被中断。这意味着这种变量在具有虚拟存储器的系统上不会跨越页边界,可以用一条机器指令对其进行访问。这种类型的变量总是包括类型修饰符 volatile,其原因是:该变量将由两个不同的控制线程 main 函数和异步执行的信号处理程序访问。
下图显示了此程序的执行时间顺序。在进程执行左面部分时(对应 main),信号屏蔽字是 0(无信号被阻塞);执行中间部分是(对应 sig_usr1),其信号屏蔽字是 SIGUSR1;执行右面部分时(对应 sig_alrm),其信号屏蔽字是 SIGUSR1 和 SIGALRM。
运行该程序的结果如下。
$ ./sigjump.out & # 在后台启动程序 [1] 16011 $ starting main: # 这是 main 函数的输出 $ $ kill -USR1 16011 # 向该后台进程发送 SIGUSR1 信号 starting sig_usr1: SIGUSR1 in sig_alrm: SIGUSR1 SIGALRM finishing sig_usr1: SIGUSR1 ending main: [1]+ Done ./sigjump.out
可见该输出与所期望的相同:当调用一个信号处理程序时,被捕捉到的信号会自动加到进程的当前信号屏蔽字中。当从信号处理程序返回时,siglongjmp 恢复了 sigsetjmp 所保存的信号屏蔽字。
如果在 Linux 中将该程序中的 sigsetjmp 和 siglongjmp 分别替换成 setjmp 和 longjmp,则最后一行输出将变成:
ending main: SIGUSR1
这意味着在调用 setjmp 之后执行 main 函数时,其 SIGUSR1 是阻塞的,这多半不是所期望的。
发表评论
-
打开伪终端设备
2018-07-09 20:50 1246在伪终端概述一节中已对 PTY进行了初步的介绍。尽管 ... -
伪终端概述
2018-06-02 11:05 1529伪终端就是指,一个应用程序看上去像一个终端,但事实上它 ... -
终端窗口大小和 termcap
2018-05-29 22:39 790多数 UNIX 系统都提供了一种跟踪当前终端窗口大小的 ... -
终端规范模式和非规范模式
2018-05-29 00:25 936终端规范模式很简单:发一个读请求,当一行已经输入后,终 ... -
终端标识
2018-05-23 11:18 565尽管控制终端的名字在多数 UNIX 系统上都是 /de ... -
波特率和行控制函数
2018-05-22 07:53 933虽然大多数终端设 ... -
终端属性和选项标志
2018-05-20 07:40 706tcgetattr 和 tcsetattr ... -
终端特殊输入字符
2018-05-17 06:33 807终端支持下表所示的特殊输入字符。 为了更改 ... -
终端 I/O 综述
2018-05-10 07:56 431终端设备可认为是由内核中的终端驱动程序控制的。每个终端 ... -
POSIX 信号量
2018-05-09 00:03 575在XSI IPC通信之信 ... -
XSI IPC 通信之共享存储
2018-04-25 07:18 942在XSI IPC通信之消息队列和XSI IPC通信之信 ... -
XSI IPC通信之信号量
2018-04-17 23:38 612在XSI IPC通信之消 ... -
XSI IPC通信之消息队列
2018-04-15 10:54 488消息队列是消息的链接表,存储在内核中,由消息队列标识符 ... -
XSI IPC 相似特征介绍
2018-02-08 23:48 477有 3 种称作 XSI IPC ... -
IPC 通信之 FIFO
2018-02-06 22:55 410FIFO 也被称为命名管道,未命名的管道只能在两个相关 ... -
IPC 通信之管道
2018-01-30 22:22 380管道是 UNIX 系统 IPC 的最古老但也是最常用的 ... -
readv/writev 函数及存储映射 I/O
2018-01-19 00:57 875readv 和 writev 函数可用于在一次函数调用 ... -
POSIX 异步 I/O
2018-01-16 21:33 448POSIX 异步 I/O 接口为对不同类型的文件进行异 ... -
fcntl 记录锁
2018-01-06 23:48 571记录锁的功能是:当有进程正在读或修改文件的某个部分时, ... -
守护进程惯例
2018-01-06 23:52 432UNIX 系统中,守护进程遵循下列通用惯例。 ...
相关推荐
信号的概念 signal函数 不可靠信号与可靠信号 信号的发送接收机制 信号集与可靠信号机制 sigsetjmp和siglongjmp函数 abort函数
- 为了确保信号处理的安全性,示例还展示了如何使用 `sigsetjmp` 和 `siglongjmp` 来实现非局部跳转,从而在信号处理函数中安全地恢复之前的执行状态。 综上所述,这些知识点涵盖了 Linux 下 C 语言编程的基本信号...
10.15 sigsetjmp和siglongjmp函数 10.16 sigsuspend函数 10.17 abort函数 10.18 system函数 10.19 sleep函数 10.20 作业控制信号 10.21 其他特征 10.22 小结 习题 第11章 线程 11.1 ...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.22 小结 244 习题 244 第11章 终端...
10.15 sigsetjmp 和siglongjmp函数 10.16 sigsuspend函数 10.17 abort函数 10.18 system 函数 10.19 sleep函数 10.20 作业控制信号 10.21 其他特征 10.21.1 信号名字 10.21.2 SVR4信号处理程序的附加参数 10.21.3 ...
10.15 sigsetjmp和siglongjmp函数 266 10.16 sigsuspend函数 268 10.17 abort函数 274 10.18 system函数 276 10.19 sleep函数 280 10.20 作业控制信号 282 10.21 其他特征 284 10.22 小结 285 习题...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4...
261 10.15 sigsetjmp和siglongjmp函数 266 10.16 sigsuspend函数 268 10.17 abort函数 274 10.18 system函数 276 10.19 sleep函数 280 10.20 作业控制信号 282 10.21 其他特征 284 10.22 小结 285 ...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21....
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4...
10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4...