Какая польза от возвращаемого значения sigsetjmp ()? - PullRequest
1 голос
/ 22 апреля 2020

В рамках упражнения мне нужно реализовать библиотеку, поддерживающую использование потоков пользовательского уровня.

Мне следует использовать системные вызовы sigsetjmp и siglongjmp.

Теперь я изо всех сил пытаюсь понять использование возвращаемого значения sigsetjmp.

Если я правильно понял, возвращаемое значение будет вторым входом для последнего siglongjmp (в случае, если это не первый sigsetjmp).

Когда мы хотим переключиться потоками, мы вызываем sigsetjmp, чтобы сохранить значения регистров в ЦП в некотором месте в памяти.

Сразу после того, как мы вызовем siglongjmp Для загрузки некоторых значений в регистры ЦП, поэтому наш следующий поток может продолжать работать с того места, где он остановился. При вызове siglongjmp мы также предоставляем целое число для следующего sigsetjmp возвращаемого значения .

Если бы я до сих пор был прав, я не понимаю, зачем было бы знать что-то о последнем потоке, который больше не работает, и мы уже сохранили его значения ЦП в памяти (потому что sigsetjmp вернулся).

Заранее спасибо

Ответы [ 2 ]

3 голосов
/ 22 апреля 2020

Возвращаемое значение из sigsetjmp() сообщает вам, вызывается ли оно в первый раз (возвращаемое значение 0), или же оно возвращается как результат siglongjmp() (возвращаемое значение не равно нулю). Поведение sigjmp() и longjmp() одинаково. При первом вызове задается аргумент sigjmp_buf или jmp_buf для записи состояния вычислений, чтобы siglongjmp() или setjmp() могли использовать его для возврата назад.

Обратите внимание, что вы должны быть осторожны с как вы используете sigsetjmp() и setjmp(); контексты, в которых они могут быть использованы, ограничены. C11 §7.13.1.1 Макрос setjmp говорит:

¶4 Вызов макроса setjmp должен появляться только в одном из следующих контекстов:

  • все управляющее выражение оператора выбора или итерации;
  • один операнд оператора отношения или равенства с другим операндом - целочисленное константное выражение, а результирующее выражение является полным управляющим выражением выбора или оператор итерации;
  • операнд унарного оператора ! с результирующим выражением, являющимся полным управляющим выражением оператора выбора или итерации; или
  • полное выражение оператора выражения (возможно приведенное к void).

¶5 Если вызов появляется в любом другом контексте, поведение не определено.

Обратите внимание, в частности, на то, что ни один из контекстов, в которых он может быть использован, не относится к «RHS оператора присваивания». Подчеркнув это, я никогда не видел сбой при назначении, но технически он вызывает неопределенное поведение для назначения результата.

Также обратите внимание, что стандарт C явно говорит, что setjmp() - это макрос .

Стандарт C не определяет sigsetjmp() или siglongjmp() - они являются расширениями POSIX стандарта C. Однако правила POSIX в основном одинаковы:

Одна из причин этого заключается в том, что конструкция хороша, работает setjmp() / longjmp() pair - чрезвычайно тонкий кусок кода. Если вы можете найти копию, стоит прочитать PJ Plauger The Standard C Library (1992) на topi c. Несмотря на то, что он старый, в его обсуждениях много мудрости.

2 голосов
/ 22 апреля 2020

Возвращаемое значение sigsetjmp - это значение, данное [возможному] siglongjmp 2-му аргументу.

По соглашению, это ненулевое значение (если siglongjmp передано 0, оно будет используйте 1).

Значение, возвращаемое sigsetjmp, показывает, как вызывающая сторона различает "нормальную" операцию по отношению к событию / сигналу.

Первый раз, когда возвращается 0. Вызывающая сторона теперь будет выполнять "нормальные" операции.

Когда вызывается siglongjmp, стек сбрасывается до точки вызова sigsetjmp. Но возвращаемое значение будет отличным от нуля, сообщая вызывающей стороне, что событие сработало, и вызывающая сторона должна выполнить «прерывание» обработки.

Обсуждаемое ненулевое значение [снова] происходит из 2-го аргумента siglongjmp. Это может быть любое ненулевое значение. Таким образом, мы можем использовать его как код типа «abort». (например) Это может быть номер сигнала, который произошел, если мы будем sh.

или любым значением: (например) enum { ABORT_NOFILE = 100, ABORT_NOMEM, ABORT_BECAUSE_ITS_TUESDAY };, с которым согласны два вызывающих / вызывающих абонента.

Во всяком случае, вот код для иллюстрации:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>

sigjmp_buf jmpbuf;
int termval = 23;

void
handler(int sig)
{

    siglongjmp(jmpbuf,termval);
}

int
main(void)
{
#if 0
    int retval;
#else
    volatile static int retval;
#endif

    signal(SIGALRM,handler);

    retval = sigsetjmp(jmpbuf,1);

    if (! retval) {
        alarm(5);

        printf("running normally ...\n");

        // do something useful ...
        while (1);
    }
    else {
        printf("signal occurred -- retval=%d\n",retval);
    }

    return 0;
}
...