Как обработчик SIGCHLD правильно использовать на переднем плане / фоне в C? - PullRequest
0 голосов
/ 23 апреля 2020

Я создаю свою собственную оболочку, программа должна работать как на переднем, так и на заднем плане. Я перенаправляю сигнал SIGTSTP от моего основного процесса на его дочерний процесс, потому что после нажатия C -Z остановится только его дочерний процесс, используя tcsetpgrp (), чтобы stdin связывался с группой процессов моего основного процесса, потому что SIGTSTP только будет отправлено в мой процесс оболочки (также используйте setpgid (0,0) в fork (), чтобы сделать все задания, расположенные в другой группе, основной группой). В случае, не нажимая Ctrl-Z, я получаю

The PGID has been changed to 56901 56901 
my prompt> 
pid: 56902 has been reaped
my prompt> 
I want to see this line

пока все хорошо, но когда я нажимаю C -Z, чтобы остановить "сон 10", он там висит,

The PGID has been changed to 56920 56920 
my prompt> 
^Zkill 56921, signum 18

похоже, что waitpid () внутри start_foreground_job () конфликтует с waitpid () в стороне обработчика SIGCHLD. Я пытаюсь удалить этот обработчик в начале start_foreground_job () и переустановить в start_background_job (), но кажется, что это приводит к проблеме гонки (не в этом демонстрационном коде, а в моем реальном рабочем коде). как заставить обработчик SIGCHLD смотреть как на передний, так и на задний план?

#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/signal.h>
#include <sys/mman.h>

int pid = 0;

void handler()
{
    pid_t pid;
    int status;
    while ((pid = waitpid(-1, &status, 0)) > 0) {
        printf("pid: %d has been reaped\n", pid);
    }
}
void send_signal(int signum)
{
    printf("kill %d, signum %d\n", pid, signum);
    kill(pid, signum);
}

void init_signals()
{
    signal(SIGCHLD, handler);
    signal(SIGTSTP, send_signal);
}


void start_foreground_job(char** argv)
{   
    //signal(SIGCHLD, SIG_DFL);

    pid = fork();
    if(pid==0)
    {  
        setpgid(0,0);
        signal(SIGTSTP, SIG_DFL);

        if((execve(argv[0], argv, NULL))<0)//envp
        {
            fprintf(stderr, "%s: Command not found.\n", argv[0]);
            exit(0);
        }
    }

    waitpid(pid, NULL, WUNTRACED);

}

void start_background_job(char** argv)
{   
    //signal(SIGCHLD, handler);


    if( fork() ==0)
    {   
        setpgid(0,0);
        signal(SIGTSTP, SIG_DFL);

        if((execve(argv[0], argv, NULL))<0)
        {
            fprintf(stderr, "%s: Command not found.\n", argv[0]);
            exit(0);
        }
    }

}


int main()
{
    init_signals();

    pid_t stdin_PGID;

    setpgid(0,0);

        /* Get the PGIDs for stdin. */
    stdin_PGID = tcgetpgrp(STDIN_FILENO);
    if (stdin_PGID == -1) {
        printf("Could not get PGID for stdin.n");
        return(EXIT_FAILURE);
    }
    else if (tcsetpgrp(STDIN_FILENO, stdin_PGID) == -1) {
        printf("Could not set PGID.n");
        return(EXIT_FAILURE);
    }

    printf("The PGID has been changed to %d %d \n", stdin_PGID,getpgid(getpid()));


    printf("my prompt> \n");

    char* argv1[] = {"/bin/sleep", "10", NULL};

    start_foreground_job(argv1);

    printf("my prompt> \n");

    char* argv2[] = {"/bin/ls", NULL};

    start_background_job(argv2);

    printf("I want to see this line\n");


}
...