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