setcontext is a C library function that along with
getcontext allows you to perform a non-local jump from one context to another. They are often used when implementing coroutines or custom threading libraries.
setjmp provide similar functionality but
setcontext was an attempt to fix the shortcomings of these functions and standardize behaviour, although in POSIX 2008 the specification of
setcontext and related functions were removed due to the difficulty of implementing them in a truly portable manner.
In the beginning there was
setjmp would capture the current register values into a data structure and
longjmp would restore those values at a later point in program execution, causing the control flow to jump back to the point where
setjmp was called. This works fine unless the place where you are jumping from is a signal handler. In this case the problem you have is that
setjmp will not restore the signal mask so the signal you were handling will not be unmasked. To fix this functions that saved and restored the signal mask called
siglongjmp were introduced.
However, this doesn’t mean it is necessarily safe to jump out of a signal handler even if you are using
siglongjmp. The problem you will often hit is that if the signal was delivered at an arbitrary point in program execution there may be locks or other global resource that need to be deallocated. The only way to avoid this is to block the appropriate signal across any part of the code that may not behave well when interrupted in this way. Unfortunately without auditing all third party libraries that probably means you can only enable handling of such a signal across very small regions of your program.
getcontext also restore and save the signal mask and
setcontext can also be used to exit from a signal handler with the caveats expressed above. However there is another way in which signal handling and
setcontext interact. The context structure used by
getcontext is of type
ucontext_t. If you installed your signal handler using
sigaction and the
sa_handler field of
struct sigaction you get a third argument to the signal handler which is of type
void * but allows casting to
ucontext_t *. So what happens if you pass this structure to setcontext?
Well the answer is, on Linux at least, “probably nothing good”. The original definition of
setcontext specified that “program execution continues with the program instruction following the instruction interrupted by the signal”, but more recent versions of the standards removed that requirement so the result is now unspecified. Some glibc ports such as powerpc, mips and tile do support restoring signal handler created contexts in the spirit of the original specification, but the rest, including x86 and ARM do not. As such it is not possible to rely on being able to restore a signal handler created context with
setcontext on Linux. It would be interesting to know if any proprietary Unixes support restoring these contexts and if any applications actually use the functionality.
One thought on “setcontext and signal handlers”
Linux kernel: 3.11.10 x86_64
Given the following signal handler, setcontext() initially does not provoke a segment fault.
But, after handling 22 additional signals, of which only 2 left the signal handler via setcontext(), a segment fault occurred.
static void signalHandler(int signalNumber, siginfo_t *signalInfo_ptr, void *userContext_void_ptr)
if (SI_USER == signalInfo_ptr->si_code || SIGCHLD == signalNumber)
if (getpid() != signalInfo_ptr->si_pid) setcontext((ucontext_t *) userContext_void_ptr);