1/* Unit tests for GRWLock
2 * Copyright (C) 2011 Red Hat, Inc
3 * Author: Matthias Clasen
4 *
5 * This work is provided "as is"; redistribution and modification
6 * in whole or in part, in any medium, physical or electronic is
7 * permitted without restriction.
8 *
9 * This work is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * In no event shall the authors or contributors be liable for any
14 * direct, indirect, incidental, special, exemplary, or consequential
15 * damages (including, but not limited to, procurement of substitute
16 * goods or services; loss of use, data, or profits; or business
17 * interruption) however caused and on any theory of liability, whether
18 * in contract, strict liability, or tort (including negligence or
19 * otherwise) arising in any way out of the use of this software, even
20 * if advised of the possibility of such damage.
21 */
22
23/* We are testing some deprecated APIs here */
24#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
25#define GLIB_DISABLE_DEPRECATION_WARNINGS
26#endif
27
28#include <glib.h>
29
30static void
31test_rwlock1 (void)
32{
33 GRWLock lock;
34
35 g_rw_lock_init (rw_lock: &lock);
36 g_rw_lock_writer_lock (rw_lock: &lock);
37 g_rw_lock_writer_unlock (rw_lock: &lock);
38 g_rw_lock_writer_lock (rw_lock: &lock);
39 g_rw_lock_writer_unlock (rw_lock: &lock);
40 g_rw_lock_clear (rw_lock: &lock);
41}
42
43static void
44test_rwlock2 (void)
45{
46 static GRWLock lock;
47
48 g_rw_lock_writer_lock (rw_lock: &lock);
49 g_rw_lock_writer_unlock (rw_lock: &lock);
50 g_rw_lock_writer_lock (rw_lock: &lock);
51 g_rw_lock_writer_unlock (rw_lock: &lock);
52}
53
54static void
55test_rwlock3 (void)
56{
57 static GRWLock lock;
58 gboolean ret;
59
60 ret = g_rw_lock_writer_trylock (rw_lock: &lock);
61 g_assert (ret);
62 ret = g_rw_lock_writer_trylock (rw_lock: &lock);
63 g_assert (!ret);
64
65 g_rw_lock_writer_unlock (rw_lock: &lock);
66}
67
68static void
69test_rwlock4 (void)
70{
71 static GRWLock lock;
72
73 g_rw_lock_reader_lock (rw_lock: &lock);
74 g_rw_lock_reader_unlock (rw_lock: &lock);
75 g_rw_lock_reader_lock (rw_lock: &lock);
76 g_rw_lock_reader_unlock (rw_lock: &lock);
77}
78
79static void
80test_rwlock5 (void)
81{
82 static GRWLock lock;
83 gboolean ret;
84
85 ret = g_rw_lock_reader_trylock (rw_lock: &lock);
86 g_assert (ret);
87 ret = g_rw_lock_reader_trylock (rw_lock: &lock);
88 g_assert (ret);
89
90 g_rw_lock_reader_unlock (rw_lock: &lock);
91 g_rw_lock_reader_unlock (rw_lock: &lock);
92}
93
94static void
95test_rwlock6 (void)
96{
97 static GRWLock lock;
98 gboolean ret;
99
100 g_rw_lock_writer_lock (rw_lock: &lock);
101 ret = g_rw_lock_reader_trylock (rw_lock: &lock);
102 g_assert (!ret);
103 g_rw_lock_writer_unlock (rw_lock: &lock);
104
105 g_rw_lock_reader_lock (rw_lock: &lock);
106 ret = g_rw_lock_writer_trylock (rw_lock: &lock);
107 g_assert (!ret);
108 g_rw_lock_reader_unlock (rw_lock: &lock);
109}
110
111
112#define LOCKS 48
113#define ITERATIONS 10000
114#define THREADS 100
115
116
117GThread *owners[LOCKS];
118GRWLock locks[LOCKS];
119
120static void
121acquire (gint nr)
122{
123 GThread *self;
124
125 self = g_thread_self ();
126
127 if (!g_rw_lock_writer_trylock (rw_lock: &locks[nr]))
128 {
129 if (g_test_verbose ())
130 g_printerr (format: "thread %p going to block on lock %d\n", self, nr);
131
132 g_rw_lock_writer_lock (rw_lock: &locks[nr]);
133 }
134
135 g_assert (owners[nr] == NULL); /* hopefully nobody else is here */
136 owners[nr] = self;
137
138 /* let some other threads try to ruin our day */
139 g_thread_yield ();
140 g_thread_yield ();
141 g_thread_yield ();
142
143 g_assert (owners[nr] == self); /* hopefully this is still us... */
144 owners[nr] = NULL; /* make way for the next guy */
145
146 g_rw_lock_writer_unlock (rw_lock: &locks[nr]);
147}
148
149static gpointer
150thread_func (gpointer data)
151{
152 gint i;
153 GRand *rand;
154
155 rand = g_rand_new ();
156
157 for (i = 0; i < ITERATIONS; i++)
158 acquire (nr: g_rand_int_range (rand_: rand, begin: 0, LOCKS));
159
160 g_rand_free (rand_: rand);
161
162 return NULL;
163}
164
165static void
166test_rwlock7 (void)
167{
168 gint i;
169 GThread *threads[THREADS];
170
171 for (i = 0; i < LOCKS; i++)
172 g_rw_lock_init (rw_lock: &locks[i]);
173
174 for (i = 0; i < THREADS; i++)
175 threads[i] = g_thread_new (name: "test", func: thread_func, NULL);
176
177 for (i = 0; i < THREADS; i++)
178 g_thread_join (thread: threads[i]);
179
180 for (i = 0; i < LOCKS; i++)
181 g_rw_lock_clear (rw_lock: &locks[i]);
182
183 for (i = 0; i < LOCKS; i++)
184 g_assert (owners[i] == NULL);
185}
186
187static gint even;
188static GRWLock even_lock;
189GThread *writers[2];
190GThread *readers[10];
191
192static void
193change_even (gpointer data)
194{
195 g_rw_lock_writer_lock (rw_lock: &even_lock);
196
197 g_assert (even % 2 == 0);
198
199 even += 1;
200
201 if (GPOINTER_TO_INT (data) == 0)
202 even += 1;
203 else
204 even -= 1;
205
206 g_assert (even % 2 == 0);
207
208 g_rw_lock_writer_unlock (rw_lock: &even_lock);
209}
210
211static void
212verify_even (gpointer data)
213{
214 g_rw_lock_reader_lock (rw_lock: &even_lock);
215
216 g_assert (even % 2 == 0);
217
218 g_rw_lock_reader_unlock (rw_lock: &even_lock);
219}
220
221static gpointer
222writer_func (gpointer data)
223{
224 gint i;
225
226 for (i = 0; i < 100000; i++)
227 change_even (data);
228
229 return NULL;
230}
231
232static gpointer
233reader_func (gpointer data)
234{
235 gint i;
236
237 for (i = 0; i < 100000; i++)
238 verify_even (data);
239
240 return NULL;
241}
242
243/* This test has 2 writers and 10 readers.
244 * The writers modify an integer multiple times,
245 * but always leave it with an even value.
246 * The readers verify that they can only observe
247 * even values
248 */
249static void
250test_rwlock8 (void)
251{
252 gint i;
253
254 even = 0;
255 g_rw_lock_init (rw_lock: &even_lock);
256
257 for (i = 0; i < 2; i++)
258 writers[i] = g_thread_new (name: "a", func: writer_func, GINT_TO_POINTER (i));
259
260 for (i = 0; i < 10; i++)
261 readers[i] = g_thread_new (name: "b", func: reader_func, NULL);
262
263 for (i = 0; i < 2; i++)
264 g_thread_join (thread: writers[i]);
265
266 for (i = 0; i < 10; i++)
267 g_thread_join (thread: readers[i]);
268
269 g_assert (even % 2 == 0);
270
271 g_rw_lock_clear (rw_lock: &even_lock);
272}
273
274int
275main (int argc, char *argv[])
276{
277 g_test_init (argc: &argc, argv: &argv, NULL);
278
279 g_test_add_func (testpath: "/thread/rwlock1", test_func: test_rwlock1);
280 g_test_add_func (testpath: "/thread/rwlock2", test_func: test_rwlock2);
281 g_test_add_func (testpath: "/thread/rwlock3", test_func: test_rwlock3);
282 g_test_add_func (testpath: "/thread/rwlock4", test_func: test_rwlock4);
283 g_test_add_func (testpath: "/thread/rwlock5", test_func: test_rwlock5);
284 g_test_add_func (testpath: "/thread/rwlock6", test_func: test_rwlock6);
285 g_test_add_func (testpath: "/thread/rwlock7", test_func: test_rwlock7);
286 g_test_add_func (testpath: "/thread/rwlock8", test_func: test_rwlock8);
287
288 return g_test_run ();
289}
290

source code of gtk/subprojects/glib/glib/tests/rwlock.c