• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* This program is a marginally modified copy of
3    drd/tests/annotate_rwlock.c,
4 
5    which was originally written by Bart van Assche.
6 
7    Unfortunately due to the need to #include helgrind.h instead of
8    drd.h, it can't be an exact copy.
9 */
10 
11 /**
12  * @file  annotate_rwlock.c
13  *
14  * @brief Multithreaded test program that triggers various access patterns
15  *        without triggering any race conditions using a reader-writer lock
16  *        implemented via busy-waiting. Annotations are used to tell DRD
17  *        which higher-level rwlock operations are being performed.
18  */
19 
20 
21 #define _GNU_SOURCE 1
22 
23 #include <assert.h>
24 #include <pthread.h>
25 #include <stdio.h>
26 #include <unistd.h>        /* usleep() */
27 #include "../../config.h"
28 #include "../../helgrind/helgrind.h"
29 
30 
31 #ifndef HAVE_BUILTIN_ATOMIC
32 #error Sorry, but this test program can only be compiled by a compiler that\
33 has built-in functions for atomic memory access.
34 #endif
35 
36 
37 typedef struct {
38   volatile int locked;
39   int          writer_count;
40   int          reader_count;
41 } rwlock_t;
42 
43 
44 static rwlock_t s_rwlock;
45 static int s_counter;
46 
47 
rwlock_init(rwlock_t * p)48 static void rwlock_init(rwlock_t* p)
49 {
50   //  DRD_IGNORE_VAR(*p);
51   p->locked       = 0;
52   p->writer_count = 0;
53   p->reader_count = 0;
54   ANNOTATE_RWLOCK_CREATE(p);
55 }
56 
rwlock_destroy(rwlock_t * p)57 static void rwlock_destroy(rwlock_t* p)
58 {
59   ANNOTATE_RWLOCK_DESTROY(p);
60   assert(p->locked       == 0);
61   assert(p->writer_count == 0);
62   assert(p->reader_count == 0);
63 }
64 
rwlock_rdlock(rwlock_t * p)65 static void rwlock_rdlock(rwlock_t* p)
66 {
67   while (1)
68   {
69     while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
70       ;
71     if (p->writer_count == 0)
72       break;
73 #ifdef __APPLE__
74     /* Darwin doesn't have an implementation of pthread_yield(). */
75     usleep(100 * 1000);
76 #else
77     pthread_yield();
78 #endif
79     (void) __sync_fetch_and_sub(&p->locked, 1);
80   }
81   p->reader_count++;
82   assert(p->reader_count >= 0);
83   assert(p->writer_count >= 0);
84   assert(p->reader_count == 0 || p->writer_count == 0);
85   (void) __sync_fetch_and_sub(&p->locked, 1);
86   //ANNOTATE_READERLOCK_ACQUIRED(p);
87   ANNOTATE_RWLOCK_ACQUIRED(p, 0);
88 }
89 
rwlock_wrlock(rwlock_t * p)90 static void rwlock_wrlock(rwlock_t* p)
91 {
92   while (1)
93   {
94     while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
95       ;
96     if (p->reader_count == 0)
97       break;
98 #ifdef __APPLE__
99     /* Darwin doesn't have an implementation of pthread_yield(). */
100     usleep(100 * 1000);
101 #else
102     pthread_yield();
103 #endif
104     (void) __sync_fetch_and_sub(&p->locked, 1);
105   }
106   p->writer_count++;
107   assert(p->reader_count >= 0);
108   assert(p->writer_count >= 0);
109   assert(p->reader_count == 0 || p->writer_count == 0);
110   (void) __sync_fetch_and_sub(&p->locked, 1);
111   //  ANNOTATE_WRITERLOCK_ACQUIRED(p);
112   ANNOTATE_RWLOCK_ACQUIRED(p, 1);
113 }
114 
rwlock_unlock(rwlock_t * p)115 static void rwlock_unlock(rwlock_t* p)
116 {
117   while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
118     ;
119   if (p->reader_count > 0)
120   {
121     p->reader_count--;
122     //ANNOTATE_READERLOCK_RELEASED(p);
123     ANNOTATE_RWLOCK_RELEASED(p, 0);
124   }
125   else
126   {
127     p->writer_count--;
128     //ANNOTATE_WRITERLOCK_RELEASED(p);
129     ANNOTATE_RWLOCK_RELEASED(p, 1);
130   }
131   assert(p->reader_count >= 0);
132   assert(p->writer_count >= 0);
133   assert(p->reader_count == 0 || p->writer_count == 0);
134   (void) __sync_fetch_and_sub(&p->locked, 1);
135 }
136 
thread_func(void * arg)137 static void* thread_func(void* arg)
138 {
139   int i;
140   int sum = 0;
141 
142   for (i = 0; i < 1000; i++)
143   {
144     rwlock_rdlock(&s_rwlock);
145     sum += s_counter;
146     rwlock_unlock(&s_rwlock);
147     rwlock_wrlock(&s_rwlock);
148     s_counter++;
149     rwlock_unlock(&s_rwlock);
150   }
151 
152   return 0;
153 }
154 
main(int argc,char ** argv)155 int main(int argc, char** argv)
156 {
157   const int thread_count = 10;
158   pthread_t tid[thread_count];
159   int i;
160 
161   rwlock_init(&s_rwlock);
162   for (i = 0; i < thread_count; i++)
163   {
164     pthread_create(&tid[i], 0, thread_func, 0);
165   }
166 
167   for (i = 0; i < thread_count; i++)
168   {
169     pthread_join(tid[i], 0);
170   }
171   rwlock_destroy(&s_rwlock);
172 
173   fprintf(stderr, "Finished.\n");
174 
175   return 0;
176 }
177