C で基本的なシェルを作成しようとしています。必要なことの 1 つは、バックグラウンド プロセスとフォアグラウンド プロセスの両方を使用できるようにすることです。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 を押しても何も起こりません。しかし、バックグラウンド プロセスは強制終了されます。
バックグラウンドプロセスが殺されるのを止める方法を知りたいです。何か案は?:)