/* Test of locking in multithreaded situations.
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2008-2012 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
/* Written by Bruno Haible <bruno@clisp.org>, 2005. */
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
#if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WINDOWS_THREADS
abort ();
return thread;
}
-static inline void gl_thread_join (gl_thread_t thread)
+static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
{
- void *retval;
- if (pthread_join (thread, &retval) != 0)
+ if (pthread_join (thread, retvalp) != 0)
abort ();
}
static inline void gl_thread_yield (void)
{
sched_yield ();
}
-static inline void * gl_thread_self (void)
+static inline void * gl_thread_self_pointer (void)
{
+# ifdef PTW32_VERSION
+ return pthread_self ().p;
+# else
return (void *) pthread_self ();
+# endif
}
#endif
#if TEST_PTH_THREADS
abort ();
return thread;
}
-static inline void gl_thread_join (gl_thread_t thread)
+static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
{
- if (!pth_join (thread, NULL))
+ if (!pth_join (thread, retvalp))
abort ();
}
static inline void gl_thread_yield (void)
{
pth_yield (NULL);
}
-static inline void * gl_thread_self (void)
+static inline void * gl_thread_self_pointer (void)
{
return pth_self ();
}
abort ();
return thread;
}
-static inline void gl_thread_join (gl_thread_t thread)
+static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
{
- void *retval;
- if (thr_join (thread, NULL, &retval) != 0)
+ if (thr_join (thread, NULL, retvalp) != 0)
abort ();
}
static inline void gl_thread_yield (void)
{
thr_yield ();
}
-static inline void * gl_thread_self (void)
+static inline void * gl_thread_self_pointer (void)
{
return (void *) thr_self ();
}
return thread;
}
}
-static inline void gl_thread_join (gl_thread_t thread)
+static inline void gl_thread_join (gl_thread_t thread, void **retvalp)
{
+ (void) retvalp;
if (WaitForSingleObject (thread, INFINITE) == WAIT_FAILED)
abort ();
if (!CloseHandle (thread))
{
Sleep (0);
}
-static inline void * gl_thread_self (void)
+static inline void * gl_thread_self_pointer (void)
{
return (void *) GetCurrentThreadId ();
}
static int
random_account (void)
{
- return ((unsigned int) rand() >> 3) % ACCOUNT_COUNT;
+ return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT;
}
static void
abort ();
}
+
+/* ------------------- Test normal (non-recursive) locks ------------------- */
+
/* Test normal locks by having several bank accounts and several threads
which shuffle around money between the accounts and another thread
checking that all the money is still there. */
{
int i1, i2, value;
- dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
gl_lock_lock (my_lock);
- dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
i1 = random_account ();
i2 = random_account ();
- value = ((unsigned int) rand() >> 3) % 10;
+ value = ((unsigned int) rand () >> 3) % 10;
account[i1] += value;
account[i2] -= value;
- dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
gl_lock_unlock (my_lock);
- dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
- dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
gl_lock_lock (my_lock);
check_accounts ();
gl_lock_unlock (my_lock);
- dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
yield ();
}
- dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
+ dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
return NULL;
}
{
while (!lock_checker_done)
{
- dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
+ dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
gl_lock_lock (my_lock);
check_accounts ();
gl_lock_unlock (my_lock);
- dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
yield ();
}
- dbgprintf ("Checker %p dying.\n", gl_thread_self ());
+ dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
return NULL;
}
-void
+static void
test_lock (void)
{
int i;
/* Wait for the threads to terminate. */
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (threads[i]);
+ gl_thread_join (threads[i], NULL);
lock_checker_done = 1;
- gl_thread_join (checkerthread);
+ gl_thread_join (checkerthread, NULL);
check_accounts ();
}
+
+/* ----------------- Test read-write (non-recursive) locks ----------------- */
+
/* Test read-write locks by having several bank accounts and several threads
which shuffle around money between the accounts and several other threads
that check that all the money is still there. */
{
int i1, i2, value;
- dbgprintf ("Mutator %p before wrlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before wrlock\n", gl_thread_self_pointer ());
gl_rwlock_wrlock (my_rwlock);
- dbgprintf ("Mutator %p after wrlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after wrlock\n", gl_thread_self_pointer ());
i1 = random_account ();
i2 = random_account ();
- value = ((unsigned int) rand() >> 3) % 10;
+ value = ((unsigned int) rand () >> 3) % 10;
account[i1] += value;
account[i2] -= value;
- dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
gl_rwlock_unlock (my_rwlock);
- dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
yield ();
}
- dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
+ dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
return NULL;
}
{
while (!rwlock_checker_done)
{
- dbgprintf ("Checker %p before check rdlock\n", gl_thread_self ());
+ dbgprintf ("Checker %p before check rdlock\n", gl_thread_self_pointer ());
gl_rwlock_rdlock (my_rwlock);
check_accounts ();
gl_rwlock_unlock (my_rwlock);
- dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
yield ();
}
- dbgprintf ("Checker %p dying.\n", gl_thread_self ());
+ dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
return NULL;
}
-void
+static void
test_rwlock (void)
{
int i;
/* Wait for the threads to terminate. */
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (threads[i]);
+ gl_thread_join (threads[i], NULL);
rwlock_checker_done = 1;
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (checkerthreads[i]);
+ gl_thread_join (checkerthreads[i], NULL);
check_accounts ();
}
+
+/* -------------------------- Test recursive locks -------------------------- */
+
/* Test recursive locks by having several bank accounts and several threads
which shuffle around money between the accounts (recursively) and another
thread checking that all the money is still there. */
{
int i1, i2, value;
- dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before lock\n", gl_thread_self_pointer ());
gl_recursive_lock_lock (my_reclock);
- dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after lock\n", gl_thread_self_pointer ());
i1 = random_account ();
i2 = random_account ();
- value = ((unsigned int) rand() >> 3) % 10;
+ value = ((unsigned int) rand () >> 3) % 10;
account[i1] += value;
account[i2] -= value;
/* Recursive with probability 0.5. */
- if (((unsigned int) rand() >> 3) % 2)
+ if (((unsigned int) rand () >> 3) % 2)
recshuffle ();
- dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before unlock\n", gl_thread_self_pointer ());
gl_recursive_lock_unlock (my_reclock);
- dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after unlock\n", gl_thread_self_pointer ());
}
static void *
{
recshuffle ();
- dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before check lock\n", gl_thread_self_pointer ());
gl_recursive_lock_lock (my_reclock);
check_accounts ();
gl_recursive_lock_unlock (my_reclock);
- dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after check unlock\n", gl_thread_self_pointer ());
yield ();
}
- dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
+ dbgprintf ("Mutator %p dying.\n", gl_thread_self_pointer ());
return NULL;
}
{
while (!reclock_checker_done)
{
- dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
+ dbgprintf ("Checker %p before check lock\n", gl_thread_self_pointer ());
gl_recursive_lock_lock (my_reclock);
check_accounts ();
gl_recursive_lock_unlock (my_reclock);
- dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Checker %p after check unlock\n", gl_thread_self_pointer ());
yield ();
}
- dbgprintf ("Checker %p dying.\n", gl_thread_self ());
+ dbgprintf ("Checker %p dying.\n", gl_thread_self_pointer ());
return NULL;
}
-void
+static void
test_recursive_lock (void)
{
int i;
/* Wait for the threads to terminate. */
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (threads[i]);
+ gl_thread_join (threads[i], NULL);
reclock_checker_done = 1;
- gl_thread_join (checkerthread);
+ gl_thread_join (checkerthread, NULL);
check_accounts ();
}
+
+/* ------------------------ Test once-only execution ------------------------ */
+
/* Test once-only execution by having several threads attempt to grab a
once-only task simultaneously (triggered by releasing a read-write lock). */
break;
dbgprintf ("Contender %p waiting for signal for round %d\n",
- gl_thread_self (), repeat);
+ gl_thread_self_pointer (), repeat);
#if ENABLE_LOCKING
/* Wait for the signal to go. */
gl_rwlock_rdlock (fire_signal[repeat]);
yield ();
#endif
dbgprintf ("Contender %p got the signal for round %d\n",
- gl_thread_self (), repeat);
+ gl_thread_self_pointer (), repeat);
/* Contend for execution. */
gl_once (once_control, once_execute);
return NULL;
}
-void
+static void
test_once (void)
{
int i, repeat;
/* Wait for the threads to terminate. */
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (threads[i]);
+ gl_thread_join (threads[i], NULL);
}
+
+/* -------------------------------------------------------------------------- */
+
int
main ()
{
/* No multithreading available. */
+#include <stdio.h>
+
int
main ()
{
+ fputs ("Skipping test: multithreading not enabled\n", stderr);
return 77;
}