Что означает «ожидание и ожидание всегда прерываются при получении сигнала»? - PullRequest
2 голосов
/ 29 марта 2019

С APUE :

Чтобы приложениям не приходилось обрабатывать прерванные системные вызовы, 4.2BSD ввел автоматический перезапуск некоторых прерванных системных вызовов. Системные вызовы, которые были автоматически перезапущены: ioctl, read, readv, write, writev, wait и waitpid.Как мы уже упоминали, первые пять из этих функций прерываются сигналом, только если они работают на медленном устройстве;wait и waitpid всегда прерываются при перехвате сигнала. Так как это вызывало проблему для некоторых приложений, которые не хотели, чтобы операция была перезапущена, если она была прервана, 4.3BSD позволила процессу отключитьэта функция для каждого сигнала.

Означает ли это, что до того, как был введен автоматический перезапуск , если процесс перехватил сигнал, wait и waitpid немедленноостановить ожидание и выполнить следующий код?

Например:

#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

void handler(int sig){}
void handler2(int sig){}


int main(){
    pid_t pid;
    int status;
    signal(SIGUSR1, handler);
    signal(SIGUSR2, handler2);    

    if((pid == fork()) < 0){
        printf("fork error\n");
    }else{
        if(pid){
            //child
            //do something, needs several hours.
        }else{
            //parent
            waitpid(pid, &status, 0);
            printf("Hello world\n");
        }
    }
    return 0;
}

Если не обеспечен автоматический перезапуск , когда я запускаю эту программу в фоновом режиме gcc test.c && ./a.out &,затем я посылаю сигнал kill -SIGUSR1 pid или kill -SIGUSR2 pid, waitpid вернется и код после waitpid(pid, &status, 0); будет выполнен.

И если при обеспечении автоматический перезапуск , waitpid будетвыполнить снова, и родитель будет ждать.

Правильно ли мое понимание?

Ответы [ 2 ]

2 голосов
/ 29 марта 2019

Исходное поведение signal() (семантика System-V) состояло в том, чтобы прервать любой системный вызов, если процесс в данный момент спит, выполнить обработчик сигнала и системный вызов вернется с -EINTR.Затем BSD4.3 изобрел механизм restart , который автоматически перезапускает любой системный вызов после его прерывания.Это позволяет избежать необходимости записывать цикл для каждого системного вызова, если задействованы обработчики сигналов.

Linux не изменила семантику signal() системного вызова .Однако функция-оболочка signal() glibc в настоящее время вызывает системный вызов sigaction() с флагом SA_RESTART по умолчанию.Итак, если вам не нужно перезапустить поведение, вы должны вызвать sigaction() и опустить этот флаг.

Итак, ваш код действительно использует restart механизм на BSD и Linux

0 голосов
/ 29 марта 2019

wait и waitpid, как и любая другая функция блокировки, могут быть прерваны с errno, установленным на EINTR - это именно потому, что обработчик сигнала может сделать очень мало - в основном установлены некоторые флаги.Теперь, если блокирующая функция не вернется с EINTR, как вы можете реагировать на сигнал каким-либо образом?!

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

...