Live data from Hacker News

Ctrl-C

kevinlawler.com

31–40 of 94 posts

Re: Ctrl-C

#31

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,…

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.

Re: Ctrl-C

#32
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...

Re: Ctrl-C

#33

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 h…

> 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]

Re: Ctrl-C

#34

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 h…

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...

Re: Ctrl-C

#35
post #3

After decades of experience I learned to use ctrl-\ (break) or ctrl-z and then kill -9 %1. Hope this helps someone.

Kill9 can keep ports locked for a bit after exiting which is a quite annoying

Re: Ctrl-C

#39
post #14

I'm confused. Which software is he talking about? I can't think of any program screwing up Ctrl-C in a bad way.

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.

Re: Ctrl-C

#40
Write your program around an event loop which if its an interactive program it already has. And read man signalfd.
Post reply on HN