Changeset View
Changeset View
Standalone View
Standalone View
head/contrib/netbsd-tests/lib/libpthread/t_mutex.c
Show All 29 Lines | |||||
__COPYRIGHT("@(#) Copyright (c) 2008\ | __COPYRIGHT("@(#) Copyright (c) 2008\ | ||||
The NetBSD Foundation, inc. All rights reserved."); | The NetBSD Foundation, inc. All rights reserved."); | ||||
__RCSID("$NetBSD: t_mutex.c,v 1.15 2017/01/16 16:23:41 christos Exp $"); | __RCSID("$NetBSD: t_mutex.c,v 1.15 2017/01/16 16:23:41 christos Exp $"); | ||||
#include <sys/time.h> /* For timespecadd */ | #include <sys/time.h> /* For timespecadd */ | ||||
#include <inttypes.h> /* For UINT16_MAX */ | #include <inttypes.h> /* For UINT16_MAX */ | ||||
#include <pthread.h> | #include <pthread.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#ifdef __FreeBSD__ | |||||
#include <stdlib.h> | |||||
#endif | |||||
#include <string.h> | #include <string.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <time.h> | #include <time.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <sys/sched.h> | #include <sys/sched.h> | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <atf-c.h> | #include <atf-c.h> | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | ATF_TC_BODY(mutex1, tc) | ||||
PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | ||||
printf("1: Thread joined. X was %d. Return value (int) was %d\n", | printf("1: Thread joined. X was %d. Return value (int) was %d\n", | ||||
x, *(int *)joinval); | x, *(int *)joinval); | ||||
ATF_REQUIRE_EQ(x, 21); | ATF_REQUIRE_EQ(x, 21); | ||||
ATF_REQUIRE_EQ(*(int *)joinval, 21); | ATF_REQUIRE_EQ(*(int *)joinval, 21); | ||||
PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); | PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); | ||||
} | } | ||||
#ifdef __FreeBSD__ | |||||
/* | |||||
* Increment the value using a noinline function that includes a small delay | |||||
* to increase the window for the RMW data race. | |||||
*/ | |||||
__noinline static int | |||||
increment(int value) | |||||
{ | |||||
for (volatile int i = 0; i < 100; i++) { | |||||
/* Small delay between read+write to increase chance of race */ | |||||
__compiler_membar(); | |||||
} | |||||
return value + 1; | |||||
} | |||||
static volatile bool thread2_started = false; | |||||
#endif | |||||
static void * | static void * | ||||
mutex2_threadfunc(void *arg) | mutex2_threadfunc(void *arg) | ||||
{ | { | ||||
long count = *(int *)arg; | long count = *(int *)arg; | ||||
#ifdef __FreeBSD__ | |||||
thread2_started = true; | |||||
#endif | |||||
printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count); | printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count); | ||||
while (count--) { | while (count--) { | ||||
PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | ||||
#ifdef __FreeBSD__ | |||||
global_x = increment(global_x); | |||||
#else | |||||
global_x++; | global_x++; | ||||
#endif | |||||
PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); | PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); | ||||
} | } | ||||
return (void *)count; | return (void *)count; | ||||
} | } | ||||
ATF_TC(mutex2); | ATF_TC(mutex2); | ||||
ATF_TC_HEAD(mutex2, tc) | ATF_TC_HEAD(mutex2, tc) | ||||
{ | { | ||||
atf_tc_set_md_var(tc, "descr", "Checks mutexes"); | atf_tc_set_md_var(tc, "descr", "Checks mutexes"); | ||||
#ifdef __NetBSD__ | #ifdef __NetBSD__ | ||||
#if defined(__powerpc__) | #if defined(__powerpc__) | ||||
atf_tc_set_md_var(tc, "timeout", "40"); | atf_tc_set_md_var(tc, "timeout", "40"); | ||||
#endif | #endif | ||||
#endif | #endif | ||||
#ifdef __FreeBSD__ | |||||
#if defined(__riscv) | |||||
atf_tc_set_md_var(tc, "timeout", "600"); | |||||
#endif | |||||
#endif | |||||
} | } | ||||
ATF_TC_BODY(mutex2, tc) | ATF_TC_BODY(mutex2, tc) | ||||
{ | { | ||||
int count, count2; | int count, count2; | ||||
#ifdef __FreeBSD__ | |||||
int num_increments; | |||||
#endif | |||||
pthread_t new; | pthread_t new; | ||||
void *joinval; | void *joinval; | ||||
printf("1: Mutex-test 2\n"); | printf("1: Mutex-test 2\n"); | ||||
#ifdef __NetBSD__ | #ifdef __NetBSD__ | ||||
#if defined(__powerpc__) | #if defined(__powerpc__) | ||||
atf_tc_expect_timeout("PR port-powerpc/44387"); | atf_tc_expect_timeout("PR port-powerpc/44387"); | ||||
#endif | #endif | ||||
#endif | #endif | ||||
PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); | PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); | ||||
global_x = 0; | global_x = 0; | ||||
#ifdef __FreeBSD__ | |||||
num_increments = count = count2 = 1000; | |||||
if (getenv("NUM_ITERATIONS") != NULL) { | |||||
num_increments = count = count2 = | |||||
MIN(INT_MAX, strtoul(getenv("NUM_ITERATIONS"), NULL, 10)); | |||||
} | |||||
printf("Will use %d iterations\n", num_increments); | |||||
#else | |||||
count = count2 = 10000000; | count = count2 = 10000000; | ||||
#endif | |||||
PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | ||||
#ifdef __FreeBSD__ | |||||
thread2_started = false; | |||||
#endif | |||||
PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex2_threadfunc, &count2)); | PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex2_threadfunc, &count2)); | ||||
printf("1: Thread %p\n", pthread_self()); | printf("1: Thread %p\n", pthread_self()); | ||||
#ifdef __FreeBSD__ | |||||
while (!thread2_started) { | |||||
/* Wait for thread 2 to start to increase chance of race */ | |||||
} | |||||
printf("1: Unlocking to start increment loop %p\n", pthread_self()); | |||||
#endif | |||||
PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); | PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); | ||||
while (count--) { | while (count--) { | ||||
PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | ||||
#ifdef __FreeBSD__ | |||||
global_x = increment(global_x); | |||||
#else | |||||
global_x++; | global_x++; | ||||
#endif | |||||
PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); | PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); | ||||
} | } | ||||
PTHREAD_REQUIRE(pthread_join(new, &joinval)); | PTHREAD_REQUIRE(pthread_join(new, &joinval)); | ||||
PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | PTHREAD_REQUIRE(mutex_lock(&mutex, &ts_lengthy)); | ||||
printf("1: Thread joined. X was %d. Return value (long) was %ld\n", | printf("1: Thread joined. X was %d. Return value (long) was %ld\n", | ||||
global_x, (long)joinval); | global_x, (long)joinval); | ||||
#ifdef __FreeBSD__ | |||||
ATF_REQUIRE_EQ_MSG(count, -1, "%d", count); | |||||
ATF_REQUIRE_EQ_MSG((long)joinval, -1, "%ld", (long)joinval); | |||||
ATF_REQUIRE_EQ_MSG(global_x, num_increments * 2, "%d vs %d", global_x, | |||||
num_increments * 2); | |||||
#else | |||||
ATF_REQUIRE_EQ(global_x, 20000000); | ATF_REQUIRE_EQ(global_x, 20000000); | ||||
#endif | |||||
#ifdef __NetBSD__ | #ifdef __NetBSD__ | ||||
#if defined(__powerpc__) | #if defined(__powerpc__) | ||||
/* XXX force a timeout in ppc case since an un-triggered race | /* XXX force a timeout in ppc case since an un-triggered race | ||||
otherwise looks like a "failure" */ | otherwise looks like a "failure" */ | ||||
/* We sleep for longer than the timeout to make ATF not | /* We sleep for longer than the timeout to make ATF not | ||||
complain about unexpected success */ | complain about unexpected success */ | ||||
sleep(41); | sleep(41); | ||||
#endif | #endif | ||||
#endif | #endif | ||||
} | } | ||||
#ifdef __FreeBSD__ | |||||
static volatile bool thread3_started = false; | |||||
#endif | |||||
static void * | static void * | ||||
mutex3_threadfunc(void *arg) | mutex3_threadfunc(void *arg) | ||||
{ | { | ||||
long count = *(int *)arg; | long count = *(int *)arg; | ||||
#ifdef __FreeBSD__ | |||||
thread3_started = true; | |||||
#endif | |||||
printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count); | printf("2: Second thread (%p). Count is %ld\n", pthread_self(), count); | ||||
while (count--) { | while (count--) { | ||||
PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy)); | PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy)); | ||||
#ifdef __FreeBSD__ | |||||
global_x = increment(global_x); | |||||
#else | |||||
global_x++; | global_x++; | ||||
#endif | |||||
PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); | PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); | ||||
} | } | ||||
return (void *)count; | return (void *)count; | ||||
} | } | ||||
ATF_TC(mutex3); | ATF_TC(mutex3); | ||||
ATF_TC_HEAD(mutex3, tc) | ATF_TC_HEAD(mutex3, tc) | ||||
{ | { | ||||
atf_tc_set_md_var(tc, "descr", "Checks mutexes using a static " | atf_tc_set_md_var(tc, "descr", "Checks mutexes using a static " | ||||
"initializer"); | "initializer"); | ||||
#ifdef __NetBSD__ | #ifdef __NetBSD__ | ||||
#if defined(__powerpc__) | #if defined(__powerpc__) | ||||
atf_tc_set_md_var(tc, "timeout", "40"); | atf_tc_set_md_var(tc, "timeout", "40"); | ||||
#endif | #endif | ||||
#endif | #endif | ||||
#ifdef __FreeBSD__ | |||||
#if defined(__riscv) | |||||
atf_tc_set_md_var(tc, "timeout", "600"); | |||||
#endif | |||||
#endif | |||||
} | } | ||||
ATF_TC_BODY(mutex3, tc) | ATF_TC_BODY(mutex3, tc) | ||||
{ | { | ||||
int count, count2; | int count, count2; | ||||
#ifdef __FreeBSD__ | |||||
int num_increments; | |||||
#endif | |||||
pthread_t new; | pthread_t new; | ||||
void *joinval; | void *joinval; | ||||
printf("1: Mutex-test 3\n"); | printf("1: Mutex-test 3\n"); | ||||
#ifdef __NetBSD__ | #ifdef __NetBSD__ | ||||
#if defined(__powerpc__) | #if defined(__powerpc__) | ||||
atf_tc_expect_timeout("PR port-powerpc/44387"); | atf_tc_expect_timeout("PR port-powerpc/44387"); | ||||
#endif | #endif | ||||
#endif | #endif | ||||
global_x = 0; | global_x = 0; | ||||
#ifdef __FreeBSD__ | |||||
num_increments = count = count2 = 1000; | |||||
if (getenv("NUM_ITERATIONS") != NULL) { | |||||
num_increments = count = count2 = | |||||
MIN(INT_MAX, strtoul(getenv("NUM_ITERATIONS"), NULL, 10)); | |||||
} | |||||
printf("Will use %d iterations\n", num_increments); | |||||
#else | |||||
count = count2 = 10000000; | count = count2 = 10000000; | ||||
#endif | |||||
PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy)); | PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy)); | ||||
PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex3_threadfunc, &count2)); | PTHREAD_REQUIRE(pthread_create(&new, NULL, mutex3_threadfunc, &count2)); | ||||
printf("1: Thread %p\n", pthread_self()); | printf("1: Thread %p\n", pthread_self()); | ||||
#ifdef __FreeBSD__ | |||||
while (!thread3_started) { | |||||
/* Wait for thread 3 to start to increase chance of race */ | |||||
} | |||||
printf("1: Unlocking to start increment loop %p\n", pthread_self()); | |||||
#endif | |||||
PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); | PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); | ||||
while (count--) { | while (count--) { | ||||
PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy)); | PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy)); | ||||
#ifdef __FreeBSD__ | |||||
global_x = increment(global_x); | |||||
#else | |||||
global_x++; | global_x++; | ||||
#endif | |||||
PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); | PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); | ||||
} | } | ||||
PTHREAD_REQUIRE(pthread_join(new, &joinval)); | PTHREAD_REQUIRE(pthread_join(new, &joinval)); | ||||
PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy)); | PTHREAD_REQUIRE(mutex_lock(&static_mutex, &ts_lengthy)); | ||||
printf("1: Thread joined. X was %d. Return value (long) was %ld\n", | printf("1: Thread joined. X was %d. Return value (long) was %ld\n", | ||||
global_x, (long)joinval); | global_x, (long)joinval); | ||||
#ifdef __FreeBSD__ | |||||
ATF_REQUIRE_EQ_MSG(count, -1, "%d", count); | |||||
ATF_REQUIRE_EQ_MSG((long)joinval, -1, "%ld", (long)joinval); | |||||
ATF_REQUIRE_EQ_MSG(global_x, num_increments * 2, "%d vs %d", global_x, | |||||
num_increments * 2); | |||||
#else | |||||
ATF_REQUIRE_EQ(global_x, 20000000); | ATF_REQUIRE_EQ(global_x, 20000000); | ||||
#endif | |||||
#ifdef __NetBSD__ | #ifdef __NetBSD__ | ||||
#if defined(__powerpc__) | #if defined(__powerpc__) | ||||
/* XXX force a timeout in ppc case since an un-triggered race | /* XXX force a timeout in ppc case since an un-triggered race | ||||
otherwise looks like a "failure" */ | otherwise looks like a "failure" */ | ||||
/* We sleep for longer than the timeout to make ATF not | /* We sleep for longer than the timeout to make ATF not | ||||
complain about unexpected success */ | complain about unexpected success */ | ||||
sleep(41); | sleep(41); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 469 Lines • Show Last 20 Lines |