Листинг 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)
[1]+ Done./child_status
$ ls — l core
ls: core: No such file or directory
$ ulimit — c
0
И хотя по умолчанию сигнал SIGABRT генерирует дамп памяти перед завершением процесса, в данном случае этого не произошло. Дело в том, что дамп памяти был отключен; согласно команде ulimit, приведенной выше, ограничение на программные ресурсы RLIMIT_CORE (см. раздел 36.3), которое задает максимальный размер файла с дампом памяти, было установлено в 0.
Повторим тот же эксперимент, но на этот раз перед отправкой потомку сигнала SIGABRT включим дамп памяти:
$ ulimit — c unlimited
$ ./child_status &
[1] 15902
$ Child started with PID = 15903
kill — ABRT 15903
$ waitpid() returned: PID=15903; status=0x0086 (0,134)
child killed by signal 6 (Aborted) (core dumped)
[1]+ Done./child_status
$ ls — l core
— rw- 1 mtk users 65536 May 6 21:01 core