1 /* $NetBSD: t_cond.c,v 1.8 2020/06/10 21:46:50 ad Exp $ */
2 
3 /*
4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __COPYRIGHT("@(#) Copyright (c) 2008\
31  The NetBSD Foundation, inc. All rights reserved.");
32 __RCSID("$NetBSD: t_cond.c,v 1.8 2020/06/10 21:46:50 ad Exp $");
33 
34 #include <sys/time.h>
35 
36 #include <errno.h>
37 #include <pthread.h>
38 #include <stdio.h>
39 #include <unistd.h>
40 
41 #include <atf-c.h>
42 
43 #include "h_common.h"
44 
45 static pthread_mutex_t mutex;
46 static pthread_cond_t cond;
47 static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER;
48 static pthread_cond_t static_cond = PTHREAD_COND_INITIALIZER;
49 static int count, share, toggle, total;
50 
51 static void *
signal_delay_wait_threadfunc(void * arg)52 signal_delay_wait_threadfunc(void *arg)
53 {
54           int *shared = (int *) arg;
55 
56           printf("2: Second thread.\n");
57 
58           printf("2: Locking mutex\n");
59           PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
60           printf("2: Got mutex.\n");
61           printf("Shared value: %d. Changing to 0.\n", *shared);
62           *shared = 0;
63 
64           PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
65           PTHREAD_REQUIRE(pthread_cond_signal(&cond));
66 
67           return NULL;
68 }
69 
70 ATF_TC(signal_delay_wait);
ATF_TC_HEAD(signal_delay_wait,tc)71 ATF_TC_HEAD(signal_delay_wait, tc)
72 {
73           atf_tc_set_md_var(tc, "descr", "Checks condition variables");
74 }
ATF_TC_BODY(signal_delay_wait,tc)75 ATF_TC_BODY(signal_delay_wait, tc)
76 {
77           pthread_t new;
78           void *joinval;
79           int sharedval;
80 
81           printf("1: condition variable test 1\n");
82 
83           PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
84           PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL));
85 
86           PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
87 
88           sharedval = 1;
89 
90           PTHREAD_REQUIRE(pthread_create(&new, NULL, signal_delay_wait_threadfunc,
91               &sharedval));
92 
93           printf("1: Before waiting.\n");
94           do {
95                     sleep(2);
96                     PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex));
97                     printf("1: After waiting, in loop.\n");
98           } while (sharedval != 0);
99 
100           printf("1: After the loop.\n");
101 
102           PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
103 
104           printf("1: After releasing the mutex.\n");
105           PTHREAD_REQUIRE(pthread_join(new, &joinval));
106 
107           printf("1: Thread joined.\n");
108 }
109 
110 static void *
signal_before_unlock_threadfunc(void * arg)111 signal_before_unlock_threadfunc(void *arg)
112 {
113           int *shared = (int *) arg;
114 
115           printf("2: Second thread.\n");
116 
117           printf("2: Locking mutex\n");
118           PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
119           printf("2: Got mutex.\n");
120           printf("Shared value: %d. Changing to 0.\n", *shared);
121           *shared = 0;
122 
123           /* Signal first, then unlock, for a different test than #1. */
124           PTHREAD_REQUIRE(pthread_cond_signal(&cond));
125           PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
126 
127           return NULL;
128 }
129 
130 ATF_TC(signal_before_unlock);
ATF_TC_HEAD(signal_before_unlock,tc)131 ATF_TC_HEAD(signal_before_unlock, tc)
132 {
133           atf_tc_set_md_var(tc, "descr",
134                     "Checks condition variables: signal before unlocking mutex");
135 }
ATF_TC_BODY(signal_before_unlock,tc)136 ATF_TC_BODY(signal_before_unlock, tc)
137 {
138           pthread_t new;
139           void *joinval;
140           int sharedval;
141 
142           printf("1: condition variable test 2\n");
143 
144           PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
145           PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL));
146 
147           PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
148 
149           sharedval = 1;
150 
151           PTHREAD_REQUIRE(pthread_create(&new, NULL,
152               signal_before_unlock_threadfunc, &sharedval));
153 
154           printf("1: Before waiting.\n");
155           do {
156                     sleep(2);
157                     PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex));
158                     printf("1: After waiting, in loop.\n");
159           } while (sharedval != 0);
160 
161           printf("1: After the loop.\n");
162 
163           PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
164 
165           printf("1: After releasing the mutex.\n");
166           PTHREAD_REQUIRE(pthread_join(new, &joinval));
167 
168           printf("1: Thread joined.\n");
169 }
170 
171 static void *
signal_before_unlock_static_init_threadfunc(void * arg)172 signal_before_unlock_static_init_threadfunc(void *arg)
173 {
174           int *shared = (int *) arg;
175 
176           printf("2: Second thread.\n");
177 
178           printf("2: Locking mutex\n");
179           PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
180           printf("2: Got mutex.\n");
181           printf("Shared value: %d. Changing to 0.\n", *shared);
182           *shared = 0;
183 
184           /* Signal first, then unlock, for a different test than #1. */
185           PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
186           PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
187 
188           return NULL;
189 }
190 
191 ATF_TC(signal_before_unlock_static_init);
ATF_TC_HEAD(signal_before_unlock_static_init,tc)192 ATF_TC_HEAD(signal_before_unlock_static_init, tc)
193 {
194           atf_tc_set_md_var(tc, "descr",
195                     "Checks condition variables: signal before unlocking "
196                     "mutex, use static initializers");
197 }
ATF_TC_BODY(signal_before_unlock_static_init,tc)198 ATF_TC_BODY(signal_before_unlock_static_init, tc)
199 {
200           pthread_t new;
201           void *joinval;
202           int sharedval;
203 
204           printf("1: condition variable test 3\n");
205 
206           PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
207 
208           sharedval = 1;
209 
210           PTHREAD_REQUIRE(pthread_create(&new, NULL,
211               signal_before_unlock_static_init_threadfunc, &sharedval));
212 
213           printf("1: Before waiting.\n");
214           do {
215                     sleep(2);
216                     PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, &static_mutex));
217                     printf("1: After waiting, in loop.\n");
218           } while (sharedval != 0);
219 
220           printf("1: After the loop.\n");
221 
222           PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
223 
224           printf("1: After releasing the mutex.\n");
225           PTHREAD_REQUIRE(pthread_join(new, &joinval));
226 
227           printf("1: Thread joined.\n");
228 }
229 
230 static void *
signal_wait_race_threadfunc(void * arg)231 signal_wait_race_threadfunc(void *arg)
232 {
233           printf("2: Second thread.\n");
234           PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
235           printf("2: Before the loop.\n");
236           while (count>0) {
237                     count--;
238                     total++;
239                     toggle = 0;
240                     /* printf("2: Before signal %d.\n", count); */
241                     PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
242                     do {
243                               PTHREAD_REQUIRE(pthread_cond_wait(&static_cond,
244                                   &static_mutex));
245                     } while (toggle != 1);
246           }
247           printf("2: After the loop.\n");
248           PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
249 
250           return NULL;
251 }
252 
253 ATF_TC(signal_wait_race);
ATF_TC_HEAD(signal_wait_race,tc)254 ATF_TC_HEAD(signal_wait_race, tc)
255 {
256           atf_tc_set_md_var(tc, "descr", "Checks condition variables");
257 }
ATF_TC_BODY(signal_wait_race,tc)258 ATF_TC_BODY(signal_wait_race, tc)
259 {
260           pthread_t new;
261           void *joinval;
262           int sharedval;
263 
264           printf("1: condition variable test 4\n");
265 
266           PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
267 
268           count = 50000;
269           toggle = 0;
270 
271           PTHREAD_REQUIRE(pthread_create(&new, NULL, signal_wait_race_threadfunc,
272               &sharedval));
273 
274           printf("1: Before waiting.\n");
275           while (count>0) {
276                     count--;
277                     total++;
278                     toggle = 1;
279                     /* printf("1: Before signal %d.\n", count); */
280                     PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
281                     do {
282                               PTHREAD_REQUIRE(pthread_cond_wait(&static_cond,
283                                   &static_mutex));
284                     } while (toggle != 0);
285           }
286           printf("1: After the loop.\n");
287 
288           toggle = 1;
289           PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
290           PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
291 
292           printf("1: After releasing the mutex.\n");
293           PTHREAD_REQUIRE(pthread_join(new, &joinval));
294 
295           printf("1: Thread joined. Final count = %d, total = %d\n",
296                     count, total);
297 
298           ATF_REQUIRE_EQ(count, 0);
299           ATF_REQUIRE_EQ(total, 50000);
300 }
301 
302 static void *
pthread_cond_timedwait_func(void * arg)303 pthread_cond_timedwait_func(void *arg)
304 {
305           struct timespec ts;
306           size_t i = 0;
307           int rv;
308 
309           for (;;) {
310 
311                     if (i++ >= 10000)
312                               pthread_exit(NULL);
313 
314                     (void)memset(&ts, 0, sizeof(struct timespec));
315 
316                     ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts) == 0);
317 
318                     /*
319                      * Set to one second in the past:
320                      * pthread_cond_timedwait(3) should
321                      * return ETIMEDOUT immediately.
322                      */
323                     ts.tv_sec = ts.tv_sec - 1;
324 
325                     PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
326                     rv = pthread_cond_timedwait(&static_cond, &static_mutex, &ts);
327 
328                     /*
329                      * Sometimes we catch ESRCH.
330                      * This should never happen.
331                      */
332                     ATF_REQUIRE(rv == ETIMEDOUT || rv == 0);
333                     PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
334           }
335 }
336 
337 ATF_TC(cond_timedwait_race);
ATF_TC_HEAD(cond_timedwait_race,tc)338 ATF_TC_HEAD(cond_timedwait_race, tc)
339 {
340           atf_tc_set_md_var(tc, "descr", "Test pthread_cond_timedwait(3)");
341 
342 }
ATF_TC_BODY(cond_timedwait_race,tc)343 ATF_TC_BODY(cond_timedwait_race, tc)
344 {
345           pthread_t tid[64];
346           size_t i;
347 
348           for (i = 0; i < __arraycount(tid); i++) {
349 
350                     PTHREAD_REQUIRE(pthread_create(&tid[i], NULL,
351                         pthread_cond_timedwait_func, NULL));
352           }
353 
354           for (i = 0; i < __arraycount(tid); i++) {
355 
356                     PTHREAD_REQUIRE(pthread_join(tid[i], NULL));
357           }
358 }
359 
360 static void *
broadcast_threadfunc(void * arg)361 broadcast_threadfunc(void *arg)
362 {
363           printf("2: Second thread.\n");
364 
365           PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
366           while (count>0) {
367                     count--;
368                     total++;
369                     toggle = 0;
370                     PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
371                     do {
372                               PTHREAD_REQUIRE(pthread_cond_wait(&static_cond,
373                                   &static_mutex));
374                     } while (toggle != 1);
375           }
376           printf("2: After the loop.\n");
377           PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
378 
379           return NULL;
380 }
381 
382 
383 ATF_TC(broadcast);
ATF_TC_HEAD(broadcast,tc)384 ATF_TC_HEAD(broadcast, tc)
385 {
386           atf_tc_set_md_var(tc, "descr",
387                     "Checks condition variables: use pthread_cond_broadcast()");
388 }
ATF_TC_BODY(broadcast,tc)389 ATF_TC_BODY(broadcast, tc)
390 {
391           pthread_t new;
392           void *joinval;
393           int sharedval;
394 
395           printf("1: condition variable test 5\n");
396 
397           PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
398 
399           count = 50000;
400           toggle = 0;
401 
402           PTHREAD_REQUIRE(pthread_create(&new, NULL, broadcast_threadfunc,
403               &sharedval));
404 
405           printf("1: Before waiting.\n");
406           while (count>0) {
407                     count--;
408                     total++;
409                     toggle = 1;
410                     PTHREAD_REQUIRE(pthread_cond_broadcast(&static_cond));
411                     do {
412                               PTHREAD_REQUIRE(pthread_cond_wait(&static_cond,
413                                   &static_mutex));
414                     } while (toggle != 0);
415           }
416           printf("1: After the loop.\n");
417 
418           toggle = 1;
419           PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
420           PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
421 
422           printf("1: After releasing the mutex.\n");
423           PTHREAD_REQUIRE(pthread_join(new, &joinval));
424 
425           printf("1: Thread joined. Final count = %d, total = %d\n", count,
426               total);
427 
428           ATF_REQUIRE_EQ(count, 0);
429           ATF_REQUIRE_EQ(total, 50000);
430 }
431 
432 static void *
bogus_timedwaits_threadfunc(void * arg)433 bogus_timedwaits_threadfunc(void *arg)
434 {
435           return NULL;
436 }
437 
438 ATF_TC(bogus_timedwaits);
ATF_TC_HEAD(bogus_timedwaits,tc)439 ATF_TC_HEAD(bogus_timedwaits, tc)
440 {
441           atf_tc_set_md_var(tc, "descr",
442                     "Checks condition variables: bogus timedwaits");
443 }
ATF_TC_BODY(bogus_timedwaits,tc)444 ATF_TC_BODY(bogus_timedwaits, tc)
445 {
446           pthread_t new;
447           struct timespec ts;
448           struct timeval tv;
449 
450           printf("condition variable test 6: bogus timedwaits\n");
451 
452           PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
453 
454           printf("unthreaded test (past)\n");
455           gettimeofday(&tv, NULL);
456           tv.tv_sec -= 2; /* Place the time in the past */
457           TIMEVAL_TO_TIMESPEC(&tv, &ts);
458 
459           ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex,
460               &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) in the "
461               "past");
462 
463           printf("unthreaded test (zero time)\n");
464           tv.tv_sec = 0;
465           tv.tv_usec = 0;
466           TIMEVAL_TO_TIMESPEC(&tv, &ts);
467 
468           ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex,
469               &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) with zero "
470               "time");
471 
472           PTHREAD_REQUIRE(pthread_create(&new, NULL, bogus_timedwaits_threadfunc,
473               NULL));
474           PTHREAD_REQUIRE(pthread_join(new, NULL));
475 
476           printf("threaded test\n");
477           gettimeofday(&tv, NULL);
478           tv.tv_sec -= 2; /* Place the time in the past */
479           TIMEVAL_TO_TIMESPEC(&tv, &ts);
480 
481           ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex,
482               &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) in the past");
483 
484           printf("threaded test (zero time)\n");
485           tv.tv_sec = 0;
486           tv.tv_usec = 0;
487           TIMEVAL_TO_TIMESPEC(&tv, &ts);
488 
489           ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex,
490               &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) with zero "
491               "time");
492 
493           PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
494 }
495 
496 static void
unlock(void * arg)497 unlock(void *arg)
498 {
499           pthread_mutex_unlock((pthread_mutex_t *)arg);
500 }
501 
502 static void *
destroy_after_cancel_threadfunc(void * arg)503 destroy_after_cancel_threadfunc(void *arg)
504 {
505           PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
506 
507           pthread_cleanup_push(unlock, &mutex);
508 
509           while (1) {
510                     share = 1;
511                     PTHREAD_REQUIRE(pthread_cond_broadcast(&cond));
512                     PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex));
513           }
514 
515           pthread_cleanup_pop(0);
516           PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
517 
518           return NULL;
519 }
520 
521 ATF_TC(destroy_after_cancel);
ATF_TC_HEAD(destroy_after_cancel,tc)522 ATF_TC_HEAD(destroy_after_cancel, tc)
523 {
524           atf_tc_set_md_var(tc, "descr", "Checks destroying a condition variable "
525               "after cancelling a wait");
526 }
ATF_TC_BODY(destroy_after_cancel,tc)527 ATF_TC_BODY(destroy_after_cancel, tc)
528 {
529           pthread_t thread;
530 
531           PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
532           PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL));
533           PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
534           PTHREAD_REQUIRE(pthread_create(&thread, NULL,
535               destroy_after_cancel_threadfunc, NULL));
536 
537           while (share == 0) {
538                     PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex));
539           }
540 
541           PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
542           PTHREAD_REQUIRE(pthread_cancel(thread));
543 
544           PTHREAD_REQUIRE(pthread_join(thread, NULL));
545           PTHREAD_REQUIRE(pthread_cond_destroy(&cond));
546 
547           PTHREAD_REQUIRE(pthread_mutex_destroy(&mutex));
548 }
549 
550 ATF_TC(condattr);
ATF_TC_HEAD(condattr,tc)551 ATF_TC_HEAD(condattr, tc)
552 {
553           atf_tc_set_md_var(tc, "descr", "Checks Condattr");
554 }
ATF_TC_BODY(condattr,tc)555 ATF_TC_BODY(condattr, tc)
556 {
557           pthread_condattr_t condattr;
558           clockid_t clockid;
559 
560           PTHREAD_REQUIRE(pthread_condattr_init(&condattr));
561           PTHREAD_REQUIRE(pthread_condattr_setclock(&condattr, CLOCK_REALTIME));
562           PTHREAD_REQUIRE(pthread_condattr_getclock(&condattr, &clockid));
563           ATF_REQUIRE_EQ(clockid, CLOCK_REALTIME);
564 
565           PTHREAD_REQUIRE(pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC));
566           PTHREAD_REQUIRE(pthread_condattr_getclock(&condattr, &clockid));
567           ATF_REQUIRE_EQ(clockid, CLOCK_MONOTONIC);
568 }
569 
ATF_TP_ADD_TCS(tp)570 ATF_TP_ADD_TCS(tp)
571 {
572 
573           ATF_TP_ADD_TC(tp, signal_delay_wait);
574           ATF_TP_ADD_TC(tp, signal_before_unlock);
575           ATF_TP_ADD_TC(tp, signal_before_unlock_static_init);
576           ATF_TP_ADD_TC(tp, signal_wait_race);
577           ATF_TP_ADD_TC(tp, cond_timedwait_race);
578           ATF_TP_ADD_TC(tp, broadcast);
579           ATF_TP_ADD_TC(tp, bogus_timedwaits);
580           ATF_TP_ADD_TC(tp, destroy_after_cancel);
581           ATF_TP_ADD_TC(tp, condattr);
582 
583           return atf_no_error();
584 }
585