1 /* Test of locking in multithreaded situations.
2 Copyright (C) 2005, 2008 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program 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. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2005. */
21 #if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WIN32_THREADS
24 # define TEST_POSIX_THREADS 1
26 #if USE_SOLARIS_THREADS
27 # define TEST_SOLARIS_THREADS 1
30 # define TEST_PTH_THREADS 1
33 # define TEST_WIN32_THREADS 1
36 /* Whether to enable locking.
37 Uncomment this to get a test program without locking, to verify that
39 #define ENABLE_LOCKING 1
41 /* Which tests to perform.
42 Uncomment some of these, to verify that all tests crash if no locking
44 #define DO_TEST_LOCK 1
45 #define DO_TEST_RWLOCK 1
46 #define DO_TEST_RECURSIVE_LOCK 1
47 #define DO_TEST_ONCE 1
49 /* Whether to help the scheduler through explicit yield().
50 Uncomment this to see if the operating system has a fair scheduler. */
51 #define EXPLICIT_YIELD 1
53 /* Whether to print debugging messages. */
54 #define ENABLE_DEBUGGING 0
56 /* Number of simultaneous threads. */
57 #define THREAD_COUNT 10
59 /* Number of operations performed in each thread.
60 This is quite high, because with a smaller count, say 5000, we often get
61 an "OK" result even without ENABLE_LOCKING (on Linux/x86). */
62 #define REPEAT_COUNT 50000
69 # undef USE_POSIX_THREADS
70 # undef USE_SOLARIS_THREADS
71 # undef USE_PTH_THREADS
72 # undef USE_WIN32_THREADS
74 #include "glthread/lock.h"
77 # if TEST_POSIX_THREADS
78 # define USE_POSIX_THREADS 1
80 # if TEST_SOLARIS_THREADS
81 # define USE_SOLARIS_THREADS 1
84 # define USE_PTH_THREADS 1
86 # if TEST_WIN32_THREADS
87 # define USE_WIN32_THREADS 1
91 #include "glthread/thread.h"
92 #include "glthread/yield.h"
95 # define dbgprintf printf
97 # define dbgprintf if (0) printf
101 # define yield() gl_thread_yield ()
106 #define ACCOUNT_COUNT 4
108 static int account[ACCOUNT_COUNT];
111 random_account (void)
113 return ((unsigned int) rand() >> 3) % ACCOUNT_COUNT;
117 check_accounts (void)
122 for (i = 0; i < ACCOUNT_COUNT; i++)
124 if (sum != ACCOUNT_COUNT * 1000)
128 /* Test normal locks by having several bank accounts and several threads
129 which shuffle around money between the accounts and another thread
130 checking that all the money is still there. */
132 gl_lock_define_initialized(static, my_lock)
135 lock_mutator_thread (void *arg)
139 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
143 dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
144 gl_lock_lock (my_lock);
145 dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
147 i1 = random_account ();
148 i2 = random_account ();
149 value = ((unsigned int) rand() >> 3) % 10;
150 account[i1] += value;
151 account[i2] -= value;
153 dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
154 gl_lock_unlock (my_lock);
155 dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
157 dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
158 gl_lock_lock (my_lock);
160 gl_lock_unlock (my_lock);
161 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
166 dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
170 static volatile int lock_checker_done;
173 lock_checker_thread (void *arg)
175 while (!lock_checker_done)
177 dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
178 gl_lock_lock (my_lock);
180 gl_lock_unlock (my_lock);
181 dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
186 dbgprintf ("Checker %p dying.\n", gl_thread_self ());
194 gl_thread_t checkerthread;
195 gl_thread_t threads[THREAD_COUNT];
197 /* Initialization. */
198 for (i = 0; i < ACCOUNT_COUNT; i++)
200 lock_checker_done = 0;
202 /* Spawn the threads. */
203 checkerthread = gl_thread_create (lock_checker_thread, NULL);
204 for (i = 0; i < THREAD_COUNT; i++)
205 threads[i] = gl_thread_create (lock_mutator_thread, NULL);
207 /* Wait for the threads to terminate. */
208 for (i = 0; i < THREAD_COUNT; i++)
209 gl_thread_join (threads[i], NULL);
210 lock_checker_done = 1;
211 gl_thread_join (checkerthread, NULL);
215 /* Test read-write locks by having several bank accounts and several threads
216 which shuffle around money between the accounts and several other threads
217 that check that all the money is still there. */
219 gl_rwlock_define_initialized(static, my_rwlock)
222 rwlock_mutator_thread (void *arg)
226 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
230 dbgprintf ("Mutator %p before wrlock\n", gl_thread_self ());
231 gl_rwlock_wrlock (my_rwlock);
232 dbgprintf ("Mutator %p after wrlock\n", gl_thread_self ());
234 i1 = random_account ();
235 i2 = random_account ();
236 value = ((unsigned int) rand() >> 3) % 10;
237 account[i1] += value;
238 account[i2] -= value;
240 dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
241 gl_rwlock_unlock (my_rwlock);
242 dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
247 dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
251 static volatile int rwlock_checker_done;
254 rwlock_checker_thread (void *arg)
256 while (!rwlock_checker_done)
258 dbgprintf ("Checker %p before check rdlock\n", gl_thread_self ());
259 gl_rwlock_rdlock (my_rwlock);
261 gl_rwlock_unlock (my_rwlock);
262 dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
267 dbgprintf ("Checker %p dying.\n", gl_thread_self ());
275 gl_thread_t checkerthreads[THREAD_COUNT];
276 gl_thread_t threads[THREAD_COUNT];
278 /* Initialization. */
279 for (i = 0; i < ACCOUNT_COUNT; i++)
281 rwlock_checker_done = 0;
283 /* Spawn the threads. */
284 for (i = 0; i < THREAD_COUNT; i++)
285 checkerthreads[i] = gl_thread_create (rwlock_checker_thread, NULL);
286 for (i = 0; i < THREAD_COUNT; i++)
287 threads[i] = gl_thread_create (rwlock_mutator_thread, NULL);
289 /* Wait for the threads to terminate. */
290 for (i = 0; i < THREAD_COUNT; i++)
291 gl_thread_join (threads[i], NULL);
292 rwlock_checker_done = 1;
293 for (i = 0; i < THREAD_COUNT; i++)
294 gl_thread_join (checkerthreads[i], NULL);
298 /* Test recursive locks by having several bank accounts and several threads
299 which shuffle around money between the accounts (recursively) and another
300 thread checking that all the money is still there. */
302 gl_recursive_lock_define_initialized(static, my_reclock)
309 dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
310 gl_recursive_lock_lock (my_reclock);
311 dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
313 i1 = random_account ();
314 i2 = random_account ();
315 value = ((unsigned int) rand() >> 3) % 10;
316 account[i1] += value;
317 account[i2] -= value;
319 /* Recursive with probability 0.5. */
320 if (((unsigned int) rand() >> 3) % 2)
323 dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
324 gl_recursive_lock_unlock (my_reclock);
325 dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
329 reclock_mutator_thread (void *arg)
333 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
337 dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
338 gl_recursive_lock_lock (my_reclock);
340 gl_recursive_lock_unlock (my_reclock);
341 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
346 dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
350 static volatile int reclock_checker_done;
353 reclock_checker_thread (void *arg)
355 while (!reclock_checker_done)
357 dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
358 gl_recursive_lock_lock (my_reclock);
360 gl_recursive_lock_unlock (my_reclock);
361 dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
366 dbgprintf ("Checker %p dying.\n", gl_thread_self ());
371 test_recursive_lock (void)
374 gl_thread_t checkerthread;
375 gl_thread_t threads[THREAD_COUNT];
377 /* Initialization. */
378 for (i = 0; i < ACCOUNT_COUNT; i++)
380 reclock_checker_done = 0;
382 /* Spawn the threads. */
383 checkerthread = gl_thread_create (reclock_checker_thread, NULL);
384 for (i = 0; i < THREAD_COUNT; i++)
385 threads[i] = gl_thread_create (reclock_mutator_thread, NULL);
387 /* Wait for the threads to terminate. */
388 for (i = 0; i < THREAD_COUNT; i++)
389 gl_thread_join (threads[i], NULL);
390 reclock_checker_done = 1;
391 gl_thread_join (checkerthread, NULL);
395 /* Test once-only execution by having several threads attempt to grab a
396 once-only task simultaneously (triggered by releasing a read-write lock). */
398 gl_once_define(static, fresh_once)
399 static int ready[THREAD_COUNT];
400 static gl_lock_t ready_lock[THREAD_COUNT];
402 static gl_rwlock_t fire_signal[REPEAT_COUNT];
404 static volatile int fire_signal_state;
406 static gl_once_t once_control;
407 static int performed;
408 gl_lock_define_initialized(static, performed_lock)
413 gl_lock_lock (performed_lock);
415 gl_lock_unlock (performed_lock);
419 once_contender_thread (void *arg)
421 int id = (int) (long) arg;
424 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
426 /* Tell the main thread that we're ready. */
427 gl_lock_lock (ready_lock[id]);
429 gl_lock_unlock (ready_lock[id]);
431 if (repeat == REPEAT_COUNT)
434 dbgprintf ("Contender %p waiting for signal for round %d\n",
435 gl_thread_self (), repeat);
437 /* Wait for the signal to go. */
438 gl_rwlock_rdlock (fire_signal[repeat]);
439 /* And don't hinder the others (if the scheduler is unfair). */
440 gl_rwlock_unlock (fire_signal[repeat]);
442 /* Wait for the signal to go. */
443 while (fire_signal_state <= repeat)
446 dbgprintf ("Contender %p got the signal for round %d\n",
447 gl_thread_self (), repeat);
449 /* Contend for execution. */
450 gl_once (once_control, once_execute);
460 gl_thread_t threads[THREAD_COUNT];
462 /* Initialize all variables. */
463 for (i = 0; i < THREAD_COUNT; i++)
466 gl_lock_init (ready_lock[i]);
469 for (i = 0; i < REPEAT_COUNT; i++)
470 gl_rwlock_init (fire_signal[i]);
472 fire_signal_state = 0;
475 /* Block all fire_signals. */
476 for (i = REPEAT_COUNT-1; i >= 0; i--)
477 gl_rwlock_wrlock (fire_signal[i]);
479 /* Spawn the threads. */
480 for (i = 0; i < THREAD_COUNT; i++)
481 threads[i] = gl_thread_create (once_contender_thread, (void *) (long) i);
483 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
485 /* Wait until every thread is ready. */
486 dbgprintf ("Main thread before synchonizing for round %d\n", repeat);
490 for (i = 0; i < THREAD_COUNT; i++)
492 gl_lock_lock (ready_lock[i]);
493 ready_count += ready[i];
494 gl_lock_unlock (ready_lock[i]);
496 if (ready_count == THREAD_COUNT)
500 dbgprintf ("Main thread after synchonizing for round %d\n", repeat);
504 /* Check that exactly one thread executed the once_execute()
510 if (repeat == REPEAT_COUNT)
513 /* Preparation for the next round: Initialize once_control. */
514 memcpy (&once_control, &fresh_once, sizeof (gl_once_t));
516 /* Preparation for the next round: Reset the performed counter. */
519 /* Preparation for the next round: Reset the ready flags. */
520 for (i = 0; i < THREAD_COUNT; i++)
522 gl_lock_lock (ready_lock[i]);
524 gl_lock_unlock (ready_lock[i]);
527 /* Signal all threads simultaneously. */
528 dbgprintf ("Main thread giving signal for round %d\n", repeat);
530 gl_rwlock_unlock (fire_signal[repeat]);
532 fire_signal_state = repeat + 1;
536 /* Wait for the threads to terminate. */
537 for (i = 0; i < THREAD_COUNT; i++)
538 gl_thread_join (threads[i], NULL);
550 printf ("Starting test_lock ..."); fflush (stdout);
552 printf (" OK\n"); fflush (stdout);
555 printf ("Starting test_rwlock ..."); fflush (stdout);
557 printf (" OK\n"); fflush (stdout);
559 #if DO_TEST_RECURSIVE_LOCK
560 printf ("Starting test_recursive_lock ..."); fflush (stdout);
561 test_recursive_lock ();
562 printf (" OK\n"); fflush (stdout);
565 printf ("Starting test_once ..."); fflush (stdout);
567 printf (" OK\n"); fflush (stdout);
575 /* No multithreading available. */
582 fputs ("Skipping test: multithreading not enabled\n", stderr);