使用Ctrl + Z在C Shell中后台处理进程

时间:2018-11-12 17:23:06

标签: c shell unix signal-handling

我正在尝试在迷你C Shell中实现Ctrl+Z的行为。我的代码当前接收到SIGTSTP信号并正确地挂起了该进程,但是我似乎无法让它移到后台并将shell进程放回前台。

我已经尽力更改了挂起的子进程组,以便我的waitpid()循环可以继续进行(因为waitpid(-1, ...)应该只找到与父进程组相同的子进程,对吗?),但是它总是卡住,等待挂起的进程结束。

while循环到达打印Continuing的地步,然后waitpid()永远不会结束,除非我从外部终止子进程。

Ctrl+C工作正常。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <string.h>

int main()
{
        char inbuf[256];
        pid_t pid;
        struct sigaction act;

        for ( ; ; )
        {
                tcsetpgrp(fileno(stdin), getpgrp());
                act.sa_handler = SIG_IGN;
                assert(sigaction(SIGINT, &act, NULL) == 0);
                assert(sigaction(SIGTSTP, &act, NULL) == 0);
                printf("> ");
                gets(inbuf);

                pid = fork();

                switch (pid)
                {
                        case -1:// error
                                perror("fork");
                                exit(EXIT_FAILURE);
                                break;
                        case 0: // child
                                setpgrp();
                                tcsetpgrp(fileno(stdin), getpgid(pid));
                                act.sa_handler = SIG_DFL;
                                assert(sigaction(SIGINT, &act, NULL) == 0);
                                assert(sigaction(SIGTSTP, &act, NULL) == 0);
                                execlp( inbuf, inbuf, (char *)0 );
                                printf("execlp failed\n");
                                exit(EXIT_FAILURE);
                                break;
                        default:// parent
                                setpgid(pid, pid);
                                int status = 0;
                                signal(SIGTTOU, SIG_IGN);
                                signal(SIGTSTP, SIG_IGN);
                                tcsetpgrp(fileno(stdin), getpgid(pid));
                                int parent_group = getpgid(pid);
                                while (1) {
                                        pid = waitpid(-1, &status, WUNTRACED);
                                        printf("PID: %d\n", pid);
                                        if (pid < 1) {
                                                printf("Breaking\n");
                                                break;
                                        }
                                        if (WIFSTOPPED(status)) {
                                                printf("STOPPED: %d!\n", pid);
                                                // I feel like I should be sending the process, pid, to the background here
                                                //tcsetpgrp(fileno(stdin), parent_group);
                                                //setpgid(pid, pid);
                                        }
                                        printf("Continuing\n");
                                }
                }

                memset(inbuf, '\0', sizeof(inbuf));
        }

        return 0;
}

0 个答案:

没有答案