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 |
31 | test_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 | |
43 | static void |
44 | test_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 | |
54 | static void |
55 | test_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 | |
68 | static void |
69 | test_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 | |
79 | static void |
80 | test_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 | |
94 | static void |
95 | test_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 | |
117 | GThread *owners[LOCKS]; |
118 | GRWLock locks[LOCKS]; |
119 | |
120 | static void |
121 | acquire (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 | |
149 | static gpointer |
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 (nr: g_rand_int_range (rand_: rand, begin: 0, LOCKS)); |
159 | |
160 | g_rand_free (rand_: rand); |
161 | |
162 | return NULL; |
163 | } |
164 | |
165 | static 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 (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 | |
187 | static gint even; |
188 | static GRWLock even_lock; |
189 | GThread *writers[2]; |
190 | GThread *readers[10]; |
191 | |
192 | static void |
193 | change_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 | |
211 | static void |
212 | verify_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 | |
221 | static gpointer |
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 |
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 |
250 | test_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 | |
274 | int |
275 | main (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 | |