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 There is not enough stack space in
137 to complete the operation.
142 * quick context test program
144 #include <sys/types.h>
145 #include <sys/stat.h>
146 #include <sys/file.h>
147 #include <ucontext.h>
154 #define LOOPS 100000000L
156 static void test1(ucontext_t *ucp, void *arg);
157 static void test2(ucontext_t *ucp, void *arg);
158 static void test3(ucontext_t *ucp, void *arg);
161 main(int ac, char **av)
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);
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);
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);
185 ucp1.uc_link = &ucp2;
186 ucp2.uc_link = &ucp3;
187 ucp3.uc_link = &ucp1;
188 setcontext_quick(&ucp1);
194 test1(ucontext_t *ucp, void *arg)
196 if ((intptr_t)ucp->uc_arg == 1) {
197 printf("test1 entered for first time\en");
198 ucp->uc_arg = (void *)(intptr_t)0;
203 test2(ucontext_t *ucp, void *arg)
205 if ((intptr_t)ucp->uc_arg == 2) {
206 printf("test2 entered for first time\en");
207 ucp->uc_arg = (void *)(intptr_t)0;
210 if (global_counter > LOOPS)
211 ucp->uc_link = NULL; /* demonstrate documented exit(0) */
215 test3(ucontext_t *ucp, void *arg)
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;
224 swapcontext_quick(ucp, ucp->uc_link);