diff --git a/m4/thread.m4 b/m4/thread.m4 index df7ffd0..80bcf27 100644 --- a/m4/thread.m4 +++ b/m4/thread.m4 @@ -10,6 +10,9 @@ AC_DEFUN([gl_THREAD], AC_REQUIRE([AC_C_INLINE]) if test $gl_threads_api = posix; then + LIBS_bkp=$LIBS + LIBS="$LIBS $LIBMULTITHREAD" AC_CHECK_FUNCS([pthread_atfork]) + LIBS=$LIBS_bkp fi ]) diff --git a/modules/cond-tests b/modules/cond-tests new file mode 100644 index 0000000..d262d9e --- /dev/null +++ b/modules/cond-tests @@ -0,0 +1,11 @@ +Files: +tests/test-cond.c + +Depends-on: +thread +yield + +Makefile.am: +TESTS += test-cond +check_PROGRAMS += test-cond +test_cond_LDADD = $(LDADD) @LIBMULTITHREAD@ @YIELD_LIB@ diff --git a/modules/lock-tests b/modules/lock-tests index 7c72c94..21e2c98 100644 --- a/modules/lock-tests +++ b/modules/lock-tests @@ -2,20 +2,10 @@ Files: tests/test-lock.c Depends-on: - -configure.ac: -dnl Checks for special libraries for the tests/test-lock test. -dnl On some systems, sched_yield is in librt, rather than in libpthread. -LIBSCHED= -if test $gl_threads_api = posix; then - dnl Solaris has sched_yield in librt, not in libpthread or libc. - AC_CHECK_LIB(rt, sched_yield, [LIBSCHED=-lrt], - [dnl Solaris 2.5.1, 2.6 has sched_yield in libposix4, not librt. - AC_CHECK_LIB(posix4, sched_yield, [LIBSCHED=-lposix4])]) -fi -AC_SUBST([LIBSCHED]) +thread +yield Makefile.am: TESTS += test-lock check_PROGRAMS += test-lock -test_lock_LDADD = $(LDADD) @LIBMULTITHREAD@ @LIBSCHED@ +test_lock_LDADD = $(LDADD) @LIBMULTITHREAD@ @YIELD_LIB@ diff --git a/modules/tls-tests b/modules/tls-tests index b9f5a23..dcaad4c 100644 --- a/modules/tls-tests +++ b/modules/tls-tests @@ -2,21 +2,11 @@ Files: tests/test-tls.c Depends-on: - -configure.ac: -dnl Checks for special libraries for the tests/test-tls test. -dnl On some systems, sched_yield is in librt, rather than in libpthread. -LIBSCHED= -if test $gl_threads_api = posix; then - dnl Solaris has sched_yield in librt, not in libpthread or libc. - AC_CHECK_LIB(rt, sched_yield, [LIBSCHED=-lrt], - [dnl Solaris 2.5.1, 2.6 has sched_yield in libposix4, not librt. - AC_CHECK_LIB(posix4, sched_yield, [LIBSCHED=-lposix4])]) -fi -AC_SUBST([LIBSCHED]) +thread +yield Makefile.am: TESTS += test-tls check_PROGRAMS += test-tls -test_tls_LDADD = $(LDADD) @LIBMULTITHREAD@ @LIBSCHED@ +test_tls_LDADD = $(LDADD) @LIBMULTITHREAD@ @YIELD_LIB@ diff --git a/tests/test-cond.c b/tests/test-cond.c new file mode 100644 index 0000000..ac77158 --- /dev/null +++ b/tests/test-cond.c @@ -0,0 +1,211 @@ +/* Test of locking in multithreaded situations. + Copyright (C) 2005 Free Software Foundation, Inc. + + 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 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 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . */ + +#include + +#if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WIN32_THREADS + +/* Whether to enable locking. + Uncomment this to get a test program without locking, to verify that + it crashes. */ +#define ENABLE_LOCKING 1 + +/* Which tests to perform. + Uncomment some of these, to verify that all tests crash if no locking + is enabled. */ +#define DO_TEST_COND 1 +#define DO_TEST_TIMEDCOND 1 + + +/* Whether to help the scheduler through explicit yield(). + Uncomment this to see if the operating system has a fair scheduler. */ +#define EXPLICIT_YIELD 1 + +/* Whether to print debugging messages. */ +#define ENABLE_DEBUGGING 0 + +#include +#include +#include + +#if !ENABLE_LOCKING +# undef USE_POSIX_THREADS +# undef USE_SOLARIS_THREADS +# undef USE_PTH_THREADS +# undef USE_WIN32_THREADS +#endif + +#include "glthread/thread.h" +#include "glthread/cond.h" +#include "glthread/lock.h" +#include "glthread/yield.h" + +#if ENABLE_DEBUGGING +# define dbgprintf printf +#else +# define dbgprintf if (0) printf +#endif + +#if EXPLICIT_YIELD +# define yield() gl_thread_yield () +#else +# define yield() +#endif + + +/* + * Condition check + */ +#include +static int cond_value = 0; +static gl_cond_t condtest = gl_cond_initializer; +static gl_lock_t lockcond = gl_lock_initializer; + +static void * +cond_routine(void *arg) +{ + gl_lock_lock(lockcond); + while ( ! cond_value ) { + gl_cond_wait(condtest, lockcond); + } + gl_lock_unlock(lockcond); + + cond_value = 2; + + return NULL; +} + +void +test_cond() +{ + int remain = 2; + gl_thread_t thread; + + cond_value = 0; + + thread = gl_thread_create(cond_routine, NULL); + do { + yield(); + remain = sleep(remain); + } while (remain); + + /* signal condition */ + gl_lock_lock(lockcond); + cond_value = 1; + gl_cond_signal(condtest); + gl_lock_unlock(lockcond); + + gl_thread_join(thread, NULL); + + if ( cond_value != 2 ) + abort(); +} + + +/* + * Timed Condition check + */ +static int cond_timeout; + +static void get_ts(struct timespec *ts) +{ + struct timeval now; + + gettimeofday(&now, NULL); + + ts->tv_sec = now.tv_sec + 1; + ts->tv_nsec = now.tv_usec * 1000; +} + +static void * +timedcond_routine(void *arg) +{ + int ret; + struct timespec ts; + + gl_lock_lock(lockcond); + while ( ! cond_value ) { + get_ts(&ts); + ret = glthread_cond_timedwait(&condtest, &lockcond, &ts); + if ( ret == ETIMEDOUT ) + cond_timeout = 1; + } + gl_lock_unlock(lockcond); + + return NULL; +} + +void +test_timedcond() +{ + int remain = 2; + gl_thread_t thread; + + cond_value = cond_timeout = 0; + + thread = gl_thread_create(timedcond_routine, NULL); + + remain = 2; + do { + yield(); + remain = sleep(remain); + } while (remain); + + /* signal condition */ + gl_lock_lock(lockcond); + cond_value = 1; + gl_cond_signal(condtest); + gl_lock_unlock(lockcond); + + gl_thread_join(thread, NULL); + + if ( ! cond_timeout ) + abort(); +} + +int +main () +{ +#if TEST_PTH_THREADS + if (!pth_init ()) + abort (); +#endif + +#if DO_TEST_COND + printf ("Starting test_cond ..."); fflush (stdout); + test_cond (); + printf (" OK\n"); fflush (stdout); +#endif +#if DO_TEST_TIMEDCOND + printf ("Starting test_timedcond ..."); fflush (stdout); + test_timedcond (); + printf (" OK\n"); fflush (stdout); +#endif + + return 0; +} + +#else + +/* No multithreading available. */ + +int +main () +{ + return 77; +} + +#endif diff --git a/tests/test-lock.c b/tests/test-lock.c index 5faa8d8..e86bbae 100644 --- a/tests/test-lock.c +++ b/tests/test-lock.c @@ -20,19 +20,6 @@ #if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WIN32_THREADS -#if USE_POSIX_THREADS -# define TEST_POSIX_THREADS 1 -#endif -#if USE_SOLARIS_THREADS -# define TEST_SOLARIS_THREADS 1 -#endif -#if USE_PTH_THREADS -# define TEST_PTH_THREADS 1 -#endif -#if USE_WIN32_THREADS -# define TEST_WIN32_THREADS 1 -#endif - /* Whether to enable locking. Uncomment this to get a test program without locking, to verify that it crashes. */ @@ -71,7 +58,9 @@ # undef USE_PTH_THREADS # undef USE_WIN32_THREADS #endif +#include "glthread/thread.h" #include "glthread/lock.h" +#include "glthread/yield.h" #if ENABLE_DEBUGGING # define dbgprintf printf @@ -79,128 +68,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 @@ -310,9 +177,9 @@ 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 (); } @@ -392,10 +259,10 @@ 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 (); } @@ -490,9 +357,9 @@ 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 (); } @@ -639,7 +506,7 @@ 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 diff --git a/tests/test-tls.c b/tests/test-tls.c index b9806bb..715a3e6 100644 --- a/tests/test-tls.c +++ b/tests/test-tls.c @@ -50,6 +50,8 @@ #include #include +#include "glthread/thread.h" +#include "glthread/yield.h" #include "glthread/tls.h" #if ENABLE_DEBUGGING @@ -58,128 +60,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 @@ -288,7 +168,7 @@ test_tls (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); for (i = 0; i < KEYS_COUNT; i++) gl_tls_key_destroy (mykeys[i]);