我正在尝试用 C 编写一个基本的 shell。我需要做的一件事是能够同时拥有后台和前台进程。Control-C 必须杀死前台进程(如果有的话),并且不能杀死任何后台进程。
我为 SIGINT 编写了一个信号处理程序,它杀死了前台进程。唯一的问题是,如果我有一个后台进程,它也会杀死它。据我了解,当按下 Control-C 时,SIGINT 会通过一个队列传递给不同的进程,如果有一个处理它,那么它就会停止。我的外壳应该正在处理它,所以它不应该被传递给后台进程,对吧?
这是我的代码:
pid_t foreground_pid;
int main(int argc, char *argv[]) {
signal(SIGINT, INThandler);
char *buf;
while(1) {
fgets(buf, 128, stdin);
*/ error checking */
*/ split buf into null terminated char* array (arg_array)
and count the number of args (num_args) */
handlerCommand(buf, arg_array, num_args);
zombieTerminator();
}
void handleCommand(char *command, char **args, int num) {
pid_t pid;
if ((pid = fork()) < 0)
printf("error\n");
else if (pid == 0) { // Child
if (!strcmp(args[num-1], "&")) {
/* redirect stdin to /dev/null */
}
execvp(args[0], args);
printf("error\n");
exit(127);
}
// parent - either wait (foreground) or continue (background)
if (!strcmp(args[num-1], "&")) {
printf(" [%ld] : %s\n", (long)pid, command);
} else {
foreground_pid = pid;
if ((pid = waitpid(pid, &status, 0)) < 0)
fprintf(stderr, "waitpid error\n");
}
return;
}
/** Terminates any zombie processes that finished in the background */
void zombieTerminator(void) {
int status;
pid_t pid;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (pid != foreground_pid) {
printf(" [%ld] exited with status: %d\n", (long)pid,
WEXITSTATUS(status));
}
}
}
/** Handles the control-c signal from the keyboard */
void INThandler(int sig) {
if (foreground_pid) {
kill(foreground_pid, SIGKILL);
foreground_pid = 0;
} else {
printf("\n%s\? ", cwd);
}
fflush(stdout);
}
当我运行前台进程时:
sleep(100)
然后我可以按 contorl-c 它会退出。应该的。但是,如果我运行后台进程:
sleep(100) &
我得到了一个新的提示,就像我应该的那样,但是如果我按下 control-c,什么都不会发生。但是后台进程被杀死了。
我很想知道如何阻止后台进程被杀死。有任何想法吗?:)