2 .\" Copyright (c) 2015 The DragonFly Project. All rights reserved.
4 .\" This code is derived from software contributed to The DragonFly Project
5 .\" by Matthew Dillon <dillon@backplane.com>
7 .\" Redistribution and use in source and binary forms, with or without
8 .\" modification, are permitted provided that the following conditions
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
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.
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
35 .Dt MAKECONTEXT_QUICK 3
38 .Nm makecontext_quick , swapcontext_quick , setcontext_quick
39 .Nd quickly modify and exchange user thread contexts
45 .Fn makecontext_quick "ucontext_t *ucp"
47 .Fn swapcontext_quick "ucontext_t *oucp" "ucontext_t *nucp"
49 .Fn setcontext_quick "ucontext_t *ucp"
51 The quick context functions work similarly to the non-quick context functions
52 but are designed for proper coroutine operation and synchronous switching.
53 The signal mask is not adjusted in any manner by these routines, no system
54 calls are made, and scratch registers are not required to be retained across
57 Since no system calls need to be made and the FP state (being scratch across
58 a procedure call) does not need to be saved or restored, these switching
59 functions are at least 10 times faster than the non-quick versions.
60 In addition, callers can setup quick contexts for cofunction chaining
61 (when one cofunction return-chains to another), and for circular cofunction
62 chaining loops, avoiding the need to save any register state at all in
68 initializes all fields of the passed-in context except
70 .Li "ucp->uc_cofunc" ,
73 All other structural fields will be zerod.
76 will also be zerod for safety.
78 The caller must pre-initialize the uc_stack fields.
79 .Li "ucp->uc_cofunc" ,
82 should be initialized prior to making any context switches.
83 This function will set the context up to call the cofunction as
84 .Li "ucp->uc_cofunc(ucp, ucp->uc_arg)" .
85 Note that this calling format is different from the non-quick context calls.
87 If the cofunction returns the wrapper will automatically reinitialize
88 the context to reissue a cofunction call and then call the next
91 If the link field is NULL, the wrapper issues an
93 If the linkages return to the ucontext, the cofunction call is reissued.
95 .Li "ucp->uc_cofunc" ,
98 fields may be adjusted at any time to change the cofunction being called.
99 Using the auto-linkage feature avoids saving register state on cofunction
100 return and is the absolute quickest context switch possible, almost as
101 fast as a normal procedure call would be.
105 function throws away the current context and switches to the target
107 Again, the signal mask is not touched and scratch registers are not saved.
108 If you desire to switch to a signal stack ucontext you must use the
111 function and not this one.
112 This function is designed for synchronous switching only.
115 .Fn swapcontext_quick
116 function saves the current register state and switches to the target
118 This function returns when the old context is resumed.
119 Again, the signal mask is not touched and scratch registers are not saved.
120 If you desire to switch to a signal stack ucontext you must use the
123 function and not this one.
124 It is acceptable to mix normal context functions with quick functions
125 as long as you understand the ramifications.
127 There is no quick version for
131 These functions have no return value.
135 * quick context test program
137 #include <sys/types.h>
138 #include <sys/stat.h>
139 #include <sys/file.h>
140 #include <ucontext.h>
147 #define LOOPS 100000000L
149 static void test1(ucontext_t *ucp, void *arg);
150 static void test2(ucontext_t *ucp, void *arg);
151 static void test3(ucontext_t *ucp, void *arg);
154 main(int ac, char **av)
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);
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);
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);
178 ucp1.uc_link = &ucp2;
179 ucp2.uc_link = &ucp3;
180 ucp3.uc_link = &ucp1;
181 setcontext_quick(&ucp1);
187 test1(ucontext_t *ucp, void *arg)
189 if ((intptr_t)ucp->uc_arg == 1) {
190 printf("test1 entered for first time\en");
191 ucp->uc_arg = (void *)(intptr_t)0;
196 test2(ucontext_t *ucp, void *arg)
198 if ((intptr_t)ucp->uc_arg == 2) {
199 printf("test2 entered for first time\en");
200 ucp->uc_arg = (void *)(intptr_t)0;
203 if (global_counter > LOOPS)
204 ucp->uc_link = NULL; /* demonstrate documented exit(0) */
208 test3(ucontext_t *ucp, void *arg)
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;
217 swapcontext_quick(ucp, ucp->uc_link);
224 There is not enough stack space in
226 to complete the operation.