]>
Commit | Line | Data |
---|---|---|
c30e8edf | 1 | /* Verify that condition variables synchronized by PI mutexes don't hang. |
6d7e8eda | 2 | Copyright (C) 2012-2023 Free Software Foundation, Inc. |
c30e8edf SP |
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 | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
c30e8edf SP |
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 * | |
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 * | |
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 | |
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 | |
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 | ||
c30e8edf SP |
247 | #define TEST_FUNCTION do_test () |
248 | #include "../test-skeleton.c" |