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