setcontext
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.
Specification
setcontext is specified in POSIX.1-2001 and the Single Unix Specification, version 2, but not all Unix-like operating systems provide them. 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:
<source lang="c"> typedef struct ucontext { struct ucontext *uc_link; sigset_t uc_sigmask; stack_t uc_stack; mcontext_t uc_mcontext; ... } ucontext_t; </source>
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.setcontextdoes not return.
int getcontext(ucontext_t *ucp)
- Saves current context into
ucp. This function returns in two possible cases: after the initial call, or when a thread switches to the context inucpviasetcontextorswapcontext. Thegetcontextfunction 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, ...)
- The
makecontextfunction sets up an alternate thread of control inucp, which has previously been initialised usinggetcontext. Theucp.uc_stackmember should be pointed to an appropriately sized stack; the constantSIGSTKSZis commonly used. Whenucpis jumped to usingsetcontextorswapcontext, execution will begin at the entry point to the function pointed to byfunc, withargcarguments as specified. Whenfuncterminates, control is returned toucp.uc_link.
int swapcontext(ucontext_t *oucp, ucontext_t *ucp)
- Transfers control to
ucpand saves the current execution state intooucp.
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.
<source lang="c">
- 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 9. Each value is saved in i_from_iterator, * 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 main_context1. */
void loop(
ucontext_t *loop_context, ucontext_t *other_context, int *i_from_iterator)
{
int i;
for (i=0; i < 10; ++i) {
/* Write the loop counter into the iterator return location. */
*i_from_iterator = i;
/* Save the loop context (this point in the code) into loop_context,
* and switch to other_context. */
swapcontext(loop_context, other_context);
}
/* The function falls through to the calling context with an implicit
* setcontext(&loop_context->uc_link); */
}
int main(void) {
/* The three contexts:
* (1) main_context1 : The point in main to which loop will return.
* (2) main_context2 : The point in main to which control from loop will
* flow by switching contexts.
* (3) loop_context : The point in loop to which control from main will
* flow by switching contexts. */
ucontext_t main_context1, main_context2, loop_context;
/* The stack for the iterator function. */
char iterator_stack[SIGSTKSZ];
/* Flag indicating that the iterator has completed. */
volatile int iterator_finished;
/* The iterator return value. */
volatile int i_from_iterator;
/* Initialise the iterator context. uc_link points to main_context1, the
* point to return to when the iterator finishes. */
loop_context.uc_link = &main_context1;
loop_context.uc_stack.ss_sp = iterator_stack;
loop_context.uc_stack.ss_size = sizeof(iterator_stack);
getcontext(&loop_context);
/* Fill in loop_context so that it makes swapcontext start loop. The
* (void (*)(void)) typecast is to avoid a compiler warning but it is
* not relevant to the behaviour of the function. */
makecontext(&loop_context, (void (*)(void)) loop,
3, &loop_context, &main_context2, &i_from_iterator);
/* Clear the finished flag. */
iterator_finished = 0;
/* Save the current context into main_context1. When loop is finished,
* control flow will return to this point. */
getcontext(&main_context1);
if (!iterator_finished) {
/* Set iterator_finished so that when the previous getcontext is
* returned to via uc_link, the above if condition is false and the
* iterator is not restarted. */
iterator_finished = 1;
while (1) {
/* Save this point into main_context2 and switch into the iterator.
* The first call will begin loop. Subsequent calls will switch to
* the swapcontext in loop. */
swapcontext(&main_context2, &loop_context);
printf("%d\n", i_from_iterator);
}
}
return 0;
} </source>
NOTE: this example is not consistent with the manual page or the specification[1]. 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)). Theoretically these problems can be worked around, but the process for doing so is not portable either.
References
External links
- System V Contexts - The GNU C Library Manual
- Template:Man
- setcontext - get/set current user context FreeBSD man page.
If you like SEOmastering Site, you can support it by - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 and more...