In C, we can't goto a label that's in another function(跨stack frame). Instead, we must use the setjmp and longjmp functions to perform this type of branching.
首先,在可能需要返回的点执行:
#include <setjmp.h>
int setjmp(jmp_buf env);
(此时setjmp函数将返回0。
参数env是特殊的数据类型jmp_buf. This data type is some form of array that is capable of holding all the information required to restore the status of the stack to the state when we call longjmp. Normally, the env variable is a global variable, since we'll need to reference it from another function.)
然后在需要返回的地方调用longjmp就可以返回刚才调用setjmp的地方:
void longjmp(jmp_buf env, int val);
(第一个参数env is the same env that we used in a call to setjmp,第二个参数将成为返回时setjmp函数的返回值,当然该参数必须不等于0.)
使用上述的setjmp/longjmp函数会有一个问题:当调用longjmp的函数是一个signal handler的时候,该signal handler函数被执行的时候,系统会自动把当前signal加入signal mask,防止 subsequent occurrences of that signal from interrupting the signal handler,这就会产生一个问题:当在signal handler中longjmp时sinal mask该如何处理,是否还原进入signal handler之前的状态?不同的系统有不同的处理。
POSIX.1规定,在signal handler中做longjmp应该使用sigsetjmp/siglongjmp:
#include <setjmp.h>
int sigsetjmp(sigjmp_buf env, int savemask);
void siglongjmp(sigjmp_buf env, int val);
这对函数与setjmp/longjmp的唯一区别是sigsetjmp多了一个参数savemask来指定在longjmp时对signal mask的处理:
If savemask is nonzero, then sigsetjmp also saves the current signal mask of the process in env. When siglongjmp is called, if the env argument was saved by a call to sigsetjmp with a nonzero savemask, then siglongjmp restores the saved signal mask.