Я создаю свою собственную оболочку, программа должна работать как на переднем, так и на заднем плане. Я перенаправляю сигнал 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");
}