blob: 8961f3ca03e4245b639cdf9605943b7eb904ca76 [file] [log] [blame]
sewardj6b45cf22009-08-14 11:11:12 +00001
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\
33has built-in functions for atomic memory access.
34#endif
35
36
37typedef struct {
38 volatile int locked;
39 int writer_count;
40 int reader_count;
41} rwlock_t;
42
43
44static rwlock_t s_rwlock;
45static int s_counter;
46
47
48static 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
57static 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
65static 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
sewardj8eb8bab2015-07-21 14:44:28 +000077 sched_yield();
sewardj6b45cf22009-08-14 11:11:12 +000078#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
90static 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
sewardj8eb8bab2015-07-21 14:44:28 +0000102 sched_yield();
sewardj6b45cf22009-08-14 11:11:12 +0000103#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
115static 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
137static 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
155int 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}