3 ms·
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 proj
by ghoward 4y ago
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 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]