Search code examples
terminalsignalszshterminal-emulatorless-unix

How does launching `less` differ from launching `cat` in ZSH with regards to the usage of alternate screen and background suspension


On my OS, by default, ZSH has the -tostop (or is the tty?).

This allows backgrounded processes to output to the shell when they have output.

Hence:

> stty -tostop
> echo 'random' >/tmp/random
> cat /tmp/random &
[1] 7588
random
[1]  + 7588 done       cat /tmp/random

Correspondingly:

> stty tostop
> echo 'random' >/tmp/random
> cat /tmp/random &
[1] 3888
[1]  + 3888 suspended (tty output)  cat /tmp/random

Reading the documentation and experimenting a bit, I discovered that ZSH has 4 types of suspended processes (you can see this by using kill -$SIGNAL $PID ; jobs):

job state              - signal that gives you job state
suspended              - SIGTSTP
suspended (signal)     - SIGSTOP
suspended (tty input)  - SIGTTIN
suspended (tty output) - SIGTTOU

This would imply that the 3888 process is receiving a SIGTTOU signal.

This all makes sense.

Now my question is that, why is it that less doesn't get affected by stty tostop or stty -tostop?

> stty tostop
> less /tmp/random &
[1] 6300
[1]  + 6300 suspended (tty output)  less --LONG-PROMPT --chop-long-lines /tmp/random

> stty -tostop
> less /tmp/random &
[1] 4808
[1]  + 4808 suspended (tty output)  less --LONG-PROMPT --chop-long-lines /tmp/random

As you can see in both cases, less is always getting suspended in the background.

Now, I know about less -X, and I also know about the alternate screen feature that terminal emulators have. In fact, you can run the above 2 commands with less -X, and it results in the same kind of suspension. Even though -X makes it not use alternate screens, less still gets suspended (tty output)!

What I want know is the actual mechanics of how less is always getting suspended with suspended (tty output), even when tostop is getting toggled, and even when -X is being toggled too. How can the shell be always sending SIGTTOU to less, unless there is some other way less is getting suspended.


Solution

  • (you don't specify your OS, but this answer is based on linux)

    Using strace you can see stty doing an ioctl on fd 0 (stdin) toggling one bit in the c_lflag value of the termios struct.

    strace also reveals that less will open /dev/tty and issue an ioctl on it to change the c_lflag.

    So less simply does the same thing as stty tostop before outputting anything.