This source file includes following definitions.
- random_account
- check_accounts
- lock_mutator_thread
- lock_checker_thread
- test_mtx_plain
- recshuffle
- reclock_mutator_thread
- reclock_checker_thread
- test_mtx_recursive
- once_execute
- once_contender_thread
- test_once
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20
21
22
23
24 #define ENABLE_LOCKING 1
25
26
27
28
29 #define DO_TEST_LOCK 1
30 #define DO_TEST_RECURSIVE_LOCK 1
31 #define DO_TEST_ONCE 1
32
33
34
35 #define EXPLICIT_YIELD 1
36
37
38 #define ENABLE_DEBUGGING 0
39
40
41 #define THREAD_COUNT 10
42
43
44
45
46 #define REPEAT_COUNT 50000
47
48 #include <threads.h>
49 #include <stdint.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include "glthread/lock.h"
55
56 #if HAVE_DECL_ALARM
57 # include <signal.h>
58 # include <unistd.h>
59 #endif
60
61 #include "macros.h"
62 #include "atomic-int-isoc.h"
63
64 #if ENABLE_DEBUGGING
65 # define dbgprintf printf
66 #else
67 # define dbgprintf if (0) printf
68 #endif
69
70 #if EXPLICIT_YIELD
71 # define yield() thrd_yield ()
72 #else
73 # define yield()
74 #endif
75
76
77 #if defined __MVS__
78
79
80
81 # define thrd_current_pointer() (*((void **) thrd_current ().__))
82 #elif defined __sun
83
84 # define thrd_current_pointer() ((void *) (uintptr_t) thrd_current ())
85 #else
86 # define thrd_current_pointer() ((void *) thrd_current ())
87 #endif
88
89 #define ACCOUNT_COUNT 4
90
91 static int account[ACCOUNT_COUNT];
92
93 static int
94 random_account (void)
95 {
96 return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
97 }
98
99 static void
100 check_accounts (void)
101 {
102 int i, sum;
103
104 sum = 0;
105 for (i = 0; i < ACCOUNT_COUNT; i++)
106 sum += account[i];
107 if (sum != ACCOUNT_COUNT * 1000)
108 abort ();
109 }
110
111
112
113
114
115
116
117
118 static mtx_t my_lock;
119
120 static int
121 lock_mutator_thread (void *arg)
122 {
123 int repeat;
124
125 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
126 {
127 int i1, i2, value;
128
129 dbgprintf ("Mutator %p before lock\n", thrd_current_pointer ());
130 ASSERT (mtx_lock (&my_lock) == thrd_success);
131 dbgprintf ("Mutator %p after lock\n", thrd_current_pointer ());
132
133 i1 = random_account ();
134 i2 = random_account ();
135 value = ((unsigned int) rand () >> 3) % 10;
136 account[i1] += value;
137 account[i2] -= value;
138
139 dbgprintf ("Mutator %p before unlock\n", thrd_current_pointer ());
140 ASSERT (mtx_unlock (&my_lock) == thrd_success);
141 dbgprintf ("Mutator %p after unlock\n", thrd_current_pointer ());
142
143 dbgprintf ("Mutator %p before check lock\n", thrd_current_pointer ());
144 ASSERT (mtx_lock (&my_lock) == thrd_success);
145 check_accounts ();
146 ASSERT (mtx_unlock (&my_lock) == thrd_success);
147 dbgprintf ("Mutator %p after check unlock\n", thrd_current_pointer ());
148
149 yield ();
150 }
151
152 dbgprintf ("Mutator %p dying.\n", thrd_current_pointer ());
153 return 0;
154 }
155
156 static struct atomic_int lock_checker_done;
157
158 static int
159 lock_checker_thread (void *arg)
160 {
161 while (get_atomic_int_value (&lock_checker_done) == 0)
162 {
163 dbgprintf ("Checker %p before check lock\n", thrd_current_pointer ());
164 ASSERT (mtx_lock (&my_lock) == thrd_success);
165 check_accounts ();
166 ASSERT (mtx_unlock (&my_lock) == thrd_success);
167 dbgprintf ("Checker %p after check unlock\n", thrd_current_pointer ());
168
169 yield ();
170 }
171
172 dbgprintf ("Checker %p dying.\n", thrd_current_pointer ());
173 return 0;
174 }
175
176 static void
177 test_mtx_plain (void)
178 {
179 int i;
180 thrd_t checkerthread;
181 thrd_t threads[THREAD_COUNT];
182
183
184 for (i = 0; i < ACCOUNT_COUNT; i++)
185 account[i] = 1000;
186 init_atomic_int (&lock_checker_done);
187 set_atomic_int_value (&lock_checker_done, 0);
188
189
190 ASSERT (thrd_create (&checkerthread, lock_checker_thread, NULL)
191 == thrd_success);
192 for (i = 0; i < THREAD_COUNT; i++)
193 ASSERT (thrd_create (&threads[i], lock_mutator_thread, NULL)
194 == thrd_success);
195
196
197 for (i = 0; i < THREAD_COUNT; i++)
198 ASSERT (thrd_join (threads[i], NULL) == thrd_success);
199 set_atomic_int_value (&lock_checker_done, 1);
200 ASSERT (thrd_join (checkerthread, NULL) == thrd_success);
201 check_accounts ();
202 }
203
204
205
206
207
208
209
210
211 static mtx_t my_reclock;
212
213 static void
214 recshuffle (void)
215 {
216 int i1, i2, value;
217
218 dbgprintf ("Mutator %p before lock\n", thrd_current_pointer ());
219 ASSERT (mtx_lock (&my_reclock) == thrd_success);
220 dbgprintf ("Mutator %p after lock\n", thrd_current_pointer ());
221
222 i1 = random_account ();
223 i2 = random_account ();
224 value = ((unsigned int) rand () >> 3) % 10;
225 account[i1] += value;
226 account[i2] -= value;
227
228
229 if (((unsigned int) rand () >> 3) % 2)
230 recshuffle ();
231
232 dbgprintf ("Mutator %p before unlock\n", thrd_current_pointer ());
233 ASSERT (mtx_unlock (&my_reclock) == thrd_success);
234 dbgprintf ("Mutator %p after unlock\n", thrd_current_pointer ());
235 }
236
237 static int
238 reclock_mutator_thread (void *arg)
239 {
240 int repeat;
241
242 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
243 {
244 recshuffle ();
245
246 dbgprintf ("Mutator %p before check lock\n", thrd_current_pointer ());
247 ASSERT (mtx_lock (&my_reclock) == thrd_success);
248 check_accounts ();
249 ASSERT (mtx_unlock (&my_reclock) == thrd_success);
250 dbgprintf ("Mutator %p after check unlock\n", thrd_current_pointer ());
251
252 yield ();
253 }
254
255 dbgprintf ("Mutator %p dying.\n", thrd_current_pointer ());
256 return 0;
257 }
258
259 static struct atomic_int reclock_checker_done;
260
261 static int
262 reclock_checker_thread (void *arg)
263 {
264 while (get_atomic_int_value (&reclock_checker_done) == 0)
265 {
266 dbgprintf ("Checker %p before check lock\n", thrd_current_pointer ());
267 ASSERT (mtx_lock (&my_reclock) == thrd_success);
268 check_accounts ();
269 ASSERT (mtx_unlock (&my_reclock) == thrd_success);
270 dbgprintf ("Checker %p after check unlock\n", thrd_current_pointer ());
271
272 yield ();
273 }
274
275 dbgprintf ("Checker %p dying.\n", thrd_current_pointer ());
276 return 0;
277 }
278
279 static void
280 test_mtx_recursive (void)
281 {
282 int i;
283 thrd_t checkerthread;
284 thrd_t threads[THREAD_COUNT];
285
286
287 for (i = 0; i < ACCOUNT_COUNT; i++)
288 account[i] = 1000;
289 init_atomic_int (&reclock_checker_done);
290 set_atomic_int_value (&reclock_checker_done, 0);
291
292
293 ASSERT (thrd_create (&checkerthread, reclock_checker_thread, NULL)
294 == thrd_success);
295 for (i = 0; i < THREAD_COUNT; i++)
296 ASSERT (thrd_create (&threads[i], reclock_mutator_thread, NULL)
297 == thrd_success);
298
299
300 for (i = 0; i < THREAD_COUNT; i++)
301 ASSERT (thrd_join (threads[i], NULL) == thrd_success);
302 set_atomic_int_value (&reclock_checker_done, 1);
303 ASSERT (thrd_join (checkerthread, NULL) == thrd_success);
304 check_accounts ();
305 }
306
307
308
309
310
311
312
313 static once_flag fresh_once = ONCE_FLAG_INIT;
314 static int ready[THREAD_COUNT];
315 static mtx_t ready_lock[THREAD_COUNT];
316 #if ENABLE_LOCKING
317 static gl_rwlock_t fire_signal[REPEAT_COUNT];
318 #else
319 static volatile int fire_signal_state;
320 #endif
321 static once_flag once_control;
322 static int performed;
323 static mtx_t performed_lock;
324
325 static void
326 once_execute (void)
327 {
328 ASSERT (mtx_lock (&performed_lock) == thrd_success);
329 performed++;
330 ASSERT (mtx_unlock (&performed_lock) == thrd_success);
331 }
332
333 static int
334 once_contender_thread (void *arg)
335 {
336 int id = (int) (intptr_t) arg;
337 int repeat;
338
339 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
340 {
341
342 ASSERT (mtx_lock (&ready_lock[id]) == thrd_success);
343 ready[id] = 1;
344 ASSERT (mtx_unlock (&ready_lock[id]) == thrd_success);
345
346 if (repeat == REPEAT_COUNT)
347 break;
348
349 dbgprintf ("Contender %p waiting for signal for round %d\n",
350 thrd_current_pointer (), repeat);
351 #if ENABLE_LOCKING
352
353 gl_rwlock_rdlock (fire_signal[repeat]);
354
355 gl_rwlock_unlock (fire_signal[repeat]);
356 #else
357
358 while (fire_signal_state <= repeat)
359 yield ();
360 #endif
361 dbgprintf ("Contender %p got the signal for round %d\n",
362 thrd_current_pointer (), repeat);
363
364
365 call_once (&once_control, once_execute);
366 }
367
368 return 0;
369 }
370
371 static void
372 test_once (void)
373 {
374 int i, repeat;
375 thrd_t threads[THREAD_COUNT];
376
377
378 for (i = 0; i < THREAD_COUNT; i++)
379 {
380 ready[i] = 0;
381 ASSERT (mtx_init (&ready_lock[i], mtx_plain) == thrd_success);
382 }
383 #if ENABLE_LOCKING
384 for (i = 0; i < REPEAT_COUNT; i++)
385 gl_rwlock_init (fire_signal[i]);
386 #else
387 fire_signal_state = 0;
388 #endif
389
390 #if ENABLE_LOCKING
391
392 for (i = REPEAT_COUNT-1; i >= 0; i--)
393 gl_rwlock_wrlock (fire_signal[i]);
394 #endif
395
396
397 for (i = 0; i < THREAD_COUNT; i++)
398 ASSERT (thrd_create (&threads[i],
399 once_contender_thread, (void *) (intptr_t) i)
400 == thrd_success);
401
402 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
403 {
404
405 dbgprintf ("Main thread before synchronizing for round %d\n", repeat);
406 for (;;)
407 {
408 int ready_count = 0;
409 for (i = 0; i < THREAD_COUNT; i++)
410 {
411 ASSERT (mtx_lock (&ready_lock[i]) == thrd_success);
412 ready_count += ready[i];
413 ASSERT (mtx_unlock (&ready_lock[i]) == thrd_success);
414 }
415 if (ready_count == THREAD_COUNT)
416 break;
417 yield ();
418 }
419 dbgprintf ("Main thread after synchronizing for round %d\n", repeat);
420
421 if (repeat > 0)
422 {
423
424
425 if (performed != 1)
426 abort ();
427 }
428
429 if (repeat == REPEAT_COUNT)
430 break;
431
432
433 memcpy (&once_control, &fresh_once, sizeof (once_flag));
434
435
436 performed = 0;
437
438
439 for (i = 0; i < THREAD_COUNT; i++)
440 {
441 ASSERT (mtx_lock (&ready_lock[i]) == thrd_success);
442 ready[i] = 0;
443 ASSERT (mtx_unlock (&ready_lock[i]) == thrd_success);
444 }
445
446
447 dbgprintf ("Main thread giving signal for round %d\n", repeat);
448 #if ENABLE_LOCKING
449 gl_rwlock_unlock (fire_signal[repeat]);
450 #else
451 fire_signal_state = repeat + 1;
452 #endif
453 }
454
455
456 for (i = 0; i < THREAD_COUNT; i++)
457 ASSERT (thrd_join (threads[i], NULL) == thrd_success);
458 }
459
460
461
462
463 int
464 main ()
465 {
466 #if HAVE_DECL_ALARM
467
468
469 int alarm_value = 600;
470 signal (SIGALRM, SIG_DFL);
471 alarm (alarm_value);
472 #endif
473
474 ASSERT (mtx_init (&my_lock, mtx_plain) == thrd_success);
475 ASSERT (mtx_init (&my_reclock, mtx_plain | mtx_recursive) == thrd_success);
476 ASSERT (mtx_init (&performed_lock, mtx_plain) == thrd_success);
477
478 #if DO_TEST_LOCK
479 printf ("Starting test_mtx_plain ..."); fflush (stdout);
480 test_mtx_plain ();
481 printf (" OK\n"); fflush (stdout);
482 #endif
483 #if DO_TEST_RECURSIVE_LOCK
484 printf ("Starting test_mtx_recursive ..."); fflush (stdout);
485 test_mtx_recursive ();
486 printf (" OK\n"); fflush (stdout);
487 #endif
488 #if DO_TEST_ONCE
489 printf ("Starting test_once ..."); fflush (stdout);
490 test_once ();
491 printf (" OK\n"); fflush (stdout);
492 #endif
493
494 return 0;
495 }