1 /* $OpenBSD: pthread_rwlock.c,v 1.3 2014/05/20 01:25:24 guenther Exp $ */
2 /* PUBLIC DOMAIN Feb 2012 <guenther@openbsd.org> */
3
4 #include <sys/types.h>
5 #include <assert.h>
6 #include <err.h>
7 #include <pthread.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <time.h>
11 #include <unistd.h>
12
13 /*
14 * Set up an rwlock with a few reader threads, start a writer blocking,
15 * then let go the reader threads one by one. Verify that the writer
16 * thread gets, gets out, and then the rwlock can be locked for reading
17 * again.
18 */
19
20 pthread_rwlock_t rw;
21
22 pthread_mutex_t m;
23 pthread_cond_t c;
24 enum
25 {
26 UNLOCKED,
27 NUM_READERS = 6,
28 WRITE_STARTED,
29 WRITE,
30 WRITE_DONE,
31 } state;
32 time_t write_started;
33
34 static void *
reader(void * arg)35 reader(void *arg)
36 {
37 int me = *(int *)arg;
38 int diff;
39
40 pthread_mutex_lock(&m);
41 assert(state < NUM_READERS);
42 pthread_rwlock_rdlock(&rw);
43 state++;
44 printf("reader %d locked, state = %d\n", me, state);
45 pthread_cond_broadcast(&c);
46 pthread_mutex_unlock(&m);
47
48 pthread_mutex_lock(&m);
49 while (state < WRITE_STARTED) {
50 pthread_cond_wait(&c, &m);
51 printf("reader %d woken, state = %d\n", me, state);
52 }
53
54 diff = difftime(time(NULL), write_started);
55 if (diff < 2)
56 sleep(3 - diff);
57
58 pthread_rwlock_unlock(&rw);
59 printf("reader %d unlocked\n", me);
60 sleep(1);
61
62 pthread_mutex_unlock(&m);
63
64 pthread_mutex_lock(&m);
65 while (state >= WRITE_STARTED) {
66 pthread_cond_wait(&c, &m);
67 printf("reader %d woken, state = %d\n", me, state);
68 }
69 state++;
70 printf("reader %d trying again (%d)\n", me, state);
71 pthread_rwlock_rdlock(&rw);
72 printf("reader %d locked again (%d)\n", me, state);
73 pthread_cond_broadcast(&c);
74 while (state != NUM_READERS) {
75 pthread_cond_wait(&c, &m);
76 printf("reader %d woken, state = %d\n", me, state);
77 }
78 pthread_mutex_unlock(&m);
79 pthread_rwlock_unlock(&rw);
80
81 printf("reader %d exiting\n", me);
82 return NULL;
83 }
84
85 static void *
writer(void * arg)86 writer(void *arg)
87 {
88 pthread_mutex_lock(&m);
89 printf("writer started, state = %d\n", state);
90 while (state != NUM_READERS) {
91 pthread_cond_wait(&c, &m);
92 printf("writer woken, state = %d\n", state);
93 }
94 state = WRITE_STARTED;
95 printf("writer starting\n");
96 write_started = time(NULL);
97 pthread_cond_broadcast(&c);
98 pthread_mutex_unlock(&m);
99
100 pthread_rwlock_wrlock(&rw);
101 printf("writer locked\n");
102
103 pthread_mutex_lock(&m);
104 state = WRITE;
105 pthread_cond_broadcast(&c);
106
107 while (state == WRITE)
108 pthread_cond_wait(&c, &m);
109
110 printf("writer unlocking\n");
111 pthread_rwlock_unlock(&rw);
112 state = UNLOCKED;
113 pthread_cond_broadcast(&c);
114 pthread_mutex_unlock(&m);
115
116 printf("writer exiting\n");
117 return NULL;
118 }
119
120
121 int
main(void)122 main(void)
123 {
124 pthread_t tr[NUM_READERS], tw;
125 int ids[NUM_READERS], i, r;
126
127 pthread_rwlock_init(&rw, NULL);
128 pthread_mutex_init(&m, NULL);
129 pthread_cond_init(&c, NULL);
130 state = UNLOCKED;
131
132 for (i = 0; i < NUM_READERS; i++) {
133 ids[i] = i;
134 if ((r = pthread_create(&tr[i], NULL, reader, &ids[i])))
135 errc(1, r, "create %d", i);
136 }
137
138 if ((r = pthread_create(&tw, NULL, writer, NULL)))
139 errc(1, r, "create writer");
140
141 pthread_mutex_lock(&m);
142 while (state != WRITE)
143 pthread_cond_wait(&c, &m);
144 state = WRITE_DONE;
145 pthread_mutex_unlock(&m);
146 pthread_cond_broadcast(&c);
147
148 pthread_join(tw, NULL);
149
150 for (i = 0; i < NUM_READERS; i++)
151 pthread_join(tr[i], NULL);
152 return 0;
153 }
154