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 <time.h>
22 #include <unistd.h>
23 
24 
25 static pthread_once_t once = PTHREAD_ONCE_INIT;
26 
27 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
28 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
29 
30 static pthread_barrier_t bar;
31 
32 static int global;
33 static int cl_called;
34 
35 static void
once_handler1(void)36 once_handler1 (void)
37 {
38   if (pthread_mutex_lock (&mut) != 0)
39     {
40       puts ("once_handler1: mutex_lock failed");
41       exit (1);
42     }
43 
44   int r = pthread_barrier_wait (&bar);
45   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
46     {
47       puts ("once_handler1: barrier_wait failed");
48       exit (1);
49     }
50 
51   pthread_cond_wait (&cond, &mut);
52 
53   /* We should never get here.  */
54 }
55 
56 
57 static void
once_handler2(void)58 once_handler2 (void)
59 {
60   global = 1;
61 }
62 
63 
64 static void
cl(void * arg)65 cl (void *arg)
66 {
67   ++cl_called;
68 }
69 
70 
71 static void *
tf1(void * arg)72 tf1 (void *arg)
73 {
74   pthread_cleanup_push (cl, NULL);
75 
76   pthread_once (&once, once_handler1);
77 
78   pthread_cleanup_pop (0);
79 
80   /* We should never get here.  */
81   puts ("pthread_once in tf returned");
82   exit (1);
83 }
84 
85 
86 static void *
tf2(void * arg)87 tf2 (void *arg)
88 {
89   pthread_cleanup_push (cl, NULL);
90 
91   int r = pthread_barrier_wait (&bar);
92   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
93     {
94       puts ("once_handler2: barrier_wait failed");
95       exit (1);
96     }
97 
98   pthread_cleanup_pop (0);
99 
100   pthread_once (&once, once_handler2);
101 
102   return NULL;
103 }
104 
105 
106 static int
do_test(void)107 do_test (void)
108 {
109   pthread_t th[2];
110 
111   if (pthread_barrier_init (&bar, NULL, 2) != 0)
112     {
113       puts ("barrier_init failed");
114       return 1;
115     }
116 
117   if (pthread_create (&th[0], NULL, tf1, NULL) != 0)
118     {
119       puts ("first create failed");
120       return 1;
121     }
122 
123   int r = pthread_barrier_wait (&bar);
124   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
125     {
126       puts ("first barrier_wait failed");
127       return 1;
128     }
129 
130   if (pthread_mutex_lock (&mut) != 0)
131     {
132       puts ("mutex_lock failed");
133       return 1;
134     }
135   /* We unlock the mutex so that we catch the case where the pthread_cond_wait
136      call incorrectly resumes and tries to get the mutex.  */
137   if (pthread_mutex_unlock (&mut) != 0)
138     {
139       puts ("mutex_unlock failed");
140       return 1;
141     }
142 
143   if (pthread_create (&th[1], NULL, tf2, NULL) != 0)
144     {
145       puts ("second create failed");
146       return 1;
147     }
148 
149   r = pthread_barrier_wait (&bar);
150   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
151     {
152       puts ("second barrier_wait failed");
153       return 1;
154     }
155 
156   /* Give the second thread a chance to reach the pthread_once call.  */
157   sleep (2);
158 
159   /* Cancel the thread.  */
160   if (pthread_cancel (th[0]) != 0)
161     {
162       puts ("cancel failed");
163       return 1;
164     }
165 
166   void *result;
167   pthread_join (th[0], &result);
168   if (result != PTHREAD_CANCELED)
169     {
170       puts ("first join didn't return PTHREAD_CANCELED");
171       return 1;
172     }
173 
174   puts ("joined first thread");
175 
176   pthread_join (th[1], &result);
177   if (result != NULL)
178     {
179       puts ("second join didn't return PTHREAD_CANCELED");
180       return 1;
181     }
182 
183   if (global != 1)
184     {
185       puts ("global still 0");
186       return 1;
187     }
188 
189   if (cl_called != 1)
190     {
191       printf ("cl_called = %d\n", cl_called);
192       return 1;
193     }
194 
195   return 0;
196 }
197 
198 #define TEST_FUNCTION do_test ()
199 #include "../test-skeleton.c"
200