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