diff options
| author | christos <christos@NetBSD.org> | 2016-07-03 14:24:58 +0000 |
|---|---|---|
| committer | christos <christos@NetBSD.org> | 2016-07-03 14:24:58 +0000 |
| commit | 774674fd4710ea607eef47c793bd0cf3d4eb5184 (patch) | |
| tree | 05cc5703bc1498308ea98c1fe07c25fdaee74f76 /tests/lib/libpthread | |
| parent | 3abdd8b82ad97d2929a64342f1bbc596ee3b1efa (diff) | |
GSoC 2016 Charles Cui: Implement thread priority protection based on work
by Andy Doran. Also document the get/set pshared thread calls as not
implemented, and add a skeleton implementation that is disabled.
XXX: document _sched_protect(2).
Diffstat (limited to 'tests/lib/libpthread')
| -rw-r--r-- | tests/lib/libpthread/t_cond.c | 25 | ||||
| -rw-r--r-- | tests/lib/libpthread/t_mutex.c | 252 |
2 files changed, 272 insertions, 5 deletions
diff --git a/tests/lib/libpthread/t_cond.c b/tests/lib/libpthread/t_cond.c index 9f33c9e0509..83a3833015d 100644 --- a/tests/lib/libpthread/t_cond.c +++ b/tests/lib/libpthread/t_cond.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_cond.c,v 1.6 2014/09/03 16:23:24 gson Exp $ */ +/* $NetBSD: t_cond.c,v 1.7 2016/07/03 14:24:59 christos Exp $ */ /* * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ #include <sys/cdefs.h> __COPYRIGHT("@(#) Copyright (c) 2008\ The NetBSD Foundation, inc. All rights reserved."); -__RCSID("$NetBSD: t_cond.c,v 1.6 2014/09/03 16:23:24 gson Exp $"); +__RCSID("$NetBSD: t_cond.c,v 1.7 2016/07/03 14:24:59 christos Exp $"); #include <sys/time.h> @@ -547,6 +547,26 @@ ATF_TC_BODY(destroy_after_cancel, tc) PTHREAD_REQUIRE(pthread_mutex_destroy(&mutex)); } +ATF_TC(condattr); +ATF_TC_HEAD(condattr, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks Condattr"); +} +ATF_TC_BODY(condattr, tc) +{ + pthread_condattr_t condattr; + clockid_t clockid; + + PTHREAD_REQUIRE(pthread_condattr_init(&condattr)); + PTHREAD_REQUIRE(pthread_condattr_setclock(&condattr, CLOCK_REALTIME)); + PTHREAD_REQUIRE(pthread_condattr_getclock(&condattr, &clockid)); + ATF_REQUIRE_EQ(clockid, CLOCK_REALTIME); + + PTHREAD_REQUIRE(pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)); + PTHREAD_REQUIRE(pthread_condattr_getclock(&condattr, &clockid)); + ATF_REQUIRE_EQ(clockid, CLOCK_MONOTONIC); +} + ATF_TP_ADD_TCS(tp) { @@ -558,6 +578,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, broadcast); ATF_TP_ADD_TC(tp, bogus_timedwaits); ATF_TP_ADD_TC(tp, destroy_after_cancel); + ATF_TP_ADD_TC(tp, condattr); return atf_no_error(); } diff --git a/tests/lib/libpthread/t_mutex.c b/tests/lib/libpthread/t_mutex.c index b5b07b31b4f..7fbb1e499a5 100644 --- a/tests/lib/libpthread/t_mutex.c +++ b/tests/lib/libpthread/t_mutex.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_mutex.c,v 1.7 2014/11/04 00:20:19 justin Exp $ */ +/* $NetBSD: t_mutex.c,v 1.8 2016/07/03 14:24:59 christos Exp $ */ /* * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -29,12 +29,15 @@ #include <sys/cdefs.h> __COPYRIGHT("@(#) Copyright (c) 2008\ The NetBSD Foundation, inc. All rights reserved."); -__RCSID("$NetBSD: t_mutex.c,v 1.7 2014/11/04 00:20:19 justin Exp $"); +__RCSID("$NetBSD: t_mutex.c,v 1.8 2016/07/03 14:24:59 christos Exp $"); #include <pthread.h> #include <stdio.h> #include <string.h> +#include <errno.h> #include <unistd.h> +#include <sys/sched.h> +#include <sys/param.h> #include <atf-c.h> @@ -304,12 +307,255 @@ ATF_TC_BODY(mutex4, tc) PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); } +static pthread_mutexattr_t attr5; +static pthread_mutex_t mutex5; +static int min_fifo_prio, max_fifo_prio; + +static void * +child_func(void* arg) +{ + int res; + + printf("child is waiting\n"); + res = _sched_protect(-2); + ATF_REQUIRE_EQ(res, -1); + ATF_REQUIRE_EQ(errno, ENOENT); + PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5)); + printf("child is owning resource\n"); + res = _sched_protect(-2); + ATF_REQUIRE_EQ(res, max_fifo_prio); + PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5)); + printf("child is done\n"); + + return 0; +} + +ATF_TC(mutex5); +ATF_TC_HEAD(mutex5, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks mutexes for priority setting"); +} + +ATF_TC_BODY(mutex5, tc) +{ + int res; + struct sched_param param; + pthread_t child; + + min_fifo_prio = sched_get_priority_min(SCHED_FIFO); + max_fifo_prio = sched_get_priority_max(SCHED_FIFO); + printf("min prio for FIFO = %d\n", min_fifo_prio); + param.sched_priority = min_fifo_prio; + /* = 0 OTHER, 1 FIFO, 2 RR, -1 NONE */ + res = sched_setscheduler(getpid(), SCHED_FIFO, ¶m); + printf("previous policy used = %d\n", res); + + res = sched_getscheduler(getpid()); + ATF_REQUIRE_EQ(res, 1); + + PTHREAD_REQUIRE(pthread_mutexattr_init(&attr5)); + PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&attr5, + PTHREAD_PRIO_PROTECT)); + PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&attr5, + max_fifo_prio)); + + PTHREAD_REQUIRE(pthread_mutex_init(&mutex5, &attr5)); + PTHREAD_REQUIRE(pthread_mutex_lock(&mutex5)); + printf("enter critical section for main\n"); + PTHREAD_REQUIRE(pthread_create(&child, NULL, child_func, NULL)); + printf("main starts to sleep\n"); + sleep(10); + printf("main completes\n"); + PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex5)); + PTHREAD_REQUIRE(pthread_join(child, NULL)); +} + +static pthread_mutex_t mutex6; +static int start = 0; +static uintmax_t high_cnt = 0, low_cnt = 0, MAX_LOOP = 100000000; + +static void * +high_prio(void* arg) +{ + struct sched_param param; + int policy; + param.sched_priority = min_fifo_prio + 10; + pthread_t childid = pthread_self(); + + PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, ¶m)); + PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, ¶m)); + printf("high protect = %d, prio = %d\n", + _sched_protect(-2), param.sched_priority); + ATF_REQUIRE_EQ(policy, 1); + printf("high prio = %d\n", param.sched_priority); + sleep(1); + int i; + long tmp = 0; + for (i = 0; i<20; i++) { + while (high_cnt < MAX_LOOP) { + tmp += (123456789 % 1234) * (987654321 % 54321); + high_cnt += 1; + } + high_cnt = 0; + sleep(1); + } + PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6)); + if (start == 0) start = 2; + PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6)); + + return 0; +} + +static void * +low_prio(void* arg) +{ + struct sched_param param; + int policy; + param.sched_priority = min_fifo_prio; + pthread_t childid = pthread_self(); + int res = _sched_protect(max_fifo_prio); + ATF_REQUIRE_EQ(res, 0); + PTHREAD_REQUIRE(pthread_setschedparam(childid, 1, ¶m)); + PTHREAD_REQUIRE(pthread_getschedparam(childid, &policy, ¶m)); + printf("low protect = %d, prio = %d\n", _sched_protect(-2), + param.sched_priority); + ATF_REQUIRE_EQ(policy, 1); + printf("low prio = %d\n", param.sched_priority); + sleep(1); + for (int i = 0; i < 20; i++) { + while (low_cnt < MAX_LOOP) { + long tmp; + tmp += (123456789 % 1234) * (987654321 % 54321); + low_cnt += 1; + } + low_cnt = 0; + sleep(1); + } + PTHREAD_REQUIRE(pthread_mutex_lock(&mutex6)); + if (start == 0) + start = 1; + PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex6)); + + return 0; +} + +ATF_TC(mutex6); +ATF_TC_HEAD(mutex6, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks scheduling for priority ceiling"); +} + +/* + * 1. main thread sets itself to be a realtime task and launched two tasks, + * one has higher priority and the other has lower priority. + * 2. each child thread(low and high priority thread) sets its scheduler and + * priority. + * 3. each child thread did several rounds of computation, after each round it + * sleep 1 second. + * 4. the child thread with low priority will call _sched_protect to increase + * its protect priority. + * 5. We verify the thread with low priority runs first. + * + * Why does it work? From the main thread, we launched the high + * priority thread first. This gives this thread the benefit of + * starting first. The low priority thread did not call _sched_protect(2). + * The high priority thread should finish the task first. After each + * round of computation, we call sleep, to put the task into the + * sleep queue, and wake up again after the timer expires. This + * gives the scheduler the chance to decide which task to run. So, + * the thread with real high priority will always block the thread + * with real low priority. + * + */ +ATF_TC_BODY(mutex6, tc) +{ + int res; + pthread_t high, low; + min_fifo_prio = sched_get_priority_min(SCHED_FIFO); + max_fifo_prio = sched_get_priority_max(SCHED_FIFO); + PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); + printf("min_fifo_prio = %d, max_fifo_info = %d\n", min_fifo_prio, + max_fifo_prio); + struct sched_param param; + param.sched_priority = min_fifo_prio; + res = sched_setscheduler(getpid(), SCHED_FIFO, ¶m); + printf("previous policy used = %d\n", res); + + res = sched_getscheduler(getpid()); + ATF_REQUIRE_EQ(res, 1); + PTHREAD_REQUIRE(pthread_create(&high, NULL, high_prio, NULL)); + PTHREAD_REQUIRE(pthread_create(&low, NULL, low_prio, NULL)); + sleep(5); + PTHREAD_REQUIRE(pthread_join(low, NULL)); + PTHREAD_REQUIRE(pthread_join(high, NULL)); + + ATF_REQUIRE_EQ(start, 1); +} + +ATF_TC(mutexattr1); +ATF_TC_HEAD(mutexattr1, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks mutexattr"); +} + +ATF_TC_BODY(mutexattr1, tc) +{ + pthread_mutexattr_t mattr; + int protocol, target; + + PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr)); + + target = PTHREAD_PRIO_NONE; + PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target)); + PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol)); + ATF_REQUIRE_EQ(protocol, target); + + /* + target = PTHREAD_PRIO_INHERIT; + PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target)); + PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol)); + ATF_REQUIRE_EQ(protocol, target); + */ + + target = PTHREAD_PRIO_PROTECT; + PTHREAD_REQUIRE(pthread_mutexattr_setprotocol(&mattr, target)); + PTHREAD_REQUIRE(pthread_mutexattr_getprotocol(&mattr, &protocol)); + ATF_REQUIRE_EQ(protocol, target); +} + +ATF_TC(mutexattr2); +ATF_TC_HEAD(mutexattr2, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks mutexattr"); +} + +ATF_TC_BODY(mutexattr2, tc) +{ + pthread_mutexattr_t mattr; + + PTHREAD_REQUIRE(pthread_mutexattr_init(&mattr)); + int max_prio = sched_get_priority_max(SCHED_FIFO); + int min_prio = sched_get_priority_min(SCHED_FIFO); + for (int i = min_prio; i <= max_prio; i++) { + int prioceiling; + PTHREAD_REQUIRE(pthread_mutexattr_setprioceiling(&mattr, i)); + PTHREAD_REQUIRE(pthread_mutexattr_getprioceiling(&mattr, + &prioceiling)); + ATF_REQUIRE_EQ(i, prioceiling); + } +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, mutex1); ATF_TP_ADD_TC(tp, mutex2); ATF_TP_ADD_TC(tp, mutex3); ATF_TP_ADD_TC(tp, mutex4); - + ATF_TP_ADD_TC(tp, mutex5); + ATF_TP_ADD_TC(tp, mutex6); + ATF_TP_ADD_TC(tp, mutexattr1); + ATF_TP_ADD_TC(tp, mutexattr2); + return atf_no_error(); } |
