2 /* This program is a marginally modified copy of
3 drd/tests/annotate_rwlock.c,
5 which was originally written by Bart van Assche.
7 Unfortunately due to the need to #include helgrind.h instead of
8 drd.h, it can't be an exact copy.
12 * @file annotate_rwlock.c
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.
26 #include <unistd.h> /* usleep() */
27 #include "../../config.h"
28 #include "../../helgrind/helgrind.h"
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.
44 static rwlock_t s_rwlock
;
48 static void rwlock_init(rwlock_t
* p
)
50 // DRD_IGNORE_VAR(*p);
54 ANNOTATE_RWLOCK_CREATE(p
);
57 static void rwlock_destroy(rwlock_t
* p
)
59 ANNOTATE_RWLOCK_DESTROY(p
);
60 assert(p
->locked
== 0);
61 assert(p
->writer_count
== 0);
62 assert(p
->reader_count
== 0);
65 static void rwlock_rdlock(rwlock_t
* p
)
69 while (__sync_val_compare_and_swap(&p
->locked
, 0, 1) == 1)
71 if (p
->writer_count
== 0)
74 /* Darwin doesn't have an implementation of pthread_yield(). */
79 (void) __sync_fetch_and_sub(&p
->locked
, 1);
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);
90 static void rwlock_wrlock(rwlock_t
* p
)
94 while (__sync_val_compare_and_swap(&p
->locked
, 0, 1) == 1)
96 if (p
->reader_count
== 0)
99 /* Darwin doesn't have an implementation of pthread_yield(). */
104 (void) __sync_fetch_and_sub(&p
->locked
, 1);
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);
115 static void rwlock_unlock(rwlock_t
* p
)
117 while (__sync_val_compare_and_swap(&p
->locked
, 0, 1) == 1)
119 if (p
->reader_count
> 0)
122 //ANNOTATE_READERLOCK_RELEASED(p);
123 ANNOTATE_RWLOCK_RELEASED(p
, 0);
128 //ANNOTATE_WRITERLOCK_RELEASED(p);
129 ANNOTATE_RWLOCK_RELEASED(p
, 1);
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);
137 static void* thread_func(void* arg
)
142 for (i
= 0; i
< 1000; i
++)
144 rwlock_rdlock(&s_rwlock
);
146 rwlock_unlock(&s_rwlock
);
147 rwlock_wrlock(&s_rwlock
);
149 rwlock_unlock(&s_rwlock
);
155 int main(int argc
, char** argv
)
157 const int thread_count
= 10;
158 pthread_t tid
[thread_count
];
161 rwlock_init(&s_rwlock
);
162 for (i
= 0; i
< thread_count
; i
++)
164 pthread_create(&tid
[i
], 0, thread_func
, 0);
167 for (i
= 0; i
< thread_count
; i
++)
169 pthread_join(tid
[i
], 0);
171 rwlock_destroy(&s_rwlock
);
173 fprintf(stderr
, "Finished.\n");