EINTR на системном вызове 'wait' - PullRequest
0 голосов
/ 15 января 2019

С man -e 2 wait:

Ожидание вызова (& статус) эквивалентно: waitpid (-1, & status, 0);

ошибочные значения:

EINTR WNOHANG не был установлен, и был разблокирован сигнал или SIGCHLD поймали; см. сигнал (7).

Так что, исходя из моего понимания выше, если мы заблокированы в «ожидании» и получении сигнала (SIGCHLD), вызов должен вернуться с -1 и для errno установлено значение EINTR. Хотя запуск следующего фрагмента докажет, что ожидание фактически перезапущено (linux 4.15.0-43, glibc 2.23):

#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/wait.h>

static void sigchld_handler(int signo)
{
    const char *const msg = "\nSIGCHLD";

    (void)signo;
    write(STDERR_FILENO, msg, strlen(msg));
}

int main(void)
{
    pid_t wait_ret = 0, pid = 0;
    int status = 0, ret = -1;

    sigaction(SIGCHLD, &(struct sigaction){
       .sa_handler = sigchld_handler,
    }, NULL);

    if ((pid = fork()) < 0)
    {
       perror("\nfork: ");
       goto Exit;
    }

    if (!pid)
    {
       sleep(3);
       return 0;
    }

    if ((wait_ret = wait(&status)) < 0)
    {
       perror("\nwait: ");
       goto Exit;
    }

    fprintf(stderr, "\nwait done, pid %d", wait_ret);
    ret = 0;

Exit:
    fprintf(stderr, "\n");
    return ret;
}

SA_RESTART не установлен - так почему перезапуск "wait".? Фактический объем производства:

SIGCHLD
wait done, pid 15242

Ожидаемый мной вывод:

SIGCHLD
wait: Interrupted system call

Примечание kill -CHLD <waiting process> вручную из оболочки даст ожидаемый результат.

Также обратите внимание, что выполнение кода во FreeBSD 11.2 также даст ожидаемый результат - ожидание прерывается с ошибкой при выходе из дочернего процесса.

1 Ответ

0 голосов
/ 15 января 2019

Здесь есть тонкость интерпретации. Вы должны начать с:

в случае успеха, [wait] возвращает идентификатор процесса прерванного потомка; при ошибке возвращается -1.

( Страница руководства Linux wait (2) )

Документы о значениях errno необходимо интерпретировать в этом свете: в случае, если wait() возвращает -1 , что указывает на ошибку, и errno установлен на EINTR, интерпретация заключается в том, что SIGCHLD или разблокированный (другой) сигнал прервал ожидание. Но это не означает, что получение SIGCHLD должно привести к сбою wait(). В частности, wait() завершится нормально, вместо того, чтобы выдавать ошибку, когда SIGCHLD возникает в результате завершения одного из дочерних процессов.

Прежде чем критиковать документы здесь, учтите, что

  • a SIGCHLD может быть доставлено по причинам, отличным от того, что ребенок был прерван
  • описания ошибок относятся ко всем функциям в этой группе, и некоторые из них могут ожидать только определенных детей. Они могут быть прерваны SIGCHLD от какого-то ребенка, которого они не ждут.

Формулировка документов также предполагает, что SIGCHLD может вызвать сбой одной или нескольких из этих функций при EINTR , даже если этот сигнал заблокирован . Я нахожу такое поведение удивительным, но помните, с чего я начал: то, что этот результат относится к числу возможных интерпретаций ошибки EINTR, не обязательно означает, что она действительно может произойти.

...