setcontext is one of a family of C library functions (the others being getcontext, makecontext and swapcontext) used for context control. The setcontext
family allows the implementation in C of advanced control flow patterns such as iterators, fibers, and coroutines. They may be viewed as an advanced version of setjmp/longjmp; whereas the latter allows only a single non-local jump up the stack, setcontext
allows the creation of multiple cooperative threads of control, each with its own stack.
Contents
Specification
setcontext
is specified in POSIX.1-2001 and the Single Unix Specification, version 2, but not all Unix-like operating systems provide them. Citing portability concerns, POSIX.1-2004 obsoleted these functions, and in POSIX.1-2008 they were removed, and POSIX Threads recommended. The functions and associated types are defined in the ucontext.h
system header file. This includes the ucontext_t
type, with which all four functions operate:
uc_link
points to the context which will be resumed when the current context exits, if the context was created with makecontext
(a secondary context). uc_sigmask
is used to store the set of signals blocked in the context, and uc_stack
is the stack used by the context. uc_mcontext
stores execution state, including all registers and CPU flags, the instruction pointer, and the stack pointer; mcontext_t
is an opaque type.
The functions are:
int setcontext(const ucontext_t *ucp)
ucp
. Execution continues from the point at which the context was stored in ucp
. setcontext
does not return.int getcontext(ucontext_t *ucp)
ucp
. This function returns in two possible cases: after the initial call, or when a thread switches to the context in ucp
via setcontext
or swapcontext
. The getcontext
function does not provide a return value to distinguish the cases (its return value is used solely to signal error), so the programmer must use an explicit flag variable, which must not be a register variable and must be declared volatile to avoid constant propagation or other compiler optimisations.void makecontext(ucontext_t *ucp, void *func(), int argc, ...)
makecontext
function sets up an alternate thread of control in ucp
, which has previously been initialised using getcontext
. The ucp.uc_stack
member should be pointed to an appropriately sized stack; the constant SIGSTKSZ
is commonly used. When ucp
is jumped to using setcontext
or swapcontext
, execution will begin at the entry point to the function pointed to by func
, with argc
arguments as specified. When func
terminates, control is returned to ucp.uc_link
.int swapcontext(ucontext_t *oucp, ucontext_t *ucp)
ucp
and saves the current execution state into oucp
.Example
The example below demonstrates an iterator using setcontext
. This form of example is unlikely to be widely seen; as setcontext
is somewhat cumbersome to use effectively, programmers writing cooperatively multitasked applications often choose to use a wrapper library such as GNU Portable Threads. Most code using setcontext
appears in such wrapper libraries, in high-level programming language implementations, or in emulators.
NOTE: this example is not consistent with the manual page or the specification. The function makecontext
requires additional parameters to be type int
, but the example passes pointers. Thus, the example may fail on 64-bit machines (specifically LP64-architectures, where sizeof(void*) > sizeof(int)
). This problem can be worked around by breaking up and reconstructing 64-bit values, but that introduces a performance penalty.
"On architectures where int and pointer types are the same size (e.g., x86-32, where both types are 32 bits), you may be able to get away with passing pointers as arguments to makecontext() following argc. However, doing this is not guaranteed to be portable, is undefined according to the standards, and won't work on architectures where pointers are larger than ints. Nevertheless, starting with version 2.8, glibc makes some changes to makecontext(3), to permit this on some 64-bit architectures (e.g., x86-64)."
For get and set context, a smaller context can be handy:
This makes an infinite loop because context holds the program counter.