DragonFly On-Line Manual Pages
MAKECONTEXT_QUICK(3) DragonFly Library Functions Manual MAKECONTEXT_QUICK(3)
NAME
makecontext_quick, swapcontext_quick, setcontext_quick -- quickly modify
and exchange user thread contexts
LIBRARY
Standard C Library (libc, -lc)
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)
DragonFly 5.5 December 21, 2015 DragonFly 5.5