1 /* Verify that condition variables synchronized by PI mutexes don't hang.
2 Copyright (C) 2012-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/syscall.h>
26 #include <unistd.h>
27 #include <sys/time.h>
28 #include <time.h>
29
30 #define THREADS_NUM 5
31 #define MAXITER 50000
32
33 static pthread_mutex_t mutex;
34 static pthread_mutexattr_t mutex_attr;
35 static pthread_cond_t cond;
36 static pthread_t threads[THREADS_NUM];
37 static int pending = 0;
38
39 typedef void * (*threadfunc) (void *);
40
41 void *
thread_fun_timed(void * arg)42 thread_fun_timed (void *arg)
43 {
44 int *ret = arg;
45 int rv, i;
46
47 printf ("Started thread_fun_timed[%d]\n", *ret);
48
49 for (i = 0; i < MAXITER / THREADS_NUM; i++)
50 {
51 rv = pthread_mutex_lock (&mutex);
52 if (rv)
53 {
54 printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
55 *ret = 1;
56 goto out;
57 }
58
59 while (!pending)
60 {
61 struct timespec ts;
62 clock_gettime(CLOCK_REALTIME, &ts);
63 ts.tv_sec += 20;
64 rv = pthread_cond_timedwait (&cond, &mutex, &ts);
65
66 /* There should be no timeout either. */
67 if (rv)
68 {
69 printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
70 *ret = 1;
71 goto out;
72 }
73 }
74
75 pending--;
76
77 rv = pthread_mutex_unlock (&mutex);
78 if (rv)
79 {
80 printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
81 *ret = 1;
82 goto out;
83 }
84 }
85
86 *ret = 0;
87
88 out:
89 return ret;
90 }
91
92 void *
thread_fun(void * arg)93 thread_fun (void *arg)
94 {
95 int *ret = arg;
96 int rv, i;
97
98 printf ("Started thread_fun[%d]\n", *ret);
99
100 for (i = 0; i < MAXITER / THREADS_NUM; i++)
101 {
102 rv = pthread_mutex_lock (&mutex);
103 if (rv)
104 {
105 printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
106 *ret = 1;
107 goto out;
108 }
109
110 while (!pending)
111 {
112 rv = pthread_cond_wait (&cond, &mutex);
113
114 if (rv)
115 {
116 printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
117 *ret = 1;
118 goto out;
119 }
120 }
121
122 pending--;
123
124 rv = pthread_mutex_unlock (&mutex);
125 if (rv)
126 {
127 printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
128 *ret = 1;
129 goto out;
130 }
131 }
132
133 *ret = 0;
134
135 out:
136 return ret;
137 }
138
139 static int
do_test_wait(threadfunc f)140 do_test_wait (threadfunc f)
141 {
142 int i;
143 int rv;
144 int counter = 0;
145 int retval[THREADS_NUM];
146
147 puts ("Starting test");
148
149 rv = pthread_mutexattr_init (&mutex_attr);
150 if (rv)
151 {
152 printf ("pthread_mutexattr_init: %s(%d)\n", strerror (rv), rv);
153 return 1;
154 }
155
156 rv = pthread_mutexattr_setprotocol (&mutex_attr, PTHREAD_PRIO_INHERIT);
157 if (rv)
158 {
159 printf ("pthread_mutexattr_setprotocol: %s(%d)\n", strerror (rv), rv);
160 return 1;
161 }
162
163 rv = pthread_mutex_init (&mutex, &mutex_attr);
164 if (rv)
165 {
166 printf ("pthread_mutex_init: %s(%d)\n", strerror (rv), rv);
167 return 1;
168 }
169
170 rv = pthread_cond_init (&cond, NULL);
171 if (rv)
172 {
173 printf ("pthread_cond_init: %s(%d)\n", strerror (rv), rv);
174 return 1;
175 }
176
177 for (i = 0; i < THREADS_NUM; i++)
178 {
179 retval[i] = i;
180 rv = pthread_create (&threads[i], NULL, f, &retval[i]);
181 if (rv)
182 {
183 printf ("pthread_create: %s(%d)\n", strerror (rv), rv);
184 return 1;
185 }
186 }
187
188 for (; counter < MAXITER; counter++)
189 {
190 rv = pthread_mutex_lock (&mutex);
191 if (rv)
192 {
193 printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
194 return 1;
195 }
196
197 if (!(counter % 100))
198 printf ("counter: %d\n", counter);
199 pending += 1;
200
201 rv = pthread_cond_signal (&cond);
202 if (rv)
203 {
204 printf ("pthread_cond_signal: %s(%d)\n", strerror (rv), rv);
205 return 1;
206 }
207
208 rv = pthread_mutex_unlock (&mutex);
209 if (rv)
210 {
211 printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
212 return 1;
213 }
214 }
215
216 for (i = 0; i < THREADS_NUM; i++)
217 {
218 void *ret;
219 rv = pthread_join (threads[i], &ret);
220 if (rv)
221 {
222 printf ("pthread_join: %s(%d)\n", strerror (rv), rv);
223 return 1;
224 }
225 if (ret && *(int *)ret)
226 {
227 printf ("Thread %d returned with an error\n", i);
228 return 1;
229 }
230 }
231
232 return 0;
233 }
234
235 static int
do_test(void)236 do_test (void)
237 {
238 puts ("Testing pthread_cond_wait");
239 int ret = do_test_wait (thread_fun);
240 if (ret)
241 return ret;
242
243 puts ("Testing pthread_cond_timedwait");
244 return do_test_wait (thread_fun_timed);
245 }
246
247 #define TEST_FUNCTION do_test ()
248 #include "../test-skeleton.c"
249