1 /* Copyright (C) 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18 
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 
24 /* LinuxThreads pthread_cleanup_{push,pop} helpers.  */
25 extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
26                                    void (*__routine) (void *),
27                                    void *__arg);
28 extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
29                                   int __execute);
30 
31 static int fds[2];
32 static pthread_barrier_t b2;
33 static int global;
34 
35 /* Defined in tst-cleanup4aux.c, never compiled with -fexceptions.  */
36 extern void fn5 (void);
37 extern void fn7 (void);
38 extern void fn9 (void);
39 
40 void
clh(void * arg)41 clh (void *arg)
42 {
43   int val = (long int) arg;
44 
45   printf ("clh (%d)\n", val);
46 
47   global *= val;
48   global += val;
49 }
50 
51 
52 static __attribute__((noinline)) void
fn_read(void)53 fn_read (void)
54 {
55   int r = pthread_barrier_wait (&b2);
56   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
57     {
58       printf ("%s: barrier_wait failed\n", __FUNCTION__);
59       exit (1);
60     }
61 
62   char c;
63   read (fds[0], &c, 1);
64 }
65 
66 
67 __attribute__((noinline)) void
fn0(void)68 fn0 (void)
69 {
70   pthread_cleanup_push (clh, (void *) 1l);
71 
72   fn_read ();
73 
74   pthread_cleanup_pop (1);
75 }
76 
77 
78 __attribute__((noinline)) void
fn1(void)79 fn1 (void)
80 {
81   /* This is the old LinuxThreads pthread_cleanup_{push,pop}.  */
82   struct _pthread_cleanup_buffer b;
83   _pthread_cleanup_push (&b, clh, (void *) 2l);
84 
85   fn0 ();
86 
87   _pthread_cleanup_pop (&b, 1);
88 }
89 
90 
91 static __attribute__((noinline)) void
fn2(void)92 fn2 (void)
93 {
94   pthread_cleanup_push (clh, (void *) 3l);
95 
96   fn1 ();
97 
98   pthread_cleanup_pop (1);
99 }
100 
101 
102 static void *
tf(void * a)103 tf (void *a)
104 {
105   switch ((long) a)
106     {
107     case 0:
108       fn2 ();
109       break;
110     case 1:
111       fn5 ();
112       break;
113     case 2:
114       fn7 ();
115       break;
116     case 3:
117       fn9 ();
118       break;
119     }
120 
121   return NULL;
122 }
123 
124 
125 int
do_test(void)126 do_test (void)
127 {
128   int result = 0;
129 
130   if (pipe (fds) != 0)
131     {
132       puts ("pipe failed");
133       exit (1);
134     }
135 
136   if (pthread_barrier_init (&b2, NULL, 2) != 0)
137     {
138       puts ("b2 init failed");
139       exit (1);
140     }
141 
142   const int expect[] =
143     {
144       15,	/* 1 2 3 */
145       276,	/* 1 4 5 6 */
146       120,	/* 1 7 8 */
147       460	/* 1 2 9 10 */
148     };
149 
150   long i;
151   for (i = 0; i < 4; ++i)
152     {
153       global = 0;
154 
155       printf ("test %ld\n", i);
156 
157       pthread_t th;
158       if (pthread_create (&th, NULL, tf, (void *) i) != 0)
159 	{
160 	  puts ("create failed");
161 	  exit (1);
162 	}
163 
164       int e = pthread_barrier_wait (&b2);
165       if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
166 	{
167 	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
168 	  exit (1);
169 	}
170 
171       pthread_cancel (th);
172 
173       void *r;
174       if ((e = pthread_join (th, &r)) != 0)
175 	{
176 	  printf ("join failed: %d\n", e);
177 	  _exit (1);
178 	}
179 
180       if (r != PTHREAD_CANCELED)
181 	{
182 	  puts ("thread not canceled");
183 	  exit (1);
184 	}
185 
186       if (global != expect[i])
187 	{
188 	  printf ("global = %d, expected %d\n", global, expect[i]);
189 	  result = 1;
190 	}
191     }
192 
193   return result;
194 }
195 
196 #define TEST_FUNCTION do_test ()
197 #include "../test-skeleton.c"
198