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
30 static void
test_rwlock1(void)31 test_rwlock1 (void)
32 {
33 GRWLock lock;
34
35 g_rw_lock_init (&lock);
36 g_rw_lock_writer_lock (&lock);
37 g_rw_lock_writer_unlock (&lock);
38 g_rw_lock_writer_lock (&lock);
39 g_rw_lock_writer_unlock (&lock);
40 g_rw_lock_clear (&lock);
41 }
42
43 static void
test_rwlock2(void)44 test_rwlock2 (void)
45 {
46 static GRWLock lock;
47
48 g_rw_lock_writer_lock (&lock);
49 g_rw_lock_writer_unlock (&lock);
50 g_rw_lock_writer_lock (&lock);
51 g_rw_lock_writer_unlock (&lock);
52 }
53
54 static void
test_rwlock3(void)55 test_rwlock3 (void)
56 {
57 static GRWLock lock;
58 gboolean ret;
59
60 ret = g_rw_lock_writer_trylock (&lock);
61 g_assert (ret);
62 ret = g_rw_lock_writer_trylock (&lock);
63 g_assert (!ret);
64
65 g_rw_lock_writer_unlock (&lock);
66 }
67
68 static void
test_rwlock4(void)69 test_rwlock4 (void)
70 {
71 static GRWLock lock;
72
73 g_rw_lock_reader_lock (&lock);
74 g_rw_lock_reader_unlock (&lock);
75 g_rw_lock_reader_lock (&lock);
76 g_rw_lock_reader_unlock (&lock);
77 }
78
79 static void
test_rwlock5(void)80 test_rwlock5 (void)
81 {
82 static GRWLock lock;
83 gboolean ret;
84
85 ret = g_rw_lock_reader_trylock (&lock);
86 g_assert (ret);
87 ret = g_rw_lock_reader_trylock (&lock);
88 g_assert (ret);
89
90 g_rw_lock_reader_unlock (&lock);
91 g_rw_lock_reader_unlock (&lock);
92 }
93
94 static void
test_rwlock6(void)95 test_rwlock6 (void)
96 {
97 static GRWLock lock;
98 gboolean ret;
99
100 g_rw_lock_writer_lock (&lock);
101 ret = g_rw_lock_reader_trylock (&lock);
102 g_assert (!ret);
103 g_rw_lock_writer_unlock (&lock);
104
105 g_rw_lock_reader_lock (&lock);
106 ret = g_rw_lock_writer_trylock (&lock);
107 g_assert (!ret);
108 g_rw_lock_reader_unlock (&lock);
109 }
110
111
112 #define LOCKS 48
113 #define ITERATIONS 10000
114 #define THREADS 100
115
116
117 GThread *owners[LOCKS];
118 GRWLock locks[LOCKS];
119
120 static void
acquire(gint nr)121 acquire (gint nr)
122 {
123 GThread *self;
124
125 self = g_thread_self ();
126
127 if (!g_rw_lock_writer_trylock (&locks[nr]))
128 {
129 if (g_test_verbose ())
130 g_printerr ("thread %p going to block on lock %d\n", self, nr);
131
132 g_rw_lock_writer_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 (&locks[nr]);
147 }
148
149 static gpointer
thread_func(gpointer data)150 thread_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 (g_rand_int_range (rand, 0, LOCKS));
159
160 g_rand_free (rand);
161
162 return NULL;
163 }
164
165 static void
test_rwlock7(void)166 test_rwlock7 (void)
167 {
168 gint i;
169 GThread *threads[THREADS];
170
171 for (i = 0; i < LOCKS; i++)
172 g_rw_lock_init (&locks[i]);
173
174 for (i = 0; i < THREADS; i++)
175 threads[i] = g_thread_new ("test", thread_func, NULL);
176
177 for (i = 0; i < THREADS; i++)
178 g_thread_join (threads[i]);
179
180 for (i = 0; i < LOCKS; i++)
181 g_rw_lock_clear (&locks[i]);
182
183 for (i = 0; i < LOCKS; i++)
184 g_assert (owners[i] == NULL);
185 }
186
187 static gint even;
188 static GRWLock even_lock;
189 GThread *writers[2];
190 GThread *readers[10];
191
192 static void
change_even(gpointer data)193 change_even (gpointer data)
194 {
195 g_rw_lock_writer_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 (&even_lock);
209 }
210
211 static void
verify_even(gpointer data)212 verify_even (gpointer data)
213 {
214 g_rw_lock_reader_lock (&even_lock);
215
216 g_assert (even % 2 == 0);
217
218 g_rw_lock_reader_unlock (&even_lock);
219 }
220
221 static gpointer
writer_func(gpointer data)222 writer_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
232 static gpointer
reader_func(gpointer data)233 reader_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 */
249 static void
test_rwlock8(void)250 test_rwlock8 (void)
251 {
252 gint i;
253
254 even = 0;
255 g_rw_lock_init (&even_lock);
256
257 for (i = 0; i < 2; i++)
258 writers[i] = g_thread_new ("a", writer_func, GINT_TO_POINTER (i));
259
260 for (i = 0; i < 10; i++)
261 readers[i] = g_thread_new ("b", reader_func, NULL);
262
263 for (i = 0; i < 2; i++)
264 g_thread_join (writers[i]);
265
266 for (i = 0; i < 10; i++)
267 g_thread_join (readers[i]);
268
269 g_assert (even % 2 == 0);
270
271 g_rw_lock_clear (&even_lock);
272 }
273
274 int
main(int argc,char * argv[])275 main (int argc, char *argv[])
276 {
277 g_test_init (&argc, &argv, NULL);
278
279 g_test_add_func ("/thread/rwlock1", test_rwlock1);
280 g_test_add_func ("/thread/rwlock2", test_rwlock2);
281 g_test_add_func ("/thread/rwlock3", test_rwlock3);
282 g_test_add_func ("/thread/rwlock4", test_rwlock4);
283 g_test_add_func ("/thread/rwlock5", test_rwlock5);
284 g_test_add_func ("/thread/rwlock6", test_rwlock6);
285 g_test_add_func ("/thread/rwlock7", test_rwlock7);
286 g_test_add_func ("/thread/rwlock8", test_rwlock8);
287
288 return g_test_run ();
289 }
290