2 * @file annotate_rwlock.c
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.
16 #include <unistd.h> /* usleep() */
17 #include "../../config.h"
18 #include "../../drd/drd.h"
21 #ifndef HAVE_BUILTIN_ATOMIC
22 #error Sorry, but this test program can only be compiled by a compiler that\
23 has built-in functions for atomic memory access.
34 static rwlock_t s_rwlock
;
38 static void rwlock_init(rwlock_t
* p
)
44 ANNOTATE_RWLOCK_CREATE(p
);
47 static void rwlock_destroy(rwlock_t
* p
)
49 ANNOTATE_RWLOCK_DESTROY(p
);
50 assert(p
->locked
== 0);
51 assert(p
->writer_count
== 0);
52 assert(p
->reader_count
== 0);
55 static void rwlock_rdlock(rwlock_t
* p
)
59 while (__sync_val_compare_and_swap(&p
->locked
, 0, 1) == 1)
61 if (p
->writer_count
== 0)
63 #ifndef HAVE_PTHREAD_YIELD
64 /* Darwin doesn't have an implementation of pthread_yield(). */
69 (void) __sync_fetch_and_sub(&p
->locked
, 1);
72 assert(p
->reader_count
>= 0);
73 assert(p
->writer_count
>= 0);
74 assert(p
->reader_count
== 0 || p
->writer_count
== 0);
75 (void) __sync_fetch_and_sub(&p
->locked
, 1);
76 ANNOTATE_READERLOCK_ACQUIRED(p
);
79 static void rwlock_wrlock(rwlock_t
* p
)
83 while (__sync_val_compare_and_swap(&p
->locked
, 0, 1) == 1)
85 if (p
->reader_count
== 0)
87 #ifndef HAVE_PTHREAD_YIELD
88 /* Darwin doesn't have an implementation of pthread_yield(). */
93 (void) __sync_fetch_and_sub(&p
->locked
, 1);
96 assert(p
->reader_count
>= 0);
97 assert(p
->writer_count
>= 0);
98 assert(p
->reader_count
== 0 || p
->writer_count
== 0);
99 (void) __sync_fetch_and_sub(&p
->locked
, 1);
100 ANNOTATE_WRITERLOCK_ACQUIRED(p
);
103 static void rwlock_unlock(rwlock_t
* p
)
105 while (__sync_val_compare_and_swap(&p
->locked
, 0, 1) == 1)
107 if (p
->reader_count
> 0)
110 ANNOTATE_READERLOCK_RELEASED(p
);
115 ANNOTATE_WRITERLOCK_RELEASED(p
);
117 assert(p
->reader_count
>= 0);
118 assert(p
->writer_count
>= 0);
119 assert(p
->reader_count
== 0 || p
->writer_count
== 0);
120 (void) __sync_fetch_and_sub(&p
->locked
, 1);
123 static void* thread_func(void* arg
)
128 for (i
= 0; i
< 1000; i
++)
130 rwlock_rdlock(&s_rwlock
);
132 rwlock_unlock(&s_rwlock
);
133 rwlock_wrlock(&s_rwlock
);
135 rwlock_unlock(&s_rwlock
);
141 int main(int argc
, char** argv
)
143 const int thread_count
= 10;
144 pthread_t tid
[thread_count
];
147 rwlock_init(&s_rwlock
);
148 for (i
= 0; i
< thread_count
; i
++)
150 pthread_create(&tid
[i
], 0, thread_func
, 0);
153 for (i
= 0; i
< thread_count
; i
++)
155 pthread_join(tid
[i
], 0);
157 rwlock_destroy(&s_rwlock
);
159 fprintf(stderr
, "Finished.\n");