1 /* Test of locking in multithreaded situations.
2 Copyright (C) 2005 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
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)
96 if (pthread_join (thread, &retval) != 0)
99 static inline void gl_thread_yield (void)
103 static inline void * gl_thread_self (void)
105 return (void *) pthread_self ();
110 typedef pth_t gl_thread_t;
111 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
113 pth_t thread = pth_spawn (NULL, func, arg);
118 static inline void gl_thread_join (gl_thread_t thread)
120 if (!pth_join (thread, NULL))
123 static inline void gl_thread_yield (void)
127 static inline void * gl_thread_self (void)
132 #if TEST_SOLARIS_THREADS
134 typedef thread_t gl_thread_t;
135 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
138 if (thr_create (NULL, 0, func, arg, 0, &thread) != 0)
142 static inline void gl_thread_join (gl_thread_t thread)
145 if (thr_join (thread, NULL, &retval) != 0)
148 static inline void gl_thread_yield (void)
152 static inline void * gl_thread_self (void)
154 return (void *) thr_self ();
157 #if TEST_WIN32_THREADS
158 # include <windows.h>
159 typedef HANDLE gl_thread_t;
160 /* Use a wrapper function, instead of adding WINAPI through a cast. */
161 struct wrapper_args { void * (*func) (void *); void *arg; };
162 static DWORD WINAPI wrapper_func (void *varg)
164 struct wrapper_args *warg = (struct wrapper_args *)varg;
165 void * (*func) (void *) = warg->func;
166 void *arg = warg->arg;
171 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
173 struct wrapper_args *warg =
174 (struct wrapper_args *) malloc (sizeof (struct wrapper_args));
182 CreateThread (NULL, 100000, wrapper_func, warg, 0, &thread_id);
188 static inline void gl_thread_join (gl_thread_t thread)
190 if (WaitForSingleObject (thread, INFINITE) == WAIT_FAILED)
192 if (!CloseHandle (thread))
195 static inline void gl_thread_yield (void)
199 static inline void * gl_thread_self (void)
201 return (void *) GetCurrentThreadId ();
205 # define yield() gl_thread_yield ()
210 #define ACCOUNT_COUNT 4
212 static int account[ACCOUNT_COUNT];
215 random_account (void)
217 return ((unsigned int) rand() >> 3) % ACCOUNT_COUNT;
221 check_accounts (void)
226 for (i = 0; i < ACCOUNT_COUNT; i++)
228 if (sum != ACCOUNT_COUNT * 1000)
232 /* Test normal locks by having several bank accounts and several threads
233 which shuffle around money between the accounts and another thread
234 checking that all the money is still there. */
236 gl_lock_define_initialized(static, my_lock)
239 lock_mutator_thread (void *arg)
243 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
247 dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
248 gl_lock_lock (my_lock);
249 dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
251 i1 = random_account ();
252 i2 = random_account ();
253 value = ((unsigned int) rand() >> 3) % 10;
254 account[i1] += value;
255 account[i2] -= value;
257 dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
258 gl_lock_unlock (my_lock);
259 dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
261 dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
262 gl_lock_lock (my_lock);
264 gl_lock_unlock (my_lock);
265 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
270 dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
274 static volatile int lock_checker_done;
277 lock_checker_thread (void *arg)
279 while (!lock_checker_done)
281 dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
282 gl_lock_lock (my_lock);
284 gl_lock_unlock (my_lock);
285 dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
290 dbgprintf ("Checker %p dying.\n", gl_thread_self ());
298 gl_thread_t checkerthread;
299 gl_thread_t threads[THREAD_COUNT];
301 /* Initialization. */
302 for (i = 0; i < ACCOUNT_COUNT; i++)
304 lock_checker_done = 0;
306 /* Spawn the threads. */
307 checkerthread = gl_thread_create (lock_checker_thread, NULL);
308 for (i = 0; i < THREAD_COUNT; i++)
309 threads[i] = gl_thread_create (lock_mutator_thread, NULL);
311 /* Wait for the threads to terminate. */
312 for (i = 0; i < THREAD_COUNT; i++)
313 gl_thread_join (threads[i]);
314 lock_checker_done = 1;
315 gl_thread_join (checkerthread);
319 /* Test read-write locks by having several bank accounts and several threads
320 which shuffle around money between the accounts and several other threads
321 that check that all the money is still there. */
323 gl_rwlock_define_initialized(static, my_rwlock)
326 rwlock_mutator_thread (void *arg)
330 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
334 dbgprintf ("Mutator %p before wrlock\n", gl_thread_self ());
335 gl_rwlock_wrlock (my_rwlock);
336 dbgprintf ("Mutator %p after wrlock\n", gl_thread_self ());
338 i1 = random_account ();
339 i2 = random_account ();
340 value = ((unsigned int) rand() >> 3) % 10;
341 account[i1] += value;
342 account[i2] -= value;
344 dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
345 gl_rwlock_unlock (my_rwlock);
346 dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
351 dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
355 static volatile int rwlock_checker_done;
358 rwlock_checker_thread (void *arg)
360 while (!rwlock_checker_done)
362 dbgprintf ("Checker %p before check rdlock\n", gl_thread_self ());
363 gl_rwlock_rdlock (my_rwlock);
365 gl_rwlock_unlock (my_rwlock);
366 dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
371 dbgprintf ("Checker %p dying.\n", gl_thread_self ());
379 gl_thread_t checkerthreads[THREAD_COUNT];
380 gl_thread_t threads[THREAD_COUNT];
382 /* Initialization. */
383 for (i = 0; i < ACCOUNT_COUNT; i++)
385 rwlock_checker_done = 0;
387 /* Spawn the threads. */
388 for (i = 0; i < THREAD_COUNT; i++)
389 checkerthreads[i] = gl_thread_create (rwlock_checker_thread, NULL);
390 for (i = 0; i < THREAD_COUNT; i++)
391 threads[i] = gl_thread_create (rwlock_mutator_thread, NULL);
393 /* Wait for the threads to terminate. */
394 for (i = 0; i < THREAD_COUNT; i++)
395 gl_thread_join (threads[i]);
396 rwlock_checker_done = 1;
397 for (i = 0; i < THREAD_COUNT; i++)
398 gl_thread_join (checkerthreads[i]);
402 /* Test recursive locks by having several bank accounts and several threads
403 which shuffle around money between the accounts (recursively) and another
404 thread checking that all the money is still there. */
406 gl_recursive_lock_define_initialized(static, my_reclock)
413 dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
414 gl_recursive_lock_lock (my_reclock);
415 dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
417 i1 = random_account ();
418 i2 = random_account ();
419 value = ((unsigned int) rand() >> 3) % 10;
420 account[i1] += value;
421 account[i2] -= value;
423 /* Recursive with probability 0.5. */
424 if (((unsigned int) rand() >> 3) % 2)
427 dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
428 gl_recursive_lock_unlock (my_reclock);
429 dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
433 reclock_mutator_thread (void *arg)
437 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
441 dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
442 gl_recursive_lock_lock (my_reclock);
444 gl_recursive_lock_unlock (my_reclock);
445 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
450 dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
454 static volatile int reclock_checker_done;
457 reclock_checker_thread (void *arg)
459 while (!reclock_checker_done)
461 dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
462 gl_recursive_lock_lock (my_reclock);
464 gl_recursive_lock_unlock (my_reclock);
465 dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
470 dbgprintf ("Checker %p dying.\n", gl_thread_self ());
475 test_recursive_lock (void)
478 gl_thread_t checkerthread;
479 gl_thread_t threads[THREAD_COUNT];
481 /* Initialization. */
482 for (i = 0; i < ACCOUNT_COUNT; i++)
484 reclock_checker_done = 0;
486 /* Spawn the threads. */
487 checkerthread = gl_thread_create (reclock_checker_thread, NULL);
488 for (i = 0; i < THREAD_COUNT; i++)
489 threads[i] = gl_thread_create (reclock_mutator_thread, NULL);
491 /* Wait for the threads to terminate. */
492 for (i = 0; i < THREAD_COUNT; i++)
493 gl_thread_join (threads[i]);
494 reclock_checker_done = 1;
495 gl_thread_join (checkerthread);
499 /* Test once-only execution by having several threads attempt to grab a
500 once-only task simultaneously (triggered by releasing a read-write lock). */
502 gl_once_define(static, fresh_once)
503 static int ready[THREAD_COUNT];
504 static gl_lock_t ready_lock[THREAD_COUNT];
506 static gl_rwlock_t fire_signal[REPEAT_COUNT];
508 static volatile int fire_signal_state;
510 static gl_once_t once_control;
511 static int performed;
512 gl_lock_define_initialized(static, performed_lock)
517 gl_lock_lock (performed_lock);
519 gl_lock_unlock (performed_lock);
523 once_contender_thread (void *arg)
525 int id = (int) (long) arg;
528 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
530 /* Tell the main thread that we're ready. */
531 gl_lock_lock (ready_lock[id]);
533 gl_lock_unlock (ready_lock[id]);
535 if (repeat == REPEAT_COUNT)
538 dbgprintf ("Contender %p waiting for signal for round %d\n",
539 gl_thread_self (), repeat);
541 /* Wait for the signal to go. */
542 gl_rwlock_rdlock (fire_signal[repeat]);
543 /* And don't hinder the others (if the scheduler is unfair). */
544 gl_rwlock_unlock (fire_signal[repeat]);
546 /* Wait for the signal to go. */
547 while (fire_signal_state <= repeat)
550 dbgprintf ("Contender %p got the signal for round %d\n",
551 gl_thread_self (), repeat);
553 /* Contend for execution. */
554 gl_once (once_control, once_execute);
564 gl_thread_t threads[THREAD_COUNT];
566 /* Initialize all variables. */
567 for (i = 0; i < THREAD_COUNT; i++)
570 gl_lock_init (ready_lock[i]);
573 for (i = 0; i < REPEAT_COUNT; i++)
574 gl_rwlock_init (fire_signal[i]);
576 fire_signal_state = 0;
579 /* Block all fire_signals. */
580 for (i = REPEAT_COUNT-1; i >= 0; i--)
581 gl_rwlock_wrlock (fire_signal[i]);
583 /* Spawn the threads. */
584 for (i = 0; i < THREAD_COUNT; i++)
585 threads[i] = gl_thread_create (once_contender_thread, (void *) (long) i);
587 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
589 /* Wait until every thread is ready. */
590 dbgprintf ("Main thread before synchonizing for round %d\n", repeat);
594 for (i = 0; i < THREAD_COUNT; i++)
596 gl_lock_lock (ready_lock[i]);
597 ready_count += ready[i];
598 gl_lock_unlock (ready_lock[i]);
600 if (ready_count == THREAD_COUNT)
604 dbgprintf ("Main thread after synchonizing for round %d\n", repeat);
608 /* Check that exactly one thread executed the once_execute()
614 if (repeat == REPEAT_COUNT)
617 /* Preparation for the next round: Initialize once_control. */
618 memcpy (&once_control, &fresh_once, sizeof (gl_once_t));
620 /* Preparation for the next round: Reset the performed counter. */
623 /* Preparation for the next round: Reset the ready flags. */
624 for (i = 0; i < THREAD_COUNT; i++)
626 gl_lock_lock (ready_lock[i]);
628 gl_lock_unlock (ready_lock[i]);
631 /* Signal all threads simultaneously. */
632 dbgprintf ("Main thread giving signal for round %d\n", repeat);
634 gl_rwlock_unlock (fire_signal[repeat]);
636 fire_signal_state = repeat + 1;
640 /* Wait for the threads to terminate. */
641 for (i = 0; i < THREAD_COUNT; i++)
642 gl_thread_join (threads[i]);
654 printf ("Starting test_lock ..."); fflush (stdout);
656 printf (" OK\n"); fflush (stdout);
659 printf ("Starting test_rwlock ..."); fflush (stdout);
661 printf (" OK\n"); fflush (stdout);
663 #if DO_TEST_RECURSIVE_LOCK
664 printf ("Starting test_recursive_lock ..."); fflush (stdout);
665 test_recursive_lock ();
666 printf (" OK\n"); fflush (stdout);
669 printf ("Starting test_once ..."); fflush (stdout);
671 printf (" OK\n"); fflush (stdout);
679 /* No multithreading available. */