drd/tests/swapcontext: Improve the portability of this test further
[valgrind.git] / drd / tests / annotate_rwlock.c
blob5ebb5fd24dae48e3adece00d0b6bdc4235aff475
1 /**
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.
8 */
11 #define _GNU_SOURCE 1
13 #include <assert.h>
14 #include <pthread.h>
15 #include <stdio.h>
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.
24 #endif
27 typedef struct {
28 volatile int locked;
29 int writer_count;
30 int reader_count;
31 } rwlock_t;
34 static rwlock_t s_rwlock;
35 static int s_counter;
38 static void rwlock_init(rwlock_t* p)
40 DRD_IGNORE_VAR(*p);
41 p->locked = 0;
42 p->writer_count = 0;
43 p->reader_count = 0;
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)
57 while (1)
59 while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
61 if (p->writer_count == 0)
62 break;
63 #ifndef HAVE_PTHREAD_YIELD
64 /* Darwin doesn't have an implementation of pthread_yield(). */
65 usleep(100 * 1000);
66 #else
67 pthread_yield();
68 #endif
69 (void) __sync_fetch_and_sub(&p->locked, 1);
71 p->reader_count++;
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)
81 while (1)
83 while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
85 if (p->reader_count == 0)
86 break;
87 #ifndef HAVE_PTHREAD_YIELD
88 /* Darwin doesn't have an implementation of pthread_yield(). */
89 usleep(100 * 1000);
90 #else
91 pthread_yield();
92 #endif
93 (void) __sync_fetch_and_sub(&p->locked, 1);
95 p->writer_count++;
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)
109 p->reader_count--;
110 ANNOTATE_READERLOCK_RELEASED(p);
112 else
114 p->writer_count--;
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)
125 int i;
126 int sum = 0;
128 for (i = 0; i < 1000; i++)
130 rwlock_rdlock(&s_rwlock);
131 sum += s_counter;
132 rwlock_unlock(&s_rwlock);
133 rwlock_wrlock(&s_rwlock);
134 s_counter++;
135 rwlock_unlock(&s_rwlock);
138 return 0;
141 int main(int argc, char** argv)
143 const int thread_count = 10;
144 pthread_t tid[thread_count];
145 int i;
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");
161 return 0;