Linux manual page (手冊(cè)):setjmp 牙甫,longjmp 。
總覽
頭文件
setjmp.h
函數(shù)
int setjmp(jmp_buf env);
noreturn void longjmp(jmp_buf env, int val);
jmp_buf
jmp_buf
類型是一種數(shù)組類型比驻,適合存儲(chǔ)恢復(fù)調(diào)用環(huán)境的信息(比如:函數(shù)棧-棧幀指針BP和棧頂指針SP巴比,程序指針PC-未來(lái)恢復(fù)時(shí)Jump到的語(yǔ)句地址懂诗,其他寄存器信息-通用寄存器等)(不包括:浮點(diǎn)狀態(tài)標(biāo)志是目、打開(kāi)的文件或任何其他數(shù)據(jù)的狀態(tài))忧侧。
詳見(jiàn):setjmp.h
描述
背景
goto 只能在函數(shù)內(nèi)跳轉(zhuǎn)孵睬,而不能在函數(shù)間跳轉(zhuǎn)播歼,因此 C 語(yǔ)言引入 setjmp 和 longjmp 。
用法
setjmp 使用 jmp_buf 保存當(dāng)前函數(shù)的調(diào)用信息掰读,longjmp 使用一個(gè)存有函數(shù)調(diào)用信息的 jmp_buf 跳轉(zhuǎn)到另一個(gè)函數(shù)并恢復(fù)調(diào)用秘狞。
setjmp
參數(shù):env 為保存函數(shù)調(diào)用環(huán)境信息的 jmp_buf 對(duì)象。
返回值:
- 0 :表示 jmp_buf 的 setjmp 時(shí)的返回值蹈集。
- 非零:表示 jmp_buf 的 longjmp 時(shí)的返回值(jmp_buf 的 longjmp會(huì)再次從 jmp_buf
的 setjmp處返回)烁试,返回值由 longjmp 中的參數(shù) val 指定。詳見(jiàn):longjmp 拢肆。
longjmp
參數(shù):env 為另一函數(shù)調(diào)用環(huán)境信息的 jmp_buf 對(duì)象减响,val 為 longjmp 回到 jmp_buf 所存函數(shù)的 setjmp 調(diào)用處的返回值。
返回值:無(wú)返回值郭怪,從 jmp_buf 指向的函數(shù)中的 setjmp 調(diào)用處返回支示。
上下文切換
吐槽一句:簡(jiǎn)書(shū)的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");
}
}