1.\" 2.\" Copyright (c) 2015 The DragonFly Project. All rights reserved. 3.\" 4.\" This code is derived from software contributed to The DragonFly Project 5.\" by Matthew Dillon <dillon@backplane.com> 6.\" 7.\" Redistribution and use in source and binary forms, with or without 8.\" modification, are permitted provided that the following conditions 9.\" are met: 10.\" 11.\" 1. Redistributions of source code must retain the above copyright 12.\" notice, this list of conditions and the following disclaimer. 13.\" 2. Redistributions in binary form must reproduce the above copyright 14.\" notice, this list of conditions and the following disclaimer in 15.\" the documentation and/or other materials provided with the 16.\" distribution. 17.\" 3. Neither the name of The DragonFly Project nor the names of its 18.\" contributors may be used to endorse or promote products derived 19.\" from this software without specific, prior written permission. 20.\" 21.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32.\" SUCH DAMAGE. 33.\" 34.Dd December 21, 2015 35.Dt MAKECONTEXT_QUICK 3 36.Os 37.Sh NAME 38.Nm makecontext_quick , swapcontext_quick , setcontext_quick 39.Nd quickly modify and exchange user thread contexts 40.Sh LIBRARY 41.Lb libc 42.Sh SYNOPSIS 43.In ucontext.h 44.Ft void 45.Fn makecontext_quick "ucontext_t *ucp" 46.Ft void 47.Fn swapcontext_quick "ucontext_t *oucp" "ucontext_t *nucp" 48.Ft void 49.Fn setcontext_quick "ucontext_t *ucp" 50.Sh DESCRIPTION 51The quick context functions work similarly to the non-quick context functions 52but are designed for proper coroutine operation and synchronous switching. 53The signal mask is not adjusted in any manner by these routines, no system 54calls are made, and scratch registers are not required to be retained across 55calls. 56.Pp 57Since no system calls need to be made and the FP state (being scratch across 58a procedure call) does not need to be saved or restored, these switching 59functions are at least 10 times faster than the non-quick versions. 60In addition, callers can setup quick contexts for cofunction chaining 61(when one cofunction return-chains to another), and for circular cofunction 62chaining loops, avoiding the need to save any register state at all in 63those configurations. 64.Pp 65The 66.Fn makecontext_quick 67function 68initializes all fields of the passed-in context except 69.Li "ucp->uc_stack" , 70.Li "ucp->uc_cofunc" , 71and 72.Li "ucp->uc_arg" . 73All other structural fields will be zerod. 74Note that 75.Li "ucp->uc_link" 76will also be zerod for safety. 77.Pp 78The caller must pre-initialize the uc_stack fields. 79.Li "ucp->uc_cofunc" , 80and 81.Li "ucp->uc_arg" 82should be initialized prior to making any context switches. 83This function will set the context up to call the cofunction as 84.Li "ucp->uc_cofunc(ucp, ucp->uc_arg)" . 85Note that this calling format is different from the non-quick context calls. 86.Pp 87If the cofunction returns the wrapper will automatically reinitialize 88the context to reissue a cofunction call and then call the next 89cofunction via 90.Li "ucp->uc_link" . 91If the link field is NULL, the wrapper issues an 92.Li "exit(0)" . 93If the linkages return to the ucontext, the cofunction call is reissued. 94The 95.Li "ucp->uc_cofunc" , 96and 97.Li "ucp->uc_arg" 98fields may be adjusted at any time to change the cofunction being called. 99Using the auto-linkage feature avoids saving register state on cofunction 100return and is the absolute quickest context switch possible, almost as 101fast as a normal procedure call would be. 102.Pp 103The 104.Fn setcontext_quick 105function throws away the current context and switches to the target 106context. 107Again, the signal mask is not touched and scratch registers are not saved. 108If you desire to switch to a signal stack ucontext you must use the 109normal 110.Fn setcontext 111function and not this one. 112This function is designed for synchronous switching only. 113.Pp 114The 115.Fn swapcontext_quick 116function saves the current register state and switches to the target 117context. 118This function returns when the old context is resumed. 119Again, the signal mask is not touched and scratch registers are not saved. 120If you desire to switch to a signal stack ucontext you must use the 121normal 122.Fn swapcontext 123function and not this one. 124It is acceptable to mix normal context functions with quick functions 125as long as you understand the ramifications. 126.Pp 127There is no quick version for 128.Fn getcontext 129on purpose. 130.Sh RETURN VALUES 131These functions have no return value. 132.Sh ERRORS 133.Bl -tag -width Er 134.It Bq Er ENOMEM 135There is not enough stack space in 136.Fa ucp 137to complete the operation. 138.El 139.Sh EXAMPLE 140.Bd -literal 141/* 142 * quick context test program 143 */ 144#include <sys/types.h> 145#include <sys/stat.h> 146#include <sys/file.h> 147#include <ucontext.h> 148#include <stdio.h> 149#include <stdlib.h> 150#include <unistd.h> 151#include <string.h> 152#include <assert.h> 153 154#define LOOPS 100000000L 155 156static void test1(ucontext_t *ucp, void *arg); 157static void test2(ucontext_t *ucp, void *arg); 158static void test3(ucontext_t *ucp, void *arg); 159 160int 161main(int ac, char **av) 162{ 163 ucontext_t ucp1; 164 ucontext_t ucp2; 165 ucontext_t ucp3; 166 167 ucp1.uc_stack.ss_sp = malloc(32768); 168 ucp1.uc_stack.ss_size = 32768; 169 ucp1.uc_cofunc = test1; 170 ucp1.uc_arg = (void *)(intptr_t)1; 171 makecontext_quick(&ucp1); 172 173 ucp2.uc_stack.ss_sp = malloc(32768); 174 ucp2.uc_stack.ss_size = 32768; 175 ucp2.uc_cofunc = test2; 176 ucp2.uc_arg = (void *)(intptr_t)2; 177 makecontext_quick(&ucp2); 178 179 ucp3.uc_stack.ss_sp = malloc(32768); 180 ucp3.uc_stack.ss_size = 32768; 181 ucp3.uc_cofunc = test3; 182 ucp3.uc_arg = (void *)(intptr_t)3; 183 makecontext_quick(&ucp3); 184 185 ucp1.uc_link = &ucp2; 186 ucp2.uc_link = &ucp3; 187 ucp3.uc_link = &ucp1; 188 setcontext_quick(&ucp1); 189} 190 191long global_counter; 192 193static void 194test1(ucontext_t *ucp, void *arg) 195{ 196 if ((intptr_t)ucp->uc_arg == 1) { 197 printf("test1 entered for first time\en"); 198 ucp->uc_arg = (void *)(intptr_t)0; 199 } 200} 201 202static void 203test2(ucontext_t *ucp, void *arg) 204{ 205 if ((intptr_t)ucp->uc_arg == 2) { 206 printf("test2 entered for first time\en"); 207 ucp->uc_arg = (void *)(intptr_t)0; 208 } 209 ++global_counter; 210 if (global_counter > LOOPS) 211 ucp->uc_link = NULL; /* demonstrate documented exit(0) */ 212} 213 214static void 215test3(ucontext_t *ucp, void *arg) 216{ 217 /* entered only once */ 218 assert((intptr_t)ucp->uc_arg == 3); 219 printf("test3 entered for first time\en"); 220 printf("cycle through test1, test2, test3 %d times\en", LOOPS); 221 ucp->uc_arg = (void *)(intptr_t)0; 222 223 for (;;) { 224 swapcontext_quick(ucp, ucp->uc_link); 225 } 226} 227.Ed 228.Sh SEE ALSO 229.Xr getcontext 3 , 230.Xr makecontext 3 , 231.Xr setcontext 3 , 232.Xr swapcontext 3 , 233.Xr ucontext 3 234