blob: 65cfd5ba1935363f4f26b1a8e863e603f8971451 [file] [log] [blame]
bartd45d9952009-05-31 18:53:54 +00001/**
2 * @file rwlock_test.c
3 *
4 * @brief Multithreaded test program that triggers various access patterns
5 * without triggering any race conditions.
bart178cc162008-05-10 12:52:02 +00006 */
7
8
bart33f1c962008-05-10 13:17:34 +00009#define _GNU_SOURCE 1
10
bart2e1470c2009-07-24 09:34:37 +000011#include <assert.h>
12#include <limits.h> /* PTHREAD_STACK_MIN */
bart178cc162008-05-10 12:52:02 +000013#include <pthread.h>
14#include <stdio.h>
bart2e1470c2009-07-24 09:34:37 +000015#include <stdlib.h> /* malloc() */
16#include <string.h> /* strerror() */
17#include <unistd.h> /* getopt() */
bartf8f76292009-07-21 16:51:02 +000018
bart2e1470c2009-07-24 09:34:37 +000019static int s_num_threads = 10;
20static int s_num_iterations = 1000;
bart07c142e2009-07-24 11:10:05 +000021static pthread_mutex_t s_mutex;
22static long long s_grand_sum; /* protected by s_mutex. */
23static pthread_rwlock_t s_rwlock;
24static int s_counter; /* protected by s_rwlock. */
bart178cc162008-05-10 12:52:02 +000025
26static void* thread_func(void* arg)
27{
bart07c142e2009-07-24 11:10:05 +000028 int i, r;
29 int sum1 = 0, sum2 = 0;
bart178cc162008-05-10 12:52:02 +000030
bart2e1470c2009-07-24 09:34:37 +000031 for (i = s_num_iterations; i > 0; i--)
bart178cc162008-05-10 12:52:02 +000032 {
bart07c142e2009-07-24 11:10:05 +000033 r = pthread_rwlock_rdlock(&s_rwlock);
34 assert(! r);
35 sum1 += s_counter;
36 r = pthread_rwlock_unlock(&s_rwlock);
37 assert(! r);
38 r = pthread_rwlock_wrlock(&s_rwlock);
39 assert(! r);
40 sum2 += s_counter++;
41 r = pthread_rwlock_unlock(&s_rwlock);
42 assert(! r);
bart178cc162008-05-10 12:52:02 +000043 }
44
bart07c142e2009-07-24 11:10:05 +000045 pthread_mutex_lock(&s_mutex);
46 s_grand_sum += sum2;
47 pthread_mutex_unlock(&s_mutex);
48
bart178cc162008-05-10 12:52:02 +000049 return 0;
50}
51
52int main(int argc, char** argv)
53{
bart2e1470c2009-07-24 09:34:37 +000054 pthread_attr_t attr;
55 pthread_t* tid;
56 int threads_created;
57 int optchar;
58 int err;
bart178cc162008-05-10 12:52:02 +000059 int i;
bart07c142e2009-07-24 11:10:05 +000060 int expected_counter;
61 long long expected_grand_sum;
bart178cc162008-05-10 12:52:02 +000062
bart2e1470c2009-07-24 09:34:37 +000063 while ((optchar = getopt(argc, argv, "i:t:")) != EOF)
bart178cc162008-05-10 12:52:02 +000064 {
bart2e1470c2009-07-24 09:34:37 +000065 switch (optchar)
66 {
67 case 'i':
68 s_num_iterations = atoi(optarg);
69 break;
70 case 't':
71 s_num_threads = atoi(optarg);
72 break;
73 default:
74 fprintf(stderr, "Error: unknown option '%c'.\n", optchar);
75 return 1;
76 }
bart178cc162008-05-10 12:52:02 +000077 }
78
bart07c142e2009-07-24 11:10:05 +000079 pthread_mutex_init(&s_mutex, NULL);
bart2e1470c2009-07-24 09:34:37 +000080 pthread_rwlock_init(&s_rwlock, NULL);
81
82 pthread_attr_init(&attr);
83 err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 4096);
84 assert(err == 0);
85
86 tid = calloc(s_num_threads, sizeof(*tid));
87 threads_created = 0;
88 for (i = 0; i < s_num_threads; i++)
bart178cc162008-05-10 12:52:02 +000089 {
bart2e1470c2009-07-24 09:34:37 +000090 err = pthread_create(&tid[i], &attr, thread_func, 0);
91 if (err)
92 printf("failed to create thread %d: %s\n", i, strerror(err));
93 else
94 threads_created++;
bart178cc162008-05-10 12:52:02 +000095 }
96
bart2e1470c2009-07-24 09:34:37 +000097 pthread_attr_destroy(&attr);
98
99 for (i = 0; i < s_num_threads; i++)
100 {
101 if (tid[i])
102 pthread_join(tid[i], 0);
103 }
104 free(tid);
105
bart07c142e2009-07-24 11:10:05 +0000106 expected_counter = threads_created * s_num_iterations;
107 fprintf(stderr, "s_counter - expected_counter = %d\n",
108 s_counter - expected_counter);
109 expected_grand_sum = 1ULL * expected_counter * (expected_counter - 1) / 2;
110 fprintf(stderr, "s_grand_sum - expected_grand_sum = %lld\n",
111 s_grand_sum - expected_grand_sum);
bart178cc162008-05-10 12:52:02 +0000112 fprintf(stderr, "Finished.\n");
113
114 return 0;
115}