1/* Copyright (C) 2001-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18#include <errno.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <ucontext.h>
23#include <unistd.h>
24
25static ucontext_t ctx[3];
26
27static int was_in_f1;
28static int was_in_f2;
29
30static char st2[32768];
31
32static volatile int flag;
33
34static void
35f1 (int a00, int a01, int a02, int a03, int a04, int a05, int a06, int a07,
36 int a08, int a09, int a10, int a11, int a12, int a13, int a14, int a15,
37 int a16, int a17, int a18, int a19, int a20, int a21, int a22, int a23,
38 int a24, int a25, int a26, int a27, int a28, int a29, int a30, int a31,
39 int a32)
40{
41 printf (format: "start f1(a00=%08x,a01=%08x,a02=%08x,a03=%08x,\n"
42 " a04=%08x,a05=%08x,a06=%08x,a07=%08x,\n"
43 " a08=%08x,a09=%08x,a10=%08x,a11=%08x,\n"
44 " a12=%08x,a13=%08x,a14=%08x,a15=%08x,\n"
45 " a16=%08x,a17=%08x,a18=%08x,a19=%08x,\n"
46 " a20=%08x,a21=%08x,a22=%08x,a23=%08x,\n"
47 " a24=%08x,a25=%08x,a26=%08x,a27=%08x,\n"
48 " a28=%08x,a29=%08x,a30=%08x,a31=%08x,\n"
49 " a32=%08x) [%d]\n",
50 a00, a01, a02, a03, a04, a05, a06, a07,
51 a08, a09, a10, a11, a12, a13, a14, a15,
52 a16, a17, a18, a19, a20, a21, a22, a23,
53 a24, a25, a26, a27, a28, a29, a30, a31,
54 a32, flag);
55
56 if (a00 != (0x00000001 << flag) || a01 != (0x00000004 << flag)
57 || a02 != (0x00000012 << flag) || a03 != (0x00000048 << flag)
58 || a04 != (0x00000123 << flag) || a05 != (0x0000048d << flag)
59 || a06 != (0x00001234 << flag) || a07 != (0x000048d1 << flag)
60 || a08 != (0x00012345 << flag) || a09 != (0x00048d15 << flag)
61 || a10 != (0x00123456 << flag) || a11 != (0x0048d159 << flag)
62 || a12 != (0x01234567 << flag) || a13 != (0x048d159e << flag)
63 || a14 != (0x12345678 << flag) || a15 != (0x48d159e2 << flag)
64 || a16 != (0x23456789 << flag) || a17 != (0x8d159e26 << flag)
65 || a18 != (0x3456789a << flag) || a19 != (0xd159e26a << flag)
66 || a20 != (0x456789ab << flag) || a21 != (0x159e26af << flag)
67 || a22 != (0x56789abc << flag) || a23 != (0x59e26af3 << flag)
68 || a24 != (0x6789abcd << flag) || a25 != (0x9e26af37 << flag)
69 || a26 != (0x789abcde << flag) || a27 != (0xe26af37b << flag)
70 || a28 != (0x89abcdef << flag) || a29 != (0x26af37bc << flag)
71 || a30 != (0x9abcdef0 << flag) || a31 != (0x6af37bc3 << flag)
72 || a32 != (0xabcdef0f << flag))
73 {
74 puts (s: "arg mismatch");
75 exit (-1);
76 }
77
78 if (flag && swapcontext (oucp: &ctx[1], ucp: &ctx[2]) != 0)
79 {
80 printf (format: "%s: swapcontext: %m\n", __FUNCTION__);
81 exit (1);
82 }
83 printf (format: "finish f1 [%d]\n", flag);
84 flag++;
85 was_in_f1++;
86}
87
88static void
89f2 (void)
90{
91 puts (s: "start f2");
92 if (swapcontext (oucp: &ctx[2], ucp: &ctx[1]) != 0)
93 {
94 printf (format: "%s: swapcontext: %m\n", __FUNCTION__);
95 exit (1);
96 }
97 puts (s: "finish f2");
98 was_in_f2 = 1;
99}
100
101volatile int global;
102
103
104static int back_in_main;
105
106
107static void
108check_called (void)
109{
110 if (back_in_main == 0)
111 {
112 puts (s: "program did not reach main again");
113 _exit (1);
114 }
115}
116
117
118int
119main (void)
120{
121 atexit (func: check_called);
122
123 char st1[32768];
124
125 puts (s: "making contexts");
126 if (getcontext (ucp: &ctx[0]) != 0)
127 {
128 if (errno == ENOSYS)
129 {
130 back_in_main = 1;
131 exit (0);
132 }
133
134 printf (format: "%s: getcontext: %m\n", __FUNCTION__);
135 exit (1);
136 }
137
138 if (getcontext (ucp: &ctx[1]) != 0)
139 {
140 printf (format: "%s: getcontext: %m\n", __FUNCTION__);
141 exit (1);
142 }
143
144 ctx[1].uc_stack.ss_sp = st1;
145 ctx[1].uc_stack.ss_size = sizeof st1;
146 ctx[1].uc_link = &ctx[0];
147 errno = 0;
148 makecontext (ucp: &ctx[1], func: (void (*) (void)) f1, argc: 33,
149 0x00000001 << flag, 0x00000004 << flag,
150 0x00000012 << flag, 0x00000048 << flag,
151 0x00000123 << flag, 0x0000048d << flag,
152 0x00001234 << flag, 0x000048d1 << flag,
153 0x00012345 << flag, 0x00048d15 << flag,
154 0x00123456 << flag, 0x0048d159 << flag,
155 0x01234567 << flag, 0x048d159e << flag,
156 0x12345678 << flag, 0x48d159e2 << flag,
157 0x23456789 << flag, 0x8d159e26 << flag,
158 0x3456789a << flag, 0xd159e26a << flag,
159 0x456789ab << flag, 0x159e26af << flag,
160 0x56789abc << flag, 0x59e26af3 << flag,
161 0x6789abcd << flag, 0x9e26af37 << flag,
162 0x789abcde << flag, 0xe26af37b << flag,
163 0x89abcdef << flag, 0x26af37bc << flag,
164 0x9abcdef0 << flag, 0x6af37bc3 << flag,
165 0xabcdef0f << flag);
166
167 /* Without this check, a stub makecontext can make us spin forever. */
168 if (errno == ENOSYS)
169 {
170 puts (s: "makecontext not implemented");
171 back_in_main = 1;
172 return 0;
173 }
174
175 /* Play some tricks with this context. */
176 if (++global == 1)
177 if (setcontext (&ctx[1]) != 0)
178 {
179 printf (format: "%s: setcontext: %m\n", __FUNCTION__);
180 exit (1);
181 }
182 if (global != 2)
183 {
184 printf (format: "%s: 'global' not incremented twice\n", __FUNCTION__);
185 exit (1);
186 }
187
188 if (getcontext (ucp: &ctx[2]) != 0)
189 {
190 printf (format: "%s: second getcontext: %m\n", __FUNCTION__);
191 exit (1);
192 }
193 ctx[2].uc_stack.ss_sp = st2;
194 ctx[2].uc_stack.ss_size = sizeof st2;
195 ctx[2].uc_link = &ctx[1];
196 makecontext (ucp: &ctx[2], func: f2, argc: 0);
197
198 puts (s: "swapping contexts");
199 if (swapcontext (oucp: &ctx[0], ucp: &ctx[2]) != 0)
200 {
201 printf (format: "%s: swapcontext: %m\n", __FUNCTION__);
202 exit (1);
203 }
204 puts (s: "back at main program");
205 back_in_main = 1;
206
207 if (was_in_f1 < 2)
208 {
209 puts (s: "didn't reach f1 twice");
210 exit (1);
211 }
212 if (was_in_f2 == 0)
213 {
214 puts (s: "didn't reach f2");
215 exit (1);
216 }
217
218 puts (s: "test succeeded");
219 return 0;
220}
221

source code of glibc/stdlib/tst-makecontext3.c