Из справочной страницы для wait
можно получить EINTR
:
EINTR WNOHANG не был установлен, и был разблокирован сигнал или SIGCHLD
Итак, если у SIGCHLD
есть обработчик, и вы находитесь в wait
, сигнал будет first .
Вот что имеет смысл.Потому что обработчики SIGCHLD
могут свободно wait
пожинать ребенка.Некоторые программы не делают wait
в базовом коде, но полагаются на обработчик.
Как уже упоминалось, не выполняйте printf
в обработчике [он делает malloc
и все ставки выключены].Тем не менее, выполнение wait
нормально [, некоторые системные вызовы в порядке / разрешены в обработчике].
В вашей программе было несколько проблем.Я немного рефакторинг.Это показывает, что SIGCHLD
происходит до того, как wait
завершается [как подразумевает man-страница].
Обратите внимание, что это довольно хороший тест, но окончательный может включать третий процесс, который должен убить исходного потомка ( после небольшого сна), чтобы позволить родителю войти в wait
.
То есть kill
произойдет (в процессе 3), после того, как основной процесс введен wait
.
Я не сделал этого, поэтому вот более простая версия:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
pid_t pid;
volatile int gotsig = 0;
void
handler_cld(int sig)
{
gotsig = 1;
}
void
handler_usr1(int sig)
{
exit(0);
}
int
main()
{
int status;
signal(SIGUSR1, handler_usr1);
signal(SIGCHLD, handler_cld);
pid = fork();
if (pid == 0) {
while (1);
}
// kill the child
kill(pid,SIGUSR1);
if ((pid = wait(&status)) > 0) {
printf("wait returned %s SIGCHLD\n",gotsig ? "after" : "before");
}
return 0;
}
ОБНОВЛЕНИЕ:
Вот более сложная версия, которая использует отдельный процесс "убийца", чтобы убить ребенка, но результаты те же:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
volatile int gotsig = 0;
void
handler_cld(int sig)
{
gotsig += 1;
}
void
handler_usr1(int sig)
{
exit(0);
}
int
main()
{
int status;
signal(SIGUSR1, handler_usr1);
signal(SIGCHLD, handler_cld);
pid_t pidcld = fork();
if (pidcld == 0) {
while (1);
}
pid_t pidkill = fork();
if (pidkill == 0) {
sleep(1);
// kill the child
kill(pidcld,SIGUSR1);
sleep(3);
exit(0);
}
pid_t pidany;
// wait for child
if ((pidany = waitpid(pidcld,&status,0)) > 0) {
printf("wait on child returned %s SIGCHLD\n",
gotsig ? "after" : "before");
}
// wait for child
if ((pidany = waitpid(pidkill,&status,0)) > 0) {
printf("wait on killer returned %s SIGCHLD\n",
gotsig ? "after" : "before");
}
return 0;
}