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 <errno.h>
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <time.h>
23 #include <unistd.h>
24 
25 
26 static pthread_barrier_t b;
27 
28 
29 /* Cleanup handling test.  */
30 static int cl_called;
31 
32 static void
cl(void * arg)33 cl (void *arg)
34 {
35   ++cl_called;
36 }
37 
38 
39 static void *
tf(void * arg)40 tf (void *arg)
41 {
42   int r = pthread_barrier_wait (&b);
43   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
44     {
45       puts ("barrier_wait failed");
46       exit (1);
47     }
48 
49   pthread_cleanup_push (cl, NULL);
50 
51   struct timespec ts = { .tv_sec = arg == NULL ? 10000000 : 0, .tv_nsec = 0 };
52   TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts));
53 
54   pthread_cleanup_pop (0);
55 
56   puts ("clock_nanosleep returned");
57 
58   exit (1);
59 }
60 
61 
62 static int
do_test(void)63 do_test (void)
64 {
65   if (pthread_barrier_init (&b, NULL, 2) != 0)
66     {
67       puts ("barrier_init failed");
68       return 1;
69     }
70 
71   pthread_t th;
72   if (pthread_create (&th, NULL, tf, NULL) != 0)
73     {
74       puts ("1st create failed");
75       return 1;
76     }
77 
78   int r = pthread_barrier_wait (&b);
79   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
80     {
81       puts ("barrier_wait failed");
82       exit (1);
83     }
84 
85   struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
86   while (nanosleep (&ts, &ts) != 0)
87     continue;
88 
89   puts ("going to cancel in-time");
90   if (pthread_cancel (th) != 0)
91     {
92       puts ("1st cancel failed");
93       return 1;
94     }
95 
96   void *status;
97   if (pthread_join (th, &status) != 0)
98     {
99       puts ("1st join failed");
100       return 1;
101     }
102   if (status != PTHREAD_CANCELED)
103     {
104       puts ("1st thread not canceled");
105       return 1;
106     }
107 
108   if (cl_called == 0)
109     {
110       puts ("cleanup handler not called");
111       return 1;
112     }
113   if (cl_called > 1)
114     {
115       puts ("cleanup handler called more than once");
116       return 1;
117     }
118 
119   puts ("in-time cancellation succeeded");
120 
121 
122   cl_called = 0;
123 
124   if (pthread_create (&th, NULL, tf, NULL) != 0)
125     {
126       puts ("2nd create failed");
127       return 1;
128     }
129 
130   puts ("going to cancel early");
131   if (pthread_cancel (th) != 0)
132     {
133       puts ("2nd cancel failed");
134       return 1;
135     }
136 
137   r = pthread_barrier_wait (&b);
138   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
139     {
140       puts ("barrier_wait failed");
141       exit (1);
142     }
143 
144   if (pthread_join (th, &status) != 0)
145     {
146       puts ("2nd join failed");
147       return 1;
148     }
149   if (status != PTHREAD_CANCELED)
150     {
151       puts ("2nd thread not canceled");
152       return 1;
153     }
154 
155   if (cl_called == 0)
156     {
157       printf ("cleanup handler not called\n");
158       return 1;
159     }
160   if (cl_called > 1)
161     {
162       printf ("cleanup handler called more than once\n");
163       return 1;
164     }
165 
166   puts ("early cancellation succeeded");
167 
168   return 0;
169 }
170 
171 #define TEST_FUNCTION do_test ()
172 #include "../test-skeleton.c"
173