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 it
5 under the terms of the GNU Library General Public License as published
6 by the Free Software Foundation; either version 2, or (at your option)
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 GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 /* Written by Bruno Haible <bruno@clisp.org>, 2005. */
25 #if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WIN32_THREADS
28 # define TEST_POSIX_THREADS 1
30 #if USE_SOLARIS_THREADS
31 # define TEST_SOLARIS_THREADS 1
34 # define TEST_PTH_THREADS 1
37 # define TEST_WIN32_THREADS 1
40 /* Whether to enable locking.
41 Uncomment this to get a test program without locking, to verify that
43 #define ENABLE_LOCKING 1
45 /* Which tests to perform.
46 Uncomment some of these, to verify that all tests crash if no locking
48 #define DO_TEST_LOCK 1
49 #define DO_TEST_RWLOCK 1
50 #define DO_TEST_RECURSIVE_LOCK 1
51 #define DO_TEST_ONCE 1
53 /* Whether to help the scheduler through explicit yield().
54 Uncomment this to see if the operating system has a fair scheduler. */
55 #define EXPLICIT_YIELD 1
57 /* Whether to print debugging messages. */
58 #define ENABLE_DEBUGGING 0
60 /* Number of simultaneous threads. */
61 #define THREAD_COUNT 10
63 /* Number of operations performed in each thread.
64 This is quite high, because with a smaller count, say 5000, we often get
65 an "OK" result even without ENABLE_LOCKING (on Linux/x86). */
66 #define REPEAT_COUNT 50000
73 # undef USE_POSIX_THREADS
74 # undef USE_SOLARIS_THREADS
75 # undef USE_PTH_THREADS
76 # undef USE_WIN32_THREADS
81 # define dbgprintf printf
83 # define dbgprintf if (0) printf
86 #if TEST_POSIX_THREADS
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)
100 if (pthread_join (thread, &retval) != 0)
103 static inline void gl_thread_yield (void)
107 static inline void * gl_thread_self (void)
109 return (void *) pthread_self ();
114 typedef pth_t gl_thread_t;
115 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
117 pth_t thread = pth_spawn (NULL, func, arg);
122 static inline void gl_thread_join (gl_thread_t thread)
124 if (!pth_join (thread, NULL))
127 static inline void gl_thread_yield (void)
131 static inline void * gl_thread_self (void)
136 #if TEST_SOLARIS_THREADS
138 typedef thread_t gl_thread_t;
139 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
142 if (thr_create (NULL, 0, func, arg, 0, &thread) != 0)
146 static inline void gl_thread_join (gl_thread_t thread)
149 if (thr_join (thread, NULL, &retval) != 0)
152 static inline void gl_thread_yield (void)
156 static inline void * gl_thread_self (void)
158 return (void *) thr_self ();
161 #if TEST_WIN32_THREADS
162 # include <windows.h>
163 typedef HANDLE gl_thread_t;
164 /* Use a wrapper function, instead of adding WINAPI through a cast. */
165 struct wrapper_args { void * (*func) (void *); void *arg; };
166 static DWORD WINAPI wrapper_func (void *varg)
168 struct wrapper_args *warg = (struct wrapper_args *)varg;
169 void * (*func) (void *) = warg->func;
170 void *arg = warg->arg;
175 static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
177 struct wrapper_args *warg =
178 (struct wrapper_args *) malloc (sizeof (struct wrapper_args));
186 CreateThread (NULL, 100000, wrapper_func, warg, 0, &thread_id);
192 static inline void gl_thread_join (gl_thread_t thread)
194 if (WaitForSingleObject (thread, INFINITE) == WAIT_FAILED)
196 if (!CloseHandle (thread))
199 static inline void gl_thread_yield (void)
203 static inline void * gl_thread_self (void)
205 return (void *) GetCurrentThreadId ();
209 # define yield() gl_thread_yield ()
214 #define ACCOUNT_COUNT 4
216 static int account[ACCOUNT_COUNT];
219 random_account (void)
221 return ((unsigned int) rand() >> 3) % ACCOUNT_COUNT;
225 check_accounts (void)
230 for (i = 0; i < ACCOUNT_COUNT; i++)
232 if (sum != ACCOUNT_COUNT * 1000)
236 /* Test normal locks by having several bank accounts and several threads
237 which shuffle around money between the accounts and another thread
238 checking that all the money is still there. */
240 gl_lock_define_initialized(static, my_lock)
243 lock_mutator_thread (void *arg)
247 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
251 dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
252 gl_lock_lock (my_lock);
253 dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
255 i1 = random_account ();
256 i2 = random_account ();
257 value = ((unsigned int) rand() >> 3) % 10;
258 account[i1] += value;
259 account[i2] -= value;
261 dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
262 gl_lock_unlock (my_lock);
263 dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
265 dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
266 gl_lock_lock (my_lock);
268 gl_lock_unlock (my_lock);
269 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
274 dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
278 static volatile int lock_checker_done;
281 lock_checker_thread (void *arg)
283 while (!lock_checker_done)
285 dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
286 gl_lock_lock (my_lock);
288 gl_lock_unlock (my_lock);
289 dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
294 dbgprintf ("Checker %p dying.\n", gl_thread_self ());
302 gl_thread_t checkerthread;
303 gl_thread_t threads[THREAD_COUNT];
305 /* Initialization. */
306 for (i = 0; i < ACCOUNT_COUNT; i++)
308 lock_checker_done = 0;
310 /* Spawn the threads. */
311 checkerthread = gl_thread_create (lock_checker_thread, NULL);
312 for (i = 0; i < THREAD_COUNT; i++)
313 threads[i] = gl_thread_create (lock_mutator_thread, NULL);
315 /* Wait for the threads to terminate. */
316 for (i = 0; i < THREAD_COUNT; i++)
317 gl_thread_join (threads[i]);
318 lock_checker_done = 1;
319 gl_thread_join (checkerthread);
323 /* Test read-write locks by having several bank accounts and several threads
324 which shuffle around money between the accounts and several other threads
325 that check that all the money is still there. */
327 gl_rwlock_define_initialized(static, my_rwlock)
330 rwlock_mutator_thread (void *arg)
334 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
338 dbgprintf ("Mutator %p before wrlock\n", gl_thread_self ());
339 gl_rwlock_wrlock (my_rwlock);
340 dbgprintf ("Mutator %p after wrlock\n", gl_thread_self ());
342 i1 = random_account ();
343 i2 = random_account ();
344 value = ((unsigned int) rand() >> 3) % 10;
345 account[i1] += value;
346 account[i2] -= value;
348 dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
349 gl_rwlock_unlock (my_rwlock);
350 dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
355 dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
359 static volatile int rwlock_checker_done;
362 rwlock_checker_thread (void *arg)
364 while (!rwlock_checker_done)
366 dbgprintf ("Checker %p before check rdlock\n", gl_thread_self ());
367 gl_rwlock_rdlock (my_rwlock);
369 gl_rwlock_unlock (my_rwlock);
370 dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
375 dbgprintf ("Checker %p dying.\n", gl_thread_self ());
383 gl_thread_t checkerthreads[THREAD_COUNT];
384 gl_thread_t threads[THREAD_COUNT];
386 /* Initialization. */
387 for (i = 0; i < ACCOUNT_COUNT; i++)
389 rwlock_checker_done = 0;
391 /* Spawn the threads. */
392 for (i = 0; i < THREAD_COUNT; i++)
393 checkerthreads[i] = gl_thread_create (rwlock_checker_thread, NULL);
394 for (i = 0; i < THREAD_COUNT; i++)
395 threads[i] = gl_thread_create (rwlock_mutator_thread, NULL);
397 /* Wait for the threads to terminate. */
398 for (i = 0; i < THREAD_COUNT; i++)
399 gl_thread_join (threads[i]);
400 rwlock_checker_done = 1;
401 for (i = 0; i < THREAD_COUNT; i++)
402 gl_thread_join (checkerthreads[i]);
406 /* Test recursive locks by having several bank accounts and several threads
407 which shuffle around money between the accounts (recursively) and another
408 thread checking that all the money is still there. */
410 gl_recursive_lock_define_initialized(static, my_reclock)
417 dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
418 gl_recursive_lock_lock (my_reclock);
419 dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
421 i1 = random_account ();
422 i2 = random_account ();
423 value = ((unsigned int) rand() >> 3) % 10;
424 account[i1] += value;
425 account[i2] -= value;
427 /* Recursive with probability 0.5. */
428 if (((unsigned int) rand() >> 3) % 2)
431 dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
432 gl_recursive_lock_unlock (my_reclock);
433 dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
437 reclock_mutator_thread (void *arg)
441 for (repeat = REPEAT_COUNT; repeat > 0; repeat--)
445 dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
446 gl_recursive_lock_lock (my_reclock);
448 gl_recursive_lock_unlock (my_reclock);
449 dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
454 dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
458 static volatile int reclock_checker_done;
461 reclock_checker_thread (void *arg)
463 while (!reclock_checker_done)
465 dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
466 gl_recursive_lock_lock (my_reclock);
468 gl_recursive_lock_unlock (my_reclock);
469 dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
474 dbgprintf ("Checker %p dying.\n", gl_thread_self ());
479 test_recursive_lock (void)
482 gl_thread_t checkerthread;
483 gl_thread_t threads[THREAD_COUNT];
485 /* Initialization. */
486 for (i = 0; i < ACCOUNT_COUNT; i++)
488 reclock_checker_done = 0;
490 /* Spawn the threads. */
491 checkerthread = gl_thread_create (reclock_checker_thread, NULL);
492 for (i = 0; i < THREAD_COUNT; i++)
493 threads[i] = gl_thread_create (reclock_mutator_thread, NULL);
495 /* Wait for the threads to terminate. */
496 for (i = 0; i < THREAD_COUNT; i++)
497 gl_thread_join (threads[i]);
498 reclock_checker_done = 1;
499 gl_thread_join (checkerthread);
503 /* Test once-only execution by having several threads attempt to grab a
504 once-only task simultaneously (triggered by releasing a read-write lock). */
506 gl_once_define(static, fresh_once)
507 static int ready[THREAD_COUNT];
508 static gl_lock_t ready_lock[THREAD_COUNT];
510 static gl_rwlock_t fire_signal[REPEAT_COUNT];
512 static volatile int fire_signal_state;
514 static gl_once_t once_control;
515 static int performed;
516 gl_lock_define_initialized(static, performed_lock)
521 gl_lock_lock (performed_lock);
523 gl_lock_unlock (performed_lock);
527 once_contender_thread (void *arg)
529 int id = (int) (long) arg;
532 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
534 /* Tell the main thread that we're ready. */
535 gl_lock_lock (ready_lock[id]);
537 gl_lock_unlock (ready_lock[id]);
539 if (repeat == REPEAT_COUNT)
542 dbgprintf ("Contender %p waiting for signal for round %d\n",
543 gl_thread_self (), repeat);
545 /* Wait for the signal to go. */
546 gl_rwlock_rdlock (fire_signal[repeat]);
547 /* And don't hinder the others (if the scheduler is unfair). */
548 gl_rwlock_unlock (fire_signal[repeat]);
550 /* Wait for the signal to go. */
551 while (fire_signal_state <= repeat)
554 dbgprintf ("Contender %p got the signal for round %d\n",
555 gl_thread_self (), repeat);
557 /* Contend for execution. */
558 gl_once (once_control, once_execute);
568 gl_thread_t threads[THREAD_COUNT];
570 /* Initialize all variables. */
571 for (i = 0; i < THREAD_COUNT; i++)
574 gl_lock_init (ready_lock[i]);
577 for (i = 0; i < REPEAT_COUNT; i++)
578 gl_rwlock_init (fire_signal[i]);
580 fire_signal_state = 0;
583 /* Block all fire_signals. */
584 for (i = REPEAT_COUNT-1; i >= 0; i--)
585 gl_rwlock_wrlock (fire_signal[i]);
587 /* Spawn the threads. */
588 for (i = 0; i < THREAD_COUNT; i++)
589 threads[i] = gl_thread_create (once_contender_thread, (void *) (long) i);
591 for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
593 /* Wait until every thread is ready. */
594 dbgprintf ("Main thread before synchonizing for round %d\n", repeat);
598 for (i = 0; i < THREAD_COUNT; i++)
600 gl_lock_lock (ready_lock[i]);
601 ready_count += ready[i];
602 gl_lock_unlock (ready_lock[i]);
604 if (ready_count == THREAD_COUNT)
608 dbgprintf ("Main thread after synchonizing for round %d\n", repeat);
612 /* Check that exactly one thread executed the once_execute()
618 if (repeat == REPEAT_COUNT)
621 /* Preparation for the next round: Initialize once_control. */
622 memcpy (&once_control, &fresh_once, sizeof (gl_once_t));
624 /* Preparation for the next round: Reset the performed counter. */
627 /* Preparation for the next round: Reset the ready flags. */
628 for (i = 0; i < THREAD_COUNT; i++)
630 gl_lock_lock (ready_lock[i]);
632 gl_lock_unlock (ready_lock[i]);
635 /* Signal all threads simultaneously. */
636 dbgprintf ("Main thread giving signal for round %d\n", repeat);
638 gl_rwlock_unlock (fire_signal[repeat]);
640 fire_signal_state = repeat + 1;
644 /* Wait for the threads to terminate. */
645 for (i = 0; i < THREAD_COUNT; i++)
646 gl_thread_join (threads[i]);
658 printf ("Starting test_lock ..."); fflush (stdout);
660 printf (" OK\n"); fflush (stdout);
663 printf ("Starting test_rwlock ..."); fflush (stdout);
665 printf (" OK\n"); fflush (stdout);
667 #if DO_TEST_RECURSIVE_LOCK
668 printf ("Starting test_recursive_lock ..."); fflush (stdout);
669 test_recursive_lock ();
670 printf (" OK\n"); fflush (stdout);
673 printf ("Starting test_once ..."); fflush (stdout);
675 printf (" OK\n"); fflush (stdout);
683 /* No multithreading available. */