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. */
25extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
26 void (*__routine) (void *),
27 void *__arg);
28compat_symbol_reference (libpthread, _pthread_cleanup_push,
29 _pthread_cleanup_push, GLIBC_2_0);
30extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
31 int __execute);
32compat_symbol_reference (libpthread, _pthread_cleanup_pop,
33 _pthread_cleanup_pop, GLIBC_2_0);
34
35static int fds[2];
36static pthread_barrier_t b2;
37static int global;
38
39/* Defined in tst-cleanup4aux.c, never compiled with -fexceptions. */
40extern void fn5 (void);
41extern void fn7 (void);
42extern void fn9 (void);
43
44void
45clh (void *arg)
46{
47 int val = (long int) arg;
48
49 printf (format: "clh (%d)\n", val);
50
51 global *= val;
52 global += val;
53}
54
55
56static __attribute__((noinline)) void
57fn_read (void)
58{
59 int r = pthread_barrier_wait (barrier: &b2);
60 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
61 {
62 printf (format: "%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
72fn0 (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
83fn1 (void)
84{
85 /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */
86 struct _pthread_cleanup_buffer b;
87 _pthread_cleanup_push (buffer: &b, routine: clh, arg: (void *) 2l);
88
89 fn0 ();
90
91 _pthread_cleanup_pop (buffer: &b, execute: 1);
92}
93
94
95static __attribute__((noinline)) void
96fn2 (void)
97{
98 pthread_cleanup_push (clh, (void *) 3l);
99
100 fn1 ();
101
102 pthread_cleanup_pop (1);
103}
104
105
106static void *
107tf (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
129int
130do_test (void)
131{
132 int result = 0;
133
134 if (pipe (pipedes: fds) != 0)
135 {
136 puts (s: "pipe failed");
137 exit (1);
138 }
139
140 if (pthread_barrier_init (barrier: &b2, NULL, count: 2) != 0)
141 {
142 puts (s: "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 (format: "test %ld\n", i);
160
161 pthread_t th;
162 if (pthread_create (newthread: &th, NULL, start_routine: tf, arg: (void *) i) != 0)
163 {
164 puts (s: "create failed");
165 exit (1);
166 }
167
168 int e = pthread_barrier_wait (barrier: &b2);
169 if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
170 {
171 printf (format: "%s: barrier_wait failed\n", __FUNCTION__);
172 exit (1);
173 }
174
175 pthread_cancel (th: th);
176
177 void *r;
178 if ((e = pthread_join (th: th, thread_return: &r)) != 0)
179 {
180 printf (format: "join failed: %d\n", e);
181 _exit (1);
182 }
183
184 if (r != PTHREAD_CANCELED)
185 {
186 puts (s: "thread not canceled");
187 exit (1);
188 }
189
190 if (global != expect[i])
191 {
192 printf (format: "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

source code of glibc/nptl/tst-cleanup4.c