Сигнал всегда захватывается родительским процессом.

58
7

Рассмотрим следующую часть кода, выполняемую в Solaris 11.3 (упрощенная версия системы (3C)):

int main(int argc, char **argv) {

pid_t pid = fork();
pid_t w;
int status;
if (pid == 0) {
execvp(argv[1], argv + 1);
perror("Failed to exec");
exit(127);
}
if (pid > 0) {
w = waitpid(pid, &status, 0);
if (w == -1) {
perror("Wait: ");
exit(1);
}
else if (WIFEXITED(status) > 0) {
printf("\nFinish code: %d\n", WEXITSTATUS(status));
}
else {
printf("\nUnexpected termination of child process.\n");
}
}
if (pid == -1) {
perror("Failed to fork");
}

}

Проблема заключается в том, что всякий раз, когда процесс завершается с помощью сигнала (например, SIGINT), сообщение "Неожиданное прекращение" никогда не печатается.

Как я вижу, вся группа процессов получает сигналы от терминала, и в этом случае родительский процесс просто заканчивается до возвращения waitpid (2) (что случается каждый раз, по-видимому).

Если это так, у меня есть следующий вопрос. Как получить информацию о сигнале, который завершил дочерний процесс у родителя без использования обработчика сигнала? Например, я мог бы добавить еще один, если-иначе блок с WIFSIGNALED проверкой и WTERMSIG вызова, проходящий переменное status (На самом деле, я сделал, но по окончанию с помощью Ctrl + C программа не поставляется никакого вывода вообще)

Так что конкретно и в каком порядке происходит там?

спросил(а) 2016-03-17T18:13:00+03:00 4 года, 7 месяцев назад
1
Решение
81

Вы говорите: "... всякий раз, когда процесс завершается с помощью сигнала (например, SIGINT)...", но вы достаточно конкретны, чтобы кто-нибудь мог ответить на ваш вопрос окончательно. Если вы отправляете сигнал дочернему процессу с помощью команды kill, у вас возникает нечетная проблема. Но если, как я подозреваю (и, как вы говорите, когда вы говорите "вся группа процессов получает сигналы от терминала"), вы просто печатаете Ctrl + C , ее просто:

    Когда вы вводите символ INTR, QUIT или SUSP, соответствующий сигнал (SIGINT, SIGQUIT или SIGTSTP) отправляется одновременно всем процессам в группе процессов терминала.
      ОК, строго говоря, это не одновременное. Это происходит в цикле в драйвере терминала (в частности, я считаю, "обработчик линии") в ядре. Никакое выполнение пользовательского процесса не может произойти до завершения этого цикла.
    Вы говорите: "... родительский процесс просто заканчивается до того, как waitpid (2) вернется (... каждый раз, по-видимому)". Технически это правда. Как описано выше, все процессы в группе процессов (включая родительский и дочерний процессы) получают сигнал (по существу) одновременно. Поскольку родительский элемент не обрабатывает сигнал, он сам завершается, прежде чем он сможет выполнить любую обработку, вызванную поступлением сигнала от ребенка. Вы говорите: "Сигнал всегда улавливается родительским процессом". Нет; см. выше. И процессы завершаются в неуказанном порядке - это может быть порядок, в котором они отображаются в таблице процессов (что неопределенно), или определяется каким-то тонким (и, возможно, недокументированным) аспектом алгоритма планировщиков.

Связанные вопросы U & L:

ответил(а) 2016-03-18T05:06:00+03:00 4 года, 7 месяцев назад
58

Он работает нормально, если вы посылаете сигналы через "kill" из другого tty? Я попробовал это на linux. Такое же поведение.

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

То, что я сделал, это сделать. /prog cat "

Выполнение kill -SIGINT отлично работает.

Выполнение элемента управления-C ничего не печатает.

Выполнение setid() впереди имеет родительский конец, но ребенок продолжает работать.

ответил(а) 2016-03-18T00:11:00+03:00 4 года, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема