xref: /dragonfly/lib/libc/gen/makecontext_quick.3 (revision 73b5ca6b)
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