Why does a SIGTSTP signal not handled by the parent move the entire group to the background (contrary to written in TTY demystified)?
0
votes
1
answer
117
views
I started learning about linux tty(s) and signals and ran into some trouble.
I am reading and using [The TTY demystified](https://www.linusakesson.net/programming/tty/) as a reference.
I made two simple golang programs.
Parent:
package main
import (
"fmt"
"syscall"
"time"
)
func main() {
attr := &syscall.ProcAttr{
Files: []uintptr{0, 1, 2},
}
_, err := syscall.ForkExec("./child/child", []string{"child"}, attr)
if err != nil {
fmt.Println("Error:", err)
return
}
for {
fmt.Println("hi from parent")
time.Sleep(time.Second * 10)
}
}
Child:
package main
import (
"fmt"
"os/signal"
"syscall"
"time"
)
func main() {
signal.Ignore(syscall.SIGTSTP) // golang's way to handle (ignore) signal
for {
fmt.Println("hi from child")
time.Sleep(time.Second * 5)
}
}
They are quite simple. Both just print a message to tty every 5/10 seconds. The only difference is that the child ignores the SIGTSTP (ctrl-z) signal. So when I press ctrl-z it suspends the parent but not the child. That's exactly what I expect. However, what I didn't expect is that the whole group is moved from the foreground to the background group. It contrasts with [The TTY demystified](https://www.linusakesson.net/programming/tty/) . Specifically:
> **When all processes in the foreground job have been suspended**, the
> session leader reads the current configuration from the TTY device,
> and stores it for later retrieval. The session leader goes on to
> install itself as the current foreground process group for the TTY
> using an ioctl call. Then, it prints something like "+ Stopped" to
> inform the user that a job was just suspended.
It says that only when **all processes in the foreground job have been suspended**, the session leader (shell/bash) moves the group to the background job...
Result of ps l -t /dev/pts/0
before and after ctrl-z:
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 1747467 1747441 20 0 14288 5632 do_wai Ss pts/0 0:00 bash
0 1000 1747496 1747467 20 0 1225432 1792 ep_pol Sl+ pts/0 0:00 ./parent
0 1000 1747501 1747496 20 0 1225424 1664 ep_pol Sl+ pts/0 0:00 child
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 1747467 1747441 20 0 14288 5632 do_sel Ss+ pts/0 0:00 bash
0 1000 1747496 1747467 20 0 1225432 1792 do_sig Tl pts/0 0:00 ./parent
0 1000 1747501 1747496 20 0 1225680 1792 ep_pol Sl pts/0 0:00 child
If I move the ignore (signal.Ignore(syscall.SIGTSTP)
) from the child to the parent, then everything works as it should (from my point of view). The child suspends (T), the parent resumes normally (R/S), but the group is still the foreground job.
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 1749437 1749410 20 0 14420 5632 do_wai Ss pts/0 0:00 bash
0 1000 1749957 1749437 20 0 1225448 1920 ep_pol Sl+ pts/0 0:00 ./parent
0 1000 1749962 1749957 20 0 1225412 1664 ep_pol Sl+ pts/0 0:00 child
yakog@yakog-computer:~/goprojects/parent$ ps l -t /dev/pts/0
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 1749437 1749410 20 0 14420 5632 do_wai Ss pts/0 0:00 bash
0 1000 1749957 1749437 20 0 1225448 1920 ep_pol Sl+ pts/0 0:00 ./parent
0 1000 1749962 1749957 20 0 1225668 1792 do_sig Tl+ pts/0 0:00 child
Why is this happening, what am I missing?
Asked by Yakog
(517 rep)
Jan 12, 2025, 01:36 AM
Last activity: Jan 12, 2025, 09:17 AM
Last activity: Jan 12, 2025, 09:17 AM