blob: 5ebb5fd24dae48e3adece00d0b6bdc4235aff475 [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>
bart5107de92009-07-22 19:04:58 +000016#include <unistd.h> /* usleep() */
bartd45d9952009-05-31 18:53:54 +000017#include "../../config.h"
18#include "../../drd/drd.h"
19
20
21#ifndef HAVE_BUILTIN_ATOMIC
22#error Sorry, but this test program can only be compiled by a compiler that\
23has built-in functions for atomic memory access.
24#endif
25
26
27typedef struct {
28 volatile int locked;
29 int writer_count;
30 int reader_count;
31} rwlock_t;
32
33
34static rwlock_t s_rwlock;
35static int s_counter;
36
37
38static void rwlock_init(rwlock_t* p)
39{
40 DRD_IGNORE_VAR(*p);
41 p->locked = 0;
42 p->writer_count = 0;
43 p->reader_count = 0;
44 ANNOTATE_RWLOCK_CREATE(p);
45}
46
47static void rwlock_destroy(rwlock_t* p)
48{
49 ANNOTATE_RWLOCK_DESTROY(p);
50 assert(p->locked == 0);
51 assert(p->writer_count == 0);
52 assert(p->reader_count == 0);
53}
54
55static void rwlock_rdlock(rwlock_t* p)
56{
57 while (1)
58 {
59 while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
60 ;
61 if (p->writer_count == 0)
62 break;
bart0ccdc4a2010-04-29 06:28:43 +000063#ifndef HAVE_PTHREAD_YIELD
bart5107de92009-07-22 19:04:58 +000064 /* Darwin doesn't have an implementation of pthread_yield(). */
65 usleep(100 * 1000);
66#else
bartd45d9952009-05-31 18:53:54 +000067 pthread_yield();
bart5107de92009-07-22 19:04:58 +000068#endif
bart9f1757f2009-08-12 13:30:55 +000069 (void) __sync_fetch_and_sub(&p->locked, 1);
bartd45d9952009-05-31 18:53:54 +000070 }
71 p->reader_count++;
72 assert(p->reader_count >= 0);
73 assert(p->writer_count >= 0);
74 assert(p->reader_count == 0 || p->writer_count == 0);
bart9f1757f2009-08-12 13:30:55 +000075 (void) __sync_fetch_and_sub(&p->locked, 1);
bart5a97c192009-07-01 18:46:27 +000076 ANNOTATE_READERLOCK_ACQUIRED(p);
bartd45d9952009-05-31 18:53:54 +000077}
78
79static void rwlock_wrlock(rwlock_t* p)
80{
81 while (1)
82 {
83 while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
84 ;
85 if (p->reader_count == 0)
86 break;
bart0ccdc4a2010-04-29 06:28:43 +000087#ifndef HAVE_PTHREAD_YIELD
bart5107de92009-07-22 19:04:58 +000088 /* Darwin doesn't have an implementation of pthread_yield(). */
89 usleep(100 * 1000);
90#else
bartd45d9952009-05-31 18:53:54 +000091 pthread_yield();
bart5107de92009-07-22 19:04:58 +000092#endif
bart9f1757f2009-08-12 13:30:55 +000093 (void) __sync_fetch_and_sub(&p->locked, 1);
bartd45d9952009-05-31 18:53:54 +000094 }
95 p->writer_count++;
96 assert(p->reader_count >= 0);
97 assert(p->writer_count >= 0);
98 assert(p->reader_count == 0 || p->writer_count == 0);
bart9f1757f2009-08-12 13:30:55 +000099 (void) __sync_fetch_and_sub(&p->locked, 1);
bart5a97c192009-07-01 18:46:27 +0000100 ANNOTATE_WRITERLOCK_ACQUIRED(p);
bartd45d9952009-05-31 18:53:54 +0000101}
102
103static void rwlock_unlock(rwlock_t* p)
104{
105 while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
106 ;
107 if (p->reader_count > 0)
108 {
109 p->reader_count--;
bart5a97c192009-07-01 18:46:27 +0000110 ANNOTATE_READERLOCK_RELEASED(p);
bartd45d9952009-05-31 18:53:54 +0000111 }
112 else
113 {
114 p->writer_count--;
bart5a97c192009-07-01 18:46:27 +0000115 ANNOTATE_WRITERLOCK_RELEASED(p);
bartd45d9952009-05-31 18:53:54 +0000116 }
117 assert(p->reader_count >= 0);
118 assert(p->writer_count >= 0);
119 assert(p->reader_count == 0 || p->writer_count == 0);
bart9f1757f2009-08-12 13:30:55 +0000120 (void) __sync_fetch_and_sub(&p->locked, 1);
bartd45d9952009-05-31 18:53:54 +0000121}
122
123static void* thread_func(void* arg)
124{
125 int i;
126 int sum = 0;
127
128 for (i = 0; i < 1000; i++)
129 {
130 rwlock_rdlock(&s_rwlock);
131 sum += s_counter;
132 rwlock_unlock(&s_rwlock);
133 rwlock_wrlock(&s_rwlock);
134 s_counter++;
135 rwlock_unlock(&s_rwlock);
136 }
137
138 return 0;
139}
140
141int main(int argc, char** argv)
142{
143 const int thread_count = 10;
144 pthread_t tid[thread_count];
145 int i;
146
147 rwlock_init(&s_rwlock);
148 for (i = 0; i < thread_count; i++)
149 {
150 pthread_create(&tid[i], 0, thread_func, 0);
151 }
152
153 for (i = 0; i < thread_count; i++)
154 {
155 pthread_join(tid[i], 0);
156 }
157 rwlock_destroy(&s_rwlock);
158
159 fprintf(stderr, "Finished.\n");
160
161 return 0;
162}