Листинг 26.2. Вывод значения статуса, возвращенного wait() и другими похожими вызовами

procexec/print_wait_status.c

#define _GNU_SOURCE /* Получаем объявление strsignal() из */

#include

#include

#include "print_wait_status.h" /* Объявление printWaitStatus() */

#include "tlpi_hdr.h"

/* ВАЖНО: в следующей функции используется вызов printf(), который не является

безопасным с точки зрения асинхронных сигналов (см. подраздел 21.1.2). Это делает

всю функцию небезопасной для работы с асинхронными сигналами (то есть будьте

осторожны, когда вызываете ее из обработчика SIGCHLD). */

void /* Анализируем статус wait() с помощью макросов W* */

printWaitStatus(const char *msg, int status)

{

if (msg!= NULL)

printf("%s", msg);

if (WIFEXITED(status)) {

printf("child exited, status=%d\n", WEXITSTATUS(status));

} else if (WIFSIGNALED(status)) {

printf("child killed by signal %d (%s)",

WTERMSIG(status), strsignal(WTERMSIG(status)));

#ifdef WCOREDUMP /* Не входит в стандарт SUSv3, может отсутствовать

в некоторых системах */

if (WCOREDUMP(status))

printf(" (core dumped)");

#endif

printf("\n");

} else if (WIFSTOPPED(status)) {

printf("child stopped by signal %d (%s)\n",

WSTOPSIG(status), strsignal(WSTOPSIG(status)));

#ifdef WIFCONTINUED /* Входит в стандарт SUSv3, но может отсутствовать

в ранних версиях Linux и некоторых реализациях UNIX */

} else if (WIFCONTINUED(status)) {

printf("child continued\n");

#endif

} else { /* Этого никогда не должно случиться */

printf("what happened to this child? (status=%x)\n",

(unsigned int) status);

}

}

procexec/print_wait_status.c

В листинге 26.3 применяется функция printWaitStatus(). Она создает дочерний процесс, который либо входит в цикл, постоянно вызывая pause() (в этот момент потомку можно слать сигналы), либо, если был предоставлен целочисленный аргумент командной строки, сразу же завершается, используя этот аргумент в качестве кода завершения. Тем временем родитель следит за потомком с помощью вызова waitpid(), выводит возвращенный код и передает его в функцию printWaitStatus(). Родитель завершает работу, обнаружив, что потомок уже остановлен — либо штатно, либо с помощью сигнала.

Следующая сессия командной оболочки демонстрирует несколько запусков программы из листинга 26.3. Для начала создадим дочерний процесс, который сразу же завершается с кодом 23:

$ ./child_status 23

Child started with PID = 15807

waitpid() returned: PID=15807; status=0x1700 (23,0)

child exited, status=23

Теперь запустим программу в фоновом режиме и отправим дочернему процессу сигналы SIGSTOP и SIGCONT:

$ ./child_status &

[1] 15870

$ Child started with PID = 15871

kill — STOP 15871

$ waitpid() returned: PID=15871; status=0x137f (19,127)

child stopped by signal 19 (Stopped (signal))

kill — CONT 15871

$ waitpid() returned: PID=15871; status=0xffff (255,255)

child continued

Последние две строчки вывода появляются только в Linux версии 2.6.10 и выше, поскольку более старые ядра не поддерживают параметр WCONTINUED для waitpid() (сессия командной оболочки получается немного хаотичной, поскольку программа выполняется в фоновом режиме и ее вывод может смешиваться с приглашением командной строки).

Продолжаем сессию командной оболочки. Отправим сигнал SIGABRT, чтобы завершить работу потомка:

kill — ABRT 15871

$ waitpid() returned: PID=15871; status=0x0006 (0,6)

child killed by signal 6 (Aborted)

Нажмите Enter, чтобы увидеть уведомление командной оболочки о завершении фоновой задачи

[1]+ Done./child_status

$ ls — l core

ls: core: No such file or directory

$ ulimit — c Выводим ограничение RLIMIT_CORE

0

И хотя по умолчанию сигнал SIGABRT генерирует дамп памяти перед завершением процесса, в данном случае этого не произошло. Дело в том, что дамп памяти был отключен; согласно команде ulimit, приведенной выше, ограничение на программные ресурсы RLIMIT_CORE (см. раздел 36.3), которое задает максимальный размер файла с дампом памяти, было установлено в 0.

Повторим тот же эксперимент, но на этот раз перед отправкой потомку сигнала SIGABRT включим дамп памяти:

$ ulimit — c unlimited Включаем дампы памяти

$ ./child_status &

[1] 15902

$ Child started with PID = 15903

kill — ABRT 15903 Передаем потомку сигнал SIGABRT

$ waitpid() returned: PID=15903; status=0x0086 (0,134)

child killed by signal 6 (Aborted) (core dumped)

Нажмите Enter, чтобы увидеть уведомление командной оболочки о завершении фоновой задачи

[1]+ Done./child_status

$ ls — l core На этот раз мы получаем дамп памяти

— rw- 1 mtk users 65536 May 6 21:01 core

Перейти на страницу:

Похожие книги