Home | History | Annotate | Line # | Download | only in libpthread
t_mutex.c revision 1.9.2.5
      1  1.9.2.5  pgoyette /* $NetBSD: t_mutex.c,v 1.9.2.5 2017/04/26 02:53:33 pgoyette Exp $ */
      2      1.1      jmmv 
      3      1.1      jmmv /*
      4      1.1      jmmv  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5      1.1      jmmv  * All rights reserved.
      6      1.1      jmmv  *
      7      1.1      jmmv  * Redistribution and use in source and binary forms, with or without
      8      1.1      jmmv  * modification, are permitted provided that the following conditions
      9      1.1      jmmv  * are met:
     10      1.1      jmmv  * 1. Redistributions of source code must retain the above copyright
     11      1.1      jmmv  *    notice, this list of conditions and the following disclaimer.
     12      1.1      jmmv  * 2. Redistributions in binary form must reproduce the above copyright
     13      1.1      jmmv  *    notice, this list of conditions and the following disclaimer in the
     14      1.1      jmmv  *    documentation and/or other materials provided with the distribution.
     15      1.1      jmmv  *
     16      1.1      jmmv  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17      1.1      jmmv  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18      1.1      jmmv  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19      1.1      jmmv  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20      1.1      jmmv  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21      1.1      jmmv  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22      1.1      jmmv  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23      1.1      jmmv  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24      1.1      jmmv  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25      1.1      jmmv  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26      1.1      jmmv  * POSSIBILITY OF SUCH DAMAGE.
     27      1.1      jmmv  */
     28      1.1      jmmv 
     29      1.1      jmmv #include <sys/cdefs.h>
     30      1.1      jmmv __COPYRIGHT("@(#) Copyright (c) 2008\
     31      1.1      jmmv  The NetBSD Foundation, inc. All rights reserved.");
     32  1.9.2.5  pgoyette __RCSID("$NetBSD: t_mutex.c,v 1.9.2.5 2017/04/26 02:53:33 pgoyette Exp $");
     33      1.1      jmmv 
     34  1.9.2.4  pgoyette #include <sys/time.h> /* For timespecadd */
     35  1.9.2.4  pgoyette #include <inttypes.h> /* For UINT16_MAX */
     36      1.1      jmmv #include <pthread.h>
     37      1.1      jmmv #include <stdio.h>
     38      1.4       riz #include <string.h>
     39      1.8  christos #include <errno.h>
     40  1.9.2.3  pgoyette #include <time.h>
     41      1.1      jmmv #include <unistd.h>
     42      1.8  christos #include <sys/sched.h>
     43      1.8  christos #include <sys/param.h>
     44      1.1      jmmv 
     45      1.1      jmmv #include <atf-c.h>
     46      1.1      jmmv 
     47      1.1      jmmv #include "h_common.h"
     48      1.1      jmmv 
     49      1.1      jmmv static pthread_mutex_t mutex;
     50      1.3      jmmv static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER;
     51      1.1      jmmv static int global_x;
     52      1.1      jmmv 
     53  1.9.2.3  pgoyette #ifdef TIMEDMUTEX
     54  1.9.2.3  pgoyette /* This code is used for verifying non-timed specific code */
     55  1.9.2.3  pgoyette static struct timespec ts_lengthy = {
     56  1.9.2.3  pgoyette 	.tv_sec = UINT16_MAX,
     57  1.9.2.3  pgoyette 	.tv_nsec = 0
     58  1.9.2.3  pgoyette };
     59  1.9.2.3  pgoyette /* This code is used for verifying timed-only specific code */
     60  1.9.2.3  pgoyette static struct timespec ts_shortlived = {
     61  1.9.2.3  pgoyette 	.tv_sec = 0,
     62  1.9.2.3  pgoyette 	.tv_nsec = 120
     63  1.9.2.3  pgoyette };
     64  1.9.2.3  pgoyette 
     65  1.9.2.3  pgoyette static int
     66  1.9.2.3  pgoyette mutex_lock(pthread_mutex_t *m, const struct timespec *ts)
     67  1.9.2.3  pgoyette {
     68  1.9.2.3  pgoyette 	struct timespec ts_wait;
     69  1.9.2.3  pgoyette 	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts_wait) != -1);
     70  1.9.2.3  pgoyette 	timespecadd(&ts_wait, ts, &ts_wait);
     71  1.9.2.3  pgoyette 
     72  1.9.2.3  pgoyette 	return pthread_mutex_timedlock(m, &ts_wait);
     73  1.9.2.3  pgoyette }
     74  1.9.2.3  pgoyette #else
     75  1.9.2.3  pgoyette #define mutex_lock(a, b) pthread_mutex_lock(a)
     76  1.9.2.3  pgoyette #endif
     77  1.9.2.3  pgoyette 
     78      1.1      jmmv static void *
     79      1.1      jmmv mutex1_threadfunc(void *arg)
     80      1.1      jmmv {
     81      1.1      jmmv 	int *param;
     82      1.1      jmmv 
     83      1.1      jmmv 	printf("2: Second thread.\n");
     84      1.1      jmmv 
     85      1.1      jmmv 	param = arg;
     86      1.1      jmmv 	printf("2: Locking mutex\n");
     87  1.9.2.3  pgoyette 	mutex_lock(&mutex, &ts_lengthy);
     88      1.1      jmmv 	printf("2: Got mutex. *param = %d\n", *param);
     89      1.1      jmmv 	ATF_REQUIRE_EQ(*param, 20);
     90      1.1      jmmv 	(*param)++;
     91      1.1      jmmv 
     92      1.1      jmmv 	pthread_mutex_unlock(&mutex);
     93      1.1      jmmv 
     94      1.1      jmmv 	return param;
     95      1.1      jmmv }
     96      1.1      jmmv 
     97      1.1      jmmv ATF_TC(mutex1);
     98      1.1      jmmv ATF_TC_HEAD(mutex1, tc)
     99      1.1      jmmv {
    100      1.1      jmmv 	atf_tc_set_md_var(tc, "descr", "Checks mutexes");
    101      1.1      jmmv }
    102      1.1      jmmv ATF_TC_BODY(mutex1, tc)
    103      1.1      jmmv {
    104      1.1      jmmv 	int x;
    105      1.1      jmmv 	pthread_t new;
    106      1.1      jmmv 	void *joinval;
    107      1.1      jmmv 
    108      1.1      jmmv 	printf("1: Mutex-test 1\n");
    109      1.1      jmmv 
    110      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
    111      1.1      jmmv 	x = 1;
    112  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    113      1.1      jmmv 	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex1_threadfunc, &x));
    114      1.1      jmmv 	printf("1: Before changing the value.\n");
    115      1.1      jmmv 	sleep(2);
    116      1.1      jmmv 	x = 20;
    117      1.1      jmmv 	printf("1: Before releasing the mutex.\n");
    118      1.1      jmmv 	sleep(2);
    119      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    120      1.1      jmmv 	printf("1: After releasing the mutex.\n");
    121      1.1      jmmv 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
    122      1.1      jmmv 
    123  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    124      1.1      jmmv 	printf("1: Thread joined. X was %d. Return value (int) was %d\n",
    125      1.1      jmmv 		x, *(int *)joinval);
    126      1.1      jmmv 	ATF_REQUIRE_EQ(x, 21);
    127      1.1      jmmv 	ATF_REQUIRE_EQ(*(int *)joinval, 21);
    128      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    129      1.1      jmmv }
    130      1.1      jmmv 
    131      1.1      jmmv static void *
    132      1.1      jmmv mutex2_threadfunc(void *arg)
    133      1.1      jmmv {
    134      1.1      jmmv 	long count = *(int *)arg;
    135      1.1      jmmv 
    136      1.1      jmmv 	printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
    137      1.1      jmmv 
    138      1.1      jmmv 	while (count--) {
    139  1.9.2.3  pgoyette 		PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    140      1.1      jmmv 		global_x++;
    141      1.1      jmmv 		PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    142      1.1      jmmv 	}
    143      1.1      jmmv 
    144      1.1      jmmv 	return (void *)count;
    145      1.1      jmmv }
    146      1.1      jmmv 
    147      1.1      jmmv ATF_TC(mutex2);
    148      1.1      jmmv ATF_TC_HEAD(mutex2, tc)
    149      1.1      jmmv {
    150      1.1      jmmv 	atf_tc_set_md_var(tc, "descr", "Checks mutexes");
    151      1.1      jmmv }
    152      1.1      jmmv ATF_TC_BODY(mutex2, tc)
    153      1.1      jmmv {
    154      1.1      jmmv 	int count, count2;
    155      1.1      jmmv 	pthread_t new;
    156      1.1      jmmv 	void *joinval;
    157      1.1      jmmv 
    158      1.1      jmmv 	printf("1: Mutex-test 2\n");
    159      1.1      jmmv 
    160      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
    161      1.4       riz 
    162      1.1      jmmv 	global_x = 0;
    163      1.1      jmmv 	count = count2 = 10000000;
    164      1.1      jmmv 
    165  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    166      1.1      jmmv 	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex2_threadfunc, &count2));
    167      1.1      jmmv 
    168      1.1      jmmv 	printf("1: Thread %p\n", pthread_self());
    169      1.1      jmmv 
    170      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    171      1.1      jmmv 
    172      1.1      jmmv 	while (count--) {
    173  1.9.2.3  pgoyette 		PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    174      1.1      jmmv 		global_x++;
    175      1.1      jmmv 		PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    176      1.1      jmmv 	}
    177      1.1      jmmv 
    178      1.1      jmmv 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
    179      1.1      jmmv 
    180  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    181      1.1      jmmv 	printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
    182      1.1      jmmv 		global_x, (long)joinval);
    183      1.1      jmmv 	ATF_REQUIRE_EQ(global_x, 20000000);
    184      1.1      jmmv }
    185      1.1      jmmv 
    186      1.1      jmmv static void *
    187      1.1      jmmv mutex3_threadfunc(void *arg)
    188      1.1      jmmv {
    189      1.1      jmmv 	long count = *(int *)arg;
    190      1.1      jmmv 
    191      1.1      jmmv 	printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count);
    192      1.1      jmmv 
    193      1.1      jmmv 	while (count--) {
    194  1.9.2.3  pgoyette 		PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy));
    195      1.1      jmmv 		global_x++;
    196      1.3      jmmv 		PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
    197      1.1      jmmv 	}
    198      1.1      jmmv 
    199      1.1      jmmv 	return (void *)count;
    200      1.1      jmmv }
    201      1.1      jmmv 
    202      1.1      jmmv ATF_TC(mutex3);
    203      1.1      jmmv ATF_TC_HEAD(mutex3, tc)
    204      1.1      jmmv {
    205      1.3      jmmv 	atf_tc_set_md_var(tc, "descr", "Checks mutexes using a static "
    206      1.3      jmmv 	    "initializer");
    207      1.1      jmmv }
    208      1.1      jmmv ATF_TC_BODY(mutex3, tc)
    209      1.1      jmmv {
    210      1.1      jmmv 	int count, count2;
    211      1.1      jmmv 	pthread_t new;
    212      1.1      jmmv 	void *joinval;
    213      1.1      jmmv 
    214      1.1      jmmv 	printf("1: Mutex-test 3\n");
    215      1.1      jmmv 
    216      1.1      jmmv 	global_x = 0;
    217      1.1      jmmv 	count = count2 = 10000000;
    218      1.1      jmmv 
    219  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy));
    220      1.1      jmmv 	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex3_threadfunc, &count2));
    221      1.1      jmmv 
    222      1.1      jmmv 	printf("1: Thread %p\n", pthread_self());
    223      1.3      jmmv 
    224      1.3      jmmv 	PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
    225      1.1      jmmv 
    226      1.1      jmmv 	while (count--) {
    227  1.9.2.3  pgoyette 		PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy));
    228      1.1      jmmv 		global_x++;
    229      1.3      jmmv 		PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex));
    230      1.1      jmmv 	}
    231      1.1      jmmv 
    232      1.1      jmmv 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
    233      1.1      jmmv 
    234  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy));
    235      1.1      jmmv 	printf("1: Thread joined. X was %d. Return value (long) was %ld\n",
    236      1.1      jmmv 		global_x, (long)joinval);
    237      1.1      jmmv 	ATF_REQUIRE_EQ(global_x, 20000000);
    238      1.1      jmmv }
    239      1.1      jmmv 
    240      1.1      jmmv static void *
    241      1.1      jmmv mutex4_threadfunc(void *arg)
    242      1.1      jmmv {
    243      1.1      jmmv 	int *param;
    244      1.1      jmmv 
    245      1.1      jmmv 	printf("2: Second thread.\n");
    246      1.1      jmmv 
    247      1.1      jmmv 	param = arg;
    248      1.1      jmmv 	printf("2: Locking mutex\n");
    249  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    250      1.1      jmmv 	printf("2: Got mutex. *param = %d\n", *param);
    251      1.1      jmmv 	(*param)++;
    252      1.1      jmmv 
    253      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    254      1.1      jmmv 
    255      1.1      jmmv 	return param;
    256      1.1      jmmv }
    257      1.1      jmmv 
    258      1.1      jmmv ATF_TC(mutex4);
    259      1.1      jmmv ATF_TC_HEAD(mutex4, tc)
    260      1.1      jmmv {
    261      1.1      jmmv 	atf_tc_set_md_var(tc, "descr", "Checks mutexes");
    262      1.1      jmmv }
    263      1.1      jmmv ATF_TC_BODY(mutex4, tc)
    264      1.1      jmmv {
    265      1.1      jmmv 	int x;
    266      1.1      jmmv 	pthread_t new;
    267      1.1      jmmv 	pthread_mutexattr_t mattr;
    268      1.1      jmmv 	void *joinval;
    269      1.1      jmmv 
    270      1.1      jmmv 	printf("1: Mutex-test 4\n");
    271      1.1      jmmv 
    272      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
    273      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE));
    274      1.1      jmmv 
    275      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, &mattr));
    276      1.1      jmmv 
    277      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutexattr_destroy(&mattr));
    278      1.1      jmmv 
    279      1.1      jmmv 	x = 1;
    280  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    281      1.1      jmmv 	PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex4_threadfunc, &x));
    282      1.1      jmmv 
    283      1.1      jmmv 	printf("1: Before recursively acquiring the mutex.\n");
    284  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    285      1.1      jmmv 
    286      1.1      jmmv 	printf("1: Before releasing the mutex once.\n");
    287      1.1      jmmv 	sleep(2);
    288      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    289      1.1      jmmv 	printf("1: After releasing the mutex once.\n");
    290      1.1      jmmv 
    291      1.1      jmmv 	x = 20;
    292      1.1      jmmv 
    293      1.1      jmmv 	printf("1: Before releasing the mutex twice.\n");
    294      1.1      jmmv 	sleep(2);
    295      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    296      1.1      jmmv 	printf("1: After releasing the mutex twice.\n");
    297      1.1      jmmv 
    298      1.1      jmmv 	PTHREAD_REQUIRE(pthread_join(new, &joinval));
    299      1.1      jmmv 
    300  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    301      1.1      jmmv 	printf("1: Thread joined. X was %d. Return value (int) was %d\n",
    302      1.1      jmmv 		x, *(int *)joinval);
    303      1.1      jmmv 	ATF_REQUIRE_EQ(x, 21);
    304      1.1      jmmv 	ATF_REQUIRE_EQ(*(int *)joinval, 21);
    305      1.1      jmmv 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    306      1.1      jmmv }
    307      1.1      jmmv 
    308      1.8  christos static pthread_mutexattr_t attr5;
    309      1.8  christos static pthread_mutex_t mutex5;
    310      1.8  christos static int min_fifo_prio, max_fifo_prio;
    311      1.8  christos 
    312      1.8  christos static void *
    313      1.8  christos child_func(void* arg)
    314      1.8  christos {
    315      1.8  christos 	int res;
    316      1.8  christos 
    317      1.8  christos 	printf("child is waiting\n");
    318      1.8  christos 	res = _sched_protect(-2);
    319  1.9.2.1  pgoyette 	ATF_REQUIRE_EQ_MSG(res, -1, "sched_protect returned %d", res);
    320      1.8  christos 	ATF_REQUIRE_EQ(errno, ENOENT);
    321  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex5, &ts_lengthy));
    322      1.8  christos 	printf("child is owning resource\n");
    323      1.8  christos 	res = _sched_protect(-2);
    324      1.8  christos 	ATF_REQUIRE_EQ(res,  max_fifo_prio);
    325      1.8  christos 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
    326      1.8  christos 	printf("child is done\n");
    327      1.8  christos 
    328      1.8  christos 	return 0;
    329      1.8  christos }
    330      1.8  christos 
    331      1.8  christos ATF_TC(mutex5);
    332      1.8  christos ATF_TC_HEAD(mutex5, tc)
    333      1.8  christos {
    334      1.8  christos 	atf_tc_set_md_var(tc, "descr", "Checks mutexes for priority setting");
    335  1.9.2.1  pgoyette 	atf_tc_set_md_var(tc, "require.user", "root");
    336      1.8  christos }
    337      1.8  christos 
    338      1.8  christos ATF_TC_BODY(mutex5, tc)
    339      1.8  christos {
    340      1.8  christos 	int res;
    341      1.8  christos 	struct sched_param param;
    342      1.8  christos 	pthread_t child;
    343      1.8  christos 
    344      1.8  christos 	min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
    345      1.8  christos 	max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
    346      1.8  christos 	printf("min prio for FIFO = %d\n", min_fifo_prio);
    347      1.8  christos 	param.sched_priority = min_fifo_prio;
    348      1.9  christos 
    349      1.8  christos 	/* = 0 OTHER, 1 FIFO, 2 RR, -1 NONE */
    350      1.8  christos 	res = sched_setscheduler(getpid(), SCHED_FIFO, &param);
    351      1.8  christos 	printf("previous policy used = %d\n", res);
    352      1.8  christos 
    353      1.8  christos 	res = sched_getscheduler(getpid());
    354  1.9.2.1  pgoyette 	ATF_REQUIRE_EQ_MSG(res, SCHED_FIFO, "sched %d != FIFO %d", res,
    355  1.9.2.1  pgoyette 	    SCHED_FIFO);
    356      1.8  christos 
    357      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_init(&attr5));
    358      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&attr5,
    359      1.8  christos 	    PTHREAD_PRIO_PROTECT));
    360      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&attr5,
    361      1.8  christos 	    max_fifo_prio));
    362      1.8  christos 
    363      1.8  christos 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex5, &attr5));
    364  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex5, &ts_lengthy));
    365      1.8  christos 	printf("enter critical section for main\n");
    366      1.8  christos 	PTHREAD_REQUIRE(pthread_create(&child, NULL, child_func, NULL));
    367      1.8  christos 	printf("main starts to sleep\n");
    368      1.8  christos 	sleep(10);
    369      1.8  christos 	printf("main completes\n");
    370      1.8  christos 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5));
    371      1.8  christos 	PTHREAD_REQUIRE(pthread_join(child, NULL));
    372      1.8  christos }
    373      1.8  christos 
    374      1.8  christos static int start = 0;
    375      1.8  christos static uintmax_t high_cnt = 0, low_cnt = 0, MAX_LOOP = 100000000;
    376      1.8  christos 
    377      1.8  christos static void *
    378      1.8  christos high_prio(void* arg)
    379      1.8  christos {
    380      1.8  christos 	struct sched_param param;
    381      1.8  christos 	int policy;
    382      1.8  christos 	param.sched_priority = min_fifo_prio + 10;
    383      1.8  christos 	pthread_t childid = pthread_self();
    384      1.8  christos 
    385      1.8  christos 	PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, &param));
    386      1.8  christos 	PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, &param));
    387      1.8  christos 	printf("high protect = %d, prio = %d\n",
    388      1.8  christos 	    _sched_protect(-2), param.sched_priority);
    389      1.8  christos 	ATF_REQUIRE_EQ(policy, 1);
    390      1.8  christos 	printf("high prio = %d\n", param.sched_priority);
    391      1.8  christos 	sleep(1);
    392      1.8  christos 	long tmp = 0;
    393      1.9  christos 	for (int i = 0; i < 20; i++) {
    394      1.8  christos 		while (high_cnt < MAX_LOOP) {
    395      1.8  christos 			tmp += (123456789 % 1234) * (987654321 % 54321);
    396      1.8  christos 			high_cnt += 1;
    397      1.8  christos 		}
    398      1.8  christos 		high_cnt = 0;
    399      1.8  christos 		sleep(1);
    400      1.8  christos 	}
    401  1.9.2.5  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    402      1.8  christos 	if (start == 0) start = 2;
    403  1.9.2.5  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    404      1.8  christos 
    405      1.8  christos 	return 0;
    406      1.8  christos }
    407      1.8  christos 
    408      1.8  christos static void *
    409      1.8  christos low_prio(void* arg)
    410      1.8  christos {
    411      1.8  christos 	struct sched_param param;
    412      1.8  christos 	int policy;
    413      1.8  christos 	param.sched_priority = min_fifo_prio;
    414      1.8  christos 	pthread_t childid = pthread_self();
    415      1.8  christos 	int res = _sched_protect(max_fifo_prio);
    416      1.8  christos 	ATF_REQUIRE_EQ(res, 0);
    417      1.8  christos 	PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, &param));
    418      1.8  christos 	PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, &param));
    419      1.8  christos 	printf("low protect = %d, prio = %d\n", _sched_protect(-2),
    420      1.8  christos 	    param.sched_priority);
    421      1.8  christos 	ATF_REQUIRE_EQ(policy, 1);
    422      1.8  christos 	printf("low prio = %d\n", param.sched_priority);
    423      1.8  christos 	sleep(1);
    424      1.9  christos 	long tmp = 0;
    425      1.8  christos 	for (int i = 0; i < 20; i++) {
    426      1.8  christos 		while (low_cnt < MAX_LOOP) {
    427      1.8  christos 			tmp += (123456789 % 1234) * (987654321 % 54321);
    428      1.8  christos 			low_cnt += 1;
    429      1.8  christos 		}
    430      1.8  christos 		low_cnt = 0;
    431      1.8  christos 		sleep(1);
    432      1.8  christos 	}
    433  1.9.2.5  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    434      1.8  christos 	if (start == 0)
    435      1.8  christos 		start = 1;
    436  1.9.2.5  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    437      1.8  christos 
    438      1.8  christos 	return 0;
    439      1.8  christos }
    440      1.8  christos 
    441      1.8  christos ATF_TC(mutex6);
    442      1.8  christos ATF_TC_HEAD(mutex6, tc)
    443      1.8  christos {
    444      1.8  christos 	atf_tc_set_md_var(tc, "descr",
    445      1.8  christos 	    "Checks scheduling for priority ceiling");
    446  1.9.2.1  pgoyette 	atf_tc_set_md_var(tc, "require.user", "root");
    447      1.8  christos }
    448      1.8  christos 
    449      1.8  christos /*
    450      1.8  christos  * 1. main thread sets itself to be a realtime task and launched two tasks,
    451      1.8  christos  *    one has higher priority and the other has lower priority.
    452      1.8  christos  * 2. each child thread(low and high priority thread) sets its scheduler and
    453      1.8  christos  *    priority.
    454      1.8  christos  * 3. each child thread did several rounds of computation, after each round it
    455      1.8  christos  *    sleep 1 second.
    456      1.8  christos  * 4. the child thread with low priority will call _sched_protect to increase
    457      1.8  christos  *    its protect priority.
    458      1.8  christos  * 5. We verify the thread with low priority runs first.
    459      1.8  christos  *
    460      1.8  christos  * Why does it work? From the main thread, we launched the high
    461      1.8  christos  * priority thread first. This gives this thread the benefit of
    462      1.8  christos  * starting first. The low priority thread did not call _sched_protect(2).
    463      1.8  christos  * The high priority thread should finish the task first. After each
    464      1.8  christos  * round of computation, we call sleep, to put the task into the
    465      1.8  christos  * sleep queue, and wake up again after the timer expires. This
    466      1.8  christos  * gives the scheduler the chance to decide which task to run. So,
    467      1.8  christos  * the thread with real high priority will always block the thread
    468      1.8  christos  * with real low priority.
    469      1.8  christos  *
    470      1.8  christos  */
    471      1.8  christos ATF_TC_BODY(mutex6, tc)
    472      1.8  christos {
    473      1.9  christos 	struct sched_param param;
    474      1.8  christos 	int res;
    475      1.8  christos 	pthread_t high, low;
    476      1.9  christos 
    477      1.8  christos 	min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
    478      1.8  christos 	max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
    479      1.8  christos 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
    480      1.8  christos 	printf("min_fifo_prio = %d, max_fifo_info = %d\n", min_fifo_prio,
    481      1.8  christos 	    max_fifo_prio);
    482      1.9  christos 
    483      1.8  christos 	param.sched_priority = min_fifo_prio;
    484      1.8  christos 	res = sched_setscheduler(getpid(), SCHED_FIFO, &param);
    485      1.8  christos 	printf("previous policy used = %d\n", res);
    486      1.8  christos 
    487      1.8  christos 	res = sched_getscheduler(getpid());
    488      1.8  christos 	ATF_REQUIRE_EQ(res, 1);
    489      1.8  christos 	PTHREAD_REQUIRE(pthread_create(&high, NULL, high_prio, NULL));
    490      1.8  christos 	PTHREAD_REQUIRE(pthread_create(&low, NULL, low_prio, NULL));
    491      1.8  christos 	sleep(5);
    492      1.8  christos 	PTHREAD_REQUIRE(pthread_join(low, NULL));
    493      1.8  christos 	PTHREAD_REQUIRE(pthread_join(high, NULL));
    494      1.8  christos 
    495  1.9.2.5  pgoyette 	ATF_REQUIRE_EQ_MSG(start, 1, "start = %d, low_cnt =%ju, "
    496  1.9.2.5  pgoyette 	    "high_cnt = %ju\n", start, high_cnt, low_cnt);
    497      1.8  christos }
    498      1.8  christos 
    499      1.8  christos ATF_TC(mutexattr1);
    500      1.8  christos ATF_TC_HEAD(mutexattr1, tc)
    501      1.8  christos {
    502      1.8  christos 	atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
    503      1.8  christos }
    504      1.8  christos 
    505      1.8  christos ATF_TC_BODY(mutexattr1, tc)
    506      1.8  christos {
    507      1.8  christos 	pthread_mutexattr_t mattr;
    508      1.8  christos 	int protocol, target;
    509      1.8  christos 
    510      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
    511      1.8  christos 
    512      1.8  christos 	target = PTHREAD_PRIO_NONE;
    513      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
    514      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
    515      1.8  christos 	ATF_REQUIRE_EQ(protocol, target);
    516      1.8  christos 
    517      1.8  christos 	/*
    518      1.8  christos 	target = PTHREAD_PRIO_INHERIT;
    519      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
    520      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
    521      1.8  christos 	ATF_REQUIRE_EQ(protocol, target);
    522      1.8  christos 	*/
    523      1.8  christos 
    524      1.8  christos 	target = PTHREAD_PRIO_PROTECT;
    525      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target));
    526      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol));
    527      1.8  christos 	ATF_REQUIRE_EQ(protocol, target);
    528      1.8  christos }
    529      1.8  christos 
    530      1.8  christos ATF_TC(mutexattr2);
    531      1.8  christos ATF_TC_HEAD(mutexattr2, tc)
    532      1.8  christos {
    533      1.8  christos 	atf_tc_set_md_var(tc, "descr", "Checks mutexattr");
    534      1.8  christos }
    535      1.8  christos 
    536      1.8  christos ATF_TC_BODY(mutexattr2, tc)
    537      1.8  christos {
    538      1.8  christos 	pthread_mutexattr_t mattr;
    539      1.8  christos 
    540      1.8  christos 	PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr));
    541      1.8  christos 	int max_prio = sched_get_priority_max(SCHED_FIFO);
    542      1.8  christos 	int min_prio = sched_get_priority_min(SCHED_FIFO);
    543      1.8  christos 	for (int i = min_prio; i <= max_prio; i++) {
    544      1.8  christos 		int prioceiling;
    545  1.9.2.4  pgoyette 		int protocol;
    546  1.9.2.4  pgoyette 
    547  1.9.2.4  pgoyette 		PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr,
    548  1.9.2.4  pgoyette 		    &protocol));
    549  1.9.2.4  pgoyette 
    550  1.9.2.4  pgoyette 		printf("priority: %d\nprotocol: %d\n", i, protocol);
    551      1.8  christos 		PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&mattr, i));
    552      1.8  christos 		PTHREAD_REQUIRE(pthread_mutexattr_getprioceiling(&mattr,
    553      1.8  christos 		    &prioceiling));
    554  1.9.2.4  pgoyette 		printf("prioceiling: %d\n", prioceiling);
    555      1.8  christos 		ATF_REQUIRE_EQ(i, prioceiling);
    556      1.8  christos 	}
    557      1.8  christos }
    558      1.8  christos 
    559  1.9.2.3  pgoyette #ifdef TIMEDMUTEX
    560  1.9.2.3  pgoyette ATF_TC(timedmutex1);
    561  1.9.2.3  pgoyette ATF_TC_HEAD(timedmutex1, tc)
    562  1.9.2.3  pgoyette {
    563  1.9.2.3  pgoyette 	atf_tc_set_md_var(tc, "descr", "Checks timeout on selflock");
    564  1.9.2.3  pgoyette }
    565  1.9.2.3  pgoyette 
    566  1.9.2.3  pgoyette ATF_TC_BODY(timedmutex1, tc)
    567  1.9.2.3  pgoyette {
    568  1.9.2.3  pgoyette 
    569  1.9.2.3  pgoyette 	printf("Timed mutex-test 1\n");
    570  1.9.2.3  pgoyette 
    571  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
    572  1.9.2.3  pgoyette 
    573  1.9.2.3  pgoyette 	printf("Before acquiring mutex\n");
    574  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
    575  1.9.2.3  pgoyette 
    576  1.9.2.3  pgoyette 	printf("Before endeavor to reacquire timed-mutex (timeout expected)\n");
    577  1.9.2.3  pgoyette 	PTHREAD_REQUIRE_STATUS(mutex_lock(&mutex, &ts_shortlived),
    578  1.9.2.3  pgoyette 	    ETIMEDOUT);
    579  1.9.2.3  pgoyette 
    580  1.9.2.3  pgoyette 	printf("Unlocking mutex\n");
    581  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    582  1.9.2.3  pgoyette }
    583  1.9.2.3  pgoyette 
    584  1.9.2.3  pgoyette ATF_TC(timedmutex2);
    585  1.9.2.3  pgoyette ATF_TC_HEAD(timedmutex2, tc)
    586  1.9.2.3  pgoyette {
    587  1.9.2.3  pgoyette 	atf_tc_set_md_var(tc, "descr",
    588  1.9.2.3  pgoyette 	    "Checks timeout on selflock with timedlock");
    589  1.9.2.3  pgoyette }
    590  1.9.2.3  pgoyette 
    591  1.9.2.3  pgoyette ATF_TC_BODY(timedmutex2, tc)
    592  1.9.2.3  pgoyette {
    593  1.9.2.3  pgoyette 
    594  1.9.2.3  pgoyette 	printf("Timed mutex-test 2\n");
    595  1.9.2.3  pgoyette 
    596  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
    597  1.9.2.3  pgoyette 
    598  1.9.2.3  pgoyette 	printf("Before acquiring mutex with timedlock\n");
    599  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    600  1.9.2.3  pgoyette 
    601  1.9.2.3  pgoyette 	printf("Before endeavor to reacquire timed-mutex (timeout expected)\n");
    602  1.9.2.3  pgoyette 	PTHREAD_REQUIRE_STATUS(mutex_lock(&mutex, &ts_shortlived),
    603  1.9.2.3  pgoyette 	    ETIMEDOUT);
    604  1.9.2.3  pgoyette 
    605  1.9.2.3  pgoyette 	printf("Unlocking mutex\n");
    606  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    607  1.9.2.3  pgoyette }
    608  1.9.2.3  pgoyette 
    609  1.9.2.3  pgoyette ATF_TC(timedmutex3);
    610  1.9.2.3  pgoyette ATF_TC_HEAD(timedmutex3, tc)
    611  1.9.2.3  pgoyette {
    612  1.9.2.3  pgoyette 	atf_tc_set_md_var(tc, "descr",
    613  1.9.2.3  pgoyette 	    "Checks timeout on selflock in a new thread");
    614  1.9.2.3  pgoyette }
    615  1.9.2.3  pgoyette 
    616  1.9.2.3  pgoyette static void *
    617  1.9.2.3  pgoyette timedmtx_thrdfunc(void *arg)
    618  1.9.2.3  pgoyette {
    619  1.9.2.3  pgoyette 	printf("Before endeavor to reacquire timed-mutex (timeout expected)\n");
    620  1.9.2.3  pgoyette 	PTHREAD_REQUIRE_STATUS(mutex_lock(&mutex, &ts_shortlived),
    621  1.9.2.3  pgoyette 	    ETIMEDOUT);
    622  1.9.2.3  pgoyette 
    623  1.9.2.3  pgoyette 	return NULL;
    624  1.9.2.3  pgoyette }
    625  1.9.2.3  pgoyette 
    626  1.9.2.3  pgoyette ATF_TC_BODY(timedmutex3, tc)
    627  1.9.2.3  pgoyette {
    628  1.9.2.3  pgoyette 	pthread_t new;
    629  1.9.2.3  pgoyette 
    630  1.9.2.3  pgoyette 	printf("Timed mutex-test 3\n");
    631  1.9.2.3  pgoyette 
    632  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
    633  1.9.2.3  pgoyette 
    634  1.9.2.3  pgoyette 	printf("Before acquiring mutex with timedlock\n");
    635  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_lock(&mutex));
    636  1.9.2.3  pgoyette 
    637  1.9.2.3  pgoyette 	printf("Before creating new thread\n");
    638  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_create(&new, NULL, timedmtx_thrdfunc, NULL));
    639  1.9.2.3  pgoyette 
    640  1.9.2.3  pgoyette 	printf("Before joining the mutex\n");
    641  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_join(new, NULL));
    642  1.9.2.3  pgoyette 
    643  1.9.2.3  pgoyette 	printf("Unlocking mutex\n");
    644  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    645  1.9.2.3  pgoyette }
    646  1.9.2.3  pgoyette 
    647  1.9.2.3  pgoyette ATF_TC(timedmutex4);
    648  1.9.2.3  pgoyette ATF_TC_HEAD(timedmutex4, tc)
    649  1.9.2.3  pgoyette {
    650  1.9.2.3  pgoyette 	atf_tc_set_md_var(tc, "descr",
    651  1.9.2.3  pgoyette 	    "Checks timeout on selflock with timedlock in a new thread");
    652  1.9.2.3  pgoyette }
    653  1.9.2.3  pgoyette 
    654  1.9.2.3  pgoyette ATF_TC_BODY(timedmutex4, tc)
    655  1.9.2.3  pgoyette {
    656  1.9.2.3  pgoyette 	pthread_t new;
    657  1.9.2.3  pgoyette 
    658  1.9.2.3  pgoyette 	printf("Timed mutex-test 4\n");
    659  1.9.2.3  pgoyette 
    660  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL));
    661  1.9.2.3  pgoyette 
    662  1.9.2.3  pgoyette 	printf("Before acquiring mutex with timedlock\n");
    663  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy));
    664  1.9.2.3  pgoyette 
    665  1.9.2.3  pgoyette 	printf("Before creating new thread\n");
    666  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_create(&new, NULL, timedmtx_thrdfunc, NULL));
    667  1.9.2.3  pgoyette 
    668  1.9.2.3  pgoyette 	printf("Before joining the mutex\n");
    669  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_join(new, NULL));
    670  1.9.2.3  pgoyette 
    671  1.9.2.3  pgoyette 	printf("Unlocking mutex\n");
    672  1.9.2.3  pgoyette 	PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex));
    673  1.9.2.3  pgoyette }
    674  1.9.2.3  pgoyette #endif
    675  1.9.2.3  pgoyette 
    676      1.1      jmmv ATF_TP_ADD_TCS(tp)
    677      1.1      jmmv {
    678      1.1      jmmv 	ATF_TP_ADD_TC(tp, mutex1);
    679      1.1      jmmv 	ATF_TP_ADD_TC(tp, mutex2);
    680      1.1      jmmv 	ATF_TP_ADD_TC(tp, mutex3);
    681      1.1      jmmv 	ATF_TP_ADD_TC(tp, mutex4);
    682      1.8  christos 	ATF_TP_ADD_TC(tp, mutex5);
    683      1.8  christos 	ATF_TP_ADD_TC(tp, mutex6);
    684      1.8  christos 	ATF_TP_ADD_TC(tp, mutexattr1);
    685      1.8  christos 	ATF_TP_ADD_TC(tp, mutexattr2);
    686  1.9.2.3  pgoyette 
    687  1.9.2.3  pgoyette #ifdef TIMEDMUTEX
    688  1.9.2.3  pgoyette 	ATF_TP_ADD_TC(tp, timedmutex1);
    689  1.9.2.3  pgoyette 	ATF_TP_ADD_TC(tp, timedmutex2);
    690  1.9.2.3  pgoyette 	ATF_TP_ADD_TC(tp, timedmutex3);
    691  1.9.2.3  pgoyette 	ATF_TP_ADD_TC(tp, timedmutex4);
    692  1.9.2.3  pgoyette #endif
    693  1.9.2.3  pgoyette 
    694      1.1      jmmv 	return atf_no_error();
    695      1.1      jmmv }
    696