xref: /dflybsd-src/lib/libc/gen/makecontext_quick.3 (revision 0e9f503d39edbb4900a0881321c33e51a8d2fbaf)
1819d0c16SMatthew Dillon.\"
2819d0c16SMatthew Dillon.\" Copyright (c) 2015 The DragonFly Project.  All rights reserved.
3819d0c16SMatthew Dillon.\"
4819d0c16SMatthew Dillon.\" This code is derived from software contributed to The DragonFly Project
5819d0c16SMatthew Dillon.\" by Matthew Dillon <dillon@backplane.com>
6819d0c16SMatthew Dillon.\"
7819d0c16SMatthew Dillon.\" Redistribution and use in source and binary forms, with or without
8819d0c16SMatthew Dillon.\" modification, are permitted provided that the following conditions
9819d0c16SMatthew Dillon.\" are met:
10819d0c16SMatthew Dillon.\"
11819d0c16SMatthew Dillon.\" 1. Redistributions of source code must retain the above copyright
12819d0c16SMatthew Dillon.\"    notice, this list of conditions and the following disclaimer.
13819d0c16SMatthew Dillon.\" 2. Redistributions in binary form must reproduce the above copyright
14819d0c16SMatthew Dillon.\"    notice, this list of conditions and the following disclaimer in
15819d0c16SMatthew Dillon.\"    the documentation and/or other materials provided with the
16819d0c16SMatthew Dillon.\"    distribution.
17819d0c16SMatthew Dillon.\" 3. Neither the name of The DragonFly Project nor the names of its
18819d0c16SMatthew Dillon.\"    contributors may be used to endorse or promote products derived
19819d0c16SMatthew Dillon.\"    from this software without specific, prior written permission.
20819d0c16SMatthew Dillon.\"
21819d0c16SMatthew Dillon.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22819d0c16SMatthew Dillon.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23819d0c16SMatthew Dillon.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24819d0c16SMatthew Dillon.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25819d0c16SMatthew Dillon.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26819d0c16SMatthew Dillon.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27819d0c16SMatthew Dillon.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28819d0c16SMatthew Dillon.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29819d0c16SMatthew Dillon.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30819d0c16SMatthew Dillon.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31819d0c16SMatthew Dillon.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32819d0c16SMatthew Dillon.\" SUCH DAMAGE.
33819d0c16SMatthew Dillon.\"
34819d0c16SMatthew Dillon.Dd December 21, 2015
35819d0c16SMatthew Dillon.Dt MAKECONTEXT_QUICK 3
36819d0c16SMatthew Dillon.Os
37819d0c16SMatthew Dillon.Sh NAME
38819d0c16SMatthew Dillon.Nm makecontext_quick , swapcontext_quick , setcontext_quick
39819d0c16SMatthew Dillon.Nd quickly modify and exchange user thread contexts
40819d0c16SMatthew Dillon.Sh LIBRARY
41819d0c16SMatthew Dillon.Lb libc
42819d0c16SMatthew Dillon.Sh SYNOPSIS
43819d0c16SMatthew Dillon.In ucontext.h
44819d0c16SMatthew Dillon.Ft void
45819d0c16SMatthew Dillon.Fn makecontext_quick "ucontext_t *ucp"
46819d0c16SMatthew Dillon.Ft void
47*0e9f503dSSascha Wildner.Fn swapcontext_quick "ucontext_t *oucp" "ucontext_t *nucp"
48819d0c16SMatthew Dillon.Ft void
49819d0c16SMatthew Dillon.Fn setcontext_quick "ucontext_t *ucp"
50819d0c16SMatthew Dillon.Sh DESCRIPTION
51819d0c16SMatthew DillonThe quick context functions work similarly to the non-quick context functions
52819d0c16SMatthew Dillonbut are designed for proper coroutine operation and synchronous switching.
53819d0c16SMatthew DillonThe signal mask is not adjusted in any manner by these routines, no system
54819d0c16SMatthew Dilloncalls are made, and scratch registers are not required to be retained across
55819d0c16SMatthew Dilloncalls.
56819d0c16SMatthew Dillon.Pp
57819d0c16SMatthew DillonSince no system calls need to be made and the FP state (being scratch across
58819d0c16SMatthew Dillona procedure call) does not need to be saved or restored, these switching
59819d0c16SMatthew Dillonfunctions are at least 10 times faster than the non-quick versions.
60819d0c16SMatthew DillonIn addition, callers can setup quick contexts for cofunction chaining
61819d0c16SMatthew Dillon(when one cofunction return-chains to another), and for circular cofunction
62819d0c16SMatthew Dillonchaining loops, avoiding the need to save any register state at all in
63819d0c16SMatthew Dillonthose configurations.
64819d0c16SMatthew Dillon.Pp
65819d0c16SMatthew DillonThe
66819d0c16SMatthew Dillon.Fn makecontext_quick
67819d0c16SMatthew Dillonfunction
68819d0c16SMatthew Dilloninitializes all fields of the passed-in context except
69819d0c16SMatthew Dillon.Li "ucp->uc_stack" ,
70819d0c16SMatthew Dillon.Li "ucp->uc_cofunc" ,
71819d0c16SMatthew Dillonand
72819d0c16SMatthew Dillon.Li "ucp->uc_arg" .
73819d0c16SMatthew DillonAll other structural fields will be zerod.
74819d0c16SMatthew DillonNote that
75819d0c16SMatthew Dillon.Li "ucp->uc_link"
76819d0c16SMatthew Dillonwill also be zerod for safety.
77819d0c16SMatthew Dillon.Pp
78819d0c16SMatthew DillonThe caller must pre-initialize the uc_stack fields.
79819d0c16SMatthew Dillon.Li "ucp->uc_cofunc" ,
80819d0c16SMatthew Dillonand
81819d0c16SMatthew Dillon.Li "ucp->uc_arg"
82819d0c16SMatthew Dillonshould be initialized prior to making any context switches.
83819d0c16SMatthew DillonThis function will set the context up to call the cofunction as
84819d0c16SMatthew Dillon.Li "ucp->uc_cofunc(ucp, ucp->uc_arg)" .
85819d0c16SMatthew DillonNote that this calling format is different from the non-quick context calls.
86819d0c16SMatthew Dillon.Pp
87819d0c16SMatthew DillonIf the cofunction returns the wrapper will automatically reinitialize
88819d0c16SMatthew Dillonthe context to reissue a cofunction call and then call the next
89819d0c16SMatthew Dilloncofunction via
90819d0c16SMatthew Dillon.Li "ucp->uc_link" .
91819d0c16SMatthew DillonIf the link field is NULL, the wrapper issues an
92819d0c16SMatthew Dillon.Li "exit(0)" .
93819d0c16SMatthew DillonIf the linkages return to the ucontext, the cofunction call is reissued.
94819d0c16SMatthew DillonThe
95819d0c16SMatthew Dillon.Li "ucp->uc_cofunc" ,
96819d0c16SMatthew Dillonand
97819d0c16SMatthew Dillon.Li "ucp->uc_arg"
98819d0c16SMatthew Dillonfields may be adjusted at any time to change the cofunction being called.
99819d0c16SMatthew DillonUsing the auto-linkage feature avoids saving register state on cofunction
100819d0c16SMatthew Dillonreturn and is the absolute quickest context switch possible, almost as
101819d0c16SMatthew Dillonfast as a normal procedure call would be.
102819d0c16SMatthew Dillon.Pp
103819d0c16SMatthew DillonThe
104819d0c16SMatthew Dillon.Fn setcontext_quick
105819d0c16SMatthew Dillonfunction throws away the current context and switches to the target
106819d0c16SMatthew Dilloncontext.
107819d0c16SMatthew DillonAgain, the signal mask is not touched and scratch registers are not saved.
108819d0c16SMatthew DillonIf you desire to switch to a signal stack ucontext you must use the
109819d0c16SMatthew Dillonnormal
110819d0c16SMatthew Dillon.Fn setcontext
111819d0c16SMatthew Dillonfunction and not this one.
112819d0c16SMatthew DillonThis function is designed for synchronous switching only.
113819d0c16SMatthew Dillon.Pp
114819d0c16SMatthew DillonThe
115819d0c16SMatthew Dillon.Fn swapcontext_quick
116819d0c16SMatthew Dillonfunction saves the current register state and switches to the target
117*0e9f503dSSascha Wildnercontext.
118*0e9f503dSSascha WildnerThis function returns when the old context is resumed.
119819d0c16SMatthew DillonAgain, the signal mask is not touched and scratch registers are not saved.
120819d0c16SMatthew DillonIf you desire to switch to a signal stack ucontext you must use the
121819d0c16SMatthew Dillonnormal
122819d0c16SMatthew Dillon.Fn swapcontext
123819d0c16SMatthew Dillonfunction and not this one.
124819d0c16SMatthew DillonIt is acceptable to mix normal context functions with quick functions
125819d0c16SMatthew Dillonas long as you understand the ramifications.
126819d0c16SMatthew Dillon.Pp
127819d0c16SMatthew DillonThere is no quick version for
128819d0c16SMatthew Dillon.Fn getcontext
129819d0c16SMatthew Dillonon purpose.
130819d0c16SMatthew Dillon.Sh RETURN VALUES
131819d0c16SMatthew DillonThese functions have no return value.
132819d0c16SMatthew Dillon.Sh ERRORS
133819d0c16SMatthew Dillon.Bl -tag -width Er
134819d0c16SMatthew Dillon.It Bq Er ENOMEM
135819d0c16SMatthew DillonThere is not enough stack space in
136819d0c16SMatthew Dillon.Fa ucp
137819d0c16SMatthew Dillonto complete the operation.
138819d0c16SMatthew Dillon.El
139819d0c16SMatthew Dillon.Sh EXAMPLE
140819d0c16SMatthew Dillon.Bd -literal
141819d0c16SMatthew Dillon/*
142a282008cSMatthew Dillon * quick context test program
143819d0c16SMatthew Dillon */
144819d0c16SMatthew Dillon#include <sys/types.h>
145819d0c16SMatthew Dillon#include <sys/stat.h>
146819d0c16SMatthew Dillon#include <sys/file.h>
147819d0c16SMatthew Dillon#include <ucontext.h>
148819d0c16SMatthew Dillon#include <stdio.h>
149819d0c16SMatthew Dillon#include <stdlib.h>
150819d0c16SMatthew Dillon#include <unistd.h>
151819d0c16SMatthew Dillon#include <string.h>
152a282008cSMatthew Dillon#include <assert.h>
153a282008cSMatthew Dillon
154a282008cSMatthew Dillon#define LOOPS	100000000L
155819d0c16SMatthew Dillon
156819d0c16SMatthew Dillonstatic void test1(ucontext_t *ucp, void *arg);
157819d0c16SMatthew Dillonstatic void test2(ucontext_t *ucp, void *arg);
158819d0c16SMatthew Dillonstatic void test3(ucontext_t *ucp, void *arg);
159819d0c16SMatthew Dillon
160819d0c16SMatthew Dillonint
161819d0c16SMatthew Dillonmain(int ac, char **av)
162819d0c16SMatthew Dillon{
163819d0c16SMatthew Dillon	ucontext_t ucp1;
164819d0c16SMatthew Dillon	ucontext_t ucp2;
165819d0c16SMatthew Dillon	ucontext_t ucp3;
166819d0c16SMatthew Dillon
167819d0c16SMatthew Dillon	ucp1.uc_stack.ss_sp = malloc(32768);
168819d0c16SMatthew Dillon	ucp1.uc_stack.ss_size = 32768;
169819d0c16SMatthew Dillon	ucp1.uc_cofunc = test1;
170a282008cSMatthew Dillon	ucp1.uc_arg = (void *)(intptr_t)1;
171819d0c16SMatthew Dillon	makecontext_quick(&ucp1);
172819d0c16SMatthew Dillon
173819d0c16SMatthew Dillon	ucp2.uc_stack.ss_sp = malloc(32768);
174819d0c16SMatthew Dillon	ucp2.uc_stack.ss_size = 32768;
175819d0c16SMatthew Dillon	ucp2.uc_cofunc = test2;
176a282008cSMatthew Dillon	ucp2.uc_arg = (void *)(intptr_t)2;
177819d0c16SMatthew Dillon	makecontext_quick(&ucp2);
178819d0c16SMatthew Dillon
179819d0c16SMatthew Dillon	ucp3.uc_stack.ss_sp = malloc(32768);
180819d0c16SMatthew Dillon	ucp3.uc_stack.ss_size = 32768;
181819d0c16SMatthew Dillon	ucp3.uc_cofunc = test3;
182a282008cSMatthew Dillon	ucp3.uc_arg = (void *)(intptr_t)3;
183819d0c16SMatthew Dillon	makecontext_quick(&ucp3);
184819d0c16SMatthew Dillon
185819d0c16SMatthew Dillon	ucp1.uc_link = &ucp2;
186819d0c16SMatthew Dillon	ucp2.uc_link = &ucp3;
187819d0c16SMatthew Dillon	ucp3.uc_link = &ucp1;
188819d0c16SMatthew Dillon	setcontext_quick(&ucp1);
189819d0c16SMatthew Dillon}
190819d0c16SMatthew Dillon
191a282008cSMatthew Dillonlong global_counter;
192819d0c16SMatthew Dillon
193819d0c16SMatthew Dillonstatic void
194819d0c16SMatthew Dillontest1(ucontext_t *ucp, void *arg)
195819d0c16SMatthew Dillon{
196a282008cSMatthew Dillon	if ((intptr_t)ucp->uc_arg == 1) {
197a282008cSMatthew Dillon		printf("test1 entered for first time\n");
198a282008cSMatthew Dillon		ucp->uc_arg = (void *)(intptr_t)0;
199a282008cSMatthew Dillon	}
200819d0c16SMatthew Dillon}
201819d0c16SMatthew Dillon
202819d0c16SMatthew Dillonstatic void
203819d0c16SMatthew Dillontest2(ucontext_t *ucp, void *arg)
204819d0c16SMatthew Dillon{
205a282008cSMatthew Dillon	if ((intptr_t)ucp->uc_arg == 2) {
206a282008cSMatthew Dillon		printf("test2 entered for first time\n");
207a282008cSMatthew Dillon		ucp->uc_arg = (void *)(intptr_t)0;
208a282008cSMatthew Dillon	}
209819d0c16SMatthew Dillon	++global_counter;
210a282008cSMatthew Dillon	if (global_counter > LOOPS)
211a282008cSMatthew Dillon		ucp->uc_link = NULL;	/* demonstrate documented exit(0) */
212819d0c16SMatthew Dillon}
213819d0c16SMatthew Dillon
214819d0c16SMatthew Dillonstatic void
215819d0c16SMatthew Dillontest3(ucontext_t *ucp, void *arg)
216819d0c16SMatthew Dillon{
217a282008cSMatthew Dillon	/* entered only once */
218a282008cSMatthew Dillon	assert((intptr_t)ucp->uc_arg == 3);
219a282008cSMatthew Dillon	printf("test3 entered for first time\n");
220a282008cSMatthew Dillon	printf("cycle through test1, test2, test3 %d times\n", LOOPS);
221a282008cSMatthew Dillon	ucp->uc_arg = (void *)(intptr_t)0;
222a282008cSMatthew Dillon
223819d0c16SMatthew Dillon	for (;;) {
224819d0c16SMatthew Dillon		swapcontext_quick(ucp, ucp->uc_link);
225819d0c16SMatthew Dillon	}
226819d0c16SMatthew Dillon}
227819d0c16SMatthew Dillon.Ed
228819d0c16SMatthew Dillon.Sh SEE ALSO
229819d0c16SMatthew Dillon.Xr getcontext 3 ,
230819d0c16SMatthew Dillon.Xr setcontext 3 ,
231819d0c16SMatthew Dillon.Xr makecontext 3 ,
232819d0c16SMatthew Dillon.Xr swapcontext 3 ,
233819d0c16SMatthew Dillon.Xr ucontext 3
234