Sample Header Ad - 728x90

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