cage icon indicating copy to clipboard operation
cage copied to clipboard

Use sigsetjmp to continue cleanup after SIGTERM/SIGINT

Open matthewbauer opened this issue 4 years ago • 4 comments

This uses the non-local goto sigsetjmp function to continue cleaning up after a SIGINT or SIGTERM has been caught. Normally, SIGINT or SIGTERM signal the end of the program and cannot be ignored. We jump to the cleanup in the signal handler.

I think this handles half of the problem in https://github.com/Hjdskes/cage/issues/146

/cc @jbeich @Hjdskes

matthewbauer avatar May 15 '20 18:05 matthewbauer

I confirm, Cage now respects Ctrl+C (SIGINT) and default kill signal (SIGTERM).

jbeich avatar May 19 '20 13:05 jbeich

Can you elaborate a bit on how this works and why this is needed, @matthewbauer?

Hjdskes avatar May 24 '20 12:05 Hjdskes

The problem is that Wayland sets SIG_BLOCK (https://github.com/wayland-project/wayland/blob/df969706f4cd479a525a69a13f86589d6b313b5b/src/event-loop.c#L731). You might say this is a bug in Wayland since you would expect the event loop to exit properly, but I think there is a reason for this SIG_BLOCK in Wayland. Moreover, you might be able to override it so that SIGINT / SIGTERM are SIG_UNBLOCK, but again I'm not sure if this could negatively effect the Wayland event loop (Note: I originally assumed that SIG_BLOCK was the default behavior, but it looks like this is explicitly set in Wayland, and SIG_UNBLOCK is the default).

More info on the behavior of SIG_BLOCK / blocking signals is available here:

http://man7.org/linux/man-pages/man7/signal.7.html

setjmp saves all its scope and returns 0. When you call longjmp, the program returns to the setjmp call, this time returning non-zero, and unpacks all of the scope. This works exactly like a goto, but beyond the scope boundaries. I am unsure of the actual difference between setjmp/longjmp and sigsetjmp/siglongjmp, besides that sigsetjmp/siglongjmp is supposed to be used in signal handlers.

The alternative to the above would be making all of the state global and moving everything that is done after wl_display_run into a cleanup function. The signal handler would just call that instead of using longjmp. Basically same effect, but in this case you have to make your scope global.

matthewbauer avatar May 24 '20 16:05 matthewbauer

Thanks for the explanation @matthewbauer! The code itself makes sense and I have no concerns around that specifically, but I wonder if this is just a workaround rather than an actual solution. To my understanding, other wlroots-based compositors do not need this workaround. I cannot promise when, but I will investigate this some more before I merge your PR. Unless you beat me to it :)

Hjdskes avatar May 31 '20 13:05 Hjdskes