xref: /freebsd/contrib/netbsd-tests/lib/libpthread/t_mutex.c (revision 640235e2c2ba32947f7c59d168437ffa1280f1e6)
1*640235e2SEnji Cooper /* $NetBSD: t_mutex.c,v 1.10 2016/07/31 13:01:29 christos Exp $ */
257718be8SEnji Cooper 
357718be8SEnji Cooper /*
457718be8SEnji Cooper  * Copyright (c) 2008 The NetBSD Foundation, Inc.
557718be8SEnji Cooper  * All rights reserved.
657718be8SEnji Cooper  *
757718be8SEnji Cooper  * Redistribution and use in source and binary forms, with or without
857718be8SEnji Cooper  * modification, are permitted provided that the following conditions
957718be8SEnji Cooper  * are met:
1057718be8SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
1157718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
1257718be8SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
1357718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
1457718be8SEnji Cooper  *    documentation and/or other materials provided with the distribution.
1557718be8SEnji Cooper  *
1657718be8SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1757718be8SEnji Cooper  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1857718be8SEnji Cooper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1957718be8SEnji Cooper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2057718be8SEnji Cooper  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2157718be8SEnji Cooper  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2257718be8SEnji Cooper  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2357718be8SEnji Cooper  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2457718be8SEnji Cooper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2557718be8SEnji Cooper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2657718be8SEnji Cooper  * POSSIBILITY OF SUCH DAMAGE.
2757718be8SEnji Cooper  */
2857718be8SEnji Cooper 
2957718be8SEnji Cooper #include <sys/cdefs.h>
3057718be8SEnji Cooper __COPYRIGHT("@(#) Copyright (c) 2008\
3157718be8SEnji Cooper  The NetBSD Foundation, inc. All rights reserved.");
32*640235e2SEnji Cooper __RCSID("$NetBSD: t_mutex.c,v 1.10 2016/07/31 13:01:29 christos Exp $");
3357718be8SEnji Cooper 
3457718be8SEnji Cooper #include <pthread.h>
3557718be8SEnji Cooper #include <stdio.h>
3657718be8SEnji Cooper #include <string.h>
37*640235e2SEnji Cooper #include <errno.h>
3857718be8SEnji Cooper #include <unistd.h>
39*640235e2SEnji Cooper #include <sys/sched.h>
40*640235e2SEnji Cooper #include <sys/param.h>
4157718be8SEnji Cooper 
4257718be8SEnji Cooper #include <atf-c.h>
4357718be8SEnji Cooper 
4457718be8SEnji Cooper #include "h_common.h"
4557718be8SEnji Cooper 
4657718be8SEnji Cooper static pthread_mutex_t mutex;
4757718be8SEnji Cooper static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER;
4857718be8SEnji Cooper static int global_x;
4957718be8SEnji Cooper 
5057718be8SEnji Cooper static void *
5157718be8SEnji Cooper mutex1_threadfunc(void *arg)
5257718be8SEnji Cooper {
5357718be8SEnji Cooper 	int *param;
5457718be8SEnji Cooper 
5557718be8SEnji Cooper 	printf("2: Second thread.\n");
5657718be8SEnji Cooper 
5757718be8SEnji Cooper 	param = arg;
5857718be8SEnji Cooper 	printf("2: Locking mutex\n");
5957718be8SEnji Cooper 	pthread_mutex_lock(&mutex);
6057718be8SEnji Cooper 	printf("2: Got mutex. *param = %d\n", *param);
6157718be8SEnji Cooper 	ATF_REQUIRE_EQ(*param, 20);
6257718be8SEnji Cooper 	(*param)++;
6357718be8SEnji Cooper 
6457718be8SEnji Cooper 	pthread_mutex_unlock(&mutex);
6557718be8SEnji Cooper 
6657718be8SEnji Cooper 	return param;
6757718be8SEnji Cooper }
6857718be8SEnji Cooper 
6957718be8SEnji Cooper ATF_TC(mutex1);
7057718be8SEnji Cooper ATF_TC_HEAD(mutex1, tc)
7157718be8SEnji Cooper {
7257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexes");
7357718be8SEnji Cooper }
7457718be8SEnji Cooper ATF_TC_BODY(mutex1, tc)
7557718be8SEnji Cooper {
7657718be8SEnji Cooper 	int x;
7757718be8SEnji Cooper 	pthread_t new;
7857718be8SEnji Cooper 	void *joinval;
7957718be8SEnji Cooper 
8057718be8SEnji Cooper 	printf("1: Mutex-test 1\n");
8157718be8SEnji Cooper 
8257718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
8357718be8SEnji Cooper 	x = 1;
8457718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
8557718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex1_threadfunc, &x));
8657718be8SEnji Cooper 	printf("1: Before changing the value.\n");
8757718be8SEnji Cooper 	sleep(2);
8857718be8SEnji Cooper 	x = 20;
8957718be8SEnji Cooper 	printf("1: Before releasing the mutex.\n");
9057718be8SEnji Cooper 	sleep(2);
9157718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
9257718be8SEnji Cooper 	printf("1: After releasing the mutex.\n");
9357718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
9457718be8SEnji Cooper 
9557718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
9657718be8SEnji Cooper 	printf("1: Thread joined. X was %d. Return value (int) was %d\n",
9757718be8SEnji Cooper 		x, *(int *)joinval);
9857718be8SEnji Cooper 	ATF_REQUIRE_EQ(x, 21);
9957718be8SEnji Cooper 	ATF_REQUIRE_EQ(*(int *)joinval, 21);
10057718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
10157718be8SEnji Cooper }
10257718be8SEnji Cooper 
10357718be8SEnji Cooper static void *
10457718be8SEnji Cooper mutex2_threadfunc(void *arg)
10557718be8SEnji Cooper {
10657718be8SEnji Cooper 	long count = *(int *)arg;
10757718be8SEnji Cooper 
10857718be8SEnji Cooper 	printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
10957718be8SEnji Cooper 
11057718be8SEnji Cooper 	while (count--) {
11157718be8SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
11257718be8SEnji Cooper 		global_x++;
11357718be8SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
11457718be8SEnji Cooper 	}
11557718be8SEnji Cooper 
11657718be8SEnji Cooper 	return (void *)count;
11757718be8SEnji Cooper }
11857718be8SEnji Cooper 
11957718be8SEnji Cooper ATF_TC(mutex2);
12057718be8SEnji Cooper ATF_TC_HEAD(mutex2, tc)
12157718be8SEnji Cooper {
12257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexes");
123190e1b1cSEnji Cooper #ifdef __NetBSD__
12457718be8SEnji Cooper #if defined(__powerpc__)
12557718be8SEnji Cooper 	atf_tc_set_md_var(tc, "timeout", "40");
12657718be8SEnji Cooper #endif
127190e1b1cSEnji Cooper #endif
12857718be8SEnji Cooper }
12957718be8SEnji Cooper ATF_TC_BODY(mutex2, tc)
13057718be8SEnji Cooper {
13157718be8SEnji Cooper 	int count, count2;
13257718be8SEnji Cooper 	pthread_t new;
13357718be8SEnji Cooper 	void *joinval;
13457718be8SEnji Cooper 
13557718be8SEnji Cooper 	printf("1: Mutex-test 2\n");
13657718be8SEnji Cooper 
137190e1b1cSEnji Cooper #ifdef __NetBSD__
13857718be8SEnji Cooper #if defined(__powerpc__)
13957718be8SEnji Cooper 	atf_tc_expect_timeout("PR port-powerpc/44387");
14057718be8SEnji Cooper #endif
141190e1b1cSEnji Cooper #endif
14257718be8SEnji Cooper 
14357718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
14457718be8SEnji Cooper 
14557718be8SEnji Cooper 	global_x = 0;
14657718be8SEnji Cooper 	count = count2 = 10000000;
14757718be8SEnji Cooper 
14857718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
14957718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex2_threadfunc, &count2));
15057718be8SEnji Cooper 
15157718be8SEnji Cooper 	printf("1: Thread %p\n", pthread_self());
15257718be8SEnji Cooper 
15357718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
15457718be8SEnji Cooper 
15557718be8SEnji Cooper 	while (count--) {
15657718be8SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
15757718be8SEnji Cooper 		global_x++;
15857718be8SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
15957718be8SEnji Cooper 	}
16057718be8SEnji Cooper 
16157718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
16257718be8SEnji Cooper 
16357718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
16457718be8SEnji Cooper 	printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
16557718be8SEnji Cooper 		global_x, (long)joinval);
16657718be8SEnji Cooper 	ATF_REQUIRE_EQ(global_x, 20000000);
16757718be8SEnji Cooper 
168190e1b1cSEnji Cooper #ifdef __NetBSD__
16957718be8SEnji Cooper #if defined(__powerpc__)
17057718be8SEnji Cooper 	/* XXX force a timeout in ppc case since an un-triggered race
17157718be8SEnji Cooper 	   otherwise looks like a "failure" */
17257718be8SEnji Cooper 	/* We sleep for longer than the timeout to make ATF not
17357718be8SEnji Cooper 	   complain about unexpected success */
17457718be8SEnji Cooper 	sleep(41);
17557718be8SEnji Cooper #endif
176190e1b1cSEnji Cooper #endif
17757718be8SEnji Cooper }
17857718be8SEnji Cooper 
17957718be8SEnji Cooper static void *
18057718be8SEnji Cooper mutex3_threadfunc(void *arg)
18157718be8SEnji Cooper {
18257718be8SEnji Cooper 	long count = *(int *)arg;
18357718be8SEnji Cooper 
18457718be8SEnji Cooper 	printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
18557718be8SEnji Cooper 
18657718be8SEnji Cooper 	while (count--) {
18757718be8SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
18857718be8SEnji Cooper 		global_x++;
18957718be8SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
19057718be8SEnji Cooper 	}
19157718be8SEnji Cooper 
19257718be8SEnji Cooper 	return (void *)count;
19357718be8SEnji Cooper }
19457718be8SEnji Cooper 
19557718be8SEnji Cooper ATF_TC(mutex3);
19657718be8SEnji Cooper ATF_TC_HEAD(mutex3, tc)
19757718be8SEnji Cooper {
19857718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexes using a static "
19957718be8SEnji Cooper 	    "initializer");
200190e1b1cSEnji Cooper #ifdef __NetBSD__
20157718be8SEnji Cooper #if defined(__powerpc__)
20257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "timeout", "40");
20357718be8SEnji Cooper #endif
204190e1b1cSEnji Cooper #endif
20557718be8SEnji Cooper }
20657718be8SEnji Cooper ATF_TC_BODY(mutex3, tc)
20757718be8SEnji Cooper {
20857718be8SEnji Cooper 	int count, count2;
20957718be8SEnji Cooper 	pthread_t new;
21057718be8SEnji Cooper 	void *joinval;
21157718be8SEnji Cooper 
21257718be8SEnji Cooper 	printf("1: Mutex-test 3\n");
21357718be8SEnji Cooper 
214190e1b1cSEnji Cooper #ifdef __NetBSD__
21557718be8SEnji Cooper #if defined(__powerpc__)
21657718be8SEnji Cooper 	atf_tc_expect_timeout("PR port-powerpc/44387");
21757718be8SEnji Cooper #endif
218190e1b1cSEnji Cooper #endif
21957718be8SEnji Cooper 
22057718be8SEnji Cooper 	global_x = 0;
22157718be8SEnji Cooper 	count = count2 = 10000000;
22257718be8SEnji Cooper 
22357718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
22457718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex3_threadfunc, &count2));
22557718be8SEnji Cooper 
22657718be8SEnji Cooper 	printf("1: Thread %p\n", pthread_self());
22757718be8SEnji Cooper 
22857718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
22957718be8SEnji Cooper 
23057718be8SEnji Cooper 	while (count--) {
23157718be8SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
23257718be8SEnji Cooper 		global_x++;
23357718be8SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
23457718be8SEnji Cooper 	}
23557718be8SEnji Cooper 
23657718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
23757718be8SEnji Cooper 
23857718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex));
23957718be8SEnji Cooper 	printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
24057718be8SEnji Cooper 		global_x, (long)joinval);
24157718be8SEnji Cooper 	ATF_REQUIRE_EQ(global_x, 20000000);
24257718be8SEnji Cooper 
243190e1b1cSEnji Cooper #ifdef __NetBSD__
24457718be8SEnji Cooper #if defined(__powerpc__)
24557718be8SEnji Cooper 	/* XXX force a timeout in ppc case since an un-triggered race
24657718be8SEnji Cooper 	   otherwise looks like a "failure" */
24757718be8SEnji Cooper 	/* We sleep for longer than the timeout to make ATF not
24857718be8SEnji Cooper 	   complain about unexpected success */
24957718be8SEnji Cooper 	sleep(41);
25057718be8SEnji Cooper #endif
251190e1b1cSEnji Cooper #endif
25257718be8SEnji Cooper }
25357718be8SEnji Cooper 
25457718be8SEnji Cooper static void *
25557718be8SEnji Cooper mutex4_threadfunc(void *arg)
25657718be8SEnji Cooper {
25757718be8SEnji Cooper 	int *param;
25857718be8SEnji Cooper 
25957718be8SEnji Cooper 	printf("2: Second thread.\n");
26057718be8SEnji Cooper 
26157718be8SEnji Cooper 	param = arg;
26257718be8SEnji Cooper 	printf("2: Locking mutex\n");
26357718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
26457718be8SEnji Cooper 	printf("2: Got mutex. *param = %d\n", *param);
26557718be8SEnji Cooper 	(*param)++;
26657718be8SEnji Cooper 
26757718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
26857718be8SEnji Cooper 
26957718be8SEnji Cooper 	return param;
27057718be8SEnji Cooper }
27157718be8SEnji Cooper 
27257718be8SEnji Cooper ATF_TC(mutex4);
27357718be8SEnji Cooper ATF_TC_HEAD(mutex4, tc)
27457718be8SEnji Cooper {
27557718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexes");
27657718be8SEnji Cooper }
27757718be8SEnji Cooper ATF_TC_BODY(mutex4, tc)
27857718be8SEnji Cooper {
27957718be8SEnji Cooper 	int x;
28057718be8SEnji Cooper 	pthread_t new;
28157718be8SEnji Cooper 	pthread_mutexattr_t mattr;
28257718be8SEnji Cooper 	void *joinval;
28357718be8SEnji Cooper 
28457718be8SEnji Cooper 	printf("1: Mutex-test 4\n");
28557718be8SEnji Cooper 
28657718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
28757718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE));
28857718be8SEnji Cooper 
28957718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, &mattr));
29057718be8SEnji Cooper 
29157718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_destroy(&mattr));
29257718be8SEnji Cooper 
29357718be8SEnji Cooper 	x = 1;
29457718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
29557718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex4_threadfunc, &x));
29657718be8SEnji Cooper 
29757718be8SEnji Cooper 	printf("1: Before recursively acquiring the mutex.\n");
29857718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
29957718be8SEnji Cooper 
30057718be8SEnji Cooper 	printf("1: Before releasing the mutex once.\n");
30157718be8SEnji Cooper 	sleep(2);
30257718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
30357718be8SEnji Cooper 	printf("1: After releasing the mutex once.\n");
30457718be8SEnji Cooper 
30557718be8SEnji Cooper 	x = 20;
30657718be8SEnji Cooper 
30757718be8SEnji Cooper 	printf("1: Before releasing the mutex twice.\n");
30857718be8SEnji Cooper 	sleep(2);
30957718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
31057718be8SEnji Cooper 	printf("1: After releasing the mutex twice.\n");
31157718be8SEnji Cooper 
31257718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
31357718be8SEnji Cooper 
31457718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
31557718be8SEnji Cooper 	printf("1: Thread joined. X was %d. Return value (int) was %d\n",
31657718be8SEnji Cooper 		x, *(int *)joinval);
31757718be8SEnji Cooper 	ATF_REQUIRE_EQ(x, 21);
31857718be8SEnji Cooper 	ATF_REQUIRE_EQ(*(int *)joinval, 21);
31957718be8SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
32057718be8SEnji Cooper }
32157718be8SEnji Cooper 
322*640235e2SEnji Cooper #ifdef __NetBSD__
323*640235e2SEnji Cooper static pthread_mutexattr_t attr5;
324*640235e2SEnji Cooper static pthread_mutex_t mutex5;
325*640235e2SEnji Cooper static int min_fifo_prio, max_fifo_prio;
326*640235e2SEnji Cooper 
327*640235e2SEnji Cooper static void *
328*640235e2SEnji Cooper child_func(void* arg)
329*640235e2SEnji Cooper {
330*640235e2SEnji Cooper 	int res;
331*640235e2SEnji Cooper 
332*640235e2SEnji Cooper 	printf("child is waiting\n");
333*640235e2SEnji Cooper 	res = _sched_protect(-2);
334*640235e2SEnji Cooper 	ATF_REQUIRE_EQ_MSG(res, -1, "sched_protect returned %d", res);
335*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(errno, ENOENT);
336*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5));
337*640235e2SEnji Cooper 	printf("child is owning resource\n");
338*640235e2SEnji Cooper 	res = _sched_protect(-2);
339*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(res,  max_fifo_prio);
340*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
341*640235e2SEnji Cooper 	printf("child is done\n");
342*640235e2SEnji Cooper 
343*640235e2SEnji Cooper 	return 0;
344*640235e2SEnji Cooper }
345*640235e2SEnji Cooper 
346*640235e2SEnji Cooper ATF_TC(mutex5);
347*640235e2SEnji Cooper ATF_TC_HEAD(mutex5, tc)
348*640235e2SEnji Cooper {
349*640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexes for priority setting");
350*640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "root");
351*640235e2SEnji Cooper }
352*640235e2SEnji Cooper 
353*640235e2SEnji Cooper ATF_TC_BODY(mutex5, tc)
354*640235e2SEnji Cooper {
355*640235e2SEnji Cooper 	int res;
356*640235e2SEnji Cooper 	struct sched_param param;
357*640235e2SEnji Cooper 	pthread_t child;
358*640235e2SEnji Cooper 
359*640235e2SEnji Cooper 	min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
360*640235e2SEnji Cooper 	max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
361*640235e2SEnji Cooper 	printf("min prio for FIFO = %d\n", min_fifo_prio);
362*640235e2SEnji Cooper 	param.sched_priority = min_fifo_prio;
363*640235e2SEnji Cooper 
364*640235e2SEnji Cooper 	/* = 0 OTHER, 1 FIFO, 2 RR, -1 NONE */
365*640235e2SEnji Cooper 	res = sched_setscheduler(getpid(), SCHED_FIFO, &param);
366*640235e2SEnji Cooper 	printf("previous policy used = %d\n", res);
367*640235e2SEnji Cooper 
368*640235e2SEnji Cooper 	res = sched_getscheduler(getpid());
369*640235e2SEnji Cooper 	ATF_REQUIRE_EQ_MSG(res, SCHED_FIFO, "sched %d != FIFO %d", res,
370*640235e2SEnji Cooper 	    SCHED_FIFO);
371*640235e2SEnji Cooper 
372*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_init(&attr5));
373*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&attr5,
374*640235e2SEnji Cooper 	    PTHREAD_PRIO_PROTECT));
375*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&attr5,
376*640235e2SEnji Cooper 	    max_fifo_prio));
377*640235e2SEnji Cooper 
378*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex5, &attr5));
379*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5));
380*640235e2SEnji Cooper 	printf("enter critical section for main\n");
381*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&child, NULL, child_func, NULL));
382*640235e2SEnji Cooper 	printf("main starts to sleep\n");
383*640235e2SEnji Cooper 	sleep(10);
384*640235e2SEnji Cooper 	printf("main completes\n");
385*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
386*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(child, NULL));
387*640235e2SEnji Cooper }
388*640235e2SEnji Cooper 
389*640235e2SEnji Cooper static pthread_mutex_t mutex6;
390*640235e2SEnji Cooper static int start = 0;
391*640235e2SEnji Cooper static uintmax_t high_cnt = 0, low_cnt = 0, MAX_LOOP = 100000000;
392*640235e2SEnji Cooper 
393*640235e2SEnji Cooper static void *
394*640235e2SEnji Cooper high_prio(void* arg)
395*640235e2SEnji Cooper {
396*640235e2SEnji Cooper 	struct sched_param param;
397*640235e2SEnji Cooper 	int policy;
398*640235e2SEnji Cooper 	param.sched_priority = min_fifo_prio + 10;
399*640235e2SEnji Cooper 	pthread_t childid = pthread_self();
400*640235e2SEnji Cooper 
401*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, &param));
402*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, &param));
403*640235e2SEnji Cooper 	printf("high protect = %d, prio = %d\n",
404*640235e2SEnji Cooper 	    _sched_protect(-2), param.sched_priority);
405*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(policy, 1);
406*640235e2SEnji Cooper 	printf("high prio = %d\n", param.sched_priority);
407*640235e2SEnji Cooper 	sleep(1);
408*640235e2SEnji Cooper 	long tmp = 0;
409*640235e2SEnji Cooper 	for (int i = 0; i < 20; i++) {
410*640235e2SEnji Cooper 		while (high_cnt < MAX_LOOP) {
411*640235e2SEnji Cooper 			tmp += (123456789 % 1234) * (987654321 % 54321);
412*640235e2SEnji Cooper 			high_cnt += 1;
413*640235e2SEnji Cooper 		}
414*640235e2SEnji Cooper 		high_cnt = 0;
415*640235e2SEnji Cooper 		sleep(1);
416*640235e2SEnji Cooper 	}
417*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6));
418*640235e2SEnji Cooper 	if (start == 0) start = 2;
419*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6));
420*640235e2SEnji Cooper 
421*640235e2SEnji Cooper 	return 0;
422*640235e2SEnji Cooper }
423*640235e2SEnji Cooper 
424*640235e2SEnji Cooper static void *
425*640235e2SEnji Cooper low_prio(void* arg)
426*640235e2SEnji Cooper {
427*640235e2SEnji Cooper 	struct sched_param param;
428*640235e2SEnji Cooper 	int policy;
429*640235e2SEnji Cooper 	param.sched_priority = min_fifo_prio;
430*640235e2SEnji Cooper 	pthread_t childid = pthread_self();
431*640235e2SEnji Cooper 	int res = _sched_protect(max_fifo_prio);
432*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(res, 0);
433*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, &param));
434*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, &param));
435*640235e2SEnji Cooper 	printf("low protect = %d, prio = %d\n", _sched_protect(-2),
436*640235e2SEnji Cooper 	    param.sched_priority);
437*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(policy, 1);
438*640235e2SEnji Cooper 	printf("low prio = %d\n", param.sched_priority);
439*640235e2SEnji Cooper 	sleep(1);
440*640235e2SEnji Cooper 	long tmp = 0;
441*640235e2SEnji Cooper 	for (int i = 0; i < 20; i++) {
442*640235e2SEnji Cooper 		while (low_cnt < MAX_LOOP) {
443*640235e2SEnji Cooper 			tmp += (123456789 % 1234) * (987654321 % 54321);
444*640235e2SEnji Cooper 			low_cnt += 1;
445*640235e2SEnji Cooper 		}
446*640235e2SEnji Cooper 		low_cnt = 0;
447*640235e2SEnji Cooper 		sleep(1);
448*640235e2SEnji Cooper 	}
449*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6));
450*640235e2SEnji Cooper 	if (start == 0)
451*640235e2SEnji Cooper 		start = 1;
452*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6));
453*640235e2SEnji Cooper 
454*640235e2SEnji Cooper 	return 0;
455*640235e2SEnji Cooper }
456*640235e2SEnji Cooper 
457*640235e2SEnji Cooper ATF_TC(mutex6);
458*640235e2SEnji Cooper ATF_TC_HEAD(mutex6, tc)
459*640235e2SEnji Cooper {
460*640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "descr",
461*640235e2SEnji Cooper 	    "Checks scheduling for priority ceiling");
462*640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "root");
463*640235e2SEnji Cooper }
464*640235e2SEnji Cooper 
465*640235e2SEnji Cooper /*
466*640235e2SEnji Cooper  * 1. main thread sets itself to be a realtime task and launched two tasks,
467*640235e2SEnji Cooper  *    one has higher priority and the other has lower priority.
468*640235e2SEnji Cooper  * 2. each child thread(low and high priority thread) sets its scheduler and
469*640235e2SEnji Cooper  *    priority.
470*640235e2SEnji Cooper  * 3. each child thread did several rounds of computation, after each round it
471*640235e2SEnji Cooper  *    sleep 1 second.
472*640235e2SEnji Cooper  * 4. the child thread with low priority will call _sched_protect to increase
473*640235e2SEnji Cooper  *    its protect priority.
474*640235e2SEnji Cooper  * 5. We verify the thread with low priority runs first.
475*640235e2SEnji Cooper  *
476*640235e2SEnji Cooper  * Why does it work? From the main thread, we launched the high
477*640235e2SEnji Cooper  * priority thread first. This gives this thread the benefit of
478*640235e2SEnji Cooper  * starting first. The low priority thread did not call _sched_protect(2).
479*640235e2SEnji Cooper  * The high priority thread should finish the task first. After each
480*640235e2SEnji Cooper  * round of computation, we call sleep, to put the task into the
481*640235e2SEnji Cooper  * sleep queue, and wake up again after the timer expires. This
482*640235e2SEnji Cooper  * gives the scheduler the chance to decide which task to run. So,
483*640235e2SEnji Cooper  * the thread with real high priority will always block the thread
484*640235e2SEnji Cooper  * with real low priority.
485*640235e2SEnji Cooper  *
486*640235e2SEnji Cooper  */
487*640235e2SEnji Cooper ATF_TC_BODY(mutex6, tc)
488*640235e2SEnji Cooper {
489*640235e2SEnji Cooper 	struct sched_param param;
490*640235e2SEnji Cooper 	int res;
491*640235e2SEnji Cooper 	pthread_t high, low;
492*640235e2SEnji Cooper 
493*640235e2SEnji Cooper 	min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
494*640235e2SEnji Cooper 	max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
495*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
496*640235e2SEnji Cooper 	printf("min_fifo_prio = %d, max_fifo_info = %d\n", min_fifo_prio,
497*640235e2SEnji Cooper 	    max_fifo_prio);
498*640235e2SEnji Cooper 
499*640235e2SEnji Cooper 	param.sched_priority = min_fifo_prio;
500*640235e2SEnji Cooper 	res = sched_setscheduler(getpid(), SCHED_FIFO, &param);
501*640235e2SEnji Cooper 	printf("previous policy used = %d\n", res);
502*640235e2SEnji Cooper 
503*640235e2SEnji Cooper 	res = sched_getscheduler(getpid());
504*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(res, 1);
505*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&high, NULL, high_prio, NULL));
506*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&low, NULL, low_prio, NULL));
507*640235e2SEnji Cooper 	sleep(5);
508*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(low, NULL));
509*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(high, NULL));
510*640235e2SEnji Cooper 
511*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(start, 1);
512*640235e2SEnji Cooper }
513*640235e2SEnji Cooper #endif
514*640235e2SEnji Cooper 
515*640235e2SEnji Cooper ATF_TC(mutexattr1);
516*640235e2SEnji Cooper ATF_TC_HEAD(mutexattr1, tc)
517*640235e2SEnji Cooper {
518*640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
519*640235e2SEnji Cooper }
520*640235e2SEnji Cooper 
521*640235e2SEnji Cooper ATF_TC_BODY(mutexattr1, tc)
522*640235e2SEnji Cooper {
523*640235e2SEnji Cooper 	pthread_mutexattr_t mattr;
524*640235e2SEnji Cooper 	int protocol, target;
525*640235e2SEnji Cooper 
526*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
527*640235e2SEnji Cooper 
528*640235e2SEnji Cooper 	target = PTHREAD_PRIO_NONE;
529*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
530*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
531*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(protocol, target);
532*640235e2SEnji Cooper 
533*640235e2SEnji Cooper 	/*
534*640235e2SEnji Cooper 	target = PTHREAD_PRIO_INHERIT;
535*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
536*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
537*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(protocol, target);
538*640235e2SEnji Cooper 	*/
539*640235e2SEnji Cooper 
540*640235e2SEnji Cooper 	target = PTHREAD_PRIO_PROTECT;
541*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
542*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
543*640235e2SEnji Cooper 	ATF_REQUIRE_EQ(protocol, target);
544*640235e2SEnji Cooper }
545*640235e2SEnji Cooper 
546*640235e2SEnji Cooper ATF_TC(mutexattr2);
547*640235e2SEnji Cooper ATF_TC_HEAD(mutexattr2, tc)
548*640235e2SEnji Cooper {
549*640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
550*640235e2SEnji Cooper }
551*640235e2SEnji Cooper 
552*640235e2SEnji Cooper ATF_TC_BODY(mutexattr2, tc)
553*640235e2SEnji Cooper {
554*640235e2SEnji Cooper 	pthread_mutexattr_t mattr;
555*640235e2SEnji Cooper 
556*640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
557*640235e2SEnji Cooper 	int max_prio = sched_get_priority_max(SCHED_FIFO);
558*640235e2SEnji Cooper 	int min_prio = sched_get_priority_min(SCHED_FIFO);
559*640235e2SEnji Cooper 	for (int i = min_prio; i <= max_prio; i++) {
560*640235e2SEnji Cooper 		int prioceiling;
561*640235e2SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&mattr, i));
562*640235e2SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutexattr_getprioceiling(&mattr,
563*640235e2SEnji Cooper 		    &prioceiling));
564*640235e2SEnji Cooper 		ATF_REQUIRE_EQ(i, prioceiling);
565*640235e2SEnji Cooper 	}
566*640235e2SEnji Cooper }
567*640235e2SEnji Cooper 
56857718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
56957718be8SEnji Cooper {
57057718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex1);
57157718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex2);
57257718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex3);
57357718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex4);
574*640235e2SEnji Cooper #ifdef __NetBSD__
575*640235e2SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex5);
576*640235e2SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex6);
577*640235e2SEnji Cooper #endif
578*640235e2SEnji Cooper 	ATF_TP_ADD_TC(tp, mutexattr1);
579*640235e2SEnji Cooper 	ATF_TP_ADD_TC(tp, mutexattr2);
58057718be8SEnji Cooper 
58157718be8SEnji Cooper 	return atf_no_error();
58257718be8SEnji Cooper }
583