Setcontext
From Wikipedia, the free encyclopedia
- The correct title of this article is setcontext. The initial letter is shown capitalized due to technical restrictions.
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; where the latter just allows a single non-local jump up the stack, setcontext
allows the creation of multiple cooperative threads of control, each with its own stack.
[edit] Specification
Setcontext is specified in POSIX.1-2001 and SUSv2.
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:
typedef struct ucontext { struct ucontext *uc_link; sigset_t uc_sigmask; stack_t uc_stack; mcontext_t uc_mcontext; ... } ucontext_t;
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)
- This function transfers control to the context in
ucp
. Execution continues from the point at which the context was stored inucp
.setcontext
does not return.
int getcontext(ucontext_t *ucp)
- Saves current context into
ucp
. This function returns in two possible states: after the initial call, and when the context inucp
is switched to viasetcontext
orswapcontext
. Thegetcontext
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 as volatile to avoid constant propagation or other compiler optimisations.
void makecontext(ucontext_t *ucp, void *func(), int argc, ...)
- The
makecontext
function sets up an alternate thread of control inucp
, which has previously been initialised usinggetcontext
. Theucp.uc_stack
member should be pointed to an appropriately sized stack; the SIGSTKSZ constant is commonly used. Whenucp
is jumped to usingsetcontext
orswapcontext
, execution will begin at the entry point to the function pointed to byfunc
, withargc
arguments as specified. Whenfunc
terminates, control is returned toucp.uc_link
.
int swapcontext(ucontext_t *oucp, ucontext_t *ucp)
- Transfers control to
ucp
and saves the current execution state intooucp
.
The setcontext
family of functions are described in the Single Unix Specification, version 2. Not all Unix-like operating systems currently provide them.
[edit] Example
The example below demonstrates a simple 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.
#include <stdio.h> #include <stdlib.h> #include <ucontext.h> /* This is the iterator function. It is entered on the first call to * swapcontext, and loops from 0 to 10. Each value is saved in * yield_i, and then swapcontext used to return to the main loop. * The main loop prints the value and calls swapcontext to swap back into * the function. When the end of the loop is reached, the function exits, * and execution switches to the context pointed to by contextMain1 (see * below). */ static void loop(ucontext_t *contextLoop, ucontext_t *contextOther, int *yield_i) { int i; for (i = 0; i < 10; ++i) { /* Write the loop counter into the iterator return location. */ *yield_i = i; /* Save the loop context (where we are now) into contextLoop, * and switch to contextOther. */ swapcontext(contextLoop, contextOther); } /* The function falls through to the calling context with an implicit * setcontext(&contextLoop->uc_link); */ } int main(void) { /* The three contexts: * (1)contextMain1 : The point in main() to which loop() will return. * (2)contextMain2 : The point in main() to which control from loop() * will flow by switching contexts. * (3)contextLoop : The point in loop() to which control from main() * will flow by switching contexts. */ ucontext_t contextMain1, contextMain2, contextLoop; /* The stack for the iterator function. */ char stackIterator[SIGSTKSZ]; /* Flag indicating that the iterator has completed. */ volatile int iteratorNotFinished; /* The iterator return value. */ volatile int yield_i; /* Initialise the iterator context. uc_link points to contextMain1, * the point to return to when the iterator finishes. */ contextLoop.uc_link = &contextMain1; contextLoop.uc_stack.ss_sp = stackIterator; contextLoop.uc_stack.ss_size = sizeof(stackIterator); /* Further initialize the context: maybe unnecessary*/ getcontext(&contextLoop); /* Fill in contextLoop so that it informs switchcontext * to start loop(). */ makecontext(&contextLoop, (void (*) (void)) loop, 3, &contextLoop, &contextMain2, &yield_i); /* Set the incompletion flag. */ iteratorNotFinished = 1; /* Save the current context into contextMain1. * When loop() is finished, control flow * will return to this point. */ getcontext (&contextMain1); if (iteratorNotFinished) { /* Set iteratorNotFinished to 0 so that when the previous * getcontext is returned to via uc_link, the above * if is false and the iterator is not restarted. */ iteratorNotFinished = 0; while (1) { /* Save this point into contextMain2 and switch into the * iterator; the first call will begin loop, * subsequent calls will switch to the swapcontext * in the function. */ swapcontext (&contextMain2, &contextLoop); printf ("%d\n", yield_i); } } return 0; }
[edit] External links
- System V Contexts - The GNU C Library Manual
- Linux man page on die.net : get/set current user context –