Я пытаюсь реализовать поведение Ctrl+Z
в оболочке mini C.Мой код в настоящее время получает сигнал SIGTSTP
и корректно приостанавливает процесс, однако я не могу заставить его переместиться в фоновый режим и вернуть процесс оболочки обратно на передний план.
Я старался изо всех силизменить группу процессов дочернего процесса, который приостановлен, чтобы мой цикл 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;
}