xref: /minix3/tests/lib/libpthread/t_cond.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /* $NetBSD: t_cond.c,v 1.6 2014/09/03 16:23:24 gson Exp $ */
211be35a1SLionel Sambuc 
311be35a1SLionel Sambuc /*
411be35a1SLionel Sambuc  * Copyright (c) 2008 The NetBSD Foundation, Inc.
511be35a1SLionel Sambuc  * All rights reserved.
611be35a1SLionel Sambuc  *
711be35a1SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
811be35a1SLionel Sambuc  * modification, are permitted provided that the following conditions
911be35a1SLionel Sambuc  * are met:
1011be35a1SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
1111be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
1211be35a1SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
1311be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
1411be35a1SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
1511be35a1SLionel Sambuc  *
1611be35a1SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1711be35a1SLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1811be35a1SLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1911be35a1SLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2011be35a1SLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2111be35a1SLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2211be35a1SLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2311be35a1SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2411be35a1SLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2511be35a1SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2611be35a1SLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
2711be35a1SLionel Sambuc  */
2811be35a1SLionel Sambuc 
2911be35a1SLionel Sambuc #include <sys/cdefs.h>
3011be35a1SLionel Sambuc __COPYRIGHT("@(#) Copyright (c) 2008\
3111be35a1SLionel Sambuc  The NetBSD Foundation, inc. All rights reserved.");
32*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: t_cond.c,v 1.6 2014/09/03 16:23:24 gson Exp $");
3311be35a1SLionel Sambuc 
3411be35a1SLionel Sambuc #include <sys/time.h>
3511be35a1SLionel Sambuc 
3611be35a1SLionel Sambuc #include <errno.h>
3711be35a1SLionel Sambuc #include <pthread.h>
3811be35a1SLionel Sambuc #include <stdio.h>
3911be35a1SLionel Sambuc #include <unistd.h>
4011be35a1SLionel Sambuc 
4111be35a1SLionel Sambuc #include <atf-c.h>
4211be35a1SLionel Sambuc 
4311be35a1SLionel Sambuc #include "h_common.h"
4411be35a1SLionel Sambuc 
4511be35a1SLionel Sambuc static pthread_mutex_t mutex;
4611be35a1SLionel Sambuc static pthread_cond_t cond;
4711be35a1SLionel Sambuc static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER;
4811be35a1SLionel Sambuc static pthread_cond_t static_cond = PTHREAD_COND_INITIALIZER;
4911be35a1SLionel Sambuc static int count, share, toggle, total;
5011be35a1SLionel Sambuc 
5111be35a1SLionel Sambuc static void *
signal_delay_wait_threadfunc(void * arg)5211be35a1SLionel Sambuc signal_delay_wait_threadfunc(void *arg)
5311be35a1SLionel Sambuc {
5411be35a1SLionel Sambuc 	int *shared = (int *) arg;
5511be35a1SLionel Sambuc 
5611be35a1SLionel Sambuc 	printf("2: Second thread.\n");
5711be35a1SLionel Sambuc 
5811be35a1SLionel Sambuc 	printf("2: Locking mutex\n");
5911be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
6011be35a1SLionel Sambuc 	printf("2: Got mutex.\n");
6111be35a1SLionel Sambuc 	printf("Shared value: %d. Changing to 0.\n", *shared);
6211be35a1SLionel Sambuc 	*shared = 0;
6311be35a1SLionel Sambuc 
6411be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
6511be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cond_signal(&cond));
6611be35a1SLionel Sambuc 
6711be35a1SLionel Sambuc 	return NULL;
6811be35a1SLionel Sambuc }
6911be35a1SLionel Sambuc 
7011be35a1SLionel Sambuc ATF_TC(signal_delay_wait);
ATF_TC_HEAD(signal_delay_wait,tc)7111be35a1SLionel Sambuc ATF_TC_HEAD(signal_delay_wait, tc)
7211be35a1SLionel Sambuc {
7311be35a1SLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks condition variables");
7411be35a1SLionel Sambuc }
ATF_TC_BODY(signal_delay_wait,tc)7511be35a1SLionel Sambuc ATF_TC_BODY(signal_delay_wait, tc)
7611be35a1SLionel Sambuc {
7711be35a1SLionel Sambuc 	pthread_t new;
7811be35a1SLionel Sambuc 	void *joinval;
7911be35a1SLionel Sambuc 	int sharedval;
8011be35a1SLionel Sambuc 
8111be35a1SLionel Sambuc 	printf("1: condition variable test 1\n");
8211be35a1SLionel Sambuc 
8311be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
8411be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL));
8511be35a1SLionel Sambuc 
8611be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
8711be35a1SLionel Sambuc 
8811be35a1SLionel Sambuc 	sharedval = 1;
8911be35a1SLionel Sambuc 
9011be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_create(&new, NULL, signal_delay_wait_threadfunc,
9111be35a1SLionel Sambuc 	    &sharedval));
9211be35a1SLionel Sambuc 
9311be35a1SLionel Sambuc 	printf("1: Before waiting.\n");
9411be35a1SLionel Sambuc 	do {
9511be35a1SLionel Sambuc 		sleep(2);
9611be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex));
9711be35a1SLionel Sambuc 		printf("1: After waiting, in loop.\n");
9811be35a1SLionel Sambuc 	} while (sharedval != 0);
9911be35a1SLionel Sambuc 
10011be35a1SLionel Sambuc 	printf("1: After the loop.\n");
10111be35a1SLionel Sambuc 
10211be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
10311be35a1SLionel Sambuc 
10411be35a1SLionel Sambuc 	printf("1: After releasing the mutex.\n");
10511be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
10611be35a1SLionel Sambuc 
10711be35a1SLionel Sambuc 	printf("1: Thread joined.\n");
10811be35a1SLionel Sambuc }
10911be35a1SLionel Sambuc 
11011be35a1SLionel Sambuc static void *
signal_before_unlock_threadfunc(void * arg)11111be35a1SLionel Sambuc signal_before_unlock_threadfunc(void *arg)
11211be35a1SLionel Sambuc {
11311be35a1SLionel Sambuc 	int *shared = (int *) arg;
11411be35a1SLionel Sambuc 
11511be35a1SLionel Sambuc 	printf("2: Second thread.\n");
11611be35a1SLionel Sambuc 
11711be35a1SLionel Sambuc 	printf("2: Locking mutex\n");
11811be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
11911be35a1SLionel Sambuc 	printf("2: Got mutex.\n");
12011be35a1SLionel Sambuc 	printf("Shared value: %d. Changing to 0.\n", *shared);
12111be35a1SLionel Sambuc 	*shared = 0;
12211be35a1SLionel Sambuc 
12311be35a1SLionel Sambuc 	/* Signal first, then unlock, for a different test than #1. */
12411be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cond_signal(&cond));
12511be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
12611be35a1SLionel Sambuc 
12711be35a1SLionel Sambuc 	return NULL;
12811be35a1SLionel Sambuc }
12911be35a1SLionel Sambuc 
13011be35a1SLionel Sambuc ATF_TC(signal_before_unlock);
ATF_TC_HEAD(signal_before_unlock,tc)13111be35a1SLionel Sambuc ATF_TC_HEAD(signal_before_unlock, tc)
13211be35a1SLionel Sambuc {
13311be35a1SLionel Sambuc 	atf_tc_set_md_var(tc, "descr",
13411be35a1SLionel Sambuc 		"Checks condition variables: signal before unlocking mutex");
13511be35a1SLionel Sambuc }
ATF_TC_BODY(signal_before_unlock,tc)13611be35a1SLionel Sambuc ATF_TC_BODY(signal_before_unlock, tc)
13711be35a1SLionel Sambuc {
13811be35a1SLionel Sambuc 	pthread_t new;
13911be35a1SLionel Sambuc 	void *joinval;
14011be35a1SLionel Sambuc 	int sharedval;
14111be35a1SLionel Sambuc 
14211be35a1SLionel Sambuc 	printf("1: condition variable test 2\n");
14311be35a1SLionel Sambuc 
14411be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
14511be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL));
14611be35a1SLionel Sambuc 
14711be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
14811be35a1SLionel Sambuc 
14911be35a1SLionel Sambuc 	sharedval = 1;
15011be35a1SLionel Sambuc 
15111be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_create(&new, NULL,
15211be35a1SLionel Sambuc 	    signal_before_unlock_threadfunc, &sharedval));
15311be35a1SLionel Sambuc 
15411be35a1SLionel Sambuc 	printf("1: Before waiting.\n");
15511be35a1SLionel Sambuc 	do {
15611be35a1SLionel Sambuc 		sleep(2);
15711be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex));
15811be35a1SLionel Sambuc 		printf("1: After waiting, in loop.\n");
15911be35a1SLionel Sambuc 	} while (sharedval != 0);
16011be35a1SLionel Sambuc 
16111be35a1SLionel Sambuc 	printf("1: After the loop.\n");
16211be35a1SLionel Sambuc 
16311be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
16411be35a1SLionel Sambuc 
16511be35a1SLionel Sambuc 	printf("1: After releasing the mutex.\n");
16611be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
16711be35a1SLionel Sambuc 
16811be35a1SLionel Sambuc 	printf("1: Thread joined.\n");
16911be35a1SLionel Sambuc }
17011be35a1SLionel Sambuc 
17111be35a1SLionel Sambuc static void *
signal_before_unlock_static_init_threadfunc(void * arg)17211be35a1SLionel Sambuc signal_before_unlock_static_init_threadfunc(void *arg)
17311be35a1SLionel Sambuc {
17411be35a1SLionel Sambuc 	int *shared = (int *) arg;
17511be35a1SLionel Sambuc 
17611be35a1SLionel Sambuc 	printf("2: Second thread.\n");
17711be35a1SLionel Sambuc 
17811be35a1SLionel Sambuc 	printf("2: Locking mutex\n");
17911be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
18011be35a1SLionel Sambuc 	printf("2: Got mutex.\n");
18111be35a1SLionel Sambuc 	printf("Shared value: %d. Changing to 0.\n", *shared);
18211be35a1SLionel Sambuc 	*shared = 0;
18311be35a1SLionel Sambuc 
18411be35a1SLionel Sambuc 	/* Signal first, then unlock, for a different test than #1. */
18511be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
18611be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
18711be35a1SLionel Sambuc 
18811be35a1SLionel Sambuc 	return NULL;
18911be35a1SLionel Sambuc }
19011be35a1SLionel Sambuc 
19111be35a1SLionel Sambuc ATF_TC(signal_before_unlock_static_init);
ATF_TC_HEAD(signal_before_unlock_static_init,tc)19211be35a1SLionel Sambuc ATF_TC_HEAD(signal_before_unlock_static_init, tc)
19311be35a1SLionel Sambuc {
19411be35a1SLionel Sambuc 	atf_tc_set_md_var(tc, "descr",
19511be35a1SLionel Sambuc 		"Checks condition variables: signal before unlocking "
19611be35a1SLionel Sambuc 		"mutex, use static initializers");
19711be35a1SLionel Sambuc }
ATF_TC_BODY(signal_before_unlock_static_init,tc)19811be35a1SLionel Sambuc ATF_TC_BODY(signal_before_unlock_static_init, tc)
19911be35a1SLionel Sambuc {
20011be35a1SLionel Sambuc 	pthread_t new;
20111be35a1SLionel Sambuc 	void *joinval;
20211be35a1SLionel Sambuc 	int sharedval;
20311be35a1SLionel Sambuc 
20411be35a1SLionel Sambuc 	printf("1: condition variable test 3\n");
20511be35a1SLionel Sambuc 
20611be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
20711be35a1SLionel Sambuc 
20811be35a1SLionel Sambuc 	sharedval = 1;
20911be35a1SLionel Sambuc 
21011be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_create(&new, NULL,
21111be35a1SLionel Sambuc 	    signal_before_unlock_static_init_threadfunc, &sharedval));
21211be35a1SLionel Sambuc 
21311be35a1SLionel Sambuc 	printf("1: Before waiting.\n");
21411be35a1SLionel Sambuc 	do {
21511be35a1SLionel Sambuc 		sleep(2);
21611be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, &static_mutex));
21711be35a1SLionel Sambuc 		printf("1: After waiting, in loop.\n");
21811be35a1SLionel Sambuc 	} while (sharedval != 0);
21911be35a1SLionel Sambuc 
22011be35a1SLionel Sambuc 	printf("1: After the loop.\n");
22111be35a1SLionel Sambuc 
22211be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
22311be35a1SLionel Sambuc 
22411be35a1SLionel Sambuc 	printf("1: After releasing the mutex.\n");
22511be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
22611be35a1SLionel Sambuc 
22711be35a1SLionel Sambuc 	printf("1: Thread joined.\n");
22811be35a1SLionel Sambuc }
22911be35a1SLionel Sambuc 
23011be35a1SLionel Sambuc static void *
signal_wait_race_threadfunc(void * arg)23111be35a1SLionel Sambuc signal_wait_race_threadfunc(void *arg)
23211be35a1SLionel Sambuc {
23311be35a1SLionel Sambuc 	printf("2: Second thread.\n");
23411be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
23511be35a1SLionel Sambuc 	printf("2: Before the loop.\n");
23611be35a1SLionel Sambuc 	while (count>0) {
23711be35a1SLionel Sambuc 		count--;
23811be35a1SLionel Sambuc 		total++;
23911be35a1SLionel Sambuc 		toggle = 0;
24011be35a1SLionel Sambuc 		/* printf("2: Before signal %d.\n", count); */
24111be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
24211be35a1SLionel Sambuc 		do {
24311be35a1SLionel Sambuc 			PTHREAD_REQUIRE(pthread_cond_wait(&static_cond,
24411be35a1SLionel Sambuc 			    &static_mutex));
24511be35a1SLionel Sambuc 		} while (toggle != 1);
24611be35a1SLionel Sambuc 	}
24711be35a1SLionel Sambuc 	printf("2: After the loop.\n");
24811be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
24911be35a1SLionel Sambuc 
25011be35a1SLionel Sambuc 	return NULL;
25111be35a1SLionel Sambuc }
25211be35a1SLionel Sambuc 
25311be35a1SLionel Sambuc ATF_TC(signal_wait_race);
ATF_TC_HEAD(signal_wait_race,tc)25411be35a1SLionel Sambuc ATF_TC_HEAD(signal_wait_race, tc)
25511be35a1SLionel Sambuc {
25611be35a1SLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks condition variables");
25711be35a1SLionel Sambuc }
ATF_TC_BODY(signal_wait_race,tc)25811be35a1SLionel Sambuc ATF_TC_BODY(signal_wait_race, tc)
25911be35a1SLionel Sambuc {
26011be35a1SLionel Sambuc 	pthread_t new;
26111be35a1SLionel Sambuc 	void *joinval;
26211be35a1SLionel Sambuc 	int sharedval;
26311be35a1SLionel Sambuc 
26411be35a1SLionel Sambuc 	printf("1: condition variable test 4\n");
26511be35a1SLionel Sambuc 
26611be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
26711be35a1SLionel Sambuc 
26811be35a1SLionel Sambuc 	count = 50000;
26911be35a1SLionel Sambuc 	toggle = 0;
27011be35a1SLionel Sambuc 
27111be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_create(&new, NULL, signal_wait_race_threadfunc,
27211be35a1SLionel Sambuc 	    &sharedval));
27311be35a1SLionel Sambuc 
27411be35a1SLionel Sambuc 	printf("1: Before waiting.\n");
27511be35a1SLionel Sambuc 	while (count>0) {
27611be35a1SLionel Sambuc 		count--;
27711be35a1SLionel Sambuc 		total++;
27811be35a1SLionel Sambuc 		toggle = 1;
27911be35a1SLionel Sambuc 		/* printf("1: Before signal %d.\n", count); */
28011be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
28111be35a1SLionel Sambuc 		do {
28211be35a1SLionel Sambuc 			PTHREAD_REQUIRE(pthread_cond_wait(&static_cond,
28311be35a1SLionel Sambuc 			    &static_mutex));
28411be35a1SLionel Sambuc 		} while (toggle != 0);
28511be35a1SLionel Sambuc 	}
28611be35a1SLionel Sambuc 	printf("1: After the loop.\n");
28711be35a1SLionel Sambuc 
28811be35a1SLionel Sambuc 	toggle = 1;
28911be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
29011be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
29111be35a1SLionel Sambuc 
29211be35a1SLionel Sambuc 	printf("1: After releasing the mutex.\n");
29311be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
29411be35a1SLionel Sambuc 
29511be35a1SLionel Sambuc 	printf("1: Thread joined. Final count = %d, total = %d\n",
29611be35a1SLionel Sambuc 		count, total);
29711be35a1SLionel Sambuc 
29811be35a1SLionel Sambuc 	ATF_REQUIRE_EQ(count, 0);
29911be35a1SLionel Sambuc 	ATF_REQUIRE_EQ(total, 50000);
30011be35a1SLionel Sambuc }
30111be35a1SLionel Sambuc 
30211be35a1SLionel Sambuc static void *
pthread_cond_timedwait_func(void * arg)30311be35a1SLionel Sambuc pthread_cond_timedwait_func(void *arg)
30411be35a1SLionel Sambuc {
30511be35a1SLionel Sambuc 	struct timespec ts;
30611be35a1SLionel Sambuc 	size_t i = 0;
30711be35a1SLionel Sambuc 	int rv;
30811be35a1SLionel Sambuc 
30911be35a1SLionel Sambuc 	for (;;) {
31011be35a1SLionel Sambuc 
31111be35a1SLionel Sambuc 		if (i++ >= 10000)
31211be35a1SLionel Sambuc 			pthread_exit(NULL);
31311be35a1SLionel Sambuc 
31411be35a1SLionel Sambuc 		(void)memset(&ts, 0, sizeof(struct timespec));
31511be35a1SLionel Sambuc 
31611be35a1SLionel Sambuc 		ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts) == 0);
31711be35a1SLionel Sambuc 
31811be35a1SLionel Sambuc 		/*
31911be35a1SLionel Sambuc 		 * Set to one second in the past:
32011be35a1SLionel Sambuc 		 * pthread_cond_timedwait(3) should
32111be35a1SLionel Sambuc 		 * return ETIMEDOUT immediately.
32211be35a1SLionel Sambuc 		 */
32311be35a1SLionel Sambuc 		ts.tv_sec = ts.tv_sec - 1;
32411be35a1SLionel Sambuc 
32511be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
32611be35a1SLionel Sambuc 		rv = pthread_cond_timedwait(&static_cond, &static_mutex, &ts);
32711be35a1SLionel Sambuc 
32811be35a1SLionel Sambuc 		/*
32911be35a1SLionel Sambuc 		 * Sometimes we catch ESRCH.
33011be35a1SLionel Sambuc 		 * This should never happen.
33111be35a1SLionel Sambuc 		 */
33211be35a1SLionel Sambuc 		ATF_REQUIRE(rv == ETIMEDOUT);
33311be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
33411be35a1SLionel Sambuc 	}
33511be35a1SLionel Sambuc }
33611be35a1SLionel Sambuc 
33711be35a1SLionel Sambuc ATF_TC(cond_timedwait_race);
ATF_TC_HEAD(cond_timedwait_race,tc)33811be35a1SLionel Sambuc ATF_TC_HEAD(cond_timedwait_race, tc)
33911be35a1SLionel Sambuc {
34011be35a1SLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Test pthread_cond_timedwait(3)");
34111be35a1SLionel Sambuc 
34211be35a1SLionel Sambuc }
ATF_TC_BODY(cond_timedwait_race,tc)34311be35a1SLionel Sambuc ATF_TC_BODY(cond_timedwait_race, tc)
34411be35a1SLionel Sambuc {
34511be35a1SLionel Sambuc 	pthread_t tid[64];
346*0a6a1f1dSLionel Sambuc 	size_t i;
34711be35a1SLionel Sambuc 
34811be35a1SLionel Sambuc 	for (i = 0; i < __arraycount(tid); i++) {
34911be35a1SLionel Sambuc 
35011be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_create(&tid[i], NULL,
35111be35a1SLionel Sambuc 		    pthread_cond_timedwait_func, NULL));
35211be35a1SLionel Sambuc 	}
35311be35a1SLionel Sambuc 
35411be35a1SLionel Sambuc 	for (i = 0; i < __arraycount(tid); i++) {
35511be35a1SLionel Sambuc 
35611be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_join(tid[i], NULL));
35711be35a1SLionel Sambuc 	}
35811be35a1SLionel Sambuc }
35911be35a1SLionel Sambuc 
36011be35a1SLionel Sambuc static void *
broadcast_threadfunc(void * arg)36111be35a1SLionel Sambuc broadcast_threadfunc(void *arg)
36211be35a1SLionel Sambuc {
36311be35a1SLionel Sambuc 	printf("2: Second thread.\n");
36411be35a1SLionel Sambuc 
36511be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
36611be35a1SLionel Sambuc 	while (count>0) {
36711be35a1SLionel Sambuc 		count--;
36811be35a1SLionel Sambuc 		total++;
36911be35a1SLionel Sambuc 		toggle = 0;
37011be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
37111be35a1SLionel Sambuc 		do {
37211be35a1SLionel Sambuc 			PTHREAD_REQUIRE(pthread_cond_wait(&static_cond,
37311be35a1SLionel Sambuc 			    &static_mutex));
37411be35a1SLionel Sambuc 		} while (toggle != 1);
37511be35a1SLionel Sambuc 	}
37611be35a1SLionel Sambuc 	printf("2: After the loop.\n");
37711be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
37811be35a1SLionel Sambuc 
37911be35a1SLionel Sambuc 	return NULL;
38011be35a1SLionel Sambuc }
38111be35a1SLionel Sambuc 
38211be35a1SLionel Sambuc 
38311be35a1SLionel Sambuc ATF_TC(broadcast);
ATF_TC_HEAD(broadcast,tc)38411be35a1SLionel Sambuc ATF_TC_HEAD(broadcast, tc)
38511be35a1SLionel Sambuc {
38611be35a1SLionel Sambuc 	atf_tc_set_md_var(tc, "descr",
38711be35a1SLionel Sambuc 		"Checks condition variables: use pthread_cond_broadcast()");
38811be35a1SLionel Sambuc }
ATF_TC_BODY(broadcast,tc)38911be35a1SLionel Sambuc ATF_TC_BODY(broadcast, tc)
39011be35a1SLionel Sambuc {
39111be35a1SLionel Sambuc 	pthread_t new;
39211be35a1SLionel Sambuc 	void *joinval;
39311be35a1SLionel Sambuc 	int sharedval;
39411be35a1SLionel Sambuc 
39511be35a1SLionel Sambuc 	printf("1: condition variable test 5\n");
39611be35a1SLionel Sambuc 
39711be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
39811be35a1SLionel Sambuc 
39911be35a1SLionel Sambuc 	count = 50000;
40011be35a1SLionel Sambuc 	toggle = 0;
40111be35a1SLionel Sambuc 
40211be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_create(&new, NULL, broadcast_threadfunc,
40311be35a1SLionel Sambuc 	    &sharedval));
40411be35a1SLionel Sambuc 
40511be35a1SLionel Sambuc 	printf("1: Before waiting.\n");
40611be35a1SLionel Sambuc 	while (count>0) {
40711be35a1SLionel Sambuc 		count--;
40811be35a1SLionel Sambuc 		total++;
40911be35a1SLionel Sambuc 		toggle = 1;
41011be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_broadcast(&static_cond));
41111be35a1SLionel Sambuc 		do {
41211be35a1SLionel Sambuc 			PTHREAD_REQUIRE(pthread_cond_wait(&static_cond,
41311be35a1SLionel Sambuc 			    &static_mutex));
41411be35a1SLionel Sambuc 		} while (toggle != 0);
41511be35a1SLionel Sambuc 	}
41611be35a1SLionel Sambuc 	printf("1: After the loop.\n");
41711be35a1SLionel Sambuc 
41811be35a1SLionel Sambuc 	toggle = 1;
41911be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
42011be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cond_signal(&static_cond));
42111be35a1SLionel Sambuc 
42211be35a1SLionel Sambuc 	printf("1: After releasing the mutex.\n");
42311be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
42411be35a1SLionel Sambuc 
42511be35a1SLionel Sambuc 	printf("1: Thread joined. Final count = %d, total = %d\n", count,
42611be35a1SLionel Sambuc 	    total);
42711be35a1SLionel Sambuc 
42811be35a1SLionel Sambuc 	ATF_REQUIRE_EQ(count, 0);
42911be35a1SLionel Sambuc 	ATF_REQUIRE_EQ(total, 50000);
43011be35a1SLionel Sambuc }
43111be35a1SLionel Sambuc 
43211be35a1SLionel Sambuc static void *
bogus_timedwaits_threadfunc(void * arg)43311be35a1SLionel Sambuc bogus_timedwaits_threadfunc(void *arg)
43411be35a1SLionel Sambuc {
43511be35a1SLionel Sambuc 	return NULL;
43611be35a1SLionel Sambuc }
43711be35a1SLionel Sambuc 
43811be35a1SLionel Sambuc ATF_TC(bogus_timedwaits);
ATF_TC_HEAD(bogus_timedwaits,tc)43911be35a1SLionel Sambuc ATF_TC_HEAD(bogus_timedwaits, tc)
44011be35a1SLionel Sambuc {
44111be35a1SLionel Sambuc 	atf_tc_set_md_var(tc, "descr",
44211be35a1SLionel Sambuc 		"Checks condition variables: bogus timedwaits");
44311be35a1SLionel Sambuc }
ATF_TC_BODY(bogus_timedwaits,tc)44411be35a1SLionel Sambuc ATF_TC_BODY(bogus_timedwaits, tc)
44511be35a1SLionel Sambuc {
44611be35a1SLionel Sambuc 	pthread_t new;
44711be35a1SLionel Sambuc 	struct timespec ts;
44811be35a1SLionel Sambuc 	struct timeval tv;
44911be35a1SLionel Sambuc 
45011be35a1SLionel Sambuc 	printf("condition variable test 6: bogus timedwaits\n");
45111be35a1SLionel Sambuc 
45211be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
45311be35a1SLionel Sambuc 
45411be35a1SLionel Sambuc 	printf("unthreaded test (past)\n");
45511be35a1SLionel Sambuc 	gettimeofday(&tv, NULL);
45611be35a1SLionel Sambuc 	tv.tv_sec -= 2; /* Place the time in the past */
45711be35a1SLionel Sambuc 	TIMEVAL_TO_TIMESPEC(&tv, &ts);
45811be35a1SLionel Sambuc 
45911be35a1SLionel Sambuc 	ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex,
46011be35a1SLionel Sambuc 	    &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) in the "
46111be35a1SLionel Sambuc 	    "past");
46211be35a1SLionel Sambuc 
46311be35a1SLionel Sambuc 	printf("unthreaded test (zero time)\n");
46411be35a1SLionel Sambuc 	tv.tv_sec = 0;
46511be35a1SLionel Sambuc 	tv.tv_usec = 0;
46611be35a1SLionel Sambuc 	TIMEVAL_TO_TIMESPEC(&tv, &ts);
46711be35a1SLionel Sambuc 
46811be35a1SLionel Sambuc 	ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex,
46911be35a1SLionel Sambuc 	    &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) with zero "
47011be35a1SLionel Sambuc 	    "time");
47111be35a1SLionel Sambuc 
47211be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_create(&new, NULL, bogus_timedwaits_threadfunc,
47311be35a1SLionel Sambuc 	    NULL));
47411be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_join(new, NULL));
47511be35a1SLionel Sambuc 
47611be35a1SLionel Sambuc 	printf("threaded test\n");
47711be35a1SLionel Sambuc 	gettimeofday(&tv, NULL);
47811be35a1SLionel Sambuc 	tv.tv_sec -= 2; /* Place the time in the past */
47911be35a1SLionel Sambuc 	TIMEVAL_TO_TIMESPEC(&tv, &ts);
48011be35a1SLionel Sambuc 
48111be35a1SLionel Sambuc 	ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex,
48211be35a1SLionel Sambuc 	    &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) in the past");
48311be35a1SLionel Sambuc 
48411be35a1SLionel Sambuc 	printf("threaded test (zero time)\n");
48511be35a1SLionel Sambuc 	tv.tv_sec = 0;
48611be35a1SLionel Sambuc 	tv.tv_usec = 0;
48711be35a1SLionel Sambuc 	TIMEVAL_TO_TIMESPEC(&tv, &ts);
48811be35a1SLionel Sambuc 
48911be35a1SLionel Sambuc 	ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex,
49011be35a1SLionel Sambuc 	    &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) with zero "
49111be35a1SLionel Sambuc 	    "time");
49211be35a1SLionel Sambuc 
49311be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
49411be35a1SLionel Sambuc }
49511be35a1SLionel Sambuc 
49611be35a1SLionel Sambuc static void
unlock(void * arg)49711be35a1SLionel Sambuc unlock(void *arg)
49811be35a1SLionel Sambuc {
49911be35a1SLionel Sambuc 	pthread_mutex_unlock((pthread_mutex_t *)arg);
50011be35a1SLionel Sambuc }
50111be35a1SLionel Sambuc 
50211be35a1SLionel Sambuc static void *
destroy_after_cancel_threadfunc(void * arg)50311be35a1SLionel Sambuc destroy_after_cancel_threadfunc(void *arg)
50411be35a1SLionel Sambuc {
50511be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
50611be35a1SLionel Sambuc 
50711be35a1SLionel Sambuc 	pthread_cleanup_push(unlock, &mutex);
50811be35a1SLionel Sambuc 
50911be35a1SLionel Sambuc 	while (1) {
51011be35a1SLionel Sambuc 		share = 1;
51111be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_broadcast(&cond));
51211be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex));
51311be35a1SLionel Sambuc 	}
51411be35a1SLionel Sambuc 
51511be35a1SLionel Sambuc 	pthread_cleanup_pop(0);
51611be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
51711be35a1SLionel Sambuc 
51811be35a1SLionel Sambuc 	return NULL;
51911be35a1SLionel Sambuc }
52011be35a1SLionel Sambuc 
52111be35a1SLionel Sambuc ATF_TC(destroy_after_cancel);
ATF_TC_HEAD(destroy_after_cancel,tc)52211be35a1SLionel Sambuc ATF_TC_HEAD(destroy_after_cancel, tc)
52311be35a1SLionel Sambuc {
52411be35a1SLionel Sambuc 	atf_tc_set_md_var(tc, "descr", "Checks destroying a condition variable "
52511be35a1SLionel Sambuc 	    "after cancelling a wait");
52611be35a1SLionel Sambuc }
ATF_TC_BODY(destroy_after_cancel,tc)52711be35a1SLionel Sambuc ATF_TC_BODY(destroy_after_cancel, tc)
52811be35a1SLionel Sambuc {
52911be35a1SLionel Sambuc 	pthread_t thread;
53011be35a1SLionel Sambuc 
53111be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
53211be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL));
53311be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
53411be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_create(&thread, NULL,
53511be35a1SLionel Sambuc 	    destroy_after_cancel_threadfunc, NULL));
53611be35a1SLionel Sambuc 
53711be35a1SLionel Sambuc 	while (share == 0) {
53811be35a1SLionel Sambuc 		PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex));
53911be35a1SLionel Sambuc 	}
54011be35a1SLionel Sambuc 
54111be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
54211be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cancel(thread));
54311be35a1SLionel Sambuc 
54411be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_join(thread, NULL));
54511be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_cond_destroy(&cond));
54611be35a1SLionel Sambuc 
54711be35a1SLionel Sambuc 	PTHREAD_REQUIRE(pthread_mutex_destroy(&mutex));
54811be35a1SLionel Sambuc }
54911be35a1SLionel Sambuc 
ATF_TP_ADD_TCS(tp)55011be35a1SLionel Sambuc ATF_TP_ADD_TCS(tp)
55111be35a1SLionel Sambuc {
55211be35a1SLionel Sambuc 
55311be35a1SLionel Sambuc 	ATF_TP_ADD_TC(tp, signal_delay_wait);
55411be35a1SLionel Sambuc 	ATF_TP_ADD_TC(tp, signal_before_unlock);
55511be35a1SLionel Sambuc 	ATF_TP_ADD_TC(tp, signal_before_unlock_static_init);
55611be35a1SLionel Sambuc 	ATF_TP_ADD_TC(tp, signal_wait_race);
55711be35a1SLionel Sambuc 	ATF_TP_ADD_TC(tp, cond_timedwait_race);
55811be35a1SLionel Sambuc 	ATF_TP_ADD_TC(tp, broadcast);
55911be35a1SLionel Sambuc 	ATF_TP_ADD_TC(tp, bogus_timedwaits);
56011be35a1SLionel Sambuc 	ATF_TP_ADD_TC(tp, destroy_after_cancel);
56111be35a1SLionel Sambuc 
56211be35a1SLionel Sambuc 	return atf_no_error();
56311be35a1SLionel Sambuc }
564