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 <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 
23 
24 static pthread_barrier_t bar;
25 
26 static int global;
27 
28 
29 static void
cleanup(void * arg)30 cleanup (void *arg)
31 {
32   global = 1;
33 }
34 
35 
36 static void *
tf(void * arg)37 tf (void *arg)
38 {
39   /* Enable cancellation, but defer it.  */
40   if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0)
41     {
42       puts ("setcancelstate failed");
43       exit (1);
44     }
45   if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0)
46     {
47       puts ("setcanceltype failed");
48       exit (1);
49     }
50 
51   /* Add cleanup handler.  */
52   pthread_cleanup_push (cleanup, NULL);
53 
54   /* Synchronize with the main thread.  */
55   int r = pthread_barrier_wait (&bar);
56   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
57     {
58       puts ("tf: first barrier_wait failed");
59       exit (1);
60     }
61 
62   /* And again.  Once this is done the main thread should have canceled
63      this thread.  */
64   r = pthread_barrier_wait (&bar);
65   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
66     {
67       puts ("tf: second barrier_wait failed");
68       exit (1);
69     }
70 
71   /* Remove the cleanup handler without executing it.  */
72   pthread_cleanup_pop (0);
73 
74   /* Now react on the cancellation.  */
75   pthread_testcancel ();
76 
77   /* This call should never return.  */
78   return NULL;
79 }
80 
81 
82 static int
do_test(void)83 do_test (void)
84 {
85   if (pthread_barrier_init (&bar, NULL, 2) != 0)
86     {
87       puts ("barrier_init failed");
88       exit (1);
89     }
90 
91   pthread_t th;
92   if (pthread_create (&th, NULL, tf, NULL) != 0)
93     {
94       puts ("pthread_create failed");
95       return 1;
96     }
97 
98   int r = pthread_barrier_wait (&bar);
99   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
100     {
101       puts ("first barrier_wait failed");
102       exit (1);
103     }
104 
105   if (pthread_cancel (th) != 0)
106     {
107       puts ("pthread_cancel failed");
108       return 1;
109     }
110 
111   r = pthread_barrier_wait (&bar);
112   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
113     {
114       puts ("second barrier_wait failed");
115       exit (1);
116     }
117 
118   void *result;
119   if (pthread_join (th, &result) != 0)
120     {
121       puts ("pthread_join failed");
122       return 1;
123     }
124 
125   if (result != PTHREAD_CANCELED)
126     {
127       puts ("thread was not canceled");
128       exit (1);
129     }
130 
131   if (global != 0)
132     {
133       puts ("cancellation handler has been called");
134       exit (1);
135     }
136 
137   return 0;
138 }
139 
140 #define TEST_FUNCTION do_test ()
141 #include "../test-skeleton.c"
142