0

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.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
CMCDragonkai
  • 6,222
  • 12
  • 56
  • 98

1 Answers1

1

(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.

mvds
  • 45,755
  • 8
  • 102
  • 111
  • I see. When you say "fd 0 (stdin)", are you referring to the stdin of the shell itself? Otherwise, which stdin are your referring to? So when less opens a file, it actually opens /dev/tty to send output to there, and you issue ioctl on it aswell. When less opens /dev/tty, is that a connection to the stdin of the shell? – CMCDragonkai Apr 24 '16 at 07:04
  • fd 0 of the shell is the same fd 0 of child processes, unless you redirect its input. `/dev/tty` is the "controlling terminal" of the process so most of the time it's equal to fd 0 of the shell, but if you connect fd 0 to a file (say `less .profile < /dev/null`) you will see that `less` still gets your keyboard input, via `/dev/tty`. However, if you redirect the output of `less` to something not a tty (say `less .profile > /dev/null`) it will notice (using `isatty(1)` which will attempt to `ioctl()` it) and will not open `/dev/tty` and ignore stdin as well. (and behave as `cat`) – mvds Apr 24 '16 at 09:46
  • `strace` is your friend (on linux) - it shows all system calls and therefore reveals all actions of the process relating to the "outside world". Simply open a shell to do your `stty` and `less` experiments, and trace that shell from another terminal using `strace -p PID -ff -o filename -s 10240 -v` or similar, which will make a separate output file named `filename.PID` for every child process. To see the inner workings of a process use `ltrace` or a debugger. – mvds Apr 24 '16 at 09:51