在上一个问题中,我发布了我自己的大部分 shell 代码。我的下一步是实现前台和后台进程执行并适当地等待它们终止,这样它们就不会像“僵尸”一样停留。
在添加在后台运行它们的可能性之前,所有进程都在前台运行。为此,我在使用 execvp() 执行任何进程后简单地调用了 wait(NULL)。现在,我检查 '&' 字符作为最后一个参数,如果它在那里,通过不调用 wait(NULL) 在后台运行进程,并且进程可以在后台愉快地运行,我将返回到我的 shell。
这一切正常(我认为),现在的问题是我还需要以某种方式调用 wait() (或 waitpid() ?),以便后台进程不会保持“僵尸”状态。那是我的问题,我不知道该怎么做...
我相信我必须处理 SIGCHLD 并在那里做一些事情,但我还没有完全理解什么时候发送 SIGCHLD 信号,因为我试图也将 wait(NULL) 添加到 childSignalHandler() 但它没有工作,因为我在后台执行了一个进程,调用了 childSignalHandler() 函数,因此调用了 wait(NULL),这意味着在“后台”进程完成之前我无法对我的 shell 执行任何操作。由于信号处理程序中的等待,它不再在后台运行。
我在这一切中缺少什么?
最后一件事,这个练习的一部分,我还需要打印进程状态的变化,比如进程终止。因此,对此的任何见解也非常感谢。
这是我目前的完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <sys/types.h>
#include "data.h" // Boolean typedef and true/false macros
void childSignalHandler(int signum) {
//
}
int main(int argc, char **argv) {
char bBuffer[BUFSIZ], *pArgs[10], *aPtr = NULL, *sPtr;
bool background;
ssize_t rBytes;
int aCount;
pid_t pid;
//signal(SIGINT, SIG_IGN);
signal(SIGCHLD, childSignalHandler);
while(1) {
write(1, "\e[1;31mmyBash \e[1;32m# \e[0m", 27);
rBytes = read(0, bBuffer, BUFSIZ-1);
if(rBytes == -1) {
perror("read");
exit(1);
}
bBuffer[rBytes-1] = '\0';
if(!strcasecmp(bBuffer, "exit")) {
exit(0);
}
sPtr = bBuffer;
aCount = 0;
do {
aPtr = strsep(&sPtr, " ");
pArgs[aCount++] = aPtr;
} while(aPtr);
background = FALSE;
if(!strcmp(pArgs[aCount-2], "&")) {
pArgs[aCount-2] = NULL;
background = TRUE;
}
if(strlen(pArgs[0]) > 1) {
pid = fork();
if(pid == -1) {
perror("fork");
exit(1);
}
if(pid == 0) {
execvp(pArgs[0], pArgs);
exit(0);
}
if(!background) {
wait(NULL);
}
}
}
return 0;
}