简体   繁体   English

如何在SIGINT上仅终止前台子进程?

[英]How to terminate only foreground child processes upon SIGINT?

I'm Implementing a simple shell program, the implementation of & and | 我正在实现一个简单的shell程序,实现&| works as intended. 按预期工作。 However, I want to handle interrupts such that in case SIGINT is received, parent (shell) and background process should not terminate, but any foreground process should terminate. 但是,我想处理中断,以便在接收到SIGINT的情况下,父进程(外壳)和后台进程不应终止,而任何前台进程均应终止。 I have initialized a signal and a handler but I would like to get suggestions how to handle it differently for each process. 我已经初始化了一个信号和一个处理程序,但是我想获得关于如何对每个进程进行不同处理的建议。

    void intHandler() {
    flagInt = 0;
    fprintf(stderr, "interrupt\n");

}

int process_arglist(int count, char** arglist) {
    struct sigaction childSig;
    struct sigaction intSig;
    intSig.sa_handler = intHandler;
    sigaction(SIGINT, &intSig, NULL);
    //initialize intSig


    int flagBg = 0; //turned to 1 in case there's a &
    int flagPipe = 0; //turned to 1 in case there's a |
    int index = 0; //index of | 0 if there's none

    //Check if there's & and set flagBg and sigaction
    if (strcmp(arglist[count - 1], "&") == 0) {
        flagBg = 1;
        childSig.sa_handler = SIG_IGN;
        childSig.sa_flags = 0;
        if(sigaction(SIGCHLD, &childSig, NULL)<0){
            fprintf(stderr, "ERROR: sigaction failed\n");
            exit(1);
        }
    }

    //Look for pipes
    int i = 0;
    while (i < count) {
        if (strcmp(arglist[i], "|") == 0) {
            flagPipe = 1;
            index = i;
        }
        i = i + 1;
    }

    //Handle &
    if (flagBg == 1) {
        int pid = fork();
        if (pid < 0) { //check if fork failed
            fprintf(stderr, "ERROR: fork failed\n");
            return 1;
        }
        if (pid == 0) { // Child's process
            arglist[count - 1] = NULL;
            if (execvp(*arglist, arglist) < 0) {     //execute the command
                fprintf(stderr, "ERROR: execvp failed\n");
                exit(1);
            }
        }
        if (pid > 0) { //Parent's process
            return 1;

        }
    }

    //Handle |
    if (flagPipe == 1) {
        //create a new process
        arglist[index] = NULL;
        int fd[2];
        if(pipe(fd)<0){
            fprintf(stderr, "ERROR: pipe failed\n");
            exit(1);
        }
        int pid = fork();
        if (pid < 0) { //check if fork failed
            fprintf(stderr, "ERROR: fork failed\n");
            return 1;
        }

        if (pid == 0) { // Child's process

            close(STDOUT_FILENO);
            dup(fd[1]);
            close(fd[0]);
            close(fd[1]);
            if (execvp(*arglist, arglist) < 0) {     //execute the first part of the commands
                fprintf(stderr, "ERROR: execvp failed\n");
                exit(1);
            }
        }
        if (pid > 0) { //Parent's process
            int pid2 = fork();
            if (pid2 < 0) {
                fprintf(stderr, "ERROR: fork failed\n");
                return 1;
            }
            if (pid2 == 0) { // Child's process
                close(STDIN_FILENO);
                dup(fd[0]);
                close(fd[1]);
                close(fd[0]);
                if (execvp(arglist[index+1], arglist+index+1) < 0) {     //execute the second part of the commands
                    fprintf(stderr, "ERROR: execvp failed\n");
                    exit(1);
                }
                exit(1);
            } else { //Parent's process
                close(fd[0]);
                close(fd[1]);
                waitpid(pid, 0, 0);
                return 1;
            }

        }
    }

    //No & and no |
    if (flagBg == 0 && flagPipe == 0) {
        int pid = fork();
        if (pid < 0) { //check if fork failed
            fprintf(stderr, "ERROR: fork failed\n");
            return 1;
        }
        if (pid == 0) {
            if (execvp(*arglist, arglist) < 0) { //execute the command
                fprintf(stderr, "ERROR: execvp failed\n");
                exit(1);
            }
        } else {
            waitpid(pid, 0, 0);
            return 1;
        }
    }

    return 0;

}

You shouldn't need to use a SIGINT sighandler to resend SIGINT to the right children. 您不需要使用SIGINT程序将SIGINT重新发送给合适的孩子。 If you run each job in a separate process group and you use tcsetpgrp to set the foreground process group of the terminal, then Ctrl+C should cause the terminal to send SIGINT to the appropriate process group for you. 如果您在单独的进程组中运行每个作业,并且使用tcsetpgrp设置终端的前台进程组,则Ctrl+C应该使终端将SIGINT发送给适合您的进程组。

My idea is to set the default handler of SIGINT as SIG_IGN, and change it to another handler which terminates when I'm running a foreground process. 我的想法是将SIGINT的默认处理程序设置为SIG_IGN,并将其更改为另一个在我运行前台进程时终止的处理程序。 However I can't understand where I should place the handler assignment in the code. 但是我不明白我应该在代码中放置处理程序的位置。

You just didn't write the code in accordance with your idea. 您只是没有按照您的想法编写代码。 To change the handling when running a foreground process, move the sigaction(SIGINT, &intSig, NULL); 要在运行前台进程时更改处理,请移动sigaction(SIGINT, &intSig, NULL); from the start of process_arglist() down to each of the three places where execvp() of a foreground process is called. process_arglist()的开始一直到调用前台进程的 execvp()的三个位置中的每个位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM