xref: /freebsd/contrib/netbsd-tests/lib/libpthread/t_mutex.c (revision 82bc57c207ffb9047474e70a069bce8b3220c74f)
1640235e2SEnji 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.");
32640235e2SEnji 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>
37640235e2SEnji Cooper #include <errno.h>
3857718be8SEnji Cooper #include <unistd.h>
39640235e2SEnji Cooper #include <sys/sched.h>
40640235e2SEnji 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 
322640235e2SEnji Cooper #ifdef __NetBSD__
323640235e2SEnji Cooper static pthread_mutexattr_t attr5;
324640235e2SEnji Cooper static pthread_mutex_t mutex5;
325640235e2SEnji Cooper static int min_fifo_prio, max_fifo_prio;
326640235e2SEnji Cooper 
327640235e2SEnji Cooper static void *
328640235e2SEnji Cooper child_func(void* arg)
329640235e2SEnji Cooper {
330640235e2SEnji Cooper 	int res;
331640235e2SEnji Cooper 
332640235e2SEnji Cooper 	printf("child is waiting\n");
333640235e2SEnji Cooper 	res = _sched_protect(-2);
334640235e2SEnji Cooper 	ATF_REQUIRE_EQ_MSG(res, -1, "sched_protect returned %d", res);
335640235e2SEnji Cooper 	ATF_REQUIRE_EQ(errno, ENOENT);
336640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5));
337640235e2SEnji Cooper 	printf("child is owning resource\n");
338640235e2SEnji Cooper 	res = _sched_protect(-2);
339640235e2SEnji Cooper 	ATF_REQUIRE_EQ(res,  max_fifo_prio);
340640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
341640235e2SEnji Cooper 	printf("child is done\n");
342640235e2SEnji Cooper 
343640235e2SEnji Cooper 	return 0;
344640235e2SEnji Cooper }
345640235e2SEnji Cooper 
346640235e2SEnji Cooper ATF_TC(mutex5);
347640235e2SEnji Cooper ATF_TC_HEAD(mutex5, tc)
348640235e2SEnji Cooper {
349640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexes for priority setting");
350640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "root");
351640235e2SEnji Cooper }
352640235e2SEnji Cooper 
353640235e2SEnji Cooper ATF_TC_BODY(mutex5, tc)
354640235e2SEnji Cooper {
355640235e2SEnji Cooper 	int res;
356640235e2SEnji Cooper 	struct sched_param param;
357640235e2SEnji Cooper 	pthread_t child;
358640235e2SEnji Cooper 
359640235e2SEnji Cooper 	min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
360640235e2SEnji Cooper 	max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
361640235e2SEnji Cooper 	printf("min prio for FIFO = %d\n", min_fifo_prio);
362640235e2SEnji Cooper 	param.sched_priority = min_fifo_prio;
363640235e2SEnji Cooper 
364640235e2SEnji Cooper 	/* = 0 OTHER, 1 FIFO, 2 RR, -1 NONE */
365640235e2SEnji Cooper 	res = sched_setscheduler(getpid(), SCHED_FIFO, &param);
366640235e2SEnji Cooper 	printf("previous policy used = %d\n", res);
367640235e2SEnji Cooper 
368640235e2SEnji Cooper 	res = sched_getscheduler(getpid());
369640235e2SEnji Cooper 	ATF_REQUIRE_EQ_MSG(res, SCHED_FIFO, "sched %d != FIFO %d", res,
370640235e2SEnji Cooper 	    SCHED_FIFO);
371640235e2SEnji Cooper 
372640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_init(&attr5));
373640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&attr5,
374640235e2SEnji Cooper 	    PTHREAD_PRIO_PROTECT));
375640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&attr5,
376640235e2SEnji Cooper 	    max_fifo_prio));
377640235e2SEnji Cooper 
378640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex5, &attr5));
379640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5));
380640235e2SEnji Cooper 	printf("enter critical section for main\n");
381640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&child, NULL, child_func, NULL));
382640235e2SEnji Cooper 	printf("main starts to sleep\n");
383640235e2SEnji Cooper 	sleep(10);
384640235e2SEnji Cooper 	printf("main completes\n");
385640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
386640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(child, NULL));
387640235e2SEnji Cooper }
388640235e2SEnji Cooper 
389640235e2SEnji Cooper static pthread_mutex_t mutex6;
390640235e2SEnji Cooper static int start = 0;
391640235e2SEnji Cooper static uintmax_t high_cnt = 0, low_cnt = 0, MAX_LOOP = 100000000;
392640235e2SEnji Cooper 
393640235e2SEnji Cooper static void *
394640235e2SEnji Cooper high_prio(void* arg)
395640235e2SEnji Cooper {
396640235e2SEnji Cooper 	struct sched_param param;
397640235e2SEnji Cooper 	int policy;
398640235e2SEnji Cooper 	param.sched_priority = min_fifo_prio + 10;
399640235e2SEnji Cooper 	pthread_t childid = pthread_self();
400640235e2SEnji Cooper 
401640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, &param));
402640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, &param));
403640235e2SEnji Cooper 	printf("high protect = %d, prio = %d\n",
404640235e2SEnji Cooper 	    _sched_protect(-2), param.sched_priority);
405640235e2SEnji Cooper 	ATF_REQUIRE_EQ(policy, 1);
406640235e2SEnji Cooper 	printf("high prio = %d\n", param.sched_priority);
407640235e2SEnji Cooper 	sleep(1);
408640235e2SEnji Cooper 	long tmp = 0;
409640235e2SEnji Cooper 	for (int i = 0; i < 20; i++) {
410640235e2SEnji Cooper 		while (high_cnt < MAX_LOOP) {
411640235e2SEnji Cooper 			tmp += (123456789 % 1234) * (987654321 % 54321);
412640235e2SEnji Cooper 			high_cnt += 1;
413640235e2SEnji Cooper 		}
414640235e2SEnji Cooper 		high_cnt = 0;
415640235e2SEnji Cooper 		sleep(1);
416640235e2SEnji Cooper 	}
417640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6));
418640235e2SEnji Cooper 	if (start == 0) start = 2;
419640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6));
420640235e2SEnji Cooper 
421640235e2SEnji Cooper 	return 0;
422640235e2SEnji Cooper }
423640235e2SEnji Cooper 
424640235e2SEnji Cooper static void *
425640235e2SEnji Cooper low_prio(void* arg)
426640235e2SEnji Cooper {
427640235e2SEnji Cooper 	struct sched_param param;
428640235e2SEnji Cooper 	int policy;
429640235e2SEnji Cooper 	param.sched_priority = min_fifo_prio;
430640235e2SEnji Cooper 	pthread_t childid = pthread_self();
431640235e2SEnji Cooper 	int res = _sched_protect(max_fifo_prio);
432640235e2SEnji Cooper 	ATF_REQUIRE_EQ(res, 0);
433640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, &param));
434640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, &param));
435640235e2SEnji Cooper 	printf("low protect = %d, prio = %d\n", _sched_protect(-2),
436640235e2SEnji Cooper 	    param.sched_priority);
437640235e2SEnji Cooper 	ATF_REQUIRE_EQ(policy, 1);
438640235e2SEnji Cooper 	printf("low prio = %d\n", param.sched_priority);
439640235e2SEnji Cooper 	sleep(1);
440640235e2SEnji Cooper 	long tmp = 0;
441640235e2SEnji Cooper 	for (int i = 0; i < 20; i++) {
442640235e2SEnji Cooper 		while (low_cnt < MAX_LOOP) {
443640235e2SEnji Cooper 			tmp += (123456789 % 1234) * (987654321 % 54321);
444640235e2SEnji Cooper 			low_cnt += 1;
445640235e2SEnji Cooper 		}
446640235e2SEnji Cooper 		low_cnt = 0;
447640235e2SEnji Cooper 		sleep(1);
448640235e2SEnji Cooper 	}
449640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6));
450640235e2SEnji Cooper 	if (start == 0)
451640235e2SEnji Cooper 		start = 1;
452640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6));
453640235e2SEnji Cooper 
454640235e2SEnji Cooper 	return 0;
455640235e2SEnji Cooper }
456640235e2SEnji Cooper 
457640235e2SEnji Cooper ATF_TC(mutex6);
458640235e2SEnji Cooper ATF_TC_HEAD(mutex6, tc)
459640235e2SEnji Cooper {
460640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "descr",
461640235e2SEnji Cooper 	    "Checks scheduling for priority ceiling");
462640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "require.user", "root");
463640235e2SEnji Cooper }
464640235e2SEnji Cooper 
465640235e2SEnji Cooper /*
466640235e2SEnji Cooper  * 1. main thread sets itself to be a realtime task and launched two tasks,
467640235e2SEnji Cooper  *    one has higher priority and the other has lower priority.
468640235e2SEnji Cooper  * 2. each child thread(low and high priority thread) sets its scheduler and
469640235e2SEnji Cooper  *    priority.
470640235e2SEnji Cooper  * 3. each child thread did several rounds of computation, after each round it
471640235e2SEnji Cooper  *    sleep 1 second.
472640235e2SEnji Cooper  * 4. the child thread with low priority will call _sched_protect to increase
473640235e2SEnji Cooper  *    its protect priority.
474640235e2SEnji Cooper  * 5. We verify the thread with low priority runs first.
475640235e2SEnji Cooper  *
476640235e2SEnji Cooper  * Why does it work? From the main thread, we launched the high
477640235e2SEnji Cooper  * priority thread first. This gives this thread the benefit of
478640235e2SEnji Cooper  * starting first. The low priority thread did not call _sched_protect(2).
479640235e2SEnji Cooper  * The high priority thread should finish the task first. After each
480640235e2SEnji Cooper  * round of computation, we call sleep, to put the task into the
481640235e2SEnji Cooper  * sleep queue, and wake up again after the timer expires. This
482640235e2SEnji Cooper  * gives the scheduler the chance to decide which task to run. So,
483640235e2SEnji Cooper  * the thread with real high priority will always block the thread
484640235e2SEnji Cooper  * with real low priority.
485640235e2SEnji Cooper  *
486640235e2SEnji Cooper  */
487640235e2SEnji Cooper ATF_TC_BODY(mutex6, tc)
488640235e2SEnji Cooper {
489640235e2SEnji Cooper 	struct sched_param param;
490640235e2SEnji Cooper 	int res;
491640235e2SEnji Cooper 	pthread_t high, low;
492640235e2SEnji Cooper 
493640235e2SEnji Cooper 	min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
494640235e2SEnji Cooper 	max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
495640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
496640235e2SEnji Cooper 	printf("min_fifo_prio = %d, max_fifo_info = %d\n", min_fifo_prio,
497640235e2SEnji Cooper 	    max_fifo_prio);
498640235e2SEnji Cooper 
499640235e2SEnji Cooper 	param.sched_priority = min_fifo_prio;
500640235e2SEnji Cooper 	res = sched_setscheduler(getpid(), SCHED_FIFO, &param);
501640235e2SEnji Cooper 	printf("previous policy used = %d\n", res);
502640235e2SEnji Cooper 
503640235e2SEnji Cooper 	res = sched_getscheduler(getpid());
504640235e2SEnji Cooper 	ATF_REQUIRE_EQ(res, 1);
505640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&high, NULL, high_prio, NULL));
506640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_create(&low, NULL, low_prio, NULL));
507640235e2SEnji Cooper 	sleep(5);
508640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(low, NULL));
509640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_join(high, NULL));
510640235e2SEnji Cooper 
511640235e2SEnji Cooper 	ATF_REQUIRE_EQ(start, 1);
512640235e2SEnji Cooper }
513640235e2SEnji Cooper #endif
514640235e2SEnji Cooper 
515640235e2SEnji Cooper ATF_TC(mutexattr1);
516640235e2SEnji Cooper ATF_TC_HEAD(mutexattr1, tc)
517640235e2SEnji Cooper {
518640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
519640235e2SEnji Cooper }
520640235e2SEnji Cooper 
521640235e2SEnji Cooper ATF_TC_BODY(mutexattr1, tc)
522640235e2SEnji Cooper {
523640235e2SEnji Cooper 	pthread_mutexattr_t mattr;
524640235e2SEnji Cooper 	int protocol, target;
525640235e2SEnji Cooper 
526640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
527640235e2SEnji Cooper 
528640235e2SEnji Cooper 	target = PTHREAD_PRIO_NONE;
529640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
530640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
531640235e2SEnji Cooper 	ATF_REQUIRE_EQ(protocol, target);
532640235e2SEnji Cooper 
533640235e2SEnji Cooper 	/*
534640235e2SEnji Cooper 	target = PTHREAD_PRIO_INHERIT;
535640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
536640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
537640235e2SEnji Cooper 	ATF_REQUIRE_EQ(protocol, target);
538640235e2SEnji Cooper 	*/
539640235e2SEnji Cooper 
540640235e2SEnji Cooper 	target = PTHREAD_PRIO_PROTECT;
541640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
542640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
543640235e2SEnji Cooper 	ATF_REQUIRE_EQ(protocol, target);
544640235e2SEnji Cooper }
545640235e2SEnji Cooper 
546640235e2SEnji Cooper ATF_TC(mutexattr2);
547640235e2SEnji Cooper ATF_TC_HEAD(mutexattr2, tc)
548640235e2SEnji Cooper {
549640235e2SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
550640235e2SEnji Cooper }
551640235e2SEnji Cooper 
552640235e2SEnji Cooper ATF_TC_BODY(mutexattr2, tc)
553640235e2SEnji Cooper {
554640235e2SEnji Cooper 	pthread_mutexattr_t mattr;
555640235e2SEnji Cooper 
556*82bc57c2SEnji Cooper #ifdef __FreeBSD__
557*82bc57c2SEnji Cooper 	atf_tc_expect_fail("fails on i == 0 with: "
558*82bc57c2SEnji Cooper 	    "pthread_mutexattr_setprioceiling(&mattr, i): Invalid argument "
559*82bc57c2SEnji Cooper 	    "-- PR # 211802");
560*82bc57c2SEnji Cooper #endif
561*82bc57c2SEnji Cooper 
562640235e2SEnji Cooper 	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
563640235e2SEnji Cooper 	int max_prio = sched_get_priority_max(SCHED_FIFO);
564640235e2SEnji Cooper 	int min_prio = sched_get_priority_min(SCHED_FIFO);
565640235e2SEnji Cooper 	for (int i = min_prio; i <= max_prio; i++) {
566640235e2SEnji Cooper 		int prioceiling;
567*82bc57c2SEnji Cooper #ifdef __FreeBSD__
568*82bc57c2SEnji Cooper 		int protocol;
569*82bc57c2SEnji Cooper 
570*82bc57c2SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr,
571*82bc57c2SEnji Cooper 		    &protocol));
572*82bc57c2SEnji Cooper 
573*82bc57c2SEnji Cooper 		printf("priority: %d\nprotocol: %d\n", i, protocol);
574*82bc57c2SEnji Cooper #endif
575640235e2SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&mattr, i));
576640235e2SEnji Cooper 		PTHREAD_REQUIRE(pthread_mutexattr_getprioceiling(&mattr,
577640235e2SEnji Cooper 		    &prioceiling));
578*82bc57c2SEnji Cooper #ifdef __FreeBSD__
579*82bc57c2SEnji Cooper 		printf("prioceiling: %d\n", prioceiling);
580*82bc57c2SEnji Cooper #endif
581640235e2SEnji Cooper 		ATF_REQUIRE_EQ(i, prioceiling);
582640235e2SEnji Cooper 	}
583640235e2SEnji Cooper }
584640235e2SEnji Cooper 
58557718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
58657718be8SEnji Cooper {
58757718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex1);
58857718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex2);
58957718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex3);
59057718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex4);
591640235e2SEnji Cooper #ifdef __NetBSD__
592640235e2SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex5);
593640235e2SEnji Cooper 	ATF_TP_ADD_TC(tp, mutex6);
594640235e2SEnji Cooper #endif
595640235e2SEnji Cooper 	ATF_TP_ADD_TC(tp, mutexattr1);
596640235e2SEnji Cooper 	ATF_TP_ADD_TC(tp, mutexattr2);
59757718be8SEnji Cooper 
59857718be8SEnji Cooper 	return atf_no_error();
59957718be8SEnji Cooper }
600