💾 Archived View for thrig.me › tech › control+c.gmi captured on 2024-02-05 at 10:46:13. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-04-19)
-=-=-=-=-=-=-
There seems to be various misinformation and misunderstanding about the wonderful control+c of the unix terminal floating about the Internet. Situation normal, in other words. Here's some more. One notion is that
Ctrl-C is just a way to tell your terminal to send a SIGING signal to the current process.
which could be true but probably is not. If the terminal has been set to generate a signal and if there is only one process in the foreground process group then a signal will go to the current process. The signal, however, will be sent to the foreground process group, so anytime there is more than one process, for example
$ sleep 9999 ^C
there will be multiple processes that receive an INT signal. Your shell, hopefully, blocks or ignores that signal. ktrace or such process tracing utilities may be educational here. Another approach is to fiddle around with the terminal state (which is global to the terminal and anything running under it):
$ perl -MTerm::ReadKey -e \ 'ReadMode 5;while($i++ < 3){printf "%vx\n",ReadKey 0}ReadMode 0' 3 3 3 $
Here control+c has produced no signal; the program instead has read 3 which according to ascii(7) is some etx thing. termios(4) covers this; there is an ISIG flag that "raw mode" or similar calls (ReadMode 5 in the case of this code) will toggle such that control+c generates no signal. This is typical in ncurses programs such as mutt, w3m, irssi, rogue, etc. (Note the dangling shell prompt; other shells will reset the terminal back into a better shape.)
Without raw mode the SIGINT can be observed going to a process, but not to anything else (your shell) that is blocking or ignoring the signal to the foreground process group:
$ perl -E '$SIG{INT}=sub {say "ouch!"};sleep 999' ^Couch!
ktrace would again help prove or disprove the foreground process group assertion, or we can write test code to try out our hypothesis. ktrace is problmatic used against a typical shell as typical shells these days are rather complicated beasts. Anyways, our hypothesis might be that the signal goes to a single process; so, to test, we need a parent and child process that both listen for a SIGINT.
$ make fpg && ./fpg cc -O2 -pipe -o fpg fpg.c parent 57587 child 30993 ^CSIG 2 -> 57587 SIG 2 -> 30993 $ kill -l | grep INT 2 INT Interrupt 18 TSTP Suspended
Both the parent and child reacted to a SIGINT. Now, someone could claim that the parent somehow re-broadcasts the signal to child processes. Disproving this assertion would require ktrace or a source code dive; the simpler explanation is that no such rebroadcast exists, and to note that both kill(2) and killpg(3) document means to signal an entire process group.
"Advanced Programming in the Unix Environment" is the book to read for more information about this topic, as well as the various man pages.
tags #unix #terminal