1819d0c16SMatthew Dillon.\" 2819d0c16SMatthew Dillon.\" Copyright (c) 2015 The DragonFly Project. All rights reserved. 3819d0c16SMatthew Dillon.\" 4819d0c16SMatthew Dillon.\" This code is derived from software contributed to The DragonFly Project 5819d0c16SMatthew Dillon.\" by Matthew Dillon <dillon@backplane.com> 6819d0c16SMatthew Dillon.\" 7819d0c16SMatthew Dillon.\" Redistribution and use in source and binary forms, with or without 8819d0c16SMatthew Dillon.\" modification, are permitted provided that the following conditions 9819d0c16SMatthew Dillon.\" are met: 10819d0c16SMatthew Dillon.\" 11819d0c16SMatthew Dillon.\" 1. Redistributions of source code must retain the above copyright 12819d0c16SMatthew Dillon.\" notice, this list of conditions and the following disclaimer. 13819d0c16SMatthew Dillon.\" 2. Redistributions in binary form must reproduce the above copyright 14819d0c16SMatthew Dillon.\" notice, this list of conditions and the following disclaimer in 15819d0c16SMatthew Dillon.\" the documentation and/or other materials provided with the 16819d0c16SMatthew Dillon.\" distribution. 17819d0c16SMatthew Dillon.\" 3. Neither the name of The DragonFly Project nor the names of its 18819d0c16SMatthew Dillon.\" contributors may be used to endorse or promote products derived 19819d0c16SMatthew Dillon.\" from this software without specific, prior written permission. 20819d0c16SMatthew Dillon.\" 21819d0c16SMatthew Dillon.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22819d0c16SMatthew Dillon.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23819d0c16SMatthew Dillon.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24819d0c16SMatthew Dillon.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25819d0c16SMatthew Dillon.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26819d0c16SMatthew Dillon.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27819d0c16SMatthew Dillon.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28819d0c16SMatthew Dillon.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29819d0c16SMatthew Dillon.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30819d0c16SMatthew Dillon.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31819d0c16SMatthew Dillon.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32819d0c16SMatthew Dillon.\" SUCH DAMAGE. 33819d0c16SMatthew Dillon.\" 34819d0c16SMatthew Dillon.Dd December 21, 2015 35819d0c16SMatthew Dillon.Dt MAKECONTEXT_QUICK 3 36819d0c16SMatthew Dillon.Os 37819d0c16SMatthew Dillon.Sh NAME 38819d0c16SMatthew Dillon.Nm makecontext_quick , swapcontext_quick , setcontext_quick 39819d0c16SMatthew Dillon.Nd quickly modify and exchange user thread contexts 40819d0c16SMatthew Dillon.Sh LIBRARY 41819d0c16SMatthew Dillon.Lb libc 42819d0c16SMatthew Dillon.Sh SYNOPSIS 43819d0c16SMatthew Dillon.In ucontext.h 44819d0c16SMatthew Dillon.Ft void 45819d0c16SMatthew Dillon.Fn makecontext_quick "ucontext_t *ucp" 46819d0c16SMatthew Dillon.Ft void 470e9f503dSSascha Wildner.Fn swapcontext_quick "ucontext_t *oucp" "ucontext_t *nucp" 48819d0c16SMatthew Dillon.Ft void 49819d0c16SMatthew Dillon.Fn setcontext_quick "ucontext_t *ucp" 50819d0c16SMatthew Dillon.Sh DESCRIPTION 51819d0c16SMatthew DillonThe quick context functions work similarly to the non-quick context functions 52819d0c16SMatthew Dillonbut are designed for proper coroutine operation and synchronous switching. 53819d0c16SMatthew DillonThe signal mask is not adjusted in any manner by these routines, no system 54819d0c16SMatthew Dilloncalls are made, and scratch registers are not required to be retained across 55819d0c16SMatthew Dilloncalls. 56819d0c16SMatthew Dillon.Pp 57819d0c16SMatthew DillonSince no system calls need to be made and the FP state (being scratch across 58819d0c16SMatthew Dillona procedure call) does not need to be saved or restored, these switching 59819d0c16SMatthew Dillonfunctions are at least 10 times faster than the non-quick versions. 60819d0c16SMatthew DillonIn addition, callers can setup quick contexts for cofunction chaining 61819d0c16SMatthew Dillon(when one cofunction return-chains to another), and for circular cofunction 62819d0c16SMatthew Dillonchaining loops, avoiding the need to save any register state at all in 63819d0c16SMatthew Dillonthose configurations. 64819d0c16SMatthew Dillon.Pp 65819d0c16SMatthew DillonThe 66819d0c16SMatthew Dillon.Fn makecontext_quick 67819d0c16SMatthew Dillonfunction 68819d0c16SMatthew Dilloninitializes all fields of the passed-in context except 69819d0c16SMatthew Dillon.Li "ucp->uc_stack" , 70819d0c16SMatthew Dillon.Li "ucp->uc_cofunc" , 71819d0c16SMatthew Dillonand 72819d0c16SMatthew Dillon.Li "ucp->uc_arg" . 73819d0c16SMatthew DillonAll other structural fields will be zerod. 74819d0c16SMatthew DillonNote that 75819d0c16SMatthew Dillon.Li "ucp->uc_link" 76819d0c16SMatthew Dillonwill also be zerod for safety. 77819d0c16SMatthew Dillon.Pp 78819d0c16SMatthew DillonThe caller must pre-initialize the uc_stack fields. 79819d0c16SMatthew Dillon.Li "ucp->uc_cofunc" , 80819d0c16SMatthew Dillonand 81819d0c16SMatthew Dillon.Li "ucp->uc_arg" 82819d0c16SMatthew Dillonshould be initialized prior to making any context switches. 83819d0c16SMatthew DillonThis function will set the context up to call the cofunction as 84819d0c16SMatthew Dillon.Li "ucp->uc_cofunc(ucp, ucp->uc_arg)" . 85819d0c16SMatthew DillonNote that this calling format is different from the non-quick context calls. 86819d0c16SMatthew Dillon.Pp 87819d0c16SMatthew DillonIf the cofunction returns the wrapper will automatically reinitialize 88819d0c16SMatthew Dillonthe context to reissue a cofunction call and then call the next 89819d0c16SMatthew Dilloncofunction via 90819d0c16SMatthew Dillon.Li "ucp->uc_link" . 91819d0c16SMatthew DillonIf the link field is NULL, the wrapper issues an 92819d0c16SMatthew Dillon.Li "exit(0)" . 93819d0c16SMatthew DillonIf the linkages return to the ucontext, the cofunction call is reissued. 94819d0c16SMatthew DillonThe 95819d0c16SMatthew Dillon.Li "ucp->uc_cofunc" , 96819d0c16SMatthew Dillonand 97819d0c16SMatthew Dillon.Li "ucp->uc_arg" 98819d0c16SMatthew Dillonfields may be adjusted at any time to change the cofunction being called. 99819d0c16SMatthew DillonUsing the auto-linkage feature avoids saving register state on cofunction 100819d0c16SMatthew Dillonreturn and is the absolute quickest context switch possible, almost as 101819d0c16SMatthew Dillonfast as a normal procedure call would be. 102819d0c16SMatthew Dillon.Pp 103819d0c16SMatthew DillonThe 104819d0c16SMatthew Dillon.Fn setcontext_quick 105819d0c16SMatthew Dillonfunction throws away the current context and switches to the target 106819d0c16SMatthew Dilloncontext. 107819d0c16SMatthew DillonAgain, the signal mask is not touched and scratch registers are not saved. 108819d0c16SMatthew DillonIf you desire to switch to a signal stack ucontext you must use the 109819d0c16SMatthew Dillonnormal 110819d0c16SMatthew Dillon.Fn setcontext 111819d0c16SMatthew Dillonfunction and not this one. 112819d0c16SMatthew DillonThis function is designed for synchronous switching only. 113819d0c16SMatthew Dillon.Pp 114819d0c16SMatthew DillonThe 115819d0c16SMatthew Dillon.Fn swapcontext_quick 116819d0c16SMatthew Dillonfunction saves the current register state and switches to the target 1170e9f503dSSascha Wildnercontext. 1180e9f503dSSascha WildnerThis function returns when the old context is resumed. 119819d0c16SMatthew DillonAgain, the signal mask is not touched and scratch registers are not saved. 120819d0c16SMatthew DillonIf you desire to switch to a signal stack ucontext you must use the 121819d0c16SMatthew Dillonnormal 122819d0c16SMatthew Dillon.Fn swapcontext 123819d0c16SMatthew Dillonfunction and not this one. 124819d0c16SMatthew DillonIt is acceptable to mix normal context functions with quick functions 125819d0c16SMatthew Dillonas long as you understand the ramifications. 126819d0c16SMatthew Dillon.Pp 127819d0c16SMatthew DillonThere is no quick version for 128819d0c16SMatthew Dillon.Fn getcontext 129819d0c16SMatthew Dillonon purpose. 130819d0c16SMatthew Dillon.Sh RETURN VALUES 131819d0c16SMatthew DillonThese functions have no return value. 132*4a5f69f6SSascha Wildner.Sh EXAMPLES 133819d0c16SMatthew Dillon.Bd -literal 134819d0c16SMatthew Dillon/* 135a282008cSMatthew Dillon * quick context test program 136819d0c16SMatthew Dillon */ 137819d0c16SMatthew Dillon#include <sys/types.h> 138819d0c16SMatthew Dillon#include <sys/stat.h> 139819d0c16SMatthew Dillon#include <sys/file.h> 140819d0c16SMatthew Dillon#include <ucontext.h> 141819d0c16SMatthew Dillon#include <stdio.h> 142819d0c16SMatthew Dillon#include <stdlib.h> 143819d0c16SMatthew Dillon#include <unistd.h> 144819d0c16SMatthew Dillon#include <string.h> 145a282008cSMatthew Dillon#include <assert.h> 146a282008cSMatthew Dillon 147a282008cSMatthew Dillon#define LOOPS 100000000L 148819d0c16SMatthew Dillon 149819d0c16SMatthew Dillonstatic void test1(ucontext_t *ucp, void *arg); 150819d0c16SMatthew Dillonstatic void test2(ucontext_t *ucp, void *arg); 151819d0c16SMatthew Dillonstatic void test3(ucontext_t *ucp, void *arg); 152819d0c16SMatthew Dillon 153819d0c16SMatthew Dillonint 154819d0c16SMatthew Dillonmain(int ac, char **av) 155819d0c16SMatthew Dillon{ 156819d0c16SMatthew Dillon ucontext_t ucp1; 157819d0c16SMatthew Dillon ucontext_t ucp2; 158819d0c16SMatthew Dillon ucontext_t ucp3; 159819d0c16SMatthew Dillon 160819d0c16SMatthew Dillon ucp1.uc_stack.ss_sp = malloc(32768); 161819d0c16SMatthew Dillon ucp1.uc_stack.ss_size = 32768; 162819d0c16SMatthew Dillon ucp1.uc_cofunc = test1; 163a282008cSMatthew Dillon ucp1.uc_arg = (void *)(intptr_t)1; 164819d0c16SMatthew Dillon makecontext_quick(&ucp1); 165819d0c16SMatthew Dillon 166819d0c16SMatthew Dillon ucp2.uc_stack.ss_sp = malloc(32768); 167819d0c16SMatthew Dillon ucp2.uc_stack.ss_size = 32768; 168819d0c16SMatthew Dillon ucp2.uc_cofunc = test2; 169a282008cSMatthew Dillon ucp2.uc_arg = (void *)(intptr_t)2; 170819d0c16SMatthew Dillon makecontext_quick(&ucp2); 171819d0c16SMatthew Dillon 172819d0c16SMatthew Dillon ucp3.uc_stack.ss_sp = malloc(32768); 173819d0c16SMatthew Dillon ucp3.uc_stack.ss_size = 32768; 174819d0c16SMatthew Dillon ucp3.uc_cofunc = test3; 175a282008cSMatthew Dillon ucp3.uc_arg = (void *)(intptr_t)3; 176819d0c16SMatthew Dillon makecontext_quick(&ucp3); 177819d0c16SMatthew Dillon 178819d0c16SMatthew Dillon ucp1.uc_link = &ucp2; 179819d0c16SMatthew Dillon ucp2.uc_link = &ucp3; 180819d0c16SMatthew Dillon ucp3.uc_link = &ucp1; 181819d0c16SMatthew Dillon setcontext_quick(&ucp1); 182819d0c16SMatthew Dillon} 183819d0c16SMatthew Dillon 184a282008cSMatthew Dillonlong global_counter; 185819d0c16SMatthew Dillon 186819d0c16SMatthew Dillonstatic void 187819d0c16SMatthew Dillontest1(ucontext_t *ucp, void *arg) 188819d0c16SMatthew Dillon{ 189a282008cSMatthew Dillon if ((intptr_t)ucp->uc_arg == 1) { 190cc789515Szrj printf("test1 entered for first time\en"); 191a282008cSMatthew Dillon ucp->uc_arg = (void *)(intptr_t)0; 192a282008cSMatthew Dillon } 193819d0c16SMatthew Dillon} 194819d0c16SMatthew Dillon 195819d0c16SMatthew Dillonstatic void 196819d0c16SMatthew Dillontest2(ucontext_t *ucp, void *arg) 197819d0c16SMatthew Dillon{ 198a282008cSMatthew Dillon if ((intptr_t)ucp->uc_arg == 2) { 199cc789515Szrj printf("test2 entered for first time\en"); 200a282008cSMatthew Dillon ucp->uc_arg = (void *)(intptr_t)0; 201a282008cSMatthew Dillon } 202819d0c16SMatthew Dillon ++global_counter; 203a282008cSMatthew Dillon if (global_counter > LOOPS) 204a282008cSMatthew Dillon ucp->uc_link = NULL; /* demonstrate documented exit(0) */ 205819d0c16SMatthew Dillon} 206819d0c16SMatthew Dillon 207819d0c16SMatthew Dillonstatic void 208819d0c16SMatthew Dillontest3(ucontext_t *ucp, void *arg) 209819d0c16SMatthew Dillon{ 210a282008cSMatthew Dillon /* entered only once */ 211a282008cSMatthew Dillon assert((intptr_t)ucp->uc_arg == 3); 212cc789515Szrj printf("test3 entered for first time\en"); 213cc789515Szrj printf("cycle through test1, test2, test3 %d times\en", LOOPS); 214a282008cSMatthew Dillon ucp->uc_arg = (void *)(intptr_t)0; 215a282008cSMatthew Dillon 216819d0c16SMatthew Dillon for (;;) { 217819d0c16SMatthew Dillon swapcontext_quick(ucp, ucp->uc_link); 218819d0c16SMatthew Dillon } 219819d0c16SMatthew Dillon} 220819d0c16SMatthew Dillon.Ed 221*4a5f69f6SSascha Wildner.Sh ERRORS 222*4a5f69f6SSascha Wildner.Bl -tag -width Er 223*4a5f69f6SSascha Wildner.It Bq Er ENOMEM 224*4a5f69f6SSascha WildnerThere is not enough stack space in 225*4a5f69f6SSascha Wildner.Fa ucp 226*4a5f69f6SSascha Wildnerto complete the operation. 227*4a5f69f6SSascha Wildner.El 228819d0c16SMatthew Dillon.Sh SEE ALSO 229819d0c16SMatthew Dillon.Xr getcontext 3 , 230819d0c16SMatthew Dillon.Xr makecontext 3 , 231c8e38d4bSSascha Wildner.Xr setcontext 3 , 232819d0c16SMatthew Dillon.Xr swapcontext 3 , 233819d0c16SMatthew Dillon.Xr ucontext 3 234