blob: 1d4ee859af0d76e04d554d581b6c38a9d5420a4e [file] [log] [blame]
bartd45d9952009-05-31 18:53:54 +00001/**
2 * @file annotate_rwlock.c
3 *
4 * @brief Multithreaded test program that triggers various access patterns
5 * without triggering any race conditions using a reader-writer lock
6 * implemented via busy-waiting. Annotations are used to tell DRD
7 * which higher-level rwlock operations are being performed.
8 */
9
10
11#define _GNU_SOURCE 1
12
13#include <assert.h>
14#include <pthread.h>
15#include <stdio.h>
16#include "../../config.h"
17#include "../../drd/drd.h"
18
19
20#ifndef HAVE_BUILTIN_ATOMIC
21#error Sorry, but this test program can only be compiled by a compiler that\
22has built-in functions for atomic memory access.
23#endif
24
25
26typedef struct {
27 volatile int locked;
28 int writer_count;
29 int reader_count;
30} rwlock_t;
31
32
33static rwlock_t s_rwlock;
34static int s_counter;
35
36
37static void rwlock_init(rwlock_t* p)
38{
39 DRD_IGNORE_VAR(*p);
40 p->locked = 0;
41 p->writer_count = 0;
42 p->reader_count = 0;
43 ANNOTATE_RWLOCK_CREATE(p);
44}
45
46static void rwlock_destroy(rwlock_t* p)
47{
48 ANNOTATE_RWLOCK_DESTROY(p);
49 assert(p->locked == 0);
50 assert(p->writer_count == 0);
51 assert(p->reader_count == 0);
52}
53
54static void rwlock_rdlock(rwlock_t* p)
55{
56 while (1)
57 {
58 while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
59 ;
60 if (p->writer_count == 0)
61 break;
62 pthread_yield();
63 __sync_fetch_and_sub(&p->locked, 1);
64 }
65 p->reader_count++;
66 assert(p->reader_count >= 0);
67 assert(p->writer_count >= 0);
68 assert(p->reader_count == 0 || p->writer_count == 0);
69 __sync_fetch_and_sub(&p->locked, 1);
bart5a97c192009-07-01 18:46:27 +000070 ANNOTATE_READERLOCK_ACQUIRED(p);
bartd45d9952009-05-31 18:53:54 +000071}
72
73static void rwlock_wrlock(rwlock_t* p)
74{
75 while (1)
76 {
77 while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
78 ;
79 if (p->reader_count == 0)
80 break;
81 pthread_yield();
82 __sync_fetch_and_sub(&p->locked, 1);
83 }
84 p->writer_count++;
85 assert(p->reader_count >= 0);
86 assert(p->writer_count >= 0);
87 assert(p->reader_count == 0 || p->writer_count == 0);
88 __sync_fetch_and_sub(&p->locked, 1);
bart5a97c192009-07-01 18:46:27 +000089 ANNOTATE_WRITERLOCK_ACQUIRED(p);
bartd45d9952009-05-31 18:53:54 +000090}
91
92static void rwlock_unlock(rwlock_t* p)
93{
94 while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
95 ;
96 if (p->reader_count > 0)
97 {
98 p->reader_count--;
bart5a97c192009-07-01 18:46:27 +000099 ANNOTATE_READERLOCK_RELEASED(p);
bartd45d9952009-05-31 18:53:54 +0000100 }
101 else
102 {
103 p->writer_count--;
bart5a97c192009-07-01 18:46:27 +0000104 ANNOTATE_WRITERLOCK_RELEASED(p);
bartd45d9952009-05-31 18:53:54 +0000105 }
106 assert(p->reader_count >= 0);
107 assert(p->writer_count >= 0);
108 assert(p->reader_count == 0 || p->writer_count == 0);
109 __sync_fetch_and_sub(&p->locked, 1);
110}
111
112static void* thread_func(void* arg)
113{
114 int i;
115 int sum = 0;
116
117 for (i = 0; i < 1000; i++)
118 {
119 rwlock_rdlock(&s_rwlock);
120 sum += s_counter;
121 rwlock_unlock(&s_rwlock);
122 rwlock_wrlock(&s_rwlock);
123 s_counter++;
124 rwlock_unlock(&s_rwlock);
125 }
126
127 return 0;
128}
129
130int main(int argc, char** argv)
131{
132 const int thread_count = 10;
133 pthread_t tid[thread_count];
134 int i;
135
136 rwlock_init(&s_rwlock);
137 for (i = 0; i < thread_count; i++)
138 {
139 pthread_create(&tid[i], 0, thread_func, 0);
140 }
141
142 for (i = 0; i < thread_count; i++)
143 {
144 pthread_join(tid[i], 0);
145 }
146 rwlock_destroy(&s_rwlock);
147
148 fprintf(stderr, "Finished.\n");
149
150 return 0;
151}