Blame


1 f3a795ae 2021-08-03 op On UNIX when you type C-z (hold control and press ‘z’) at your terminal the program you have opened, let’s say ed(1), will be suspended and put into the background. Later, with ‘fg’ it can be bring back into foreground.
2 f3a795ae 2021-08-03 op
3 f3a795ae 2021-08-03 op But how it works?
4 f3a795ae 2021-08-03 op
5 f3a795ae 2021-08-03 op When the tty driver sees that you’ve typed control-z it’ll send a SIGTSTP signal to the process in the foreground. Then, the shell should do its part and handle the situation, usually by printing something like “Suspended $progname” and the prompt.
6 f3a795ae 2021-08-03 op
7 f3a795ae 2021-08-03 op Actually, the exact key binding is probably customizable via stty(1), but that’s not important.
8 f3a795ae 2021-08-03 op
9 f3a795ae 2021-08-03 op The tty driver is not the only one that’s entitled to send signals. Any program can send a SIGTSTP to any other program (OK, as long as they are running as the same user, or you’re root); so, for instance, you can kill ed with ‘kill -TSTP $pid’ from another terminal to achieve the same thing as pressing C-z.
10 f3a795ae 2021-08-03 op
11 f3a795ae 2021-08-03 op ## ncurses
12 f3a795ae 2021-08-03 op
13 f3a795ae 2021-08-03 op In a ideal world a program shouldn’t know anything about SIGTSTP. This is not an ideal world though. If you don’t trust me, the proof is that ed is not the most used text editor. Most interactive terminal applications uses ncurses (or similar).
14 f3a795ae 2021-08-03 op
15 f3a795ae 2021-08-03 op By calling ‘raw()’ when initialising ncurses, the program won’t receive signals for special keys (like control-c, control-z, …), so it can handle those keys by itself. (Think how funny must be running emacs in a terminal and seeing it being killed every time you press control-c.)
16 f3a795ae 2021-08-03 op
17 f3a795ae 2021-08-03 op So, how can ncurses applications (like vi, tmux & co) suspend themselves? The answer is pretty easy given the context, yet it took me a while to figure it out:
18 f3a795ae 2021-08-03 op
19 f3a795ae 2021-08-03 op ```C snippet that shows how to suspend the current program and give the control back to the shell.
20 f3a795ae 2021-08-03 op #include <ncurses.h>
21 f3a795ae 2021-08-03 op #include <signal.h>
22 f3a795ae 2021-08-03 op #include <unistd.h>
23 f3a795ae 2021-08-03 op
24 f3a795ae 2021-08-03 op /* if you’re using ncurses: */
25 f3a795ae 2021-08-03 op endwin();
26 f3a795ae 2021-08-03 op
27 f3a795ae 2021-08-03 op /* kill the current program */
28 f3a795ae 2021-08-03 op kill(getpid(), SIGSTOP);
29 f3a795ae 2021-08-03 op
30 f3a795ae 2021-08-03 op /* if you’re using ncurses, redraw the UI */
31 f3a795ae 2021-08-03 op refresh();
32 f3a795ae 2021-08-03 op clear();
33 f3a795ae 2021-08-03 op redraw_my_awesome_ui();
34 f3a795ae 2021-08-03 op ```
35 f3a795ae 2021-08-03 op
36 f3a795ae 2021-08-03 op Yes, by killing yourself. (UNIX terminology leads to funny sentences, see?)
37 f3a795ae 2021-08-03 op
38 f3a795ae 2021-08-03 op But why SIGSTOP and not SIGTSTP as previously stated? Well, the manpage for signal(3) says that SIGSTOP and SIGTSTP have the same default action, but while a SIGTSTP can be caught or ignored, SIGSTOP cannot.
39 f3a795ae 2021-08-03 op
40 f3a795ae 2021-08-03 op The astute reader may have read the kill(2) man page and saw that if pid is zero, the signal is sent to the current process; so we could have wrote ‘kill(0, SIGSTOP)’. Unfortunately, what kill(2) *exactly* says is
41 f3a795ae 2021-08-03 op
42 f3a795ae 2021-08-03 op > If pid is zero:
43 f3a795ae 2021-08-03 op > sig is sent to all processes whose group ID is equal to the process group ID of the sender, and for which the process has permission; this is a variant of killpg(3).
44 f3a795ae 2021-08-03 op
45 f3a795ae 2021-08-03 op If your program is made by multiple process, you’d stop all of them! This may be preferred, or it may not; I chosen to explicitly kill the current process (and only that!) for this very reason.
46 f3a795ae 2021-08-03 op
47 f3a795ae 2021-08-03 op ## Wrapping up
48 f3a795ae 2021-08-03 op
49 f3a795ae 2021-08-03 op It’s fun to see how things works, especially when you are able to figure it up by yourself. I was trying to handle C-z in telescope, a gemini client I’m writing, and it took me a while to understand how suspend the current process. I searched a bit the internet but everything I found boiled down to “control-z, bg/fg or kill it with SIGTSTP”; which turns out was the correct solution, but wasn’t clear to me at first. I tend to forget that I can send signals to myself.
50 f3a795ae 2021-08-03 op
51 f3a795ae 2021-08-03 op ## Some links
52 f3a795ae 2021-08-03 op
53 f3a795ae 2021-08-03 op => gemini://gemini.omarpolo.com/cgi/man/stty stty(1) manpage
54 f3a795ae 2021-08-03 op => gemini://gemini.omarpolo.com/cgi/man/2/kill kill(2) manpage
55 f3a795ae 2021-08-03 op => gemini://gemini.omarpolo.com/cgi/man/curs_inopts curs_inopts(3) manpage — talks about cbreak, raw and other interesting stuff
56 f3a795ae 2021-08-03 op => gemini://gemini.omarpolo.com/cgi/man/3/signal signal(3) manpage
57 f3a795ae 2021-08-03 op
58 f3a795ae 2021-08-03 op => //telescope.omarpolo.com Telescope