Я пишу простую оболочку на C, которая поддерживает выполнение обычных команд Linux, а также пару встроенных команд, которые я написал сам (например, «выход» для выхода из оболочки).Оболочка создает новый дочерний элемент для каждой введенной команды.У меня есть обработчик SIGCHLD, который получает детей-зомби, когда дочерний процесс завершается.Моя проблема заключается в том, что всякий раз, когда я запускаю фоновый процесс, родитель (сама программа-оболочка) также уничтожается при вызове обработчика SIGCHLD.
Я уже посмотрел в этом посте и сделалнебольшой обработчик SIGPIPE, но он никогда не вызывается, поэтому я не думаю, что это проблема.
Эта eval
функция обрабатывает каждую введенную команду и решает, запускать ли ее на переднем плане или в фоне:
void eval(char *cmdline)
{
char *argv[MAXARGS];
char buf[MAXLINE];
int bg;
pid_t pid;
sigset_t mask_all, mask_one, prev_one;
sigfillset(&mask_all);
sigemptyset(&mask_one);
sigaddset(&mask_one, SIGCHLD);
strcpy(buf, cmdline);
/* Is it a background command (ends in &) ? */
bg = parseline(buf, argv);
/*Ignore empty lines */
if(argv[0] == NULL)
return;
/*builtin_cmd just handles my own custom commands */
if(!builtin_cmd(argv)) {
/*Block SIGCHLD signals */
sigprocmask(SIG_BLOCK, &mask_one, &prev_one);
if((pid = fork()) == 0) {
/* Unblock SIGCHLD */
sigprocmask(SIG_SETMASK, &prev_one, NULL);
if(execve(argv[0], argv, environ) < 0) {
fprintf(stderr, "%s: Command not found\n", argv[0]);
fflush(stderr);
exit(0);
}
}
/* Block all signals */
sigprocmask(SIG_BLOCK, &mask_all, NULL);
setpgid(pid, 0);
if(!bg) {
/*Wait for foreground job to complete */
int status;
if(waitpid(pid, &status, 0) < 0) {
fprintf(stderr, "wait pid error");
}
} else {
/* Add the job to the jobs array */
/* BG just means it's in the background */
addjob(jobs, pid, BG, cmdline);
int jid = (*getjobpid(jobs, pid)).jid;
printf("[%d] (%d) %s", jid, pid, cmdline);
}
/*Unblock signals */
sigprocmask(SIG_SETMASK, &prev_one, NULL);
}
return;
}
Вот мой обработчик SIGCHLD:
void sigchld_handler(int sig)
{
int olderrno = errno;
sigset_t mask_all, prev_all;
sigfillset(&mask_all);
/*Reap zombie */
pid_t pid;
if((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
sigprocmask(SIG_BLOCK, &mask_all, &prev_all); //Block all signals
deletejob(jobs, pid); //Delete job from jobs array
sigprocmask(SIG_SETMASK, &prev_all, NULL); //Unblock signals
}
//WHY DOES THIS EXECUTE FOR BACKGROUND JOBS???
if(errno != ECHILD) {
printf("waitpid error");
}
errno = olderrno;
return;
}
Ожидание убивает детей, что, как я знаю, из утверждений печати, которые я поместил в него.Но когда я запускаю фоновые процессы, родительский процесс также уничтожается, и выводится сообщение об ошибке waitpid.
brett@brett-linux:~/Desktop/Shell$ ./tsh
tsh> /bin/sleep 1 &
[1] (7223) /bin/sleep 1 &
tsh> waitpid error
brett@brett-linux:~/Desktop/Shell$
Как видите, программа просто умирает.Почему это происходит?