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
swap(ucontext_t * fu,void * fs[10],ucontext_t * tu,void * ts[10])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
use_buffer(char * buf)50 use_buffer (char *buf)
51 {
52   buf[0] = '\0';
53 }
54 
55 static void
down(int i,const char * msg,ucontext_t * me,void * mes[10],ucontext_t * other,void * others[10])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
go1(void)90 go1 (void)
91 {
92   down (1000, "go1", &c1, s1, &c2, s2);
93   pthread_exit (NULL);
94 }
95 
96 static void
go2(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 *
start_thread(void * context)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
main(int argc,char ** argv)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 }
172