我如何通知编译器 `getcontext` 可以 return 多次?

How do I inform the compiler that `getcontext` can return multiple times?

getcontext can return multiple times. For example, I have sketched a C program analogous to the one demostrated here:

#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <ucontext.h>

struct communication {
        const ucontext_t *return_ctx;
        int return_value;
};

static void
test(ucontext_t *thisctx, struct communication *comm)
{
        int i = 0;
        assert(getcontext(thisctx) == 0);
        // getcontext will return 3 times with i having different values

        comm->return_value = ++i;
        setcontext(comm->return_ctx);
        assert(0);
}

int
main(void)
{
        ucontext_t mainctx, testctx;
        struct communication comm;
        char test_stack[SIGSTKSZ];

        assert(getcontext(&testctx) == 0);
        testctx.uc_stack.ss_sp = test_stack;
        testctx.uc_stack.ss_size = sizeof test_stack;
        makecontext(&testctx, test, 2,
                &testctx, &comm);

        for (int i = 0; i < 3; ++i) {
                // Rewind test's execution where 'getcontext' returns
                comm.return_ctx = &mainctx;
                assert(swapcontext(&mainctx, &testctx) == 0);
                assert(printf("%d\n", comm.return_value) > 0);
        }

        return 0;
}

编译并运行它

$ gcc -std=gnu99 -O3 -o getcontext_test getcontext_test.c
$ ./getcontext_test
1
1
1

没有给出预期的 1 2 3 因为编译器认为 i 在分配给 comm->return_value.

时只能等于 1

我可以通过定义 i volatile 来解决这个问题,但是我想要一个更规范的方法来解决这个问题。

对你想要的东西的必要(但可能不充分)要求是 i(在 test 函数中;你所询问的标识符的函数之间的名称重复是不幸的是)volatile。这已经是标准 (7.13.2.1 ¶3) 中的要求:

All accessible objects have values, and all other components of the abstract machine have state, as of the time the longjmp function was called, except that the values of objects of automatic storage duration that are local to the function containing the invocation of the corresponding setjmp macro that do not have volatile-qualified type and have been changed between the setjmp invocation and longjmp call are indeterminate.

for objects 可以在 setjmp 的连续 return 之间修改,所以你应该(并且应该)做同样的事情是完全合理的getcontext.

由于其他原因,编译器可能需要不止一次地意识到 getcontext return。在 GCC 和兼容的编译器(除 MSVC 之外的大多数编译器)上,您可以使用 __attribute__((__returns_twice__)) 实现此目的。但是,如果需要,声明 getcontext(或编译器内部)的 header 应该已经在做类似的事情了。