NAME
makecontext_quick
,
swapcontext_quick
,
setcontext_quick
—
quickly modify and exchange user thread
contexts
LIBRARY
library “libc”
SYNOPSIS
#include
<ucontext.h>
void
makecontext_quick
(ucontext_t
*ucp);
void
swapcontext_quick
(ucontext_t
*oucp, ucontext_t
*nucp);
void
setcontext_quick
(ucontext_t
*ucp);
DESCRIPTION
The quick context functions work similarly to the non-quick context functions but are designed for proper coroutine operation and synchronous switching. The signal mask is not adjusted in any manner by these routines, no system calls are made, and scratch registers are not required to be retained across calls.Since no system calls need to be made and the FP state (being scratch across a procedure call) does not need to be saved or restored, these switching functions are at least 10 times faster than the non-quick versions. In addition, callers can setup quick contexts for cofunction chaining (when one cofunction return-chains to another), and for circular cofunction chaining loops, avoiding the need to save any register state at all in those configurations.
The
makecontext_quick
()
function initializes all fields of the passed-in context except
ucp->uc_stack
,
ucp->uc_cofunc
, and
ucp->uc_arg
. All other structural fields will be
zerod. Note that ucp->uc_link
will also be zerod
for safety.
The caller must pre-initialize the uc_stack fields.
ucp->uc_cofunc
, and
ucp->uc_arg
should be initialized prior to making
any context switches. This function will set the context up to call the
cofunction as ucp->uc_cofunc(ucp,
ucp->uc_arg)
. Note that this calling format is different from the
non-quick context calls.
If the cofunction returns the wrapper will automatically
reinitialize the context to reissue a cofunction call and then call the next
cofunction via ucp->uc_link
. If the link field is
NULL, the wrapper issues an exit(0)
. If the linkages
return to the ucontext, the cofunction call is reissued. The
ucp->uc_cofunc
, and
ucp->uc_arg
fields may be adjusted at any time to
change the cofunction being called. Using the auto-linkage feature avoids
saving register state on cofunction return and is the absolute quickest
context switch possible, almost as fast as a normal procedure call would
be.
The
setcontext_quick
()
function throws away the current context and switches to the target context.
Again, the signal mask is not touched and scratch registers are not saved.
If you desire to switch to a signal stack ucontext you must use the normal
setcontext
()
function and not this one. This function is designed for synchronous
switching only.
The
swapcontext_quick
()
function saves the current register state and switches to the target
context. This function returns when the old context is resumed. Again, the
signal mask is not touched and scratch registers are not saved. If you
desire to switch to a signal stack ucontext you must use the normal
swapcontext
()
function and not this one. It is acceptable to mix normal context functions
with quick functions as long as you understand the ramifications.
There is no quick version for
getcontext
()
on purpose.
RETURN VALUES
These functions have no return value.
EXAMPLES
/* * quick context test program */ #include <sys/types.h> #include <sys/stat.h> #include <sys/file.h> #include <ucontext.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <assert.h> #define LOOPS 100000000L static void test1(ucontext_t *ucp, void *arg); static void test2(ucontext_t *ucp, void *arg); static void test3(ucontext_t *ucp, void *arg); int main(int ac, char **av) { ucontext_t ucp1; ucontext_t ucp2; ucontext_t ucp3; ucp1.uc_stack.ss_sp = malloc(32768); ucp1.uc_stack.ss_size = 32768; ucp1.uc_cofunc = test1; ucp1.uc_arg = (void *)(intptr_t)1; makecontext_quick(&ucp1); ucp2.uc_stack.ss_sp = malloc(32768); ucp2.uc_stack.ss_size = 32768; ucp2.uc_cofunc = test2; ucp2.uc_arg = (void *)(intptr_t)2; makecontext_quick(&ucp2); ucp3.uc_stack.ss_sp = malloc(32768); ucp3.uc_stack.ss_size = 32768; ucp3.uc_cofunc = test3; ucp3.uc_arg = (void *)(intptr_t)3; makecontext_quick(&ucp3); ucp1.uc_link = &ucp2; ucp2.uc_link = &ucp3; ucp3.uc_link = &ucp1; setcontext_quick(&ucp1); } long global_counter; static void test1(ucontext_t *ucp, void *arg) { if ((intptr_t)ucp->uc_arg == 1) { printf("test1 entered for first time\n"); ucp->uc_arg = (void *)(intptr_t)0; } } static void test2(ucontext_t *ucp, void *arg) { if ((intptr_t)ucp->uc_arg == 2) { printf("test2 entered for first time\n"); ucp->uc_arg = (void *)(intptr_t)0; } ++global_counter; if (global_counter > LOOPS) ucp->uc_link = NULL; /* demonstrate documented exit(0) */ } static void test3(ucontext_t *ucp, void *arg) { /* entered only once */ assert((intptr_t)ucp->uc_arg == 3); printf("test3 entered for first time\n"); printf("cycle through test1, test2, test3 %d times\n", LOOPS); ucp->uc_arg = (void *)(intptr_t)0; for (;;) { swapcontext_quick(ucp, ucp->uc_link); } }
ERRORS
- [
ENOMEM
] - There is not enough stack space in ucp to complete the operation.
SEE ALSO
getcontext(3), makecontext(3), setcontext(3), swapcontext(3), ucontext(3)