X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=tests%2Ftest-lock.c;h=57392dbb86aa46060644e9cf3b39b2102e8d768b;hb=a8a1dc286152661e640f0839e3ccd79e0898db6d;hp=2153f223e820b41293801b9e3a1977aebac47508;hpb=a897449aaae8e6c051f3b9daaf984de5c5e092f3;p=gnulib.git diff --git a/tests/test-lock.c b/tests/test-lock.c index 2153f223e..57392dbb8 100644 --- a/tests/test-lock.c +++ b/tests/test-lock.c @@ -1,10 +1,10 @@ /* Test of locking in multithreaded situations. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2008-2013 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,16 +12,13 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ /* Written by Bruno Haible , 2005. */ -#ifdef HAVE_CONFIG_H -# include -#endif +#include -#if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WIN32_THREADS +#if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WINDOWS_THREADS #if USE_POSIX_THREADS # define TEST_POSIX_THREADS 1 @@ -32,8 +29,8 @@ #if USE_PTH_THREADS # define TEST_PTH_THREADS 1 #endif -#if USE_WIN32_THREADS -# define TEST_WIN32_THREADS 1 +#if USE_WINDOWS_THREADS +# define TEST_WINDOWS_THREADS 1 #endif /* Whether to enable locking. @@ -72,9 +69,27 @@ # undef USE_POSIX_THREADS # undef USE_SOLARIS_THREADS # undef USE_PTH_THREADS -# undef USE_WIN32_THREADS +# undef USE_WINDOWS_THREADS #endif -#include "lock.h" +#include "glthread/lock.h" + +#if !ENABLE_LOCKING +# if TEST_POSIX_THREADS +# define USE_POSIX_THREADS 1 +# endif +# if TEST_SOLARIS_THREADS +# define USE_SOLARIS_THREADS 1 +# endif +# if TEST_PTH_THREADS +# define USE_PTH_THREADS 1 +# endif +# if TEST_WINDOWS_THREADS +# define USE_WINDOWS_THREADS 1 +# endif +#endif + +#include "glthread/thread.h" +#include "glthread/yield.h" #if ENABLE_DEBUGGING # define dbgprintf printf @@ -82,128 +97,6 @@ # define dbgprintf if (0) printf #endif -#if TEST_POSIX_THREADS -# include -# include -typedef pthread_t gl_thread_t; -static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg) -{ - pthread_t thread; - if (pthread_create (&thread, NULL, func, arg) != 0) - abort (); - return thread; -} -static inline void gl_thread_join (gl_thread_t thread) -{ - void *retval; - if (pthread_join (thread, &retval) != 0) - abort (); -} -static inline void gl_thread_yield (void) -{ - sched_yield (); -} -static inline void * gl_thread_self (void) -{ - return (void *) pthread_self (); -} -#endif -#if TEST_PTH_THREADS -# include -typedef pth_t gl_thread_t; -static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg) -{ - pth_t thread = pth_spawn (NULL, func, arg); - if (thread == NULL) - abort (); - return thread; -} -static inline void gl_thread_join (gl_thread_t thread) -{ - if (!pth_join (thread, NULL)) - abort (); -} -static inline void gl_thread_yield (void) -{ - pth_yield (NULL); -} -static inline void * gl_thread_self (void) -{ - return pth_self (); -} -#endif -#if TEST_SOLARIS_THREADS -# include -typedef thread_t gl_thread_t; -static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg) -{ - thread_t thread; - if (thr_create (NULL, 0, func, arg, 0, &thread) != 0) - abort (); - return thread; -} -static inline void gl_thread_join (gl_thread_t thread) -{ - void *retval; - if (thr_join (thread, NULL, &retval) != 0) - abort (); -} -static inline void gl_thread_yield (void) -{ - thr_yield (); -} -static inline void * gl_thread_self (void) -{ - return (void *) thr_self (); -} -#endif -#if TEST_WIN32_THREADS -# include -typedef HANDLE gl_thread_t; -/* Use a wrapper function, instead of adding WINAPI through a cast. */ -struct wrapper_args { void * (*func) (void *); void *arg; }; -static DWORD WINAPI wrapper_func (void *varg) -{ - struct wrapper_args *warg = (struct wrapper_args *)varg; - void * (*func) (void *) = warg->func; - void *arg = warg->arg; - free (warg); - func (arg); - return 0; -} -static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg) -{ - struct wrapper_args *warg = - (struct wrapper_args *) malloc (sizeof (struct wrapper_args)); - if (warg == NULL) - abort (); - warg->func = func; - warg->arg = arg; - { - DWORD thread_id; - HANDLE thread = - CreateThread (NULL, 100000, wrapper_func, warg, 0, &thread_id); - if (thread == NULL) - abort (); - return thread; - } -} -static inline void gl_thread_join (gl_thread_t thread) -{ - if (WaitForSingleObject (thread, INFINITE) == WAIT_FAILED) - abort (); - if (!CloseHandle (thread)) - abort (); -} -static inline void gl_thread_yield (void) -{ - Sleep (0); -} -static inline void * gl_thread_self (void) -{ - return (void *) GetCurrentThreadId (); -} -#endif #if EXPLICIT_YIELD # define yield() gl_thread_yield () #else @@ -217,7 +110,7 @@ static int account[ACCOUNT_COUNT]; static int random_account (void) { - return ((unsigned int) rand() >> 3) % ACCOUNT_COUNT; + return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT; } static void @@ -232,6 +125,9 @@ check_accounts (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. */ @@ -247,30 +143,30 @@ lock_mutator_thread (void *arg) { 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; } @@ -281,20 +177,20 @@ lock_checker_thread (void *arg) { 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; @@ -313,12 +209,15 @@ test_lock (void) /* 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. */ @@ -334,24 +233,24 @@ rwlock_mutator_thread (void *arg) { 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; } @@ -362,20 +261,20 @@ rwlock_checker_thread (void *arg) { 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; @@ -395,13 +294,16 @@ test_rwlock (void) /* 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. */ @@ -413,23 +315,23 @@ recshuffle (void) { 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 * @@ -441,16 +343,16 @@ reclock_mutator_thread (void *arg) { 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; } @@ -461,20 +363,20 @@ reclock_checker_thread (void *arg) { 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; @@ -493,12 +395,15 @@ test_recursive_lock (void) /* 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). */ @@ -536,10 +441,10 @@ once_contender_thread (void *arg) gl_lock_unlock (ready_lock[id]); if (repeat == REPEAT_COUNT) - break; + 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]); @@ -548,10 +453,10 @@ once_contender_thread (void *arg) #else /* Wait for the signal to go. */ while (fire_signal_state <= repeat) - yield (); + 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); @@ -560,7 +465,7 @@ once_contender_thread (void *arg) return NULL; } -void +static void test_once (void) { int i, repeat; @@ -590,32 +495,32 @@ test_once (void) for (repeat = 0; repeat <= REPEAT_COUNT; repeat++) { /* Wait until every thread is ready. */ - dbgprintf ("Main thread before synchonizing for round %d\n", repeat); + dbgprintf ("Main thread before synchronizing for round %d\n", repeat); for (;;) - { - int ready_count = 0; - for (i = 0; i < THREAD_COUNT; i++) - { - gl_lock_lock (ready_lock[i]); - ready_count += ready[i]; - gl_lock_unlock (ready_lock[i]); - } - if (ready_count == THREAD_COUNT) - break; - yield (); - } - dbgprintf ("Main thread after synchonizing for round %d\n", repeat); + { + int ready_count = 0; + for (i = 0; i < THREAD_COUNT; i++) + { + gl_lock_lock (ready_lock[i]); + ready_count += ready[i]; + gl_lock_unlock (ready_lock[i]); + } + if (ready_count == THREAD_COUNT) + break; + yield (); + } + dbgprintf ("Main thread after synchronizing for round %d\n", repeat); if (repeat > 0) - { - /* Check that exactly one thread executed the once_execute() - function. */ - if (performed != 1) - abort (); - } + { + /* Check that exactly one thread executed the once_execute() + function. */ + if (performed != 1) + abort (); + } if (repeat == REPEAT_COUNT) - break; + break; /* Preparation for the next round: Initialize once_control. */ memcpy (&once_control, &fresh_once, sizeof (gl_once_t)); @@ -625,11 +530,11 @@ test_once (void) /* Preparation for the next round: Reset the ready flags. */ for (i = 0; i < THREAD_COUNT; i++) - { - gl_lock_lock (ready_lock[i]); - ready[i] = 0; - gl_lock_unlock (ready_lock[i]); - } + { + gl_lock_lock (ready_lock[i]); + ready[i] = 0; + gl_lock_unlock (ready_lock[i]); + } /* Signal all threads simultaneously. */ dbgprintf ("Main thread giving signal for round %d\n", repeat); @@ -642,9 +547,12 @@ test_once (void) /* 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 () { @@ -681,9 +589,12 @@ main () /* No multithreading available. */ +#include + int main () { + fputs ("Skipping test: multithreading not enabled\n", stderr); return 77; }