sigsetjmp & siglongjmp 的小把戏

typedef 数组

最近看到 sigsetjmp siglongjmp 的代码,musl 里对 jmp_buf 的写法很独特。原来 C 里面还是有好多东西自己不知道的啊。

// aarch64
typedef unsigned long __jmp_buf[22];

typedef struct __jmp_buf_tag {
    
    
	__jmp_buf __jb;
	unsigned long __fl;
	unsigned long __ss[128/sizeof(long)];
} jmp_buf[1];

typedef jmp_buf sigjmp_buf;

上面的代码是 setjmp.h 里的定义,把一个 struct 类型定义成一个数组。第一次看有点让人疑惑。

  • 我们先看下 typedef 数组的简单的场景:
#include <stdio.h>

typedef char STR[1024]; // STR是一个长度为1024的char类型数组类型的别名

int main()
{
    
    
    STR a = "1234";       // -> char a[1024] = "1234";
    printf("%s\n", a);
    return 0;
}
  • 我们再来看下数组作为函数参数的情况,下面三种写法是等价的,数组名会被当成指针传递。
// 在函数中传递一个一维数组作为参数
void myFunction(int *param); // 传递指针
void myFunction(int param[]); // 未定义大小的数组
void myFunction(int param[10]); // 已定义大小的数组

综合上面两点,我们再看 jmp_buf 的声明,可以看到它是长度为1,struct __jmp_buf_tag 类型数组的别名。
它的好处是这样的:

  • 在声明 jmp_buf 的时候,可以把数据分配到堆栈上。
  • 作为参数传递的时候则作为一个指针。
// env_buf, array of one element of `struct __jmp_buf_tag`
sigjmp_buf env_buf; // -> struct __jmp_buf_tag env_buf[1];

sigsetjmp siglongjmp

// env is treated as a pointer of `struct __jmp_buf_tag`

// If the return is from a successful direct invocation, sigsetjmp() returns 0. 
// If the return is from a call to siglongjmp(), sigsetjmp() returns a non-zero value.
int sigsetjmp(sigjmp_buf env, int savemask); // set jump point for a non-local goto
// - savemask 表示是否保存当前线程的信号掩码

// After siglongjmp() is completed, program execution continues as if the corresponding invocation of sigsetjmp() had just returned the value specified by val. The siglongjmp() function cannot cause sigsetjmp() to return 0; if val is 0, sigsetjmp() returns the value 1.
// 可以看到 siglongjmp 调用的效果是回到上次 sigsetjmp 调用返回的位置,并且返回值通过 val 指定。如果上次 sigsetjmp 的时候保存了信号掩码,siglongjmp 会恢复保存的信号掩码。
void siglongjmp(sigjmp_buf env, int val); // non-local goto with signal handling

综上其中一种用法如下:

...
sigjmp_buf env; 

func()
{
    
    
	...
	siglongjmp(env, 1); // back to last sigsetjmp	
}

if (sigsetjmp(env, 1) == 0) {
    
    
	do_sth();
} else {
    
    
	// back from siglongjmp
	do_sth_else();
}
...

猜你喜欢

转载自blog.csdn.net/FJDJFKDJFKDJFKD/article/details/127231995