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