3 * Test getcontext, setcontext, makecontext, and swapcontext system calls.
5 * Part of this test is somewhat based on the GNU GCC ucontext test set.
18 #include <sys/signal.h>
20 /* We can't use a global subtest variable reliably, because threads might
21 change the value when we reenter a thread (i.e., report wrong subtest
23 #define err(st, en) do { subtest = st; e(en); } while(0)
28 void func1(int a
, int b
, int c
, int d
, int e
, int f
, int g
, int h
, int
29 i
, int j
, int k
, int l
, int m
, int n
, int o
, int p
, int q
, int r
, int s
,
30 int t
, int u
, int v
, int w
, int x
, int y
, int z
, int aa
, int bb
);
34 void verify_main_reenter(void);
46 int entered_func1
, entered_func2
, reentered_main
, entered_overflow
;
48 static char st_stack
[SSIZE
];
49 static volatile int shift
, global
;
63 foo
= a
* b
; /* 2.42 */
64 bar
= c
* d
; /* 14.52 */
69 foo
*= d
; /* 25.168 */
70 foo
/= e
; /* 4.5760 */
72 bar
*= b
; /* 29.524 */
73 bar
/= e
; /* 5.3680 */
86 if(fabs(foo
- (a
* b
)) > 0.0001) err(8, 1);
87 if(fabs(bar
- (c
* d
)) > 0.0001) err(8, 2);
95 /* Initialize FPU context and verify it's set to round to nearest. */
96 if (fegetround() != FE_TONEAREST
) err(9, 1);
98 /* Now we change the rounding to something else, and this should be preserved
99 between context swaps. */
100 if (fesetround(FE_DOWNWARD
) != 0) err(9, 2);
104 if (swapcontext(&ctx
[2], &ctx
[1]) == -1) err(9, 2);
106 if (fegetround() != FE_DOWNWARD
) err(9, 4);
117 /* Initialize FPU context and verify it's set to round to nearest. */
118 if (fegetround() != FE_TONEAREST
) err(10, 1);
120 /* Now we change the rounding to something else, and this should be preserved
121 between context swaps. */
122 if (fesetround(FE_UPWARD
) != 0) err(10, 2);
124 /* Quick check to make sure that getcontext does not reset the FPU state. */
127 if (fegetround() != FE_UPWARD
) err(10, 3);
131 if (fegetround() != FE_UPWARD
) err(10, 4);
133 if (swapcontext(&ctx
[1], &ctx
[2]) == -1) err(10, 5);
135 /* Returning to main thread through uc_link */
138 static void fail(void)
140 /* Shouldn't get here */
144 void func1(int a
, int b
, int c
, int d
, int e
, int f
, int g
,
145 int h
, int i
, int j
, int k
, int l
, int m
, int n
,
146 int o
, int p
, int q
, int r
, int s
, int t
, int u
,
147 int v
, int w
, int x
, int y
, int z
, int aa
, int bb
)
149 if ( a
!= (0x0000001 << shift
) || b
!= (0x0000004 << shift
) ||
150 c
!= (0x0000010 << shift
) || d
!= (0x0000040 << shift
) ||
151 e
!= (0x0000100 << shift
) || f
!= (0x0000400 << shift
) ||
152 g
!= (0x0001000 << shift
) || h
!= (0x0004000 << shift
) ||
153 i
!= (0x0010000 << shift
) || j
!= (0x0040000 << shift
) ||
154 k
!= (0x0100000 << shift
) || l
!= (0x0400000 << shift
) ||
155 m
!= (0x1000000 << shift
) || n
!= (0x4000000 << shift
) ||
156 o
!= (0x0000002 << shift
) || p
!= (0x0000008 << shift
) ||
157 q
!= (0x0000020 << shift
) || r
!= (0x0000080 << shift
) ||
158 s
!= (0x0000200 << shift
) || t
!= (0x0000800 << shift
) ||
159 u
!= (0x0002000 << shift
) || v
!= (0x0008000 << shift
) ||
160 w
!= (0x0020000 << shift
) || x
!= (0x0080000 << shift
) ||
161 y
!= (0x0200000 << shift
) || z
!= (0x0800000 << shift
) ||
162 aa
!= (0x2000000 << shift
) || bb
!= (0x8000000 << shift
) ) {
166 if (shift
&& swapcontext (&ctx
[1], &ctx
[2]) != 0) err(2, 2);
173 if (swapcontext(&ctx
[2], &ctx
[1]) != 0) err(3, 1);
179 if (errct
== 0) printf("ok\n");
187 big_stack
= malloc(16 * 1024 * 1024); /* 16 MB */
188 /* If this fails, it is likely brk system call failed due stack/data segments
189 collision detection. Unless the system really is low on memory, this is an
191 if (big_stack
== NULL
) err(7, 1);
194 void verify_main_reenter(void)
196 if (reentered_main
== 0) err(4, 1);
199 int set_context_test_value
;
200 static void set_context_test_thread1(void){
201 set_context_test_value
|= 0x1;
207 static void set_context_test_thread2(void){
208 set_context_test_value
|= 0x1 << 1;
217 atexit(verify_main_reenter
);
219 /* Save current context in ctx[0] */
220 if (getcontext(&ctx
[0]) != 0) {
221 /* Don't verify reentering main, not going to happen */
227 ctx
[1].uc_stack
.ss_sp
= st_stack
;
228 ctx
[1].uc_stack
.ss_size
= SSIZE
;
229 ctx
[1].uc_link
= &ctx
[0]; /* When done running, return here */
231 /* ctx[1] is going to run func1 and then return here (uc_link). */
232 /* We'll see later on whether makecontext worked. */
233 makecontext(&ctx
[1], (void (*) (void)) func1
, 28,
234 (0x0000001 << shift
), (0x0000004 << shift
),
235 (0x0000010 << shift
), (0x0000040 << shift
),
236 (0x0000100 << shift
), (0x0000400 << shift
),
237 (0x0001000 << shift
), (0x0004000 << shift
),
238 (0x0010000 << shift
), (0x0040000 << shift
),
239 (0x0100000 << shift
), (0x0400000 << shift
),
240 (0x1000000 << shift
), (0x4000000 << shift
),
241 (0x0000002 << shift
), (0x0000008 << shift
),
242 (0x0000020 << shift
), (0x0000080 << shift
),
243 (0x0000200 << shift
), (0x0000800 << shift
),
244 (0x0002000 << shift
), (0x0008000 << shift
),
245 (0x0020000 << shift
), (0x0080000 << shift
),
246 (0x0200000 << shift
), (0x0800000 << shift
),
247 (0x2000000 << shift
), (0x8000000 << shift
));
250 /* First time we're here. Let's run ctx[1] and return to ctx[0] when
251 * we're done. Note that we return to above the 'makecontext' call. */
252 if (setcontext(&ctx
[1]) != 0) err(1, 2);
255 /* When ++global was 1 we let ctx[1] run and returned to ctx[0], so
256 above ++global is executed again and should've become 2. */
260 /* Setup ctx[2] to run func2 */
261 if (getcontext(&ctx
[2]) != 0) err(1, 4);
262 ctx
[2].uc_stack
.ss_sp
= malloc(SSIZE
);
263 ctx
[2].uc_stack
.ss_size
= SSIZE
;
264 ctx
[2].uc_link
= &ctx
[1];
265 makecontext(&ctx
[2], (void (*) (void)) func2
, 0);
267 /* Now things become tricky. ctx[2] is set up such that when it finishes
268 running, and starts ctx[1] again. However, func1 swaps back to func2. Then,
269 when func2 has finished running, we continue with ctx[1] and, finally, we
271 if (swapcontext(&ctx
[0], &ctx
[2]) != 0) err(1, 5); /* makecontext failed? */
274 /* The call graph is as follows:
278 * 7 /----########----\
282 * #########----/ #########
283 * # func1 #<-------4-------# func2 #
284 * #########--------5------>#########
287 * \---------6--------/
289 * Main calls func1, func1 increases entered_func1, and returns to main. Main
290 * calls func2, swaps to func1, swaps to func2, which increases entered_func2,
291 * continues with func1, which increases entered_func1 again, continues to
292 * main, where reentered_main is set to 1. In effect, entered_func1 == 2,
293 * entered_func2 == 1, reentered_main == 1. Verify that. */
295 if (entered_func1
!= 2) err(1, 6);
296 if (entered_func2
!= 1) err(1, 7);
297 /* reentered_main == 1 is verified upon exit */
299 /* Try to allocate too small a stack */
300 free(ctx
[2].uc_stack
.ss_sp
); /* Deallocate stack space first */
301 if (getcontext(&ctx
[2]) != 0) err(1, 8);
302 ctx
[2].uc_stack
.ss_sp
= malloc(MINSIGSTKSZ
-1);
303 ctx
[2].uc_stack
.ss_size
= MINSIGSTKSZ
-1;
304 ctx
[2].uc_link
= &ctx
[0];
305 makecontext(&ctx
[2], (void (*) (void)) fail
, 0);
306 /* Because makecontext is void, we can only detect an error by trying to use
307 the invalid context */
308 if (swapcontext(&ctx
[0], &ctx
[2]) == 0) err(1, 9);
310 /* Try to allocate a huge stack to force the usage of brk/sbrk system call
311 to enlarge the data segment. Because we are fiddling with the stack
312 pointer, the OS might think the stack segment and data segment have
313 collided and kill us. This is wrong and therefore the following should
315 free(ctx
[2].uc_stack
.ss_sp
); /* Deallocate stack space first */
316 if (getcontext(&ctx
[2]) != 0) err(1, 14);
317 ctx
[2].uc_stack
.ss_sp
= malloc(8 * 1024 * 1024); /* 8 MB */
318 ctx
[2].uc_stack
.ss_size
= 8 * 1024 * 1024;
319 ctx
[2].uc_link
= &ctx
[0];
320 makecontext(&ctx
[2], (void (*) (void)) test_brk
, 0);
321 if (swapcontext(&ctx
[0], &ctx
[2]) != 0) err(1, 15);
323 ctx
[1].uc_link
= &ctx
[0];
324 ctx
[2].uc_link
= NULL
;
325 makecontext(&ctx
[1], (void (*) (void)) do_parent
, 0);
326 makecontext(&ctx
[2], (void (*) (void)) do_child
, 0);
327 if (swapcontext(&ctx
[0], &ctx
[2]) == -1) err(1, 16);
329 /* test setcontext first do some cleanup */
331 free(ctx
[1].uc_stack
.ss_sp
);
332 free(ctx
[2].uc_stack
.ss_sp
);
334 memset(&ctx
[0],0,sizeof(ucontext_t
));
335 memset(&ctx
[1],0,sizeof(ucontext_t
));
336 memset(&ctx
[2],0,sizeof(ucontext_t
));
339 /* create 3 new contexts */
342 /* control will be returned here */
343 set_context_test_value
= 0;
344 if (getcontext(&ctx
[0]) != 0) err(1, 17);
345 if (set_context_test_value
!= 0x3) err(1, 20);
348 if (getcontext(&ctx
[1]) != 0) err(1, 18);
349 if (getcontext(&ctx
[2]) != 0) err(1, 19);
351 // allocate new stacks */
352 ctx
[1].uc_stack
.ss_sp
= malloc(SSIZE
);
353 ctx
[1].uc_stack
.ss_size
= SSIZE
;
354 ctx
[2].uc_stack
.ss_sp
= malloc(SSIZE
);
355 ctx
[2].uc_stack
.ss_size
= SSIZE
;
357 makecontext(&ctx
[1],set_context_test_thread1
,0);
358 makecontext(&ctx
[2],set_context_test_thread2
,0);
359 if( setcontext(&ctx
[1]) != 0){