Как сообщить компилятору, что getcontext может возвращаться несколько раз? - PullRequest
0 голосов
/ 01 ноября 2018

getcontext может возвращаться несколько раз. Например, я набросал программу на C, аналогичную той, что была продемонстрирована здесь :

#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 может равняться 1 только при присвоении comm->return_value.

Я могу обойти это, определив i volatile, однако я бы хотел более канонический подход к этой проблеме.

1 Ответ

0 голосов
/ 01 ноября 2018

Необходимым (но, возможно, недостаточным) требованием для того, что вы хотите, является i (в функции test; дублирование имени между функциями идентификатора, о котором вы спрашиваете, является неудачным) volatile. Это уже требование в стандарте (7.13.2.1 №3):

Все доступные объекты имеют значения, а все другие компоненты абстрактной машины имеют состояние на момент вызова функции longjmp, за исключением того, что значения объектов с длительностью автоматического хранения, локальные для функции, содержащей вызов соответствующий макрос setjmp, который не имеет тип volatile-квалифицированный и был изменен между вызовом setjmp и вызовом longjmp, является неопределенным.

для объектов, которые могут быть изменены между последовательными возвратами setjmp, поэтому вполне логично, что вы должны (и должны) делать то же самое с getcontext.

По другим причинам может быть необходимо, чтобы компилятор знал, что getcontext возвращает более одного раза. На GCC и совместимых компиляторах (почти все, кроме MSVC) вы можете достичь этого с помощью __attribute__((__returns_twice__)). Однако заголовок, объявивший getcontext (или внутренние компоненты компилятора), уже должен делать что-то подобное, если это необходимо.

...