xref: /dragonfly/lib/libc/gen/makecontext_quick.3 (revision 07ed7d32)
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 ERRORS
133.Bl -tag -width Er
134.It Bq Er ENOMEM
135There is not enough stack space in
136.Fa ucp
137to complete the operation.
138.El
139.Sh EXAMPLE
140.Bd -literal
141/*
142 * quick context test program
143 */
144#include <sys/types.h>
145#include <sys/stat.h>
146#include <sys/file.h>
147#include <ucontext.h>
148#include <stdio.h>
149#include <stdlib.h>
150#include <unistd.h>
151#include <string.h>
152#include <assert.h>
153
154#define LOOPS	100000000L
155
156static void test1(ucontext_t *ucp, void *arg);
157static void test2(ucontext_t *ucp, void *arg);
158static void test3(ucontext_t *ucp, void *arg);
159
160int
161main(int ac, char **av)
162{
163	ucontext_t ucp1;
164	ucontext_t ucp2;
165	ucontext_t ucp3;
166
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);
172
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);
178
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);
184
185	ucp1.uc_link = &ucp2;
186	ucp2.uc_link = &ucp3;
187	ucp3.uc_link = &ucp1;
188	setcontext_quick(&ucp1);
189}
190
191long global_counter;
192
193static void
194test1(ucontext_t *ucp, void *arg)
195{
196	if ((intptr_t)ucp->uc_arg == 1) {
197		printf("test1 entered for first time\en");
198		ucp->uc_arg = (void *)(intptr_t)0;
199	}
200}
201
202static void
203test2(ucontext_t *ucp, void *arg)
204{
205	if ((intptr_t)ucp->uc_arg == 2) {
206		printf("test2 entered for first time\en");
207		ucp->uc_arg = (void *)(intptr_t)0;
208	}
209	++global_counter;
210	if (global_counter > LOOPS)
211		ucp->uc_link = NULL;	/* demonstrate documented exit(0) */
212}
213
214static void
215test3(ucontext_t *ucp, void *arg)
216{
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;
222
223	for (;;) {
224		swapcontext_quick(ucp, ucp->uc_link);
225	}
226}
227.Ed
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