MAKECONTEXT_QUICK(3)

NAME
makecontext_quick, swapcontext_quick, setcontext_quick - quickly modify and exchange user thread contexts

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)