1 /* Verify that condition variables synchronized by PI mutexes don't hang on
2    on cancellation.
3    Copyright (C) 2012-2022 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5 
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10 
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15 
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <https://www.gnu.org/licenses/>.  */
19 
20 #include <pthread.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/syscall.h>
28 #include <unistd.h>
29 #include <sys/time.h>
30 #include <time.h>
31 
32 #define NUM 5
33 #define ITERS 10000
34 #define COUNT 100
35 
36 typedef void *(*thr_func) (void *);
37 
38 pthread_mutex_t mutex;
39 pthread_cond_t cond;
40 
cleanup(void * u)41 void cleanup (void *u)
42 {
43   /* pthread_cond_wait should always return with the mutex locked.  The
44      pthread_mutex_unlock implementation does not actually check whether we
45      own the mutex for several mutex kinds, so check this explicitly.  */
46   int ret = pthread_mutex_trylock (&mutex);
47   if (ret != EDEADLK && ret != EBUSY)
48     {
49       printf ("mutex not locked in cleanup %d\n", ret);
50       abort ();
51     }
52   if (pthread_mutex_unlock (&mutex))
53     abort ();
54 }
55 
56 void *
signaller(void * u)57 signaller (void *u)
58 {
59   int i, ret = 0;
60   void *tret = NULL;
61 
62   for (i = 0; i < ITERS; i++)
63     {
64       if ((ret = pthread_mutex_lock (&mutex)) != 0)
65         {
66 	  tret = (void *)1;
67 	  printf ("signaller:mutex_lock failed: %s\n", strerror (ret));
68 	  goto out;
69 	}
70       if ((ret = pthread_cond_signal (&cond)) != 0)
71         {
72 	  tret = (void *)1;
73 	  printf ("signaller:signal failed: %s\n", strerror (ret));
74 	  goto unlock_out;
75 	}
76       if ((ret = pthread_mutex_unlock (&mutex)) != 0)
77         {
78 	  tret = (void *)1;
79 	  printf ("signaller:mutex_unlock failed: %s\n", strerror (ret));
80 	  goto out;
81 	}
82       pthread_testcancel ();
83     }
84 
85 out:
86   return tret;
87 
88 unlock_out:
89   if ((ret = pthread_mutex_unlock (&mutex)) != 0)
90     printf ("signaller:mutex_unlock[2] failed: %s\n", strerror (ret));
91   goto out;
92 }
93 
94 void *
waiter(void * u)95 waiter (void *u)
96 {
97   int i, ret = 0;
98   void *tret = NULL;
99   int seq = (uintptr_t) u;
100 
101   for (i = 0; i < ITERS / NUM; i++)
102     {
103       if ((ret = pthread_mutex_lock (&mutex)) != 0)
104         {
105 	  tret = (void *) (uintptr_t) 1;
106 	  printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
107 	  goto out;
108 	}
109       pthread_cleanup_push (cleanup, NULL);
110 
111       if ((ret = pthread_cond_wait (&cond, &mutex)) != 0)
112         {
113 	  tret = (void *) (uintptr_t) 1;
114 	  printf ("waiter[%u]:wait failed: %s\n", seq, strerror (ret));
115 	  goto unlock_out;
116 	}
117 
118       if ((ret = pthread_mutex_unlock (&mutex)) != 0)
119         {
120 	  tret = (void *) (uintptr_t) 1;
121 	  printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
122 	  goto out;
123 	}
124       pthread_cleanup_pop (0);
125     }
126 
127 out:
128   puts ("waiter tests done");
129   return tret;
130 
131 unlock_out:
132   if ((ret = pthread_mutex_unlock (&mutex)) != 0)
133     printf ("waiter:mutex_unlock[2] failed: %s\n", strerror (ret));
134   goto out;
135 }
136 
137 void *
timed_waiter(void * u)138 timed_waiter (void *u)
139 {
140   int i, ret;
141   void *tret = NULL;
142   int seq = (uintptr_t) u;
143 
144   for (i = 0; i < ITERS / NUM; i++)
145     {
146       struct timespec ts;
147 
148       if ((ret = clock_gettime(CLOCK_REALTIME, &ts)) != 0)
149         {
150 	  tret = (void *) (uintptr_t) 1;
151 	  printf ("%u:clock_gettime failed: %s\n", seq, strerror (errno));
152 	  goto out;
153 	}
154       ts.tv_sec += 20;
155 
156       if ((ret = pthread_mutex_lock (&mutex)) != 0)
157         {
158 	  tret = (void *) (uintptr_t) 1;
159 	  printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
160 	  goto out;
161 	}
162       pthread_cleanup_push (cleanup, NULL);
163 
164       /* We should not time out either.  */
165       if ((ret = pthread_cond_timedwait (&cond, &mutex, &ts)) != 0)
166         {
167 	  tret = (void *) (uintptr_t) 1;
168 	  printf ("waiter[%u]:timedwait failed: %s\n", seq, strerror (ret));
169 	  goto unlock_out;
170 	}
171       if ((ret = pthread_mutex_unlock (&mutex)) != 0)
172         {
173 	  tret = (void *) (uintptr_t) 1;
174 	  printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
175 	  goto out;
176 	}
177       pthread_cleanup_pop (0);
178     }
179 
180 out:
181   puts ("timed_waiter tests done");
182   return tret;
183 
184 unlock_out:
185   if ((ret = pthread_mutex_unlock (&mutex)) != 0)
186     printf ("waiter[%u]:mutex_unlock[2] failed: %s\n", seq, strerror (ret));
187   goto out;
188 }
189 
190 int
do_test_wait(thr_func f)191 do_test_wait (thr_func f)
192 {
193   pthread_t w[NUM];
194   pthread_t s;
195   pthread_mutexattr_t attr;
196   int i, j, ret = 0;
197   void *thr_ret;
198 
199   for (i = 0; i < COUNT; i++)
200     {
201       if ((ret = pthread_mutexattr_init (&attr)) != 0)
202         {
203 	  printf ("mutexattr_init failed: %s\n", strerror (ret));
204 	  goto out;
205 	}
206 
207       if ((ret = pthread_mutexattr_setprotocol (&attr,
208                                                 PTHREAD_PRIO_INHERIT)) != 0)
209         {
210 	  printf ("mutexattr_setprotocol failed: %s\n", strerror (ret));
211 	  goto out;
212 	}
213 
214       if ((ret = pthread_cond_init (&cond, NULL)) != 0)
215         {
216 	  printf ("cond_init failed: %s\n", strerror (ret));
217 	  goto out;
218 	}
219 
220       if ((ret = pthread_mutex_init (&mutex, &attr)) != 0)
221         {
222 	  printf ("mutex_init failed: %s\n", strerror (ret));
223 	  goto out;
224 	}
225 
226       for (j = 0; j < NUM; j++)
227         if ((ret = pthread_create (&w[j], NULL,
228                                    f, (void *) (uintptr_t) j)) != 0)
229 	  {
230 	    printf ("waiter[%d]: create failed: %s\n", j, strerror (ret));
231 	    goto out;
232 	  }
233 
234       if ((ret = pthread_create (&s, NULL, signaller, NULL)) != 0)
235         {
236 	  printf ("signaller: create failed: %s\n", strerror (ret));
237 	  goto out;
238 	}
239 
240       for (j = 0; j < NUM; j++)
241         {
242           pthread_cancel (w[j]);
243 
244           if ((ret = pthread_join (w[j], &thr_ret)) != 0)
245 	    {
246 	      printf ("waiter[%d]: join failed: %s\n", j, strerror (ret));
247 	      goto out;
248 	    }
249 
250           if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
251 	    {
252 	      ret = 1;
253 	      goto out;
254 	    }
255         }
256 
257       /* The signalling thread could have ended before it was cancelled.  */
258       pthread_cancel (s);
259 
260       if ((ret = pthread_join (s, &thr_ret)) != 0)
261         {
262 	  printf ("signaller: join failed: %s\n", strerror (ret));
263 	  goto out;
264 	}
265 
266       if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
267         {
268           ret = 1;
269           goto out;
270         }
271     }
272 
273 out:
274   return ret;
275 }
276 
277 int
do_test(int argc,char ** argv)278 do_test (int argc, char **argv)
279 {
280   int ret = do_test_wait (waiter);
281 
282   if (ret)
283     return ret;
284 
285   return do_test_wait (timed_waiter);
286 }
287 
288 #include "../test-skeleton.c"
289