diff --git a/lib/glthread/cond.c b/lib/glthread/cond.c index e3073d5..d7a3626 100644 --- a/lib/glthread/cond.c +++ b/lib/glthread/cond.c @@ -18,11 +18,200 @@ /* Written by Yoann Vandoorselaere , 2008. */ #include +#include #include "glthread/cond.h" /* ========================================================================= */ +#if USE_WIN32_THREADS + +/* + * WIN32 implementation based on http://www.cs.wustl.edu/~schmidt/win32-cv-1.html + */ + +int glthread_cond_init_func(gl_cond_t *cv) +{ + cv->waiters_count = 0; + cv->wait_generation_count = 0; + cv->release_count = 0; + + InitializeCriticalSection(&cv->lock); + + /* Create a manual-reset event. */ + cv->event = CreateEvent (NULL, TRUE, FALSE, NULL); + cv->guard.done = 1; + + return 0; +} + + +static void +init_once(gl_cond_t *cv) +{ + if (!cv->guard.done) + { + if (InterlockedIncrement (&cv->guard.started) == 0) + /* This thread is the first one to need this lock. Initialize it. */ + glthread_cond_init (cv); + else + /* Yield the CPU while waiting for another thread to finish + initializing this lock. */ + while (!cv->guard.done) + Sleep (0); + } +} + + +int glthread_cond_destroy_func(gl_cond_t *cv) +{ + CloseHandle(cv->event); + return 0; +} + + +static int cond_wait(gl_cond_t *cv, gl_lock_t *external_mutex, DWORD msec) +{ + int ret, my_generation, wait_done; + + init_once(cv); + + EnterCriticalSection(&cv->lock); + + /* Increment count of waiters, + and store current generation in our activation record. */ + cv->waiters_count++; + my_generation = cv->wait_generation_count; + + LeaveCriticalSection(&cv->lock); + glthread_lock_unlock(external_mutex); + + do + { + /* Wait until the event is signaled. */ + ret = WaitForSingleObject (cv->event, msec); + if ( ret != WAIT_OBJECT_0 ) + break; + + EnterCriticalSection (&cv->lock); + /* Exit the loop when the event is signaled and there are still + waiting threads from this that haven't been released from this wait yet. + */ + wait_done = cv->release_count > 0 && cv->wait_generation_count != my_generation; + LeaveCriticalSection (&cv->lock); + } while (!wait_done); + + glthread_lock_lock(external_mutex); + EnterCriticalSection(&cv->lock); + cv->waiters_count--; + + if ( ret == WAIT_OBJECT_0 ) + { + if ( --cv->release_count == 0 ) + /* We're the last waiter to be notified, so reset the manual event. */ + ResetEvent (cv->event); + } + + LeaveCriticalSection (&cv->lock); + + return (ret == WAIT_TIMEOUT) ? ETIMEDOUT : (ret == WAIT_OBJECT_0) ? 0 : -1; +} + + +int glthread_cond_wait_func(gl_cond_t *cv, gl_lock_t *external_mutex) +{ + return cond_wait(cv, external_mutex, INFINITE); +} + + +/* Subtract the `struct timeval' values X and Y, + storing the result in RESULT. + Return 1 if the difference is negative, otherwise 0. */ + +static int +timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) +{ + /* Perform the carry for the later subtraction by updating y. */ + if (x->tv_usec < y->tv_usec) + { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) + { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + + /* Compute the time remaining to wait. + tv_usec is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} + + +int glthread_cond_timedwait_func(gl_cond_t *cv, gl_lock_t *external_mutex, struct timespec *ts) +{ + struct timeval res, now, end; + + end.tv_sec = ts->tv_sec; + end.tv_usec = ts->tv_nsec / 1000; + gettimeofday(&now, NULL); + + timeval_subtract(&res, &end, &now); + + return cond_wait(cv, external_mutex, (res.tv_sec * 1000) + (res.tv_usec / 1000)); +} + + +int glthread_cond_broadcast_func(gl_cond_t *cv) +{ + init_once(cv); + + EnterCriticalSection(&cv->lock); + /* The pthread_cond_broadcast() and pthread_cond_signal() functions shall + have no effect if there are no threads currently blocked on cond. + */ + if (cv->waiters_count > 0) + { + SetEvent(cv->event); + /* Release all the threads in this generation. */ + cv->release_count = cv->waiters_count; + cv->wait_generation_count++; + } + LeaveCriticalSection(&cv->lock); + + return 0; +} + + +int glthread_cond_signal_func(gl_cond_t *cv) +{ + init_once(cv); + + EnterCriticalSection(&cv->lock); + /* The pthread_cond_broadcast() and pthread_cond_signal() functions shall + have no effect if there are no threads currently blocked on cond. + */ + if (cv->waiters_count > cv->release_count) + { + SetEvent(cv->event); /* Signal the manual-reset event.*/ + cv->release_count++; + cv->wait_generation_count++; + } + LeaveCriticalSection(&cv->lock); + + return 0; +} + + +#endif + #if USE_PTH_THREADS /* -------------------------- gl_cond_t datatype -------------------------- */ diff --git a/lib/glthread/cond.h b/lib/glthread/cond.h index 5939004..54c150a 100644 --- a/lib/glthread/cond.h +++ b/lib/glthread/cond.h @@ -52,6 +52,7 @@ #include #include #include +#include #include "glthread/lock.h" @@ -266,13 +267,67 @@ extern int glthread_cond_timedwait_multithreaded (gl_cond_t *cond, gl_lock_t *lo #endif + +/* ========================================================================= */ + +#if USE_WIN32_THREADS + +# ifdef __cplusplus +extern "C" { +# endif + +/* -------------------------- gl_cond_t datatype -------------------------- */ + +typedef struct { + gl_spinlock_t guard; + CRITICAL_SECTION lock; + + int waiters_count; + int release_count; + int wait_generation_count; + HANDLE event; +} gl_cond_t; + +# define gl_cond_define(STORAGECLASS, NAME) \ + STORAGECLASS gl_cond_t NAME; +# define gl_cond_define_initialized(STORAGECLASS, NAME) \ + STORAGECLASS gl_cond_t NAME = gl_cond_initializer; +# define gl_cond_initializer \ + { { 0, -1 } } +# define glthread_cond_init(COND) \ + glthread_cond_init_func (COND) +# define glthread_cond_wait(COND, LOCK) \ + glthread_cond_wait_func (COND, LOCK) +# define glthread_cond_timedwait(COND, LOCK, ABSTIME) \ + glthread_cond_timedwait_func (COND, LOCK, ABSTIME) +# define glthread_cond_signal(COND) \ + glthread_cond_signal_func (COND) +# define glthread_cond_broadcast(COND) \ + glthread_cond_broadcast_func (COND) +# define glthread_cond_destroy(COND) \ + glthread_cond_destroy_func (COND) + +int glthread_cond_init_func(gl_cond_t *cv); +int glthread_cond_signal_func(gl_cond_t *cv); +int glthread_cond_broadcast_func(gl_cond_t *cv); +int glthread_cond_wait_func(gl_cond_t *cv, gl_lock_t *external_mutex); +int glthread_cond_timedwait_func(gl_cond_t *cv, gl_lock_t *external_mutex, struct timespec *ts); +int glthread_cond_destroy_func(gl_cond_t *cv); + +# ifdef __cplusplus +} +# endif + +#endif + /* ========================================================================= */ -#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS) +#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS) /* Provide dummy implementation if threads are not supported. */ typedef int gl_cond_t; +# define gl_cond_initializer 0 # define gl_cond_define(STORAGECLASS, NAME) # define gl_cond_define_initialized(STORAGECLASS, NAME) # define glthread_cond_init(COND) 0 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 b/modules/cond index c1a62a3..846a4b7 100644 --- a/modules/cond +++ b/modules/cond @@ -7,9 +7,12 @@ lib/glthread/cond.c m4/cond.m4 Depends-on: +errno +time threadlib lock stdbool +gettimeofday configure.ac: gl_COND diff --git a/modules/cond-tests b/modules/cond-tests new file mode 100644 index 0000000..98e0654 --- /dev/null +++ b/modules/cond-tests @@ -0,0 +1,13 @@ +Files: +tests/test-cond.c + +Depends-on: +thread +yield +sleep +gettimeofday + +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..b47ac53 --- /dev/null +++ b/tests/test-cond.c @@ -0,0 +1,212 @@ +/* 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 +#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]);