Add a testcase for BZ #14716
[glibc.git] / nptl / tst-cond25.c
blob370cd67d1cab1cab47e960031690eceaf4dc2347
1 /* Verify that condition variables synchronized by PI mutexes don't hang on
2 on cancellation.
3 Copyright (C) 2012 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
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.
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.
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 <http://www.gnu.org/licenses/>. */
20 #include <pthread.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/syscall.h>
27 #include <unistd.h>
28 #include <sys/time.h>
29 #include <time.h>
31 #define NUM 5
32 #define ITERS 10000
33 #define COUNT 100
35 typedef void *(*thr_func) (void *);
37 pthread_mutex_t mutex;
38 pthread_cond_t cond;
40 void cleanup (void *u)
42 /* pthread_cond_wait should always return with the mutex locked. */
43 if (pthread_mutex_unlock (&mutex))
44 abort ();
47 void *
48 signaller (void *u)
50 int i, ret = 0;
51 void *tret = NULL;
53 for (i = 0; i < ITERS; i++)
55 if ((ret = pthread_mutex_lock (&mutex)) != 0)
57 tret = (void *)1;
58 printf ("signaller:mutex_lock failed: %s\n", strerror (ret));
59 goto out;
61 if ((ret = pthread_cond_signal (&cond)) != 0)
63 tret = (void *)1;
64 printf ("signaller:signal failed: %s\n", strerror (ret));
65 goto unlock_out;
67 if ((ret = pthread_mutex_unlock (&mutex)) != 0)
69 tret = (void *)1;
70 printf ("signaller:mutex_unlock failed: %s\n", strerror (ret));
71 goto out;
73 pthread_testcancel ();
76 out:
77 return tret;
79 unlock_out:
80 if ((ret = pthread_mutex_unlock (&mutex)) != 0)
81 printf ("signaller:mutex_unlock[2] failed: %s\n", strerror (ret));
82 goto out;
85 void *
86 waiter (void *u)
88 int i, ret = 0;
89 void *tret = NULL;
90 int seq = (int)u;
92 for (i = 0; i < ITERS / NUM; i++)
94 if ((ret = pthread_mutex_lock (&mutex)) != 0)
96 tret = (void *)1;
97 printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
98 goto out;
100 pthread_cleanup_push (cleanup, NULL);
102 if ((ret = pthread_cond_wait (&cond, &mutex)) != 0)
104 tret = (void *)1;
105 printf ("waiter[%u]:wait failed: %s\n", seq, strerror (ret));
106 goto unlock_out;
109 if ((ret = pthread_mutex_unlock (&mutex)) != 0)
111 tret = (void *)1;
112 printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
113 goto out;
115 pthread_cleanup_pop (0);
118 out:
119 puts ("waiter tests done");
120 return tret;
122 unlock_out:
123 if ((ret = pthread_mutex_unlock (&mutex)) != 0)
124 printf ("waiter:mutex_unlock[2] failed: %s\n", strerror (ret));
125 goto out;
128 void *
129 timed_waiter (void *u)
131 int i, ret;
132 void *tret = NULL;
133 int seq = (int)u;
135 for (i = 0; i < ITERS / NUM; i++)
137 struct timespec ts;
139 if ((ret = clock_gettime(CLOCK_REALTIME, &ts)) != 0)
141 tret = (void *)1;
142 printf ("%u:clock_gettime failed: %s\n", seq, strerror (errno));
143 goto out;
145 ts.tv_sec += 20;
147 if ((ret = pthread_mutex_lock (&mutex)) != 0)
149 tret = (void *)1;
150 printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
151 goto out;
153 pthread_cleanup_push (cleanup, NULL);
155 /* We should not time out either. */
156 if ((ret = pthread_cond_timedwait (&cond, &mutex, &ts)) != 0)
158 tret = (void *)1;
159 printf ("waiter[%u]:timedwait failed: %s\n", seq, strerror (ret));
160 goto unlock_out;
162 if ((ret = pthread_mutex_unlock (&mutex)) != 0)
164 tret = (void *)1;
165 printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
166 goto out;
168 pthread_cleanup_pop (0);
171 out:
172 puts ("timed_waiter tests done");
173 return tret;
175 unlock_out:
176 if ((ret = pthread_mutex_unlock (&mutex)) != 0)
177 printf ("waiter[%u]:mutex_unlock[2] failed: %s\n", seq, strerror (ret));
178 goto out;
182 do_test_wait (thr_func f)
184 pthread_t w[NUM];
185 pthread_t s;
186 pthread_mutexattr_t attr;
187 int i, j, ret = 0;
188 void *thr_ret;
190 for (i = 0; i < COUNT; i++)
192 if ((ret = pthread_mutexattr_init (&attr)) != 0)
194 printf ("mutexattr_init failed: %s\n", strerror (ret));
195 goto out;
198 if ((ret = pthread_mutexattr_setprotocol (&attr, PTHREAD_PRIO_INHERIT)) != 0)
200 printf ("mutexattr_setprotocol failed: %s\n", strerror (ret));
201 goto out;
204 if ((ret = pthread_cond_init (&cond, NULL)) != 0)
206 printf ("cond_init failed: %s\n", strerror (ret));
207 goto out;
210 if ((ret = pthread_mutex_init (&mutex, &attr)) != 0)
212 printf ("mutex_init failed: %s\n", strerror (ret));
213 goto out;
216 for (j = 0; j < NUM; j++)
217 if ((ret = pthread_create (&w[j], NULL, f, (void *)j)) != 0)
219 printf ("waiter[%d]: create failed: %s\n", j, strerror (ret));
220 goto out;
223 if ((ret = pthread_create (&s, NULL, signaller, NULL)) != 0)
225 printf ("signaller: create failed: %s\n", strerror (ret));
226 goto out;
229 for (j = 0; j < NUM; j++)
231 pthread_cancel (w[j]);
233 if ((ret = pthread_join (w[j], &thr_ret)) != 0)
235 printf ("waiter[%d]: join failed: %s\n", j, strerror (ret));
236 goto out;
239 if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
241 ret = 1;
242 goto out;
246 /* The signalling thread could have ended before it was cancelled. */
247 pthread_cancel (s);
249 if ((ret = pthread_join (s, &thr_ret)) != 0)
251 printf ("signaller: join failed: %s\n", strerror (ret));
252 goto out;
255 if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
257 ret = 1;
258 goto out;
262 out:
263 return ret;
267 do_test (int argc, char **argv)
269 int ret = do_test_wait (waiter);
271 if (ret)
272 return ret;
274 return do_test_wait (timed_waiter);
277 #define TIMEOUT 5
278 #include "../test-skeleton.c"