Тестовые примеры на языке C для WIFSIGNALED, WIFSTOPPED, WIFCONTINUED
Вопрос
Я играю с waitpid() и signal() и ищу надежные тестовые примеры для возврата WIFSIGNALED(status) = WIFSTOPPED(status) = WIFCONTINUED (status) = true, но не могу найти ни одного...
Скажите мне, как я могу убедиться, что они возвращают true, чтобы я мог отладить свой код?
Кроме того, было бы полезно несколько советов о том, какие сигналы следует перехватывать с помощью signal() для проверки этих макросов...
Решение
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define NELEMS(x) (sizeof (x) / sizeof (x)[0])
static void testsignaled(void) {
kill(getpid(), SIGINT);
}
static void teststopped(void) {
kill(getpid(), SIGSTOP);
}
static void testcontinued(void) {
kill(getpid(), SIGSTOP);
/* Busy-work to keep us from exiting before the parent waits.
* This is a race.
*/
alarm(1);
while(1) {}
}
int main(void) {
void (*test[])(void) = {testsignaled, teststopped, testcontinued};
pid_t pid[NELEMS(test)];
int i, status;
for(i = 0; i < sizeof test / sizeof test[0]; ++i) {
pid[i] = fork();
if(0 == pid[i]) {
test[i]();
return 0;
}
}
/* Pause to let the child processes to do their thing.
* This is a race.
*/
sleep(1);
/* Observe the stoppage of the third process and continue it. */
wait4(pid[2], &status, WUNTRACED, 0);
kill(pid[2], SIGCONT);
/* Wait for the child processes. */
for(i = 0; i < NELEMS(test); ++i) {
wait4(pid[i], &status, WCONTINUED | WUNTRACED, 0);
printf("%d%s%s%s\n", i, WIFCONTINUED(status) ? " CONTINUED" : "", WIFSIGNALED(status) ? " SIGNALED" : "", WIFSTOPPED(status) ? " STOPPED" : "");
}
return 0;
}
Другие советы
Работа с WIFSIGNALED проста.Дочерний процесс может совершить самоубийство с kill()
системный вызов.Также можно проверить дампы ядра — их создают некоторые сигналы (SIGQUIT, IIRC);некоторые сигналы этого не делают (SIGINT).
Обработка WIFSTOPPED может оказаться сложнее.Самый простой шаг — попросить ребенка отправить себе сигнал SIGSTOP с kill()
системный вызов еще раз.На самом деле, я думаю, это должно сработать.Обратите внимание, что вы можете проверить SIGTTIN, SIGTTOU и SIGTSTOP — я считаю, что они учитываются для WIFSTOPPED.(Также существует вероятность того, что SIGSTOP работает нормально только тогда, когда он отправляется отладчиком процессу, который он запускает, через системный вызов, отличный от POSIX, ptrace()
.)
Я думаю, что обработка WIFCONTINUED должна быть сделана родителем;после того, как вы обнаружите, что процесс остановлен, ваш вызывающий код должен продолжить его, отправив ему сигнал SIGCONT (kill()
снова).Ребенок не может сделать это сам;оно было остановлено.Опять же, я не уверен, есть ли лишние морщины, о которых стоит беспокоиться - возможно.
Структура, подобная приведенной ниже, позволит вам проверить результаты wait()
и waitpid()
звонки.
pid_t pid = fork();
if (pid == 0) {
/* child */
sleep(200);
}
else {
/* parent */
kill(pid, SIGSTOP);
/* do wait(), waitpid() stuff */
}
На самом деле вам не нужно ловить сигналы (используя signal()
или связанная функция), которые отправляются. signal()
устанавливает обработчик, который переопределяет поведение по умолчанию для конкретного сигнала - поэтому, если вы хотите проверить сигнал, завершающий ваш процесс, выберите тот, который имеет такое поведение по умолчанию - "man -s7 signal
" предоставит вам подробную информацию о поведении сигнала по умолчанию.
Для упомянутых вами макросов используйте SIGSTOP
для WIFSTOPPED(status)
, SIGCONT
для WIFCONTINUED (status)
и SIGINT
для WIFSIGNALED(status)
Если вам нужна большая гибкость при тестировании, вы можете использовать команду kill (см. "man kill
"), чтобы отправлять сигналы вашему процессу. kill -l
перечислит все сигналы, которые можно отправить.
в ваших тестах вы можете выполнить fork() и отправить конкретный сигнал вашим дочерним процессам?В этом сценарии ваши дочерние процессы являются тестовыми примерами?
РЕДАКТИРОВАТЬ
мой ответ о кодировании теста C.Вы распадаетесь, получаете PID вашего дочернего процесса (процесс с установленными обработками сигнала), затем вы можете отправить ему сигнал, используя его, используя kill(2)
.Таким образом, вы можете проверить статус выхода