]>
Commit | Line | Data |
---|---|---|
e14304ef ILT |
1 | /* { dg-do run } */ |
2 | /* { dg-require-effective-target split_stack } */ | |
3 | /* { dg-require-effective-target pthread_h } */ | |
4 | /* { dg-require-effective-target ucontext_h } */ | |
5 | /* { dg-options "-pthread -fsplit-stack" } */ | |
6 | ||
7 | #include <stdlib.h> | |
8 | #include <pthread.h> | |
9 | #include <ucontext.h> | |
10 | ||
11 | extern void __splitstack_getcontext (void *context[10]); | |
12 | ||
13 | extern void __splitstack_setcontext (void *context[10]); | |
14 | ||
15 | extern void *__splitstack_makecontext (size_t, void *context[10], size_t *); | |
16 | ||
17 | extern void __splitstack_block_signals (int *, int *); | |
18 | ||
19 | extern void __splitstack_block_signals_context (void *context[10], int *, | |
20 | int *); | |
21 | ||
22 | extern void *__splitstack_find (void *, void *, size_t *, void **, void **, | |
23 | void **); | |
24 | ||
25 | extern void *__splitstack_find_context (void *context[10], size_t *, void **, | |
26 | void **, void **); | |
27 | ||
28 | static ucontext_t c1; | |
29 | static void *s1[10]; | |
30 | ||
31 | static ucontext_t c2; | |
32 | static void *s2[10]; | |
33 | ||
34 | static void swap (ucontext_t *, void *fs[10], ucontext_t *, void *ts[10]) | |
35 | __attribute__ ((no_split_stack)); | |
36 | ||
37 | static void | |
38 | swap (ucontext_t *fu, void *fs[10], ucontext_t *tu, void *ts[10]) | |
39 | { | |
40 | __splitstack_getcontext (fs); | |
41 | __splitstack_setcontext (ts); | |
42 | swapcontext (fu, tu); | |
43 | __splitstack_setcontext (fs); | |
44 | } | |
45 | ||
46 | /* Use a noinline function to ensure that the buffer is not removed | |
47 | from the stack. */ | |
48 | static void use_buffer (char *buf) __attribute__ ((noinline)); | |
49 | static void | |
50 | use_buffer (char *buf) | |
51 | { | |
52 | buf[0] = '\0'; | |
53 | } | |
54 | ||
55 | static void | |
56 | down (int i, const char *msg, ucontext_t *me, void *mes[10], | |
57 | ucontext_t *other, void *others[10]) | |
58 | { | |
59 | char buf[10000]; | |
60 | ||
61 | if (i > 0) | |
62 | { | |
63 | use_buffer (buf); | |
64 | swap (me, mes, other, others); | |
65 | down (i - 1, msg, me, mes, other, others); | |
66 | } | |
67 | else | |
68 | { | |
69 | int c = 0; | |
70 | void *stack; | |
71 | size_t stack_size; | |
72 | void *next_segment = NULL; | |
73 | void *next_sp = NULL; | |
74 | void *initial_sp = NULL; | |
75 | ||
76 | stack = __splitstack_find_context (mes, &stack_size, &next_segment, | |
77 | &next_sp, &initial_sp); | |
78 | if (stack != NULL) | |
79 | { | |
80 | ++c; | |
81 | while (__splitstack_find (next_segment, next_sp, &stack_size, | |
82 | &next_segment, &next_sp, &initial_sp) | |
83 | != NULL) | |
84 | ++c; | |
85 | } | |
86 | } | |
87 | } | |
88 | ||
89 | static void | |
90 | go1 (void) | |
91 | { | |
92 | down (1000, "go1", &c1, s1, &c2, s2); | |
93 | pthread_exit (NULL); | |
94 | } | |
95 | ||
96 | static void | |
97 | go2 (void) | |
98 | { | |
99 | down (1000, "go2", &c2, s2, &c1, s1); | |
100 | pthread_exit (NULL); | |
101 | } | |
102 | ||
103 | struct thread_context | |
104 | { | |
105 | ucontext_t *u; | |
106 | void **s; | |
107 | }; | |
108 | ||
109 | static void *start_thread (void *) __attribute__ ((no_split_stack)); | |
110 | ||
111 | static void * | |
112 | start_thread (void *context) | |
113 | { | |
114 | struct thread_context *tc = (struct thread_context *) context; | |
115 | int block; | |
116 | ||
117 | block = 0; | |
118 | __splitstack_block_signals (&block, NULL); | |
119 | __splitstack_setcontext (tc->s); | |
120 | setcontext (tc->u); | |
121 | abort (); | |
122 | } | |
123 | ||
124 | int | |
125 | main (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) | |
126 | { | |
127 | pthread_t tid; | |
128 | int err; | |
129 | size_t size; | |
130 | struct thread_context tc; | |
131 | int block; | |
132 | ||
133 | if (getcontext (&c1) < 0) | |
134 | abort (); | |
135 | ||
136 | c2 = c1; | |
137 | ||
138 | c1.uc_stack.ss_sp = __splitstack_makecontext (8192, &s1[0], &size); | |
139 | if (c1.uc_stack.ss_sp == NULL) | |
140 | abort (); | |
141 | c1.uc_stack.ss_flags = 0; | |
142 | c1.uc_stack.ss_size = size; | |
143 | c1.uc_link = NULL; | |
144 | block = 0; | |
145 | __splitstack_block_signals_context (&s1[0], &block, NULL); | |
146 | makecontext (&c1, go1, 0); | |
147 | ||
148 | c2.uc_stack.ss_sp = __splitstack_makecontext (8192, &s2[0], &size); | |
149 | if (c2.uc_stack.ss_sp == NULL) | |
150 | abort (); | |
151 | c2.uc_stack.ss_flags = 0; | |
152 | c2.uc_stack.ss_size = size; | |
153 | c2.uc_link = NULL; | |
154 | __splitstack_block_signals_context (&s2[0], &block, NULL); | |
155 | makecontext (&c2, go2, 0); | |
156 | ||
157 | block = 0; | |
158 | __splitstack_block_signals (&block, NULL); | |
159 | ||
160 | tc.u = &c1; | |
161 | tc.s = &s1[0]; | |
162 | err = pthread_create (&tid, NULL, start_thread, &tc); | |
163 | if (err != 0) | |
164 | abort (); | |
165 | ||
166 | err = pthread_join (tid, NULL); | |
167 | if (err != 0) | |
168 | abort (); | |
169 | ||
170 | return 0; | |
171 | } |