[apue] use Ctrl+S to stop the output without suspending the foreground process

Keywords: Linux shell

Before that, we always knew to use Ctrl+Z to suspend the foreground process to prevent the process from running, and then we can switch the background process to the foreground through the job control (jobs / fg N) of the shell to continue running.

Recently, I learned a new method. For foreground processes with console output, you can use Ctrl+S to STOP the output of a process, so as to pause the process.

You can then restart the (START) process output by using Ctrl+Q or entering any character to continue.

 

Seeing this method, I immediately thought of writing a script to verify it:

deadloop.sh

1 #! /bin/sh
2 var=1
3 while :
4 do
5   echo this is $var
6   var=$(($var+1))
7   usleep 100000
8 done

 

This script outputs a log "this is N" every 100 milliseconds, where N is the log sequence number, which can help us determine whether there is output loss between a pause and a restart.

During the operation, press Ctrl+S, and the output is paused as expected:

>./deadloop.sh 
this is 1
this is 2
this is 3
this is 4

 

 

Press Ctrl+Q again to continue the output until you press Ctrl+Z to suspend the process:

>./deadloop.sh 
this is 1
this is 2
this is 3
this is 4
this is 5
this is 6
this is 7
this is 8
this is 9
this is 10
this is 11
^Z
[1]+  Stopped                 ./deadloop.sh
>

 

 

First of all, you can see that the output sequence number after the restart can be connected with that before the restart, so there is no output loss in the middle, that is, the process is suspended, not just the output is stopped.

Secondly, when pressing Ctrl+Z, the terminal will echo ^ Z, while when pressing Ctrl+S or Ctrl+Q, the terminal will not echo anything.

 

So we focus on comparing the process state when pressing Ctrl+S with that when pressing Ctrl+Z to see the difference between the two pause modes.

Use the ps command to view the status of the following two pauses:

Ctrl+S

>ps xfo pid,ppid,pgid,sid,tpgid,suid,euid,user,stat,tty,command
PID PPID PGID SID TPGID SUID EUID USER STAT TT COMMAND 6653 6652 2786 2786 -1 500 500 yunhai S ? \_ gnome-pty-helper 6655 6652 6655 6655 6655 500 500 yunhai Ss+ pts/0 \_ /bin/bash 12539 6652 12539 12539 16673 500 500 yunhai Ss pts/1 \_ /bin/bash 16673 12539 16673 12539 16673 500 500 yunhai S+ pts/1 | \_ /bin/sh ./deadloop.sh 12797 6652 12797 12797 13349 500 500 yunhai Ss pts/2 \_ /bin/bash 15959 6652 15959 15959 16766 500 500 yunhai Ss pts/3 \_ /bin/bash 16766 15959 16766 15959 16766 500 500 yunhai R+ pts/3 \_ ps xfo pid,ppid,pgid,sid,tpgid,suid,euid,user,stat,tty,command

  

Ctrl+Z

>ps xfo pid,ppid,pgid,sid,tpgid,suid,euid,user,stat,tty,command
  PID  PPID  PGID   SID TPGID  SUID  EUID USER     STAT TT       COMMAND
 6653  6652  2786  2786    -1   500   500 yunhai   S    ?         \_ gnome-pty-helper
 6655  6652  6655  6655  6655   500   500 yunhai   Ss+  pts/0     \_ /bin/bash
12539  6652 12539 12539 16717   500   500 yunhai   Ss   pts/1     \_ /bin/bash
16673 12539 16673 12539 16717   500   500 yunhai   T    pts/1     |   \_ /bin/sh ./deadloop.sh
16688 16673 16673 12539 16717   500   500 yunhai   T    pts/1     |   |   \_ usleep 100000
16717 12539 16717 12539 16717   500   500 yunhai   R+   pts/1     |   \_ ps xfo pid,ppid,pgid,sid,tpgid,suid,euid,user,stat,tty,command
12797  6652 12797 12797 13349   500   500 yunhai   Ss   pts/2     \_ /bin/bash
15959  6652 15959 15959 15959   500   500 yunhai   Ss+  pts/3     \_ /bin/bash

 

 

The biggest difference you can see is that the state of a process stopped by Ctrl+Z is suspended ('T '), while the state of a process stopped by Ctrl+S is running ('S +').

On the other hand, when we start the stap to detect the signal transmission between processes, we can receive the following output when the Ctrl+Z stops the process:

stap_signal.sh

22       events/3         16688 usleep           20     SIGTSTP         
22       events/3         16673 deadloop.sh      20     SIGTSTP        
16673    deadloop.sh      12539 bash             17     SIGCHLD        
16688    usleep           16673 deadloop.sh      17     SIGCHLD 

 

 

That is to say, SIGTSTP signal sent to the front process can be observed. When using Ctrl+S, no special signal is detected (only sigchild sent to the parent process at the end of usleep process).

 

Note: SIGCHLD here does not mean the end of deadloop.sh and usleep, but rather a notification to the parent process when it is suspended. For this, please refer to an article I wrote earlier:

[apue] waiting for subprocesses

 

During the pause, use the pstack command to view the process stack information suspended in two ways:

Ctrl+S

>pstack 16673
#0  0x00119424 in __kernel_vsyscall ()
#1  0x007a7cd3 in __write_nocancel () from /lib/libc.so.6
#2  0x007411b4 in _IO_new_file_write () from /lib/libc.so.6
#3  0x00742a90 in _IO_new_do_write () from /lib/libc.so.6
#4  0x00741c80 in _IO_new_file_overflow () from /lib/libc.so.6
#5  0x00744b2a in __overflow () from /lib/libc.so.6
#6  0x0073e0b5 in putc () from /lib/libc.so.6
#7  0x080aebb0 in echo_builtin ()
#8  0x08070c51 in ?? ()
#9  0x08072e41 in ?? ()
#10 0x08073aa0 in execute_command_internal ()
#11 0x080747a4 in execute_command ()
#12 0x08076d89 in ?? ()
#13 0x08073a02 in execute_command_internal ()
#14 0x080747a4 in execute_command ()
#15 0x08076d89 in ?? ()
#16 0x08073a02 in execute_command_internal ()
#17 0x080747a4 in execute_command ()
#18 0x080750e4 in ?? ()
#19 0x08073bc4 in execute_command_internal ()
#20 0x080747a4 in execute_command ()
#21 0x08060857 in reader_loop ()
#22 0x0805fed9 in main ()

 

 

Ctrl+Z

>pstack 16673
#0  0x00119424 in __kernel_vsyscall ()
#1  0x00776673 in __waitpid_nocancel () from /lib/libc.so.6
#2  0x080830f2 in ?? ()
#3  0x0808432e in wait_for ()
#4  0x08074635 in execute_command_internal ()
#5  0x08076dcd in ?? ()
#6  0x08073a02 in execute_command_internal ()
#7  0x080747a4 in execute_command ()
#8  0x080750e4 in ?? ()
#9  0x08073bc4 in execute_command_internal ()
#10 0x080747a4 in execute_command ()
#11 0x08060857 in reader_loop ()
#12 0x0805fed9 in main ()

 

 

The former stops at write system call, and the latter stops at waitpid system call.

So the former should be suspended at the time of output, while the latter is suspended while waiting for the return of the usleep subprocess.

You can experience the difference between these two ways in details.

 

Finally, you can use Ctrl+S to stop the foreground process if you need to turn on the icon flag of the terminal. Use the previous Gadget:

[apue] a small tool for viewing the current terminal flag bit settings

 

You can check whether the input flag of the terminal has turned on this flag:

>./term
input flag 0x00006f02
    BRKINT
    ICRNL
    IMAXBEL
    IXANY
    IXON
output flag 0x00000005
    ONLCR
    OPOST
control flag 0x000004bf
    CREAD
    CSIZE
    CS6
    CS7
    CS8
    HUPCL
local flag 0x00008a3b
    ECHO
    ECHOE
    ECHOK
    ICANON
    IEXTEN
    ISIG

 

 

Generally, terminals are open. If you turn on the IXANY flag bit again, you can restart the stopped output with any key, rather than using Ctrl+Q.

Finally, there is a hidden premise that the suspended process has frequent output in the foreground, otherwise Ctrl+S is useless.

 

To sum up, today I learned a new method to suspend the running foreground process, which may be hard to catch for the operation and maintenance veteran, but it's completely new for me,

So I spent some time studying linux. I feel that linux is broad and profound, and there may be some good things hidden in it. It's worth exploring!

Posted by Kurrel on Sat, 25 Jan 2020 07:07:36 -0800