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
11extern void __splitstack_getcontext (void *context[10]);
12
13extern void __splitstack_setcontext (void *context[10]);
14
15extern void *__splitstack_makecontext (size_t, void *context[10], size_t *);
16
17extern void __splitstack_block_signals (int *, int *);
18
19extern void __splitstack_block_signals_context (void *context[10], int *,
20						int *);
21
22extern void *__splitstack_find (void *, void *, size_t *, void **, void **,
23				void **);
24
25extern void *__splitstack_find_context (void *context[10], size_t *, void **,
26					void **, void **);
27
28static ucontext_t c1;
29static void *s1[10];
30
31static ucontext_t c2;
32static void *s2[10];
33
34static void swap (ucontext_t *, void *fs[10], ucontext_t *, void *ts[10])
35  __attribute__ ((no_split_stack));
36
37static void
38swap (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.  */
48static void use_buffer (char *buf) __attribute__ ((noinline));
49static void
50use_buffer (char *buf)
51{
52  buf[0] = '\0';
53}
54
55static void
56down (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
89static void
90go1 (void)
91{
92  down (1000, "go1", &c1, s1, &c2, s2);
93  pthread_exit (NULL);
94}
95
96static void
97go2 (void)
98{
99  down (1000, "go2", &c2, s2, &c1, s1);
100  pthread_exit (NULL);
101}
102
103struct thread_context
104{
105  ucontext_t *u;
106  void **s;
107};
108
109static void *start_thread (void *) __attribute__ ((no_split_stack));
110
111static void *
112start_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
124int
125main (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