.\" .\" Copyright (c) 2015 The DragonFly Project. All rights reserved. .\" .\" This code is derived from software contributed to The DragonFly Project .\" by Matthew Dillon .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" 3. Neither the name of The DragonFly Project nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific, prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS .\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE .\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, .\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; .\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED .\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .Dd December 21, 2015 .Dt MAKECONTEXT_QUICK 3 .Os .Sh NAME .Nm makecontext_quick , swapcontext_quick , setcontext_quick .Nd quickly modify and exchange user thread contexts .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In ucontext.h .Ft void .Fn makecontext_quick "ucontext_t *ucp" .Ft void .Fn swapcontext_quick "ucontext_t *oucp" "ucontext_t *nucp" .Ft void .Fn setcontext_quick "ucontext_t *ucp" .Sh 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. .Pp 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. .Pp The .Fn makecontext_quick function initializes all fields of the passed-in context except .Li "ucp->uc_stack" , .Li "ucp->uc_cofunc" , and .Li "ucp->uc_arg" . All other structural fields will be zerod. Note that .Li "ucp->uc_link" will also be zerod for safety. .Pp The caller must pre-initialize the uc_stack fields. .Li "ucp->uc_cofunc" , and .Li "ucp->uc_arg" should be initialized prior to making any context switches. This function will set the context up to call the cofunction as .Li "ucp->uc_cofunc(ucp, ucp->uc_arg)" . Note that this calling format is different from the non-quick context calls. .Pp If the cofunction returns the wrapper will automatically reinitialize the context to reissue a cofunction call and then call the next cofunction via .Li "ucp->uc_link" . If the link field is NULL, the wrapper issues an .Li "exit(0)" . If the linkages return to the ucontext, the cofunction call is reissued. The .Li "ucp->uc_cofunc" , and .Li "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. .Pp The .Fn 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 .Fn setcontext function and not this one. This function is designed for synchronous switching only. .Pp The .Fn 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 .Fn swapcontext function and not this one. It is acceptable to mix normal context functions with quick functions as long as you understand the ramifications. .Pp There is no quick version for .Fn getcontext on purpose. .Sh RETURN VALUES These functions have no return value. .Sh EXAMPLES .Bd -literal /* * quick context test program */ #include #include #include #include #include #include #include #include #include #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\en"); 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\en"); 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\en"); printf("cycle through test1, test2, test3 %d times\en", LOOPS); ucp->uc_arg = (void *)(intptr_t)0; for (;;) { swapcontext_quick(ucp, ucp->uc_link); } } .Ed .Sh ERRORS .Bl -tag -width Er .It Bq Er ENOMEM There is not enough stack space in .Fa ucp to complete the operation. .El .Sh SEE ALSO .Xr getcontext 3 , .Xr makecontext 3 , .Xr setcontext 3 , .Xr swapcontext 3 , .Xr ucontext 3