问题
I am trying to install a CTRL-Z (SIGTSTP) handler for a running foreground process.
I set the handler (sigaction
) right before I wait
in the parent. Is this the right place? It doesn't seem to work right..
EDIT:
I am writing a shell. Here is an outline of how my code looks like. I currently set the handler in the parent as shown below (which doesn't seem to work).
// input from user for command to run
pid_t pid;
pid = fork();
// Child Process
if (pid == 0) {
// handle child stuff here
// exec() etc...
}
else if (pid < 0)
// error stuff
/* Parent Here */
else {
// Give process terminal access
// SET HANDLER FOR SIGTSTP HERE???
wait()
// Restore terminal access
}
回答1:
You are doing things complete wrong.
You DON'T send SIGTSTP to child process, the tty send SIGTSTP to child process DIRECTLY.
Try
$ stty -a
speed 38400 baud; rows 55; columns 204; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
Notice:
susp = ^Z;
that tells the tty how to deal with "CTRL-Z", when the tty gets ^Z it sends SIGTSTP signal to all process in the current foreground process group
How to handle process group
When you launch a new process in the shell, before execvX
, put the new process into a new process group, then call tcsetpgrp
to set the new process group foreground. So any future signal will send to the child process directly. if the child forks new process, they will be in the same process group; so the entire process group will be suspended when ^Z is pressed.
pid = fork()
if (pid) {
// parent
setpgid(pid, pid); // put child into a new process group
int status;
wait(pid, &status, 0);
} else {
// child
pid = getpid();
setpgid(pid, pid);
if (isatty(0)) tcsetpgrp(0, pid);
if (isatty(1)) tcsetpgrp(1, pid);
if (isatty(2)) tcsetpgrp(2, pid);
execvX ...
}
Once any signal comes from tty causing child processes stop/term/exit your shell will return from wait
, check status to know what happened to the child.
Prevent your shell from stopping
Your shell should mask SIGTSTP signal, because shell do not suspend. You do this at the beginning, when you start the shell. but don't forget fork will derive sigmask, so you need to enable SIGTSTP after fork in the child process.
回答2:
To handle a SIGTSTP
to the child, this is needed after waitpid
:
if (WIFSTOPPED(status)) {
printf("Child received SIGTSTP");
}
来源:https://stackoverflow.com/questions/9853921/installing-sigtstp-foreground-process