1 /* Test of locking in multithreaded situations.
2 Copyright (C) 2005, 2008-2012 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 Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser 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_WINDOWS_THREADS
24 # define TEST_POSIX_THREADS 1
26 #if USE_SOLARIS_THREADS
27 # define TEST_SOLARIS_THREADS 1
30 # define TEST_PTH_THREADS 1
32 #if USE_WINDOWS_THREADS
33 # define TEST_WINDOWS_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_WINDOWS_THREADS
77 # define dbgprintf printf
79 # define dbgprintf if (0) printf
82 #if TEST_POSIX_THREADS
85 typedef pthread_t gl_thread_t;
86 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
89 if (pthread_create (&thread, NULL, func, arg) != 0)
93 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
95 if (pthread_join (thread, retvalp) != 0)
98 static inline void gl_thread_yield (void)
102 static inline void * gl_thread_self_pointer (void)
104 # ifdef PTW32_VERSION
105 return pthread_self ().p;
107 return (void *) pthread_self ();
113 typedef pth_t gl_thread_t;
114 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
116 pth_t thread = pth_spawn (NULL, func, arg);
121 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
123 if (!pth_join (thread, retvalp))
126 static inline void gl_thread_yield (void)
130 static inline void * gl_thread_self_pointer (void)
135 #if TEST_SOLARIS_THREADS
137 typedef thread_t gl_thread_t;
138 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
141 if (thr_create (NULL, 0, func, arg, 0, &thread) != 0)
145 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
147 if (thr_join (thread, NULL, retvalp) != 0)
150 static inline void gl_thread_yield (void)
154 static inline void * gl_thread_self_pointer (void)
156 return (void *) thr_self ();
159 #if TEST_WINDOWS_THREADS
160 # include <windows.h>
161 typedef HANDLE gl_thread_t;
162 /* Use a wrapper function, instead of adding WINAPI through a cast. */
163 struct wrapper_args { void * (*func) (void *); void *arg; };
164 static DWORD WINAPI wrapper_func (void *varg)
166 struct wrapper_args *warg = (struct wrapper_args *)varg;
167 void * (*func) (void *) = warg->func;
168 void *arg = warg->arg;
173 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
175 struct wrapper_args *warg =
176 (struct wrapper_args *) malloc (sizeof (struct wrapper_args));
184 CreateThread (NULL, 100000, wrapper_func, warg, 0, &thread_id);
190 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
193 if (WaitForSingleObject (thread, INFINITE) == WAIT_FAILED)
195 if (!CloseHandle (thread))
198 static inline void gl_thread_yield (void)
202 static inline void * gl_thread_self_pointer (void)
204 return (void *) GetCurrentThreadId ();
208 # define yield() gl_thread_yield ()
213 #define ACCOUNT_COUNT 4
215 static int account[ACCOUNT_COUNT];
218 random_account (void)
220 return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
224 check_accounts (void)
229 for (i = 0; i < ACCOUNT_COUNT; i++)
231 if (sum != ACCOUNT_COUNT * 1000)
236 /* ------------------- Test normal (non-recursive) locks ------------------- */
238 /* Test normal locks by having several bank accounts and several threads
239 which shuffle around money between the accounts and another thread
240 checking that all the money is still there. */
242 gl_lock_define_initialized(static, my_lock)
245 lock_mutator_thread (void *arg)
249 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
253 dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
254 gl_lock_lock (my_lock);
255 dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
257 i1 = random_account ();
258 i2 = random_account ();
259 value = ((unsigned int) rand () >> 3) % 10;
260 account[i1] += value;
261 account[i2] -= value;
263 dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
264 gl_lock_unlock (my_lock);
265 dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
267 dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
268 gl_lock_lock (my_lock);
270 gl_lock_unlock (my_lock);
271 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
276 dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
280 static volatile int lock_checker_done;
283 lock_checker_thread (void *arg)
285 while (!lock_checker_done)
287 dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
288 gl_lock_lock (my_lock);
290 gl_lock_unlock (my_lock);
291 dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
296 dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
304 gl_thread_t checkerthread;
305 gl_thread_t threads[THREAD_COUNT];
307 /* Initialization. */
308 for (i = 0; i < ACCOUNT_COUNT; i++)
310 lock_checker_done = 0;
312 /* Spawn the threads. */
313 checkerthread = gl_thread_create (lock_checker_thread, NULL);
314 for (i = 0; i < THREAD_COUNT; i++)
315 threads[i] = gl_thread_create (lock_mutator_thread, NULL);
317 /* Wait for the threads to terminate. */
318 for (i = 0; i < THREAD_COUNT; i++)
319 gl_thread_join (threads[i], NULL);
320 lock_checker_done = 1;
321 gl_thread_join (checkerthread, NULL);
326 /* ----------------- Test read-write (non-recursive) locks ----------------- */
328 /* Test read-write locks by having several bank accounts and several threads
329 which shuffle around money between the accounts and several other threads
330 that check that all the money is still there. */
332 gl_rwlock_define_initialized(static, my_rwlock)
335 rwlock_mutator_thread (void *arg)
339 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
343 dbgprintf ("Mutator %p before wrlock\n", gl_thread_self_pointer ());
344 gl_rwlock_wrlock (my_rwlock);
345 dbgprintf ("Mutator %p after wrlock\n", gl_thread_self_pointer ());
347 i1 = random_account ();
348 i2 = random_account ();
349 value = ((unsigned int) rand () >> 3) % 10;
350 account[i1] += value;
351 account[i2] -= value;
353 dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
354 gl_rwlock_unlock (my_rwlock);
355 dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
360 dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
364 static volatile int rwlock_checker_done;
367 rwlock_checker_thread (void *arg)
369 while (!rwlock_checker_done)
371 dbgprintf ("Checker %p before check rdlock\n", gl_thread_self_pointer ());
372 gl_rwlock_rdlock (my_rwlock);
374 gl_rwlock_unlock (my_rwlock);
375 dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
380 dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
388 gl_thread_t checkerthreads[THREAD_COUNT];
389 gl_thread_t threads[THREAD_COUNT];
391 /* Initialization. */
392 for (i = 0; i < ACCOUNT_COUNT; i++)
394 rwlock_checker_done = 0;
396 /* Spawn the threads. */
397 for (i = 0; i < THREAD_COUNT; i++)
398 checkerthreads[i] = gl_thread_create (rwlock_checker_thread, NULL);
399 for (i = 0; i < THREAD_COUNT; i++)
400 threads[i] = gl_thread_create (rwlock_mutator_thread, NULL);
402 /* Wait for the threads to terminate. */
403 for (i = 0; i < THREAD_COUNT; i++)
404 gl_thread_join (threads[i], NULL);
405 rwlock_checker_done = 1;
406 for (i = 0; i < THREAD_COUNT; i++)
407 gl_thread_join (checkerthreads[i], NULL);
412 /* -------------------------- Test recursive locks -------------------------- */
414 /* Test recursive locks by having several bank accounts and several threads
415 which shuffle around money between the accounts (recursively) and another
416 thread checking that all the money is still there. */
418 gl_recursive_lock_define_initialized(static, my_reclock)
425 dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
426 gl_recursive_lock_lock (my_reclock);
427 dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
429 i1 = random_account ();
430 i2 = random_account ();
431 value = ((unsigned int) rand () >> 3) % 10;
432 account[i1] += value;
433 account[i2] -= value;
435 /* Recursive with probability 0.5. */
436 if (((unsigned int) rand () >> 3) % 2)
439 dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
440 gl_recursive_lock_unlock (my_reclock);
441 dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
445 reclock_mutator_thread (void *arg)
449 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
453 dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
454 gl_recursive_lock_lock (my_reclock);
456 gl_recursive_lock_unlock (my_reclock);
457 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
462 dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
466 static volatile int reclock_checker_done;
469 reclock_checker_thread (void *arg)
471 while (!reclock_checker_done)
473 dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
474 gl_recursive_lock_lock (my_reclock);
476 gl_recursive_lock_unlock (my_reclock);
477 dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
482 dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
487 test_recursive_lock (void)
490 gl_thread_t checkerthread;
491 gl_thread_t threads[THREAD_COUNT];
493 /* Initialization. */
494 for (i = 0; i < ACCOUNT_COUNT; i++)
496 reclock_checker_done = 0;
498 /* Spawn the threads. */
499 checkerthread = gl_thread_create (reclock_checker_thread, NULL);
500 for (i = 0; i < THREAD_COUNT; i++)
501 threads[i] = gl_thread_create (reclock_mutator_thread, NULL);
503 /* Wait for the threads to terminate. */
504 for (i = 0; i < THREAD_COUNT; i++)
505 gl_thread_join (threads[i], NULL);
506 reclock_checker_done = 1;
507 gl_thread_join (checkerthread, NULL);
512 /* ------------------------ Test once-only execution ------------------------ */
514 /* Test once-only execution by having several threads attempt to grab a
515 once-only task simultaneously (triggered by releasing a read-write lock). */
517 gl_once_define(static, fresh_once)
518 static int ready[THREAD_COUNT];
519 static gl_lock_t ready_lock[THREAD_COUNT];
521 static gl_rwlock_t fire_signal[REPEAT_COUNT];
523 static volatile int fire_signal_state;
525 static gl_once_t once_control;
526 static int performed;
527 gl_lock_define_initialized(static, performed_lock)
532 gl_lock_lock (performed_lock);
534 gl_lock_unlock (performed_lock);
538 once_contender_thread (void *arg)
540 int id = (int) (long) arg;
543 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
545 /* Tell the main thread that we're ready. */
546 gl_lock_lock (ready_lock[id]);
548 gl_lock_unlock (ready_lock[id]);
550 if (repeat == REPEAT_COUNT)
553 dbgprintf ("Contender %p waiting for signal for round %d\n",
554 gl_thread_self_pointer (), repeat);
556 /* Wait for the signal to go. */
557 gl_rwlock_rdlock (fire_signal[repeat]);
558 /* And don't hinder the others (if the scheduler is unfair). */
559 gl_rwlock_unlock (fire_signal[repeat]);
561 /* Wait for the signal to go. */
562 while (fire_signal_state <= repeat)
565 dbgprintf ("Contender %p got the signal for round %d\n",
566 gl_thread_self_pointer (), repeat);
568 /* Contend for execution. */
569 gl_once (once_control, once_execute);
579 gl_thread_t threads[THREAD_COUNT];
581 /* Initialize all variables. */
582 for (i = 0; i < THREAD_COUNT; i++)
585 gl_lock_init (ready_lock[i]);
588 for (i = 0; i < REPEAT_COUNT; i++)
589 gl_rwlock_init (fire_signal[i]);
591 fire_signal_state = 0;
594 /* Block all fire_signals. */
595 for (i = REPEAT_COUNT-1; i >= 0; i--)
596 gl_rwlock_wrlock (fire_signal[i]);
598 /* Spawn the threads. */
599 for (i = 0; i < THREAD_COUNT; i++)
600 threads[i] = gl_thread_create (once_contender_thread, (void *) (long) i);
602 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
604 /* Wait until every thread is ready. */
605 dbgprintf ("Main thread before synchronizing for round %d\n", repeat);
609 for (i = 0; i < THREAD_COUNT; i++)
611 gl_lock_lock (ready_lock[i]);
612 ready_count += ready[i];
613 gl_lock_unlock (ready_lock[i]);
615 if (ready_count == THREAD_COUNT)
619 dbgprintf ("Main thread after synchronizing for round %d\n", repeat);
623 /* Check that exactly one thread executed the once_execute()
629 if (repeat == REPEAT_COUNT)
632 /* Preparation for the next round: Initialize once_control. */
633 memcpy (&once_control, &fresh_once, sizeof (gl_once_t));
635 /* Preparation for the next round: Reset the performed counter. */
638 /* Preparation for the next round: Reset the ready flags. */
639 for (i = 0; i < THREAD_COUNT; i++)
641 gl_lock_lock (ready_lock[i]);
643 gl_lock_unlock (ready_lock[i]);
646 /* Signal all threads simultaneously. */
647 dbgprintf ("Main thread giving signal for round %d\n", repeat);
649 gl_rwlock_unlock (fire_signal[repeat]);
651 fire_signal_state = repeat + 1;
655 /* Wait for the threads to terminate. */
656 for (i = 0; i < THREAD_COUNT; i++)
657 gl_thread_join (threads[i], NULL);
661 /* -------------------------------------------------------------------------- */
672 printf ("Starting test_lock ..."); fflush (stdout);
674 printf (" OK\n"); fflush (stdout);
677 printf ("Starting test_rwlock ..."); fflush (stdout);
679 printf (" OK\n"); fflush (stdout);
681 #if DO_TEST_RECURSIVE_LOCK
682 printf ("Starting test_recursive_lock ..."); fflush (stdout);
683 test_recursive_lock ();
684 printf (" OK\n"); fflush (stdout);
687 printf ("Starting test_once ..."); fflush (stdout);
689 printf (" OK\n"); fflush (stdout);
697 /* No multithreading available. */
704 fputs ("Skipping test: multithreading not enabled\n", stderr);