[HN Gopher] Ctrl-C
       ___________________________________________________________________
        
       Ctrl-C
        
       Author : kcl
       Score  : 188 points
       Date   : 2022-08-05 11:26 UTC (1 days ago)
        
 (HTM) web link (kevinlawler.com)
 (TXT) w3m dump (kevinlawler.com)
        
       | ghoward wrote:
       | Surprisingly, it _is_ possible to do exactly what the author
       | wants. I know because I 've done it. However, it _is_ as
       | complicated as the author says it is.
       | 
       | The project in question is my `bc` [1].
       | 
       | Until version 3.0.0 [2], it used a "yield" architecture: every
       | loop it could enter had a check for a signal. This got tedious,
       | so I decided to make the jump to instant-ish reset.
       | 
       | I was lucky in several ways. First, `bc` is a really good program
       | to reset; you just stop it executing, wipe all data away, and ask
       | for more input with a blank slate. Second, it is single-threaded.
       | 
       | Nevertheless, it was still really difficult, especially to have
       | no memory leaks.
       | 
       | First, I had to learn how to use `sigsetjmp()` and
       | `siglongjmp()`. Yep, that was how I was going to do this. Once I
       | learned, I implemented a stack of `sigjmp_buf`'s. Then, when a
       | signal happens, each individual `sigjmp_buf` is used. This
       | allowed me to properly free memory on the way.
       | 
       | In essence, if a function had allocated memory, then it would
       | push a `sigjmp_buf` on the stack, and then when a `siglongjmp()`
       | happened, execution would go to a label where that memory would
       | be freed before continuing the jump series.
       | 
       | Then I implemented signal locks. It is safe to `siglongjmp()` out
       | of signal handler, as long as it didn't interrupt code that was
       | non-async-signal-safe. So I used signal locks for that, and when
       | "unlocking" the lock, it would check for a signal and jump. And
       | if the signal handler sees a lock, it just sets a flag and
       | returns.
       | 
       | Then I had to go through my codebase and protect every bit of
       | non-async-signal-safe code with locks. It was tedious, but the
       | result is fantastic.
       | 
       | Edit: I forgot to add that there is more information at [3] and
       | [4].
       | 
       | Nowadays, I'm working on a threaded build system, and when it
       | gets SIGINT, it sends a message to threads to stop as soon as
       | their children are done. If it receives a second, it just exits.
       | 
       | So yeah, every application is different, but it _is_ possible.
       | 
       | [1]: https://git.yzena.com/gavin/bc
       | 
       | [2]:
       | https://git.yzena.com/gavin/bc/src/branch/master/NEWS.md#3-0...
       | 
       | [3]:
       | https://git.yzena.com/gavin/bc/src/branch/master/manuals/dev...
       | 
       | [4]:
       | https://git.yzena.com/gavin/bc/src/branch/master/manuals/dev...
        
         | [deleted]
        
       | nrabulinski wrote:
       | I don't think I've ever encountered a CLI application which I
       | couldn't kill with ^C other than defunct processes
        
         | vladvasiliu wrote:
         | vi?
        
         | hprotagonist wrote:
         | it's the prefix for user keybinds in emacs.
         | 
         | it shows the current line number in nano.
         | 
         | etc.
        
         | krallja wrote:
         | irb, python, bash, psql
        
       | rgbrgb wrote:
       | Would love if prompts fixed this so it was easy to implement in
       | my CLI app: https://github.com/terkelg/prompts/issues/252
        
       | untitaker_ wrote:
       | I feel this. Signal handling in Python code is especially
       | complicated. I'm not even talking about multithreading here (not
       | like you get anything out of it anyway).
       | 
       | Python registers POSIX signal handlers, that upon SIGTERM/SIGINT,
       | set a flag. Next time the interpreter loop runs, the flag is
       | checked before the next instruction is being run and the stack is
       | unwinded.
       | 
       | When you call out to some C code, that C code may run for a long
       | time. During that time, there is no interpreter loop actually
       | looping. Therefore, all signals are ignored in principle while C
       | code runs.
       | 
       | It's possible for Python code to become uninterruptible while it
       | is calling something like pthread_join.
       | 
       | See https://stackoverflow.com/questions/39930722/how-do-i-
       | catch-...
       | 
       | Then of course, you have that on top of all the other problems
       | mentioned by the blogpost.
        
         | actionfromafar wrote:
         | This explains so much.
        
       | hkgjjgjfjfjfjf wrote:
        
       | pdw wrote:
       | I'm confused. Which software is he talking about? I can't think
       | of any program screwing up Ctrl-C in a bad way.
        
         | quickthrower2 wrote:
         | I use Firebase emulator and man that likes to carry on running
         | (or limping?) after Ctrl-C alot, hogging the port so you need
         | to hunt it down and kill it before you can start it again. Both
         | on Linux and Windows.
         | 
         | I think it is a Java (or more to the point JVM) program, not
         | sure if that has anything to do with it. In addition I believe
         | it is a lot of parallel programs running at once, or they could
         | be different threads. As there are lots of Firebase services it
         | needs to emulate.
        
       | M9HF8wwiaAdZKEZ wrote:
       | As far as I can tell, this appears to be confusing Ctrl+C
       | (SIGINT, which terminates a process, and is usually _not_
       | restartable), with Ctrl+Z (SIGTSTP, which pauses a process, and
       | is thus restartable).
       | 
       | The only software I can think of that could "restart" after a
       | Ctrl+C is usually daemons or other long-lived processes (which
       | already need to be able to "restart" after any kind of shutdown
       | and thus have significant amounts of code dedicated to
       | serializing and unserializing their internal state).
       | 
       | TFA even goes so far as to talk about memory leaks - which are
       | completely irrelevant when your process is about to exit anyway!
        
         | drdec wrote:
         | > this appears to be confusing Ctrl+C (SIGINT, which terminates
         | a process, and is usually not restartable),
         | 
         | Respectfully, you seem to be confusing SIGINT, which is an
         | interrupt signal and SIGTERM, which is a terminate signal. Many
         | processes interpret SIGINT in a way which is indistinguishable
         | from SIGTERM, but others do not (e.g. most REPLs).
        
         | wruza wrote:
         | This article is quite a roller coaster to get what it is about.
         | As far as I understand it, the author wants SIGINT to become
         | some sort of a universal "cancel" button which may or may not
         | exit a process, because the idea is to stop and rollback to a
         | nearest sensible restart point. E.g. an interactive disk
         | formatting tool may stop lenghty formatting on SIGINT but
         | wouldn't just exit. It would clean up the mess and return to
         | its menu where e.g. batch configuration happens, so a user
         | doesn't lose next steps. The author basically wants modern gui
         | features in console via signals.
        
           | mattarm wrote:
           | Yeah, and as others have pointed out already, many existing
           | interactive terminal programs handle SIGINT in this way. E.g.
           | programming language repls interrupt running code and return
           | to the top level prompt. E.g. mutt (SIGINT will cause mutt to
           | politely asks if you want to exit before doing so).
           | 
           | I think of it this way: we have both SIGINT and SIGTERM for a
           | reason. One "interrupts" and the other "terminates" and there
           | are often good reasons to handle "interrupt" differently from
           | "terminate" -- at least in interactive programs.
        
         | krallja wrote:
         | No, you misread the article.
         | 
         | Open a Ruby interpreter (`irb`). Type `i=0; loop { i += 1 }`.
         | Press Ctrl+C.
         | 
         | * Irb is still running.
         | 
         | * Your infinite loop has been stopped.
         | 
         | Type `i`:
         | 
         | * The REPL state preserved as much progress as it could when
         | you aborted the run.
         | 
         | Now do the same thing in `sh`. Now `python`. Now `psql`. All
         | handle Ctrl+C in the way the article mentioned!
        
           | thayne wrote:
           | So what is an example of an application that doesn't do this,
           | that you would want to?
        
       | jillesvangurp wrote:
       | A lot of multi threaded server software handles ctr+c just fine.
       | A lot of Java based server software have a shutdown hook, which
       | is something that you can easily add to any jvm based program
       | because it is part of the standard library. If you use Spring
       | Boot, for example, it has one and it will start shutting down
       | your Spring Context and call any destroy functions on
       | DestroyingBean implementations, which is how you can add your own
       | shut down logic in Spring.
       | 
       | Good explanation here of shutdown hooks:
       | https://www.baeldung.com/jvm-shutdown-hooks
        
       | xyzzy_plugh wrote:
       | This makes no sense. Ctrl-C is just a way to tell your terminal
       | to send a SIGINT signal to the current process. How that process
       | handles the signal is up to it! It's by definition ignorable, as
       | the author points out, but it's not rocket science to handle it
       | in a sane fashion even in a multi-threaded application. Modern
       | languages make this trivial. The author makes it sound like some
       | dark art but in reality you just have to read the manpages.
       | 
       | SIGINT is really designed for interactive applications. Most
       | processes should simply treat it like a SIGTERM unless they have
       | some sort of REPL. Unless you need graceful shutdown, most
       | processes shouldn't mask either signal. If they do, the polite
       | thing is to unmask after receiving the first signal so subsequent
       | signals immediately terminate.
        
         | colanderman wrote:
         | Agreed -- if signal handlers are too messy, `sem_post(3)`,
         | `sigwait(2)`, or `signalfd(2)` will get that control flow where
         | you want it. Then the problem is reduced to "my application
         | needs to handle a graceful shutdown event", which, though
         | possibly complex, isn't really that novel.
        
         | cryptonector wrote:
         | > it's not rocket science to handle it in a sane fashion even
         | in a multi-threaded application
         | 
         | It's not, though you need to be careful if you want to exit
         | cleanly -- you can't just exit() or _exit(). You have to get
         | all the threads to exit, and that requires a global volatile
         | sig_atomic_t flag and some way to signal all threads that might
         | be sleeping in event loops or what have you.
        
           | [deleted]
        
           | FeepingCreature wrote:
           | Sure you can just exit(), you just have to be sure that all
           | your on-disk state changes are atomic. Which you should make
           | sure of anyways.
        
           | quietbritishjim wrote:
           | A separate thread with sigwait() may be easier. Though I must
           | admit, I've rarely had to do that manually, as I'm usually
           | using a language or framework that gives an easier way to get
           | notified about signals (e.g. Python KeyboardInterrupt or
           | listeners in Boost ASIO or libuv). Aside from saving some
           | boilerplate, those also emulate equivalent signals in
           | Windows.
           | 
           | Threads waiting on event loops is exactly what you want on
           | shutdown: that's what you use to notify them to exit.
        
         | vonwoodson wrote:
         | Tried searching for your username name, but, nothing happens.
        
         | kcl wrote:
         | There is an entire world here beyond registering for a signal
         | that comment seems unaware of. Even the simplest of
         | preliminaries: registering for a signal is arguably non-trivial
         | and incorrectly specified in many places since sigaction()
         | supersedes signal().
         | 
         | > it's not rocket science to handle it in a sane fashion even
         | in a multi-threaded application. Modern languages make this
         | trivial. The author makes it sound like some dark art
         | 
         | Which language? I'll specify one so we can begin the process of
         | picking each apart. Python? There is a sibling thread
         | indicating Python issues. I don't know what the actual internal
         | status is with Python signal handling but I am guessing the
         | interpreter actually doesn't handle it correctly if I spent any
         | time digging. Do you mean apps implemented in Python? They will
         | almost certainly not be internally data-consistent. Exposing a
         | signal handling wrapper _means very little_ particularly when
         | they frequently do this by ignoring all of the bad
         | implications. I just checked Python 's docs, and not
         | surprisingly, Python guarantees you'll be stuck in tight loops:
         | https://docs.python.org/3/library/signal.html That's just one
         | gotcha of many that they probably aren't treating. This
         | dialogue is going to play out the same way regardless of which
         | language you choose.
         | 
         | Do you mean Postgres? I haven't used it recently but the last
         | comment I read on HN seemed to indicate you needed to kill it
         | in order to stop ongoing queries in at least some situations.
         | If by a stroke of luck it does support SIGINT recovery (which
         | would be great), what about the hundreds of other db
         | applications that have appeared recently? You can't just call
         | the signal handler wrapper and declare victory.
        
         | klez wrote:
         | > SIGINT is really designed for interactive applications.
         | 
         | Which are the applications the article is talking about anyway.
        
           | nickez wrote:
           | It mentions ACID compliant databases for one.
        
         | tolciho wrote:
         | The SIGINT (if the terminal is configured to generate one) goes
         | to the foreground process group, not the current process. See
         | the termios man page, look for INTR. This gets complicated in
         | shell pipelines (oh look, a process group) where one or more of
         | the tools involved are fiddling with the global terminal state,
         | in which case there may be a process group signal, or there
         | might instead be a key for some random program of the pipeline
         | to to read, which it may ignore.
         | 
         | With an important productivity app like rogue(6) there is
         | (probably) only one process in the foreground process group,
         | and curses has (probably) set the terminal to have control+c
         | either ignored or delivered to the rogue process as a key
         | event. The player probably does not want to have their rogue
         | process vanish because they hit control+c by habit, like
         | trek(6) likes to do, but someone wrote blocksig(1) as an exec
         | wrapper so that SIGINT can be ignored. With a complicated shell
         | pipeline, the player probably does want the whole thing to go
         | away, but that may be difficult depending on exactly how
         | complicated the shell pipeline is and whether any processes in
         | that pipeline are fiddling with the global terminal state.
         | (Global to the process groups and their PIDs under that
         | particular terminal, not the whole system or universe or
         | whatever. But global enough to cause problems.)
         | 
         | Opinions also vary here, some want that LISP image to never go
         | away (those emacs users, probably), others may want control+c
         | to murder the LISP image so they can go back to hacking in vi.
         | POSIX probably says something about shell pipelines and
         | control+c and such, which various shells may or may not follow,
         | exactly. Etc...
        
           | jwilk wrote:
           | > someone wrote blocksig(1)
           | 
           | Link?
        
             | tolciho wrote:
             | https://thrig.github.io/2022/08/06/control+c.html probably
             | gets you close enough
        
         | intelVISA wrote:
         | Not really sure what the authorial intent is here tbh.
        
       | pixelbeat__ wrote:
       | I agree that this is an awkward but very desirable property for a
       | system to have.
       | 
       | I was calling this "responsive idempotence" when discussing how
       | the GNU coreutils are tested:
       | 
       | https://www.pixelbeat.org/docs/coreutils-testing.html
        
       | ruslan wrote:
       | Just wonder if author is aware of SIGSTOP/SIGCONT that allows to
       | pause/resume any process gracefully ? Both signals can be caught
       | and handled.
       | 
       | Crtl-C (SIGINT), as far as I know, was used to "gracefully
       | terminate" interactive process from day zero of Unix. I cannot
       | find any use in that of what author proposes: suspend execution
       | by sending SIGINT, but then what ? Get to some process built-in
       | debugging shell ? Isn't that what GDB was made for ?
        
       | taf2 wrote:
       | I prefer when programs listen for SIGQUIT... it makes more sense
       | that this would be used to quit a process then SIGINT - IMO ...
        
       | dmarinus wrote:
       | After decades of experience I learned to use ctrl-\ (break) or
       | ctrl-z and then kill -9 %1. Hope this helps someone.
        
         | dingdingdang wrote:
         | Excellent advice, thanks for sharing. Would in turn recommend
         | using CopyQ to store this tips (and other like it) as a pinned
         | items in folder with explanations for use two years later,
         | that's how I personally stay on top of terminal kung-fu without
         | overloading the consciousness-in-meat*
         | 
         | *
         | https://www.mit.edu/people/dpolicar/writing/prose/text/think...
        
           | drdec wrote:
           | I wouldn't call this excellent advice - kill -9 will rob the
           | process of the opportunity to clean up after itself and leave
           | everything in a good state (e.g. any binary files being
           | manipulated by the application). So I would use this as a
           | last resort - start with Ctrl+C and then "kill INT %1" and
           | then "kill TERM %1" before "kill KILL %1".
           | 
           | (For those who don't know "kill KILL" is equivalent to "kill
           | -9". And despite the name "kill" is a tool for sending
           | signals to processes.)
        
         | klez wrote:
         | Which is exactly what the author is saying shouldn't be needed.
        
           | dmarinus wrote:
           | Author is talking about looking up PIDs, kill -9 %1 saves you
           | from that.
        
             | kcl wrote:
             | It is true this improves the bad path. It ignores desired
             | happy path cases: downstream processes, custom debugging,
             | graceful shutdown, preserved workspaces, and so on.
        
         | awild wrote:
         | Kill9 can keep ports locked for a bit after exiting which is a
         | quite annoying
        
           | M9HF8wwiaAdZKEZ wrote:
           | Anything can keep ports locked for a bit (if either side
           | doesn't properly close the connection). That's how TCP works.
           | Set reuseaddr on your daemon's sockets.
        
       | AshamedCaptain wrote:
       | Laugh all you want, but this is is precisely why I like "old-
       | fashioned" asynchronous exceptions (the ones which unwind the
       | stack), and ensure most programs are ready to handle a clean
       | stack unwind at practically any point inside the program (e.g.
       | asynchronous-unwind-tables).
        
         | kcl wrote:
         | The way exceptions are handled as a result of siglongjmp'ing
         | out of a signal handler is currently platform-inconsistent and
         | one of the many dark areas I alluded to. It isn't even
         | consistent on Linux between compilers.
        
       | fmajid wrote:
       | I don't have any expectations of a program doing an orderly
       | shutdown and trying to avoid corrupting files on disk when
       | interrupted by Ctrl-C.
        
       | teddyh wrote:
       | This is a _far_ better resource on the subject:
       | 
       |  _Proper handling of SIGINT /SIGQUIT_:
       | https://www.cons.org/cracauer/sigint.html
        
       | aumerle wrote:
       | Write your program around an event loop which if its an
       | interactive program it already has. And read man signalfd.
        
       | ape4 wrote:
       | I thought this was going to be another C++ replacement - actually
       | not a bad name.
        
       | jesprenj wrote:
       | Even though it makes sense from the name, SIGINT, to interrupt,
       | I've rarely seen console software "return control" to the user
       | when the signal is received.
       | 
       | What I've mostly seen in programs is a clean exit from the
       | running application, if live user input is not intended to be
       | used. Clearing a line or something similar like redrawing the
       | terminal (that's mostly Ctrl-L though) is what interactive
       | programs do, let's say shells or ncurses UI programs.
       | 
       | Whenever I made some hobby scripts that exit cleanly when
       | receiving a SIGINT, I've made a global counter of interrupts.
       | When SIGINT is received, the counter is incremented, which tells
       | the main loop to stop as soon as possible. But if this counter
       | exceeds three signals, the application would exit immediatley.
       | This may not be ideal, but CTRL-C CTRL-C CTRL-C is easier than
       | kill -9 `pgrep a.out`.
       | 
       | Like the top comment says, expecting a concrete and general
       | behaviour on different types of software for such a broad signal
       | doesn't gain wide approval.
       | 
       | What "return of control" did the author mean, on what kinds
       | software?
        
         | emmelaich wrote:
         | REPLs for one.
        
       | rmetzler wrote:
       | Currently I find kubectl often don't really respond for CTRL-C
       | and also can't be removed with kill -9 on MacOS.
        
       | e63f67dd-065b wrote:
       | I'm having trouble judging what exactly the author wants here. My
       | best reading is that he wants interactive programs to respond to
       | SIGINT not by bailing out but by terminating the current task and
       | returning to user input.
       | 
       | I'm having trouble, however, thinking of programs to which this
       | applies. I just scrolled through my shell history, and the most
       | common interactive program I've used in my history file is a
       | debugger, which handles killing the active program correctly with
       | no issues, followed by resource monitoring applications, shells,
       | etc.
       | 
       | Can somebody tell me an example command-line application where
       | there's a high degree of interactivity but is also multithreaded,
       | has DB consistency guarantees, network requests in-flight, etc?
       | I'm genuinely having trouble thinking of anything that's not a
       | REPL or vim/emacs.
        
         | drdec wrote:
         | I'm not sure that the author is exclusively talking about
         | command-line applications. The expected behaviors would make
         | sense inside IDEs, particularly if they are blocked by a modal
         | window.
        
         | mike-the-mikado wrote:
         | I think the author makes of common mistake of talking so
         | generally that readers cannot think of any specific examples.
         | 
         | He would help his case by giving specific examples of
         | problematic programs.
        
       | codethief wrote:
       | > We don't want our ctrl-c to leak memory. [...] If you allocate
       | a piece of memory, you need to store a pointer to that memory
       | from the object graph, and both of those operations need to occur
       | inside of a critical section. Otherwise, if you get interrupted
       | right after the allocation, there won't be any way to reach your
       | memory and it will leak.
       | 
       | Maybe I'm missing something here but... so what? If at the end of
       | your Ctrl+C signal handler you exit() as expected, then the OS
       | will clean up your process's memory anyway.
        
         | klez wrote:
         | That's the point: Ctrl-C shouldn't just gracefully kill the
         | process, it should interrupt the current computation and let
         | you resume your work without exiting the application. The use
         | case here is interactive applications (think a REPL, for
         | example), not commands you run, simply expect an output from
         | and then they just exit (like, say, curl).
        
           | M9HF8wwiaAdZKEZ wrote:
           | > it should interrupt the current computation and let you
           | resume your work without exiting the application
           | 
           | That's not what Ctrl+C is meant for or used for. It's used to
           | terminate the running application, not the running task
           | within that application.
           | 
           | If you want to be able to "resume your work" then you should
           | press Ctrl+Z.
           | 
           | If you want something else then the application should
           | probably be listening for some other keystroke. "Catch Ctrl+C
           | and do something else" is a pretty awful idea for the very
           | reason mentioned at the top of TFA (when you press Ctrl+C,
           | it's to get out of whatever you're stuck in, so that you
           | don't have to go open another terminal and type in killall
           | ...)
        
             | macleginn wrote:
             | > That's not what Ctrl+C is meant for or used for. It's
             | used to terminate the running application, not the running
             | task within that application.
             | 
             | I spend a lot of time running computations in REPL, and
             | sometimes I realise that I made a mistake and I don't want
             | to wait for the current operation to complete, or the
             | mistake itself is such that the operation will complete
             | only after I become old and die. In this case, I expect
             | Ctrl+C to abort the current computation and return to the
             | REPL, with the previous state (all the variable
             | assignments) intact (modulo assignments made inside the
             | loop I killed). I think a lot of people have the same
             | expectation, and it's usually satisfied in modern REPLs.
        
             | snet0 wrote:
             | You might have killed enough programs with Ctrl-C, but
             | SIGINT is an interrupt, not a kill, terminate or quit.
        
             | duped wrote:
             | If the application is a shell or REPL (an application
             | running other programs) then that is exactly what you want
             | to use CTRL-C for.
        
             | klez wrote:
             | > That's not what Ctrl+C is meant for or used for. It's
             | used to terminate the running application, not the running
             | task within that application.
             | 
             | If that's not how it should behave, how come any REPL I
             | have handy handles Ctrl-C the exact same way? i.e. it
             | doesn't exit the interpreter, it gets me back to the REPL.
             | You can try yourself by getting stuck in a while loop and
             | pressing Ctrl-C
             | 
             | Python (3) does it;
             | 
             | jshell does it;
             | 
             | guile does it;
             | 
             | csi (chicken scheme) does it;
             | 
             | sbcl does it;
             | 
             | bash does it
        
               | hnlmorg wrote:
               | Because they either fork their processes so the running
               | task is it's own process (which is how classic shells,
               | like Bash, work) or they capture ^c and interpret it to
               | behave like the classic shells do because that's the
               | behaviour people expect from shells.
               | 
               | You have to remember that Bash isn't a language like
               | Python in the sense that it's core libraries are built
               | into the Python runtime. in classic shells like bash
               | literally every command is an executable. Granted they'll
               | ship some "builtins" but they're still invoked via fork()
               | to behave like external commands. So literally every
               | 'if', 'echo' and 'for' (etc) has its own process ID in
               | Linux/UNIX. Thus you can 'kill' an 'echo'.
        
               | klez wrote:
               | > or they capture ^c and interpret it to behave like the
               | classic shells do because that's the behaviour people
               | expect from shells.
               | 
               | Which is kinda the point.
               | 
               | > So literally every 'if', 'echo' and 'for' (etc) has its
               | own process ID in Linux/UNIX. Thus you can 'kill' an
               | 'echo'.
               | 
               | Do they? Because if I try like this `while :; do echo;
               | done` and in another terminal I do `ps -x --forest` I can
               | see the original bash running but it doesn't have any
               | child process.
               | 
               | Besides, is it relevant to the discussion at hand?
        
               | hnlmorg wrote:
               | > Which is kinda the point.
               | 
               | I thought I'd get picked up on that part. My point was
               | that shells are just a UI for invoking other applications
               | (like a desktop shell but CLI). That's the precedence and
               | anything that's shell-like but doesn't follow POSIX is
               | still inclined to emulate the same behaviour of killing
               | applications because that's the behaviour that people
               | expect after decades of POSIX.
               | 
               | So it really is more about killing applications than
               | killing tasks.
               | 
               | > Do they?
               | 
               | That was the original design (there's even standalone
               | executables for those commands included in coreutils for
               | historic reasons). However Bash might have since
               | optimised out a few forks.
               | 
               | The shell I've written certainly doesn't fork() every
               | built in either. However that doesn't change how ^c's
               | behaviour was intended.
               | 
               | > Besides, is it relevant to the discussion at hand?
               | 
               | I'm talking about the behaviour for ^c and how it is
               | handed in the shell, as a direct response to your comment
               | about it. So yes. It's exactly relevant to the
               | discussion.
        
               | PaulDavisThe1st wrote:
               | > So literally every 'if', 'echo' and 'for' (etc) has its
               | own process ID in Linux/UNIX
               | 
               | echo: yes
               | 
               | if, for: no
               | 
               | Control flow statements do not execute in subshells
               | (processes) unless explicitly told to do so.
               | 
               | You may be thinking of test(1) aka [                  if
               | [ a == b ] ; then ....
               | 
               | which was originally written:                  if test a
               | == b ; then
               | 
               | test(1) is its own executable. But [ is a builtin command
               | and does not execute in a separate process.
        
           | gfodor wrote:
           | The article's point is basically proven by how many people
           | here don't even understand he's talking about this, and not
           | killing the program with Ctrl-C.
        
             | zokier wrote:
             | Rather the opposite; people have hard time understanding
             | what he is talking about because most applications that
             | people use already handle ctrl-c as author wants, so its
             | not a problem many people encounter often. So its
             | reasonable that people then think its talking about the
             | problem that many are encountering, programs that just
             | swallow ctrl-c without doing anything. This is not helped
             | by author having this bit near the beginning:
             | 
             | > More often than not I find myself having to kill the
             | running process from an external app, such as the shell,
             | after first figuring out what the process ID is.
             | 
             | See for example these sibling threads:
             | https://news.ycombinator.com/item?id=32369096
             | https://news.ycombinator.com/item?id=32367401
        
               | gfodor wrote:
               | Well maybe then it only proves people don't read the
               | articles they comment on :)
        
           | dgfitz wrote:
           | IMHO anyone launching an app via a terminal and Ctrl-C
           | killing it either is developing the app (in which case they
           | can manage the signal however they like) or they don't care
           | and just want the app to die. Any "good" repl won't let you
           | exit via Ctrl-C so that point is moot.
        
             | vermilingua wrote:
             | > Any "good" repl won't let you exit via Ctrl-C
             | 
             | And in order to achieve that, it has to take the care
             | described in TFA.
        
               | dgfitz wrote:
               | Agreed. Not sure what your point is.
        
           | codethief wrote:
           | You don't mention REPLs etc. until the very end of the
           | article:
           | 
           | > It definitely applies to interpreters, database-style
           | terminal interfaces, REPLs, consoles, calculators, command-
           | lines, and other categories I've unintentionally left out.
           | 
           | So if your article is supposed to be exclusively about those,
           | I'd suggest you make this clear right in the beginning.
        
             | klez wrote:
             | I suggest you tell this to the author, not to me :P
        
               | codethief wrote:
               | Oops, sorry, I confused you with kcl. :)
        
         | ynik wrote:
         | > If at the end of your Ctrl+C signal handler you exit() as
         | expected
         | 
         | exit() is not signal-safe; signal handlers are expected to call
         | quick_exit() or _Exit() instead.
        
       | CoffeeCollector wrote:
       | What is a "tight C loop"?
        
         | klez wrote:
         | It's a loop with few instruction that iterates many times,
         | written in C.
        
           | CoffeeCollector wrote:
           | Can't we have a tight loop in any language? What's special
           | about C here?
        
             | josephcsible wrote:
             | Tight loops in higher-level languages generally always have
             | yield points/opportunities to break provided by the
             | runtime, even if the loop itself doesn't appear to have
             | any.
        
       | g5095 wrote:
       | "More often than not I find myself having to kill the running
       | process from an external app, such as the shell, after first
       | figuring out what the process ID is."
       | 
       | Short cut here, ctrl-z to background the process, then kill -9 %1
       | to kill the first job (type jobs for the numbers)
        
       ___________________________________________________________________
       (page generated 2022-08-06 23:00 UTC)