1/* Verify that condition variables synchronized by PI mutexes don't hang.
2 Copyright (C) 2012-2024 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
33static pthread_mutex_t mutex;
34static pthread_mutexattr_t mutex_attr;
35static pthread_cond_t cond;
36static pthread_t threads[THREADS_NUM];
37static int pending = 0;
38
39typedef void * (*threadfunc) (void *);
40
41void *
42thread_fun_timed (void *arg)
43{
44 int *ret = arg;
45 int rv, i;
46
47 printf (format: "Started thread_fun_timed[%d]\n", *ret);
48
49 for (i = 0; i < MAXITER / THREADS_NUM; i++)
50 {
51 rv = pthread_mutex_lock (mutex: &mutex);
52 if (rv)
53 {
54 printf (format: "pthread_mutex_lock: %s(%d)\n", strerror (errnum: rv), rv);
55 *ret = 1;
56 goto out;
57 }
58
59 while (!pending)
60 {
61 struct timespec ts;
62 clock_gettime(CLOCK_REALTIME, tp: &ts);
63 ts.tv_sec += 20;
64 rv = pthread_cond_timedwait (cond: &cond, mutex: &mutex, abstime: &ts);
65
66 /* There should be no timeout either. */
67 if (rv)
68 {
69 printf (format: "pthread_cond_wait: %s(%d)\n", strerror (errnum: rv), rv);
70 *ret = 1;
71 goto out;
72 }
73 }
74
75 pending--;
76
77 rv = pthread_mutex_unlock (mutex: &mutex);
78 if (rv)
79 {
80 printf (format: "pthread_mutex_unlock: %s(%d)\n", strerror (errnum: rv), rv);
81 *ret = 1;
82 goto out;
83 }
84 }
85
86 *ret = 0;
87
88out:
89 return ret;
90}
91
92void *
93thread_fun (void *arg)
94{
95 int *ret = arg;
96 int rv, i;
97
98 printf (format: "Started thread_fun[%d]\n", *ret);
99
100 for (i = 0; i < MAXITER / THREADS_NUM; i++)
101 {
102 rv = pthread_mutex_lock (mutex: &mutex);
103 if (rv)
104 {
105 printf (format: "pthread_mutex_lock: %s(%d)\n", strerror (errnum: rv), rv);
106 *ret = 1;
107 goto out;
108 }
109
110 while (!pending)
111 {
112 rv = pthread_cond_wait (cond: &cond, mutex: &mutex);
113
114 if (rv)
115 {
116 printf (format: "pthread_cond_wait: %s(%d)\n", strerror (errnum: rv), rv);
117 *ret = 1;
118 goto out;
119 }
120 }
121
122 pending--;
123
124 rv = pthread_mutex_unlock (mutex: &mutex);
125 if (rv)
126 {
127 printf (format: "pthread_mutex_unlock: %s(%d)\n", strerror (errnum: rv), rv);
128 *ret = 1;
129 goto out;
130 }
131 }
132
133 *ret = 0;
134
135out:
136 return ret;
137}
138
139static int
140do_test_wait (threadfunc f)
141{
142 int i;
143 int rv;
144 int counter = 0;
145 int retval[THREADS_NUM];
146
147 puts (s: "Starting test");
148
149 rv = pthread_mutexattr_init (attr: &mutex_attr);
150 if (rv)
151 {
152 printf (format: "pthread_mutexattr_init: %s(%d)\n", strerror (errnum: rv), rv);
153 return 1;
154 }
155
156 rv = pthread_mutexattr_setprotocol (attr: &mutex_attr, protocol: PTHREAD_PRIO_INHERIT);
157 if (rv)
158 {
159 printf (format: "pthread_mutexattr_setprotocol: %s(%d)\n", strerror (errnum: rv), rv);
160 return 1;
161 }
162
163 rv = pthread_mutex_init (mutex: &mutex, mutexattr: &mutex_attr);
164 if (rv)
165 {
166 printf (format: "pthread_mutex_init: %s(%d)\n", strerror (errnum: rv), rv);
167 return 1;
168 }
169
170 rv = pthread_cond_init (cond: &cond, NULL);
171 if (rv)
172 {
173 printf (format: "pthread_cond_init: %s(%d)\n", strerror (errnum: rv), rv);
174 return 1;
175 }
176
177 for (i = 0; i < THREADS_NUM; i++)
178 {
179 retval[i] = i;
180 rv = pthread_create (newthread: &threads[i], NULL, start_routine: f, arg: &retval[i]);
181 if (rv)
182 {
183 printf (format: "pthread_create: %s(%d)\n", strerror (errnum: rv), rv);
184 return 1;
185 }
186 }
187
188 for (; counter < MAXITER; counter++)
189 {
190 rv = pthread_mutex_lock (mutex: &mutex);
191 if (rv)
192 {
193 printf (format: "pthread_mutex_lock: %s(%d)\n", strerror (errnum: rv), rv);
194 return 1;
195 }
196
197 if (!(counter % 100))
198 printf (format: "counter: %d\n", counter);
199 pending += 1;
200
201 rv = pthread_cond_signal (cond: &cond);
202 if (rv)
203 {
204 printf (format: "pthread_cond_signal: %s(%d)\n", strerror (errnum: rv), rv);
205 return 1;
206 }
207
208 rv = pthread_mutex_unlock (mutex: &mutex);
209 if (rv)
210 {
211 printf (format: "pthread_mutex_unlock: %s(%d)\n", strerror (errnum: rv), rv);
212 return 1;
213 }
214 }
215
216 for (i = 0; i < THREADS_NUM; i++)
217 {
218 void *ret;
219 rv = pthread_join (th: threads[i], thread_return: &ret);
220 if (rv)
221 {
222 printf (format: "pthread_join: %s(%d)\n", strerror (errnum: rv), rv);
223 return 1;
224 }
225 if (ret && *(int *)ret)
226 {
227 printf (format: "Thread %d returned with an error\n", i);
228 return 1;
229 }
230 }
231
232 return 0;
233}
234
235static int
236do_test (void)
237{
238 puts (s: "Testing pthread_cond_wait");
239 int ret = do_test_wait (f: thread_fun);
240 if (ret)
241 return ret;
242
243 puts (s: "Testing pthread_cond_timedwait");
244 return do_test_wait (f: thread_fun_timed);
245}
246
247#define TEST_FUNCTION do_test ()
248#include "../test-skeleton.c"
249

source code of glibc/sysdeps/pthread/tst-cond24.c