Linux manual page (手册):setjmp ,longjmp 。
总览
头文件
setjmp.h
函数
int setjmp(jmp_buf env);
noreturn void longjmp(jmp_buf env, int val);
jmp_buf
jmp_buf
类型是一种数组类型,适合存储恢复调用环境的信息(比如:函数栈-栈帧指针BP和栈顶指针SP,程序指针PC-未来恢复时Jump到的语句地址,其他寄存器信息-通用寄存器等)(不包括:浮点状态标志、打开的文件或任何其他数据的状态)。
详见:setjmp.h
描述
背景
goto 只能在函数内跳转,而不能在函数间跳转,因此 C 语言引入 setjmp 和 longjmp 。
用法
setjmp 使用 jmp_buf 保存当前函数的调用信息,longjmp 使用一个存有函数调用信息的 jmp_buf 跳转到另一个函数并恢复调用。
setjmp
参数:env 为保存函数调用环境信息的 jmp_buf 对象。
返回值:
- 0 :表示 jmp_buf 的 setjmp 时的返回值。
- 非零:表示 jmp_buf 的 longjmp 时的返回值(jmp_buf 的 longjmp会再次从 jmp_buf
的 setjmp处返回),返回值由 longjmp 中的参数 val 指定。详见:longjmp 。
longjmp
参数:env 为另一函数调用环境信息的 jmp_buf 对象,val 为 longjmp 回到 jmp_buf 所存函数的 setjmp 调用处的返回值。
返回值:无返回值,从 jmp_buf 指向的函数中的 setjmp 调用处返回。
上下文切换
吐槽一句:简书的markdown不好用耶,有办法让下面的代码块能更好看些吗?
#define context_switch(coroutine_a, coroutine_b) \
if (setjmp(coroutine_a->jmp_buf) == 0) { \
/* \
* setjmp save coroutine a jmp_buf success \
* use longjmp goto coroutine b jmp_buf setjmp and return 1 \
*/ \
longjmp(coroutine_b->jmp_buf, 1) \
} \
/* setjmp is not 0, so return from longjmp, then coroutine b run continue */ \
示例
#include <setjmp.h>
jmp_buf context_main, context_a, context_b;
void pirnt_a();
void print_b();
void main()
{
if (setjmp(context_main)==0) {
print_a();
} else {
printf("2.return main\n");
}
if (setjmp(context_main)==0) {
print_b();
} else {
printf("6.return main\n");
printf("7.return b from main\n");
longjmp(context_main, 1);
}
}
void print_a()
{
if (setjmp(context_a)==0) {
printf("1.return main from a\n");
longjmp(context_main, 1);
} else {
printf("4.return a\n");
printf("5.return main from a\n");
longjmp(context_b, 1);
}
}
void print_b()
{
if (setjmp(context_a)==0) {
printf("3.return a from b\n");
longjmp(context_a, 1);
} else {
printf("8.return b\n");
}
}