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 EXAMPLES 133.Bd -literal 134/* 135 * quick context test program 136 */ 137#include <sys/types.h> 138#include <sys/stat.h> 139#include <sys/file.h> 140#include <ucontext.h> 141#include <stdio.h> 142#include <stdlib.h> 143#include <unistd.h> 144#include <string.h> 145#include <assert.h> 146 147#define LOOPS 100000000L 148 149static void test1(ucontext_t *ucp, void *arg); 150static void test2(ucontext_t *ucp, void *arg); 151static void test3(ucontext_t *ucp, void *arg); 152 153int 154main(int ac, char **av) 155{ 156 ucontext_t ucp1; 157 ucontext_t ucp2; 158 ucontext_t ucp3; 159 160 ucp1.uc_stack.ss_sp = malloc(32768); 161 ucp1.uc_stack.ss_size = 32768; 162 ucp1.uc_cofunc = test1; 163 ucp1.uc_arg = (void *)(intptr_t)1; 164 makecontext_quick(&ucp1); 165 166 ucp2.uc_stack.ss_sp = malloc(32768); 167 ucp2.uc_stack.ss_size = 32768; 168 ucp2.uc_cofunc = test2; 169 ucp2.uc_arg = (void *)(intptr_t)2; 170 makecontext_quick(&ucp2); 171 172 ucp3.uc_stack.ss_sp = malloc(32768); 173 ucp3.uc_stack.ss_size = 32768; 174 ucp3.uc_cofunc = test3; 175 ucp3.uc_arg = (void *)(intptr_t)3; 176 makecontext_quick(&ucp3); 177 178 ucp1.uc_link = &ucp2; 179 ucp2.uc_link = &ucp3; 180 ucp3.uc_link = &ucp1; 181 setcontext_quick(&ucp1); 182} 183 184long global_counter; 185 186static void 187test1(ucontext_t *ucp, void *arg) 188{ 189 if ((intptr_t)ucp->uc_arg == 1) { 190 printf("test1 entered for first time\en"); 191 ucp->uc_arg = (void *)(intptr_t)0; 192 } 193} 194 195static void 196test2(ucontext_t *ucp, void *arg) 197{ 198 if ((intptr_t)ucp->uc_arg == 2) { 199 printf("test2 entered for first time\en"); 200 ucp->uc_arg = (void *)(intptr_t)0; 201 } 202 ++global_counter; 203 if (global_counter > LOOPS) 204 ucp->uc_link = NULL; /* demonstrate documented exit(0) */ 205} 206 207static void 208test3(ucontext_t *ucp, void *arg) 209{ 210 /* entered only once */ 211 assert((intptr_t)ucp->uc_arg == 3); 212 printf("test3 entered for first time\en"); 213 printf("cycle through test1, test2, test3 %d times\en", LOOPS); 214 ucp->uc_arg = (void *)(intptr_t)0; 215 216 for (;;) { 217 swapcontext_quick(ucp, ucp->uc_link); 218 } 219} 220.Ed 221.Sh ERRORS 222.Bl -tag -width Er 223.It Bq Er ENOMEM 224There is not enough stack space in 225.Fa ucp 226to complete the operation. 227.El 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