1 /* Test of locking in multithreaded situations.
2 Copyright (C) 2005, 2008-2015 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
87 # define sched_yield() pthread_yield()
89 typedef pthread_t gl_thread_t;
90 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
93 if (pthread_create (&thread, NULL, func, arg) != 0)
97 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
99 if (pthread_join (thread, retvalp) != 0)
102 static inline void gl_thread_yield (void)
106 static inline void * gl_thread_self_pointer (void)
108 # ifdef PTW32_VERSION
109 return pthread_self ().p;
111 return (void *) pthread_self ();
117 typedef pth_t gl_thread_t;
118 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
120 pth_t thread = pth_spawn (NULL, func, arg);
125 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
127 if (!pth_join (thread, retvalp))
130 static inline void gl_thread_yield (void)
134 static inline void * gl_thread_self_pointer (void)
139 #if TEST_SOLARIS_THREADS
141 typedef thread_t gl_thread_t;
142 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
145 if (thr_create (NULL, 0, func, arg, 0, &thread) != 0)
149 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
151 if (thr_join (thread, NULL, retvalp) != 0)
154 static inline void gl_thread_yield (void)
158 static inline void * gl_thread_self_pointer (void)
160 return (void *) thr_self ();
163 #if TEST_WINDOWS_THREADS
164 # include <windows.h>
165 typedef HANDLE gl_thread_t;
166 /* Use a wrapper function, instead of adding WINAPI through a cast. */
167 struct wrapper_args { void * (*func) (void *); void *arg; };
168 static DWORD WINAPI wrapper_func (void *varg)
170 struct wrapper_args *warg = (struct wrapper_args *)varg;
171 void * (*func) (void *) = warg->func;
172 void *arg = warg->arg;
177 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
179 struct wrapper_args *warg =
180 (struct wrapper_args *) malloc (sizeof (struct wrapper_args));
188 CreateThread (NULL, 100000, wrapper_func, warg, 0, &thread_id);
194 static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
197 if (WaitForSingleObject (thread, INFINITE) == WAIT_FAILED)
199 if (!CloseHandle (thread))
202 static inline void gl_thread_yield (void)
206 static inline void * gl_thread_self_pointer (void)
208 return (void *) GetCurrentThreadId ();
212 # define yield() gl_thread_yield ()
217 #define ACCOUNT_COUNT 4
219 static int account[ACCOUNT_COUNT];
222 random_account (void)
224 return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
228 check_accounts (void)
233 for (i = 0; i < ACCOUNT_COUNT; i++)
235 if (sum != ACCOUNT_COUNT * 1000)
240 /* ------------------- Test normal (non-recursive) locks ------------------- */
242 /* Test normal locks by having several bank accounts and several threads
243 which shuffle around money between the accounts and another thread
244 checking that all the money is still there. */
246 gl_lock_define_initialized(static, my_lock)
249 lock_mutator_thread (void *arg)
253 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
257 dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
258 gl_lock_lock (my_lock);
259 dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
261 i1 = random_account ();
262 i2 = random_account ();
263 value = ((unsigned int) rand () >> 3) % 10;
264 account[i1] += value;
265 account[i2] -= value;
267 dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
268 gl_lock_unlock (my_lock);
269 dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
271 dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
272 gl_lock_lock (my_lock);
274 gl_lock_unlock (my_lock);
275 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
280 dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
284 static volatile int lock_checker_done;
287 lock_checker_thread (void *arg)
289 while (!lock_checker_done)
291 dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
292 gl_lock_lock (my_lock);
294 gl_lock_unlock (my_lock);
295 dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
300 dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
308 gl_thread_t checkerthread;
309 gl_thread_t threads[THREAD_COUNT];
311 /* Initialization. */
312 for (i = 0; i < ACCOUNT_COUNT; i++)
314 lock_checker_done = 0;
316 /* Spawn the threads. */
317 checkerthread = gl_thread_create (lock_checker_thread, NULL);
318 for (i = 0; i < THREAD_COUNT; i++)
319 threads[i] = gl_thread_create (lock_mutator_thread, NULL);
321 /* Wait for the threads to terminate. */
322 for (i = 0; i < THREAD_COUNT; i++)
323 gl_thread_join (threads[i], NULL);
324 lock_checker_done = 1;
325 gl_thread_join (checkerthread, NULL);
330 /* ----------------- Test read-write (non-recursive) locks ----------------- */
332 /* Test read-write locks by having several bank accounts and several threads
333 which shuffle around money between the accounts and several other threads
334 that check that all the money is still there. */
336 gl_rwlock_define_initialized(static, my_rwlock)
339 rwlock_mutator_thread (void *arg)
343 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
347 dbgprintf ("Mutator %p before wrlock\n", gl_thread_self_pointer ());
348 gl_rwlock_wrlock (my_rwlock);
349 dbgprintf ("Mutator %p after wrlock\n", gl_thread_self_pointer ());
351 i1 = random_account ();
352 i2 = random_account ();
353 value = ((unsigned int) rand () >> 3) % 10;
354 account[i1] += value;
355 account[i2] -= value;
357 dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
358 gl_rwlock_unlock (my_rwlock);
359 dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
364 dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
368 static volatile int rwlock_checker_done;
371 rwlock_checker_thread (void *arg)
373 while (!rwlock_checker_done)
375 dbgprintf ("Checker %p before check rdlock\n", gl_thread_self_pointer ());
376 gl_rwlock_rdlock (my_rwlock);
378 gl_rwlock_unlock (my_rwlock);
379 dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
384 dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
392 gl_thread_t checkerthreads[THREAD_COUNT];
393 gl_thread_t threads[THREAD_COUNT];
395 /* Initialization. */
396 for (i = 0; i < ACCOUNT_COUNT; i++)
398 rwlock_checker_done = 0;
400 /* Spawn the threads. */
401 for (i = 0; i < THREAD_COUNT; i++)
402 checkerthreads[i] = gl_thread_create (rwlock_checker_thread, NULL);
403 for (i = 0; i < THREAD_COUNT; i++)
404 threads[i] = gl_thread_create (rwlock_mutator_thread, NULL);
406 /* Wait for the threads to terminate. */
407 for (i = 0; i < THREAD_COUNT; i++)
408 gl_thread_join (threads[i], NULL);
409 rwlock_checker_done = 1;
410 for (i = 0; i < THREAD_COUNT; i++)
411 gl_thread_join (checkerthreads[i], NULL);
416 /* -------------------------- Test recursive locks -------------------------- */
418 /* Test recursive locks by having several bank accounts and several threads
419 which shuffle around money between the accounts (recursively) and another
420 thread checking that all the money is still there. */
422 gl_recursive_lock_define_initialized(static, my_reclock)
429 dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
430 gl_recursive_lock_lock (my_reclock);
431 dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
433 i1 = random_account ();
434 i2 = random_account ();
435 value = ((unsigned int) rand () >> 3) % 10;
436 account[i1] += value;
437 account[i2] -= value;
439 /* Recursive with probability 0.5. */
440 if (((unsigned int) rand () >> 3) % 2)
443 dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
444 gl_recursive_lock_unlock (my_reclock);
445 dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
449 reclock_mutator_thread (void *arg)
453 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
457 dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
458 gl_recursive_lock_lock (my_reclock);
460 gl_recursive_lock_unlock (my_reclock);
461 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
466 dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
470 static volatile int reclock_checker_done;
473 reclock_checker_thread (void *arg)
475 while (!reclock_checker_done)
477 dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
478 gl_recursive_lock_lock (my_reclock);
480 gl_recursive_lock_unlock (my_reclock);
481 dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
486 dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
491 test_recursive_lock (void)
494 gl_thread_t checkerthread;
495 gl_thread_t threads[THREAD_COUNT];
497 /* Initialization. */
498 for (i = 0; i < ACCOUNT_COUNT; i++)
500 reclock_checker_done = 0;
502 /* Spawn the threads. */
503 checkerthread = gl_thread_create (reclock_checker_thread, NULL);
504 for (i = 0; i < THREAD_COUNT; i++)
505 threads[i] = gl_thread_create (reclock_mutator_thread, NULL);
507 /* Wait for the threads to terminate. */
508 for (i = 0; i < THREAD_COUNT; i++)
509 gl_thread_join (threads[i], NULL);
510 reclock_checker_done = 1;
511 gl_thread_join (checkerthread, NULL);
516 /* ------------------------ Test once-only execution ------------------------ */
518 /* Test once-only execution by having several threads attempt to grab a
519 once-only task simultaneously (triggered by releasing a read-write lock). */
521 gl_once_define(static, fresh_once)
522 static int ready[THREAD_COUNT];
523 static gl_lock_t ready_lock[THREAD_COUNT];
525 static gl_rwlock_t fire_signal[REPEAT_COUNT];
527 static volatile int fire_signal_state;
529 static gl_once_t once_control;
530 static int performed;
531 gl_lock_define_initialized(static, performed_lock)
536 gl_lock_lock (performed_lock);
538 gl_lock_unlock (performed_lock);
542 once_contender_thread (void *arg)
544 int id = (int) (long) arg;
547 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
549 /* Tell the main thread that we're ready. */
550 gl_lock_lock (ready_lock[id]);
552 gl_lock_unlock (ready_lock[id]);
554 if (repeat == REPEAT_COUNT)
557 dbgprintf ("Contender %p waiting for signal for round %d\n",
558 gl_thread_self_pointer (), repeat);
560 /* Wait for the signal to go. */
561 gl_rwlock_rdlock (fire_signal[repeat]);
562 /* And don't hinder the others (if the scheduler is unfair). */
563 gl_rwlock_unlock (fire_signal[repeat]);
565 /* Wait for the signal to go. */
566 while (fire_signal_state <= repeat)
569 dbgprintf ("Contender %p got the signal for round %d\n",
570 gl_thread_self_pointer (), repeat);
572 /* Contend for execution. */
573 gl_once (once_control, once_execute);
583 gl_thread_t threads[THREAD_COUNT];
585 /* Initialize all variables. */
586 for (i = 0; i < THREAD_COUNT; i++)
589 gl_lock_init (ready_lock[i]);
592 for (i = 0; i < REPEAT_COUNT; i++)
593 gl_rwlock_init (fire_signal[i]);
595 fire_signal_state = 0;
598 /* Block all fire_signals. */
599 for (i = REPEAT_COUNT-1; i >= 0; i--)
600 gl_rwlock_wrlock (fire_signal[i]);
602 /* Spawn the threads. */
603 for (i = 0; i < THREAD_COUNT; i++)
604 threads[i] = gl_thread_create (once_contender_thread, (void *) (long) i);
606 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
608 /* Wait until every thread is ready. */
609 dbgprintf ("Main thread before synchronizing for round %d\n", repeat);
613 for (i = 0; i < THREAD_COUNT; i++)
615 gl_lock_lock (ready_lock[i]);
616 ready_count += ready[i];
617 gl_lock_unlock (ready_lock[i]);
619 if (ready_count == THREAD_COUNT)
623 dbgprintf ("Main thread after synchronizing for round %d\n", repeat);
627 /* Check that exactly one thread executed the once_execute()
633 if (repeat == REPEAT_COUNT)
636 /* Preparation for the next round: Initialize once_control. */
637 memcpy (&once_control, &fresh_once, sizeof (gl_once_t));
639 /* Preparation for the next round: Reset the performed counter. */
642 /* Preparation for the next round: Reset the ready flags. */
643 for (i = 0; i < THREAD_COUNT; i++)
645 gl_lock_lock (ready_lock[i]);
647 gl_lock_unlock (ready_lock[i]);
650 /* Signal all threads simultaneously. */
651 dbgprintf ("Main thread giving signal for round %d\n", repeat);
653 gl_rwlock_unlock (fire_signal[repeat]);
655 fire_signal_state = repeat + 1;
659 /* Wait for the threads to terminate. */
660 for (i = 0; i < THREAD_COUNT; i++)
661 gl_thread_join (threads[i], NULL);
665 /* -------------------------------------------------------------------------- */
676 printf ("Starting test_lock ..."); fflush (stdout);
678 printf (" OK\n"); fflush (stdout);
681 printf ("Starting test_rwlock ..."); fflush (stdout);
683 printf (" OK\n"); fflush (stdout);
685 #if DO_TEST_RECURSIVE_LOCK
686 printf ("Starting test_recursive_lock ..."); fflush (stdout);
687 test_recursive_lock ();
688 printf (" OK\n"); fflush (stdout);
691 printf ("Starting test_once ..."); fflush (stdout);
693 printf (" OK\n"); fflush (stdout);
701 /* No multithreading available. */
708 fputs ("Skipping test: multithreading not enabled\n", stderr);