22 ms·
Ctrl-C
- hkgjjgjfjfjfjf 4y ago
- jillesvangurp 4y agoA 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 https://www.baeldung.com/jvm-shutdown-hooks
- dmarinus 4y agoAfter decades of experience I learned to use ctrl-\ (break) or ctrl-z and then kill -9 %1. Hope this helps someone.
- klez 4y agoWhich is exactly what the author is saying shouldn't be needed.
- dmarinus 4y agoAuthor is talking about looking up PIDs, kill -9 %1 saves you from that.
- kcl 4y agoIt is true this improves the bad path. It ignores desired happy path cases: downstream processes, custom debugging, graceful shutdown, preserved workspaces, and so on.
- kragen 4y agoIt may not be %1; if the shell says [2]+ Stopped units it's %2. But it's also %+, %%, and just %, which is what the "+" after the [2] means. In my case %1 is evince zhegalkin-sm7433.pdf (Running, not Stopped), which I definitely do not want to kill. Plenty of people open a new terminal window for every new program they want to run, but I commonly have several "jobs" in the same window, stopped or even running. Less often now that monitors are bigger, but still.
- dingdingdang 4y agoExcellent 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/thinkingMeat.html https://www.mit.edu/people/dpolicar/writing/prose/text/think...
- drdec 4y agoI 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.)
- dingdingdang 4y agoThanks for elaborating: the ctrl-c as first port of call was assumed obvious from my side but the: " "kill INT %1" and then "kill TERM %1" before "kill KILL %1". " is good advice as progressive measures
- awild 4y agoKill9 can keep ports locked for a bit after exiting which is a quite annoying
- M9HF8wwiaAdZKEZ 4y agoAnything 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 4y agoLaugh 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 4y agoThe 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.
- codethief 4y ago> 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 4y agoThat'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).
- dgfitz 4y agoIMHO 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 4y ago> 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 4y agoAgreed. Not sure what your point is.
- M9HF8wwiaAdZKEZ 4y ago> 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 ...)
- nrabulinski 4y agoI don’t think I’ve ever encountered a CLI application which I couldn’t kill with ^C other than defunct processes
- vladvasiliu 4y agovi?
- hprotagonist 4y agoit’s the prefix for user keybinds in emacs. it shows the current line number in nano. etc.
- krallja 4y agoirb, python, bash, psql
- untitaker_ 4y agoI 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-an-interrupt-signal-in-python-when-inside-a-blocking-boost-c-me 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 4y agoThis explains so much.
- rzimmerman 4y agoDefinitely - it is a total chore to get a threaded Python program to handle Ctrl-C/SIGINT properly. Single-threaded Python handles it well - as long as you don't register a custom signal handler, Ctrl-C raises a KeyboardInterrupt exception immediately. KeyboardInterrupt is not a subclass of Exception, (it inherits from SystemExit, which inherits from BaseException directly), so any "except Exception:" clauses don't catch it. Which is the intent. This is also a primary reason to never use bare "except:" clauses (it will prevent Ctrl-C from working!). For multithreaded Python, the easiest thing to do is just mark all your threads as daemon=True, so they die if the main thread exits. When you can't do that, the best bet is some "threading.Event" and custom SIGINT handler that triggers the event. I kind of wish SIGNINT by default would raise the KeyboardInterrupt in all threads, but I'm sure there are good reasons not to.
- pdw 4y agoI'm confused. Which software is he talking about? I can't think of any program screwing up Ctrl-C in a bad way.
- quickthrower2 4y agoI 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.
- xyzzy_plugh 4y agoThis 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.
- klez 4y ago> SIGINT is really designed for interactive applications. Which are the applications the article is talking about anyway.
- nickez 4y agoIt mentions ACID compliant databases for one.
- colanderman 4y agoAgreed -- 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.
- intelVISA 4y agoNot really sure what the authorial intent is here tbh.
- cryptonector 4y ago> 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.
- fmajid 4y agoI 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.
- ape4 4y agoI thought this was going to be another C++ replacement - actually not a bad name.
- rmetzler 4y agoCurrently I find kubectl often don't really respond for CTRL-C and also can't be removed with kill -9 on MacOS.
- CoffeeCollector 4y agoWhat is a “tight C loop”?
- klez 4y agoIt's a loop with few instruction that iterates many times, written in C.
- CoffeeCollector 4y agoCan’t we have a tight loop in any language? What’s special about C here?
- josephcsible 4y agoTight 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.
- CoffeeCollector 4y agoSeems to me this says more about the programmer than the language.
- klez 4y agoThe fact that I was responding to someone asking what a tight *C* loop is, nothing more.
- g5095 4y ago"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)
- e63f67dd-065b 4y agoI'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 4y agoI'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 4y agoI 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.
- ghoward 4y agoSurprisingly, 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 https://git.yzena.com/gavin/bc [2]: https://git.yzena.com/gavin/bc/src/branch/master/NEWS.md#3-0-0 https://git.yzena.com/gavin/bc/src/branch/master/NEWS.md#3-0... [3]: https://git.yzena.com/gavin/bc/src/branch/master/manuals/development.md#async-signal-safe-115-signal-handling https://git.yzena.com/gavin/bc/src/branch/master/manuals/dev... [4]: https://git.yzena.com/gavin/bc/src/branch/master/manuals/development.md#user-content-error-handling https://git.yzena.com/gavin/bc/src/branch/master/manuals/dev...
- deleted 4y ago[deleted]
- rgbrgb 4y agoWould love if prompts fixed this so it was easy to implement in my CLI app: https://github.com/terkelg/prompts/issues/252 https://github.com/terkelg/prompts/issues/252
- aumerle 4y agoWrite your program around an event loop which if its an interactive program it already has. And read man signalfd.
- M9HF8wwiaAdZKEZ 4y agoAs 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!
- wruza 4y agoThis 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 4y agoYeah, 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 4y agoNo, 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!
- ruslan 4y agoJust 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 ?
- kragen 4y agoSIGSTOP cannot be caught and handled; you're thinking of SIGTSTP. Non-interactive programs do not need any special handling for SIGINT, and that seems to be what you're talking about. The author was talking about interactive programs like irb, bc, bash, gdb, and python, all of which behave as they desire, returning you to their REPL prompt upon receipt of SIGINT. One example of an interactive program that does not have the desired behavior is GNU Units.
- pixelbeat__ 4y agoI 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 https://www.pixelbeat.org/docs/coreutils-testing.html
- jesprenj 4y agoEven 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 4y agoREPLs for one.
- taf2 4y agoI prefer when programs listen for SIGQUIT… it makes more sense that this would be used to quit a process then SIGINT - IMO …
- teddyh 4y agoThis is a far better resource on the subject: Proper handling of SIGINT/SIGQUIT: https://www.cons.org/cracauer/sigint.html https://www.cons.org/cracauer/sigint.html
- mlhpdx 4y agoMaybe I’m missing the point, but this (essentially random example) is multithreaded (asynchronous) and gracefully handles ctrl-c. Yes, it’s a high level language that makes it easy, I guess. https://github.com/mlhpdx/SimplestLoadBalancer https://github.com/mlhpdx/SimplestLoadBalancer