1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * @file rwlock_test.c 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * @brief Multithreaded test program that triggers various access patterns 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * without triggering any race conditions. 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define _GNU_SOURCE 1 10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <assert.h> 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <limits.h> /* PTHREAD_STACK_MIN */ 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h> 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h> 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h> /* malloc() */ 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <string.h> /* strerror() */ 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h> /* getopt() */ 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int s_num_threads = 10; 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int s_num_iterations = 1000; 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic pthread_mutex_t s_mutex; 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic long long s_grand_sum; /* protected by s_mutex. */ 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic pthread_rwlock_t s_rwlock; 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int s_counter; /* protected by s_rwlock. */ 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* thread_func(void* arg) 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int i, r; 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int sum1 = 0, sum2 = 0; 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = s_num_iterations; i > 0; i--) 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown r = pthread_rwlock_rdlock(&s_rwlock); 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(! r); 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sum1 += s_counter; 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown r = pthread_rwlock_unlock(&s_rwlock); 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(! r); 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown r = pthread_rwlock_wrlock(&s_rwlock); 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(! r); 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sum2 += s_counter++; 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown r = pthread_rwlock_unlock(&s_rwlock); 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(! r); 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_lock(&s_mutex); 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s_grand_sum += sum2; 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_unlock(&s_mutex); 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main(int argc, char** argv) 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_t attr; 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_t* tid; 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int threads_created; 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int optchar; 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int err; 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int i; 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int expected_counter; 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown long long expected_grand_sum; 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown while ((optchar = getopt(argc, argv, "i:t:")) != EOF) 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (optchar) 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 'i': 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s_num_iterations = atoi(optarg); 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 't': 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s_num_threads = atoi(optarg); 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown default: 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fprintf(stderr, "Error: unknown option '%c'.\n", optchar); 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 1; 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_mutex_init(&s_mutex, NULL); 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_rwlock_init(&s_rwlock, NULL); 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_init(&attr); 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 4096); 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert(err == 0); 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tid = calloc(s_num_threads, sizeof(*tid)); 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown threads_created = 0; 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < s_num_threads; i++) 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown err = pthread_create(&tid[i], &attr, thread_func, 0); 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (err) 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown printf("failed to create thread %d: %s\n", i, strerror(err)); 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown threads_created++; 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_attr_destroy(&attr); 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (i = 0; i < s_num_threads; i++) 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (tid[i]) 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pthread_join(tid[i], 0); 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown free(tid); 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown expected_counter = threads_created * s_num_iterations; 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fprintf(stderr, "s_counter - expected_counter = %d\n", 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s_counter - expected_counter); 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown expected_grand_sum = 1ULL * expected_counter * (expected_counter - 1) / 2; 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fprintf(stderr, "s_grand_sum - expected_grand_sum = %lld\n", 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown s_grand_sum - expected_grand_sum); 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown fprintf(stderr, "Finished.\n"); 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 116