[HN Gopher] Beyond Ctrl-C: The dark corners of Unix signal handling
___________________________________________________________________
Beyond Ctrl-C: The dark corners of Unix signal handling
Author : PuercoPop
Score : 147 points
Date : 2024-09-04 19:24 UTC (4 days ago)
(HTM) web link (sunshowers.io)
(TXT) w3m dump (sunshowers.io)
| chrsig wrote:
| My favorite signal surprise was running nginx and/or httpd in the
| foreground and wondering why on earth it quit whenver i resized
| the window.
|
| Turns out, they use SIGWINCH (which is sent on WINdow CHange) for
| graceful shutdown.
|
| It's a silly, silly problem.
| eadmund wrote:
| > Turns out, they use SIGWINCH (which is sent on WINdow CHange)
| for graceful shutdown.
|
| That's ... that's even worse than people who send errors with
| an HTTP 200 response code.
| chrsig wrote:
| y'know...what really is an error, anyway?
| thebruce87m wrote:
| For what is an error, if not a success at failing?
| chrsig wrote:
| Exactly. Gotta be happy you got a response at all!
| aunderscored wrote:
| Disagree. Annoyingly there is a reasonable case for 200 but
| with an error, if http is your transport but not your
| application, then 200 says "yes, the message was transfered
| and understood correctly, here is your response" which may be
| an error response from the application
| Izkata wrote:
| For example: Apache (httpd) replaces the 4xx and 5xx
| response body with its own content instead of whatever
| you'd returned from an external handler like wsgi. You have
| to use a 2xx (except for 204) to get a relevant error
| message back out.
| AdieuToLogic wrote:
| > For example: Apache (httpd) replaces the 4xx and 5xx
| response body with its own content instead of whatever
| you'd returned from an external handler like wsgi.
|
| This is the default behavior. Apache httpd can be
| configured to produce different responses by way of
| ErrorDocument[0]. From the documentation:
| Customized error responses can be defined for any HTTP
| status code designated as an error condition - that is,
| any 4xx or 5xx status.
|
| HTH
|
| 0 - https://httpd.apache.org/docs/trunk/custom-error.html
| jjnoakes wrote:
| Even with custom error documents configured in the web
| server, you still lose the application-specific (and
| probably request- and error-specific) message generated
| by the application itself.
| Izkata wrote:
| Yeah, this is how we ran across it - whoever originally
| wrote a particular feature was trying to do the right
| thing by using an HTTP error code, but with a message
| that would be presented to the user about why that
| operation failed. A generic response wouldn't work, there
| were multiple possible reasons all fixable by the user,
| and tying a whole error code to one specific feature
| would've probably been a bad idea anyway.
| Groxx wrote:
| Which is why "you resized the terminal window, clearly you
| meant to shut down this web server" is _even crazier_ , yes
| aunderscored wrote:
| Indeed. That is _particularly_ good at violating the
| principle of least astonishment
| thezilch wrote:
| That's ... not what most people are doing. People send
| _application_ errors on HTTP 200 response codes, because HTTP
| response codes are for HTTP and not applications. Most "REST"
| libraries and webdev get this wrong, building ever more
| fragile web services.
| ChocolateGod wrote:
| Applications using status codes is useful because it can
| tell browsers and load balancers to not cache the page in a
| uniform way.
| thayne wrote:
| Why? That's what SIGTERM is for.
| chrsig wrote:
| No clue what the decision making process was.
|
| There's a bug report for httpd dating back to 2011[0]. The
| nginx mailling list also has a grumpy person contemporary
| with that[1].
|
| My guess is someone thought "httpd is a server running
| somewhere without a monitor attached, why on earth would it
| get a SIGWINCH!? surely it's available to use for something
| completely different", not considering users running it in
| the foreground during development. Nginx probably followed
| suit for convention, but that's pure speculation on my part.
|
| Also that was before docker really took off (I'm not sure if
| it was around in 2011 yet; still in it's infancy maybe).
| Running it in the foreground didn't happen as much yet.
| People were still using wamp or installing it via apt and
| restarting via sudo.
|
| [0] https://bz.apache.org/bugzilla/show_bug.cgi?id=50669
|
| [1] https://mailman.nginx.org/pipermail/nginx/2011-August/028
| 640...
| hulitu wrote:
| > why on earth would it get a SIGWINCH!?
|
| Reminds me of those "/* not reached */" stories.
| ibash wrote:
| I tried to find out why.
|
| Unfortunately the change that introduces it predates the
| official release by a few months. And predates the mailing
| list by about a year:
|
| https://trac.nginx.org/nginx/changeset/5238e93961a189c13eeff.
| ..
| chrsig wrote:
| ok, I found a commit in 2005, coming about because
| linuxthreads was interfering with the SIGUSR1 signal.
|
| It looks like they wound up making it platform specific, so
| BSDs and unix like operating systems might still use
| SIGUSR1.
|
| https://github.com/apache/httpd/commit/395896ae8d19bbea10f8
| 2...
| lolinder wrote:
| They use SIGWINCH for gracefully shutting down workers but
| not the main process [0]. SIGQUIT is used for a graceful
| shutdown and SIGTERM for a sort of graceful shutdown (with
| timeouts).
|
| SIGWINCH is apparently used for an online upgrade [1].
| Because it only shuts the workers down you can quickly
| transition back to the old binary and old configuration if
| there's a problem, even after upgrading the binary or config
| stored on the hard drive.
|
| I'm sure there are other ways to get a similar capability,
| but this set of signals is apparently what they came up with.
|
| [0] http://nginx.org/en/docs/dev/development_guide.html#proce
| sse...
|
| [1] https://www.digitalocean.com/community/tutorials/how-to-
| upgr...
| ykonstant wrote:
| I don't know whether to laugh or cry.
| chrsig wrote:
| definitely laugh! life's too short, you'll never get out
| alive :)
| efxhoy wrote:
| I recently wrote a little data transfer service in python that
| runs in ECS. When developing it locally it was easy to handle
| SIGINT: try write a batch, except KeyboardInterrupt, if caught
| mark the transfer as incomplete and finally commit the change and
| shut down.
|
| But there's no exception in python to catch for a SIGTERM, which
| is what ECS and other service mangers send when it's time to shut
| down. So I had to add a signal handler. Would have been neat if
| SIGTERM could be caught like SIGINT with a "native" exception.
| Spivak wrote:
| I mean you can just have the signal handler throw StopRequested
| in your Python boilerplate and never think about it again.
|
| One common pattern is raising KeyboardInterrupt from your
| handler so it's all handled the same.
| mananaysiempre wrote:
| from signal import SIGTERM, raise_signal, signal import
| sys # for excepthook class Terminate(BaseException):
| pass def _excepthook(type, value, traceback):
| if not issubclass(type, Terminate): return
| _prevhook(type, value, traceback) # If a Terminate
| went unhandled, make sure we are killed # by SIGTERM
| as far as wait(2) and friends are concerned.
| signal(SIGTERM, _prevterm) raise_signal(SIGTERM)
| _prevhook, sys.excepthook = sys.excepthook, _excepthook
| def terminate(signo=SIGTERM, frame=None):
| signal(SIGTERM, _prevterm) raise Terminate
| _prevterm = signal(SIGTERM, terminate)
| layer8 wrote:
| > Another common extension is to use what is sometimes called a
| double Ctrl-C pattern. The first time the user hits Ctrl-C, you
| attempt to shut down the database cleanly, but the second time
| you encounter it, you give up and exit immediately.
|
| This is a terrible behavior, because users tend to hit Ctrl-C
| multiple times without intending anything different than on a
| single hit (not to mention bouncing key mechanics and short key
| repeat delays). Unclean exits should be reserved for SIGQUIT
| (Ctrl-\\) and SIGKILL (by definition).
| bcrl wrote:
| That shouldn't matter. Your database should be consistent in
| the face of an unclean exit. ACID has been around for a _long_
| time.
| tripdout wrote:
| If you don't know about it, sure, but I find it's kind of
| convenient to get a safe shutdown and then be able to easily
| say "I don't care, just stop this program" without needing a
| separate kill -9 command or something.
| layer8 wrote:
| As I wrote, Ctrl-\ should do the trick. And it's just not
| practical having to know which program applies the double
| pattern, and having to train yourself to not accidentally hit
| Ctrl-C twice.
| __MatrixMan__ wrote:
| My brush with the double-ctrl-C pattern was in a place that
| wrote a lot of Java. It was generally frowned on to write
| any code that relied on signals which windows users can't
| send, and if I recall, Java made it quite difficult anyhow.
|
| Windows does have a tradition of using ctrl-c to quit
| though, so SIGINT ends up being one of the few that you can
| use in both places. It's not pretty, but giving it a
| different meaning based on how many times you've ordered it
| seems like a somewhat natural next step, if a hacky one.
| wombatpm wrote:
| Kids these day. Try resetting server windows on a sgi.
|
| Subject: -42- How can I restart the X server? Date: 10 Sep
| 1995 00:00:01 EST To restart the X server
| (Xsgi) once, do any one of the following (in increasing
| order of brutality): - killall -TERM Xsgi -
| hold down the left-Control, left-Shift, F12 and keypad slash
| keys (this is fondly known as the "Vulcan Death
| Grip") - /usr/gfx/stopgfx; /usr/gfx/startgfx -
| reboot To restart the X server every time someone
| logs out of the console, edit /var/X11/xdm/xdm-config,
| change the setting of
| "DisplayManager._0.terminateServer" from "False" to "True"
| and do 'killall -HUP xdm'.
| jcelerier wrote:
| > Unclean exits should be reserved for SIGQUIT (Ctrl-\\) and
| SIGKILL (by definition).
|
| I don't know how it works on your keyboard but on french
| layout, Ctrl-\ is a two-hands, three-fingers, very unpleasant
| on the wrist, keyboard shortcut. Not a chance I'd use that for
| such a common operation.
| Sophira wrote:
| While on UK keyboards it's the opposite "problem" - the left
| Ctrl key and the \ key are right next to each other (making
| it potentially a one-finger operation), which is the opposite
| of how a US keyboard is laid out (where Ctrl-\ was presumably
| intended to need to be a two-handed, two-finger operation).
| mananaysiempre wrote:
| stty quit ^] ?
| Izkata wrote:
| > which is the opposite of how a US keyboard is laid out
| (where Ctrl-\ was presumably intended to need to be a two-
| handed, two-finger operation).
|
| We have a right Ctrl, so one-hand two-finger.
| LtWorf wrote:
| two handed operations shouldn't exist.
| remram wrote:
| I think the point is that it is not to be a common operation.
| jcelerier wrote:
| well I don't know, it feels like I must mash ctrl-c twenty
| times per day on average at least
| mananaysiempre wrote:
| The byte that sends SIGQUIT is very much configurable with
| stty quit ^X , but unfortunately X has to be a-z or one of
| \\]^_ (that is, 0x41 through 0x5F except 0x5B = [ which would
| conflict with other uses of ESC = ^[ = 0x1B) because of how
| the Ctrl modifier traditionally works. Looking at a map of
| AZERTY, I don't see any good options, but you may still want
| to experiment.
| cperciva wrote:
| I map SIGQUIT to ^Q because that's the easiest to remember.
| glandium wrote:
| I suppose you never hit CTRL+S by accident?
| cperciva wrote:
| Rarely enough that needing to open another terminal and
| use kill to send a signal doesn't bother me.
| kzrdude wrote:
| stty -ixon
|
| Make sure that thing is disabled
| marcosdumay wrote:
| I like that Konlose defaults into disabling that thing.
| And also that there is a visual sign of the terminal
| being stopped.
| jks wrote:
| Curiously, on many terminal emulators the following work:
|
| Ctrl-2 = Ctrl-@ = NUL byte
|
| Ctrl-3 = Ctrl-[ = ESC
|
| Ctrl-4 = Ctrl-\ = default for SIGQUIT
|
| Ctrl-5 = Ctrl-] = jump to definition in vim
|
| Ctrl-6 = Ctrl-^ = mosh escape key
|
| Ctrl-7 = Ctrl-_ = undo in Emacs
|
| I think these probably originate in xterm.
| bonzini wrote:
| In the Meson build system's test harness, a single Ctrl-C
| terminates the longest running test with a SIGTERM; while three
| Ctrl-C in a second interrupt the whole run as if you sent _the
| harness_ a SIGTERM. This was done because it 's not uncommon
| that there are hundreds of tests left to run and you have seen
| what you want, and it's useful to have an intuitive shortcut
| for that case.
|
| However, in both cases it's a clean shutdown, all running are
| terminated and the test report is printed.
| marcosdumay wrote:
| It's worse, because there are languages that encode
| interruption into the error handling functionality, so it's
| common that people mismanage their errors and programs require
| several Ctrl-C presses to actually reach the interruption
| handler.
|
| What means that you have to memorize a list of "oh, this
| program needs Ctrl-C 3 times; oh, this program must only
| receive Ctrl-C once!"... I don't know of any "oh, this program
| needs Ctrl-C exactly 2 times", but it's an annoying
| possibility.
| wongarsu wrote:
| Any software I've come across that uses intentional double
| ctrl-c shows a message after the first ctrl-c. Something to
| the effect of "shutting down gracefully, press ctrl-c again
| for immediate shutdown".
|
| Hence you can just press it once and wait half a second, if
| no message to this effect appears you can spam ctrl-c.
| Levitating wrote:
| They can print a message that states that it is attempting to
| quit cleanly but can be forced to quit by pressing Ctrl+C
| another time(s). Unison does this.
| cperciva wrote:
| The article doesn't mention the most useful of all signals:
| SIGINFO, aka "please print to stderr your current status". Very
| useful for tools like dd and tar.
|
| Probably because Linux doesn't implement it. Worst mistake Linus
| ever made.
|
| Also, it talks about self-pipe but doesn't mention that self-
| _socket_ is much better since you can 't select on a pipe.
| fragmede wrote:
| _dd_ prints out status when sent SIGUSR1, but yeah that would
| be cool if other utilities did that as well off SIGINFO.
| cperciva wrote:
| And does ^T map to SIGUSR1? That's the other thing which
| makes it so useful in BSD.
| saagarjha wrote:
| You wouldn't want it to, because the default behavior for
| SIGUSR1 is to terminate.
| cperciva wrote:
| Exactly. Whereas on BSD hitting ^T is (a) very likely to
| print useful information, and (b) if it doesn't do that,
| won't do anything at all.
| epcoa wrote:
| > self-socket is much better since you can't select on a pipe.
|
| This needs further explanation. Why can't you select on a pipe?
| You certainly can use select/poll on pipes in general and I'm
| not sure of any reason in particular they won't work for the
| self pipe notification.
|
| Its even right in the original:
| https://cr.yp.to/docs/selfpipe.html
| cperciva wrote:
| Oops, brainfart. Sadly it's too late for me to edit that
| comment.
|
| Yes, you can select just fine on pipes. What I was thinking
| of is that _recv_ and _send_ doesn 't work on pipes, and
| asynchronous I/O frameworks typically want to use send/recv
| rather than write/read because the latter don't have a flags
| parameter.
___________________________________________________________________
(page generated 2024-09-08 23:01 UTC)