From the question:
Is it good programming practice to use setjmp and longjmp in C?
Two of the comments left said:
"You can't throw an exception in a signal handler, but you can do a longjmp safely -- as long as you know what you are doing. – Dietrich Epp Aug 31 at 19:57 @Dietrich: +1 to your comment. This is a little-known and completely-under-appreciated fact. There are a number of problems that cannot be solved (nasty race conditions) without using longjmp out of signal handlers. Asynchronous interruption of blocking syscalls is the classic example."
I was under the impression that signal handlers were called by the kernel when it encountered an exceptional condition (e.g. divide by 0). Also, that they're only called if you specifically register them.
This would seem to imply (to me) that they aren't called through your normal code.
Moving on with that thought... setjmp and longjmp as I understand them are for collapsing up the stack to a previous point and state. I don't understand how you can collapse up a stack when a signal handler is called since its called from the Kernel as a one-off circumstance rather than from your own code. What's the next thing up the stack from a signal handler!?
In most systems a signal handler has it's own stack, separate from the main stack. That's why you could longjmp out of a handler. I think it's not a wise thing to do though.
longjmp
does not perform normal stack unwinding. Instead, the stack pointer is simply restored from the context saved bysetjmp
.Here is an illustration on how this can bite you with non-async-safe critical parts in your code. It is advisable to e.g. mask the offending signal during critical code.
The way the kernel "calls" a signal handler is by interrupting the thread, saving the signal mask and processor state in a
ucontext_t
structure on the stack just beyond (below, on grows-down implementations) the interrupted code's stack pointer, and restarting execution at the address of the signal handler. The kernel does not need to keep track of any "this process is in a signal handler" state; that's entirely a consequence of the new call frame that was created.If the interrupted thread was in the middle of a system call, the kernel will back out of the kernelspace code and adjust the return address to repeat the system call (if
SA_RESTART
is set for the signal and the system call is a restartable one) or putEINTR
in the return code (if not restartable).It should be noted that
longjmp
is async-signal-unsafe. This means it invokes undefined behavior if you call it from a signal handler if the signal interrupted another async-signal-unsafe function. But as long as the interrupted code is not using library functions, or only using library functions that are marked async-signal-safe, it's legal to calllongjmp
from a signal handler.Finally, my answer is based on POSIX since the question is tagged
unix
. If the question were just about pure C, I suspect the answer is somewhat different, but signals are rather useless without POSIX anyway...You can't use
longjmp
to get out of a signal handler.The reason for this is that
setjmp
only saves the resources (process registers) etc. that the calling-convention specifies that should be saved over a plain function call.When an interrupt occurs, the function being interrupted may have a much larger state, and it will not be restored correctly by
longjmp
.