siglongjmp和sigsetjmp 用法
1. 引入原因
由于在信号处理期间自动屏蔽了正在被处理的信号,而使用setjmp/longjmp跳出信号处理程序时又不会自动将
信号屏蔽码修改会原来的屏蔽码,从而引起该信号被永久屏蔽。
可以使用sigsetjmp/siglongjmp来解决这一问题。
2. 语法
#include<setjmp.h> void siglongjmp(sigjmp_buf env,int val); int sigsetjmp(sigjmp_buf env,int savemask);
POSIX标准没有为siglongjmp定义错误。sigsetjmp被直接激活是返回0,通过siglongjmp被激活是返回参数val的值。
3. 与setjmp和longjmp之间区别
这两个函数与setjmp和longjmp之间的唯一区别是sigsetjmp增加了一个参数。如果savemask非0,则sigsetjmp在env中保存进程的当前信号屏蔽字。调用siglongjmp时,如果带 非0 savemask的sigsetjmp调用已经保存了env,则siglongjmp从其中恢复保存的信号屏蔽字。
/* * sigExpGotoT.c * * Created on: 2020年7月30日 * Author: zhuying10 */ #include <stdio.h> #include <signal.h> #include <setjmp.h> jmp_buf env; void handler (int signal) { printf("caught exception\n"); longjmp(env, 2); } int main(int argc, char* argv[]) { { struct sigaction sa = {}; sa.sa_handler = handler; //sigemptyset(&sa.sa_mask); //sa.sa_flags = 0; if(sigaction(SIGFPE, &sa, NULL) == -1) { perror("sigaction"); } } if (0 == setjmp(env)) { int a = 3/(argc - 1); printf("a is %d\n", a); } else { //exception printf("in exception\n"); } return 1; }
int setjmp(jmp_buf env) |
建立本地的jmp_buf 缓冲区并且初始化,用于将来跳转回此处。这个子程序保存程序的调用环境于env 参数所指的缓冲区,env 将被longjmp 使用。如果是从setjmp 直接调用返回,setjmp 返回值为0。如果是从longjmp 恢复的程序调用环境返回,setjmp 返回非零值。 |
void longjmp(jmp_buf env, int value) |
恢复env 所指的缓冲区中的程序调用环境上下文,env 所指缓冲区的内容是由setjmp 子程序调用所保存。value 的值从longjmp 传递给setjmp 。longjmp 完成后,程序从对应的setjmp 调用处继续执行,如同setjmp 调用刚刚完成。如果value 传递给longjmp 零值,setjmp 的返回值为1;否则,setjmp 的返回值为value 。 |
当使用longjmp的时候,j的内容被销毁。
这种方法看起来与goto相似,但是是有区别的,区别如下:
(1)goto语句不能跳出C语言当前的函数。
(2)用longjmp只能跳回曾经到过的地方。在执行setjmp的地方仍留有一个过程活动记录。从这个角度上讲,longjmp更象是“从何处来”,而不是“要往哪去”。另外,longjmp接受一个额外的整形参数并返回它的值,这可以知道是由longjmp转移到这里的还是从上一条语句执行后自然执行到这里的。