C: Выполнение операции ввода / вывода и отправка сигнала приводят к тому, что select () постоянно прерывается? - PullRequest
1 голос
/ 09 ноября 2019

Я пытаюсь обработать подключение к сокету из другого процесса, асинхронно обрабатывая SIGALRM из функции alarm. Чтобы смоделировать и проверить это, я использую команды Linux nc 127.0.0.1 [port] и kill -14 $(myprocess). Однако при выполнении команды kill, за которой следует команда nc, select мгновенно возвращается в бесконечном цикле, как в моде. Код C, содержащий оператор select, приведен ниже.

int main() {
    int port = 4555;
    int master_sockfd;
    bind_and_listen(&master_sockfd, port);
    signal(SIGALRM, handle_alarm);

    for (;;) {
        fd_set readfds;
        int max_fd = master_sockfd;
        FD_ZERO(&readfds);
        FD_SET(master_sockfd, &readfds);

        printf("waiting for master_sockfd to be set\n");

        int activity = select(max_fd + 1, &readfds, NULL, NULL, NULL);

        if ((activity < 0) && (errno != EINTR)) {
            perror("select() ");
            exit(EXIT_FAILURE);

        } else if (errno == EINTR) {
            perror("select() ");
            if (FD_ISSET(master_sockfd, &readfds)) {
                printf("Why is sockfd ready for I/O if select was interrupted with a signal?\n");
            }
            continue;

        } else if (FD_ISSET(master_sockfd, &readfds)) {
            printf("Reading from socket\n");
            // handle client
        }
    }
    return 0;
}

void handle_alarm() {
    printf("handling alarm\n");
}

Затем при выполнении kill -14 $(myprocess); nc 127.0.0.1 4555 Вывод будет следующим:

select() : Interrupted system call
Why is sockfd ready for I/O if select was interrupted with a signal?
waiting for master_sockfd to be set
select() : Interrupted system call
Why is sockfd ready for I/O if select was interrupted with a signal?
waiting for master_sockfd to be set
select() : Interrupted system call
Why is sockfd ready for I/O if select was interrupted with a signal?
waiting for master_sockfd to be set
.
.
.

, который печатается бесконечно.

Почему это происходит?

1 Ответ

2 голосов
/ 09 ноября 2019

Когда select () не работает, вы не можете полагаться на значения параметров из него. Они могут отражать что-то, ничего или какое-то промежуточное состояние. В вашем случае, похоже, что select () никогда не обновлял fdsets вообще;поэтому они отражают ваше первоначальное значение. Это имеет смысл;оно было прервано, поэтому оно никогда не записывало свои результаты.

Ваше обнаружение ошибок также не совсем верно, оно должно быть:

if (activity < 0) {
    /* select failed */
    if (errno != EINTR) {
        /* handle non-eintr cases */
    } else {
        /* handle eintr case */
    }
} else {
    /*select succeeded */
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...