From e2fd6e2de322cc12d9153da548ab76379049c11c Mon Sep 17 00:00:00 2001 From: rpj Date: Tue, 25 Jul 2000 16:14:23 +0000 Subject: 2000-07-25 Ross Johnson * sched.c (sched_get_priority_max): Handle different WinCE and Win32 priority values together. (sched_get_priority_min): Ditto. - Tristan Savatier * create.c (pthread_create): Force new threads to wait until pthread_create has the new thread's handle; we also retain a local copy of the handle for internal use until pthread_create returns. * private.c (_pthread_threadStart): Initialise ei[]. (_pthread_threadStart): When beginthread is used to start the thread, force waiting until the creator thread had the thread handle. * cancel.c (_pthread_cancel_thread): Include context switch code for defined(_X86_) environments in addition to _M_IX86. * rwlock.c (pthread_rwlock_destroy): Assignment changed to avoid compiler warning. * private.c (_pthread_get_exception_services_code): Cast NULL return value to avoid compiler warning. * cleanup.c (pthread_pop_cleanup): Initialise "cleanup" variable to avoid compiler warnings. * misc.c (_pthread_new): Change "new" variable to "t" to avoid confusion with the C++ keyword of the same name. * condvar.c (cond_wait_cleanup): Initialise lastWaiter variable. (cond_timedwait): Remove unused local variables. to avoid compiler warnings. * dll.c (dllMain): Remove 2000-07-21 change - problem appears to be in pthread_create(). 2000-07-22 Ross Johnson * tsd.c (pthread_key_create): If a destructor was given and the pthread_mutex_init failed, then would try to reference a NULL pointer (*key); eliminate this section of code by using a dynamically initialised mutex (PTHREAD_MUTEX_INITIALIZER). * tsd.c (pthread_setspecific): Return an error if unable to set the value; simplify cryptic conditional. * tsd.c (pthread_key_delete): Locking threadsLock relied on mutex_lock returning an error if the key has no destructor. ThreadsLock is only initialised if the key has a destructor. Making this mutex a static could reduce the number of mutexes used by an application since it is actually created only at first use and it's often destroyed soon after. 2000-07-22 Ross Johnson * FAQ: Added Q5 and Q6. tests/ChangeLog: 2000-07-25 Ross Johnson * runtest.bat: modified to work under W98. * runall.bat: Add new tests; modified to work under W98. It was ok under NT. * Makefile: Add new tests. * exception1.c: New; Test passing exceptions back to the application and retaining library internal exceptions. * join0.c: New; Test a single join. --- ChangeLog | 90 +++++++++++++++++++++++++++++++- FAQ | 68 +++++++++++++++++++++++++ GNUmakefile | 140 +++++++++++++++++++++++++------------------------- Makefile | 12 +++-- README.WinCE | 13 +---- TODO | 23 +++++++-- attr.c | 9 +++- cancel.c | 14 ++--- cleanup.c | 19 ++++--- condvar.c | 4 +- config.h | 16 ++++++ config.h.in | 16 ++++++ create.c | 44 ++++++++++++---- dll.c | 6 +++ implement.h | 2 +- misc.c | 16 +++--- mutex.c | 35 ++++++++++--- private.c | 34 +++++++++---- pthread.h | 31 +++++++---- rwlock.c | 2 +- sched.c | 30 ++++++++++- signal.c | 2 +- tests/ChangeLog | 14 +++++ tests/Makefile | 7 ++- tests/cancel2.c | 3 +- tests/cancel3.c | 4 +- tests/cancel4.c | 2 +- tests/ccl.bat | 18 +++---- tests/join1.c | 13 +++-- tests/loadfree.c | 2 +- tests/runall.bat | 130 +++++++++++++++++++++++----------------------- tests/runtest.bat | 150 +++++++++++++++++++++++++++++------------------------- tsd.c | 63 +++++++++++++---------- 33 files changed, 695 insertions(+), 337 deletions(-) diff --git a/ChangeLog b/ChangeLog index e1adedd..8a1a53c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,64 @@ -2000-07-25 Ross Johnson +2000-07-25 Ross Johnson + + * sched.c (sched_get_priority_max): Handle different WinCE and + Win32 priority values together. + (sched_get_priority_min): Ditto. + - Tristan Savatier + + * create.c (pthread_create): Force new threads to wait until + pthread_create has the new thread's handle; we also retain + a local copy of the handle for internal use until + pthread_create returns. + + * private.c (_pthread_threadStart): Initialise ei[]. + (_pthread_threadStart): When beginthread is used to start the + thread, force waiting until the creator thread had the + thread handle. + + * cancel.c (_pthread_cancel_thread): Include context switch + code for defined(_X86_) environments in addition to _M_IX86. + + * rwlock.c (pthread_rwlock_destroy): Assignment changed + to avoid compiler warning. + + * private.c (_pthread_get_exception_services_code): Cast + NULL return value to avoid compiler warning. + + * cleanup.c (pthread_pop_cleanup): Initialise "cleanup" variable + to avoid compiler warnings. + + * misc.c (_pthread_new): Change "new" variable to "t" to avoid + confusion with the C++ keyword of the same name. + + * condvar.c (cond_wait_cleanup): Initialise lastWaiter variable. + (cond_timedwait): Remove unused local variables. to avoid + compiler warnings. * dll.c (dllMain): Remove 2000-07-21 change - problem appears to be in pthread_create(). +2000-07-22 Ross Johnson + + * tsd.c (pthread_key_create): If a destructor was given + and the pthread_mutex_init failed, then would try to + reference a NULL pointer (*key); eliminate this section of + code by using a dynamically initialised mutex + (PTHREAD_MUTEX_INITIALIZER). + + * tsd.c (pthread_setspecific): Return an error if + unable to set the value; simplify cryptic conditional. + + * tsd.c (pthread_key_delete): Locking threadsLock relied + on mutex_lock returning an error if the key has no destructor. + ThreadsLock is only initialised if the key has a destructor. + Making this mutex a static could reduce the number of mutexes + used by an application since it is actually created only at + first use and it's often destroyed soon after. + +2000-07-22 Ross Johnson + + * FAQ: Added Q5 and Q6. + 2000-07-21 Ross Johnson * create.c (pthread_create): Set threadH to 0 (zero) @@ -29,6 +85,38 @@ * signal.c (pthread_sigmask): return an error value if pthread_self() returns NULL. +2000-03-02 Ross Johnson + + * attr.c (pthread_attr_init): Set default stacksize to zero (0) + rather than PTHREAD_STACK_MIN even though these are now the same. + + * pthread.h (PTHREAD_STACK_MIN): Lowered to 0. + +2000-01-28 Ross Johnson + + * mutex.c (pthread_mutex_init): Free mutex if it has been alloced; + if critical sections can be used instead of Win32 mutexes, test + that the critical section works and return an error if not. + +2000-01-07 Ross Johnson + + * cleanup.c (pthread_pop_cleanup): Include SEH code only if MSC is not + compiling as C++. + (pthread_push_cleanup): Include SEH code only if MSC is not + compiling as C++. + + * pthread.h: Include SEH code only if MSC is not + compiling as C++. + + * implement.h: Include SEH code only if MSC is not + compiling as C++. + + * cancel.c (_pthread_cancel_thread): Add _M_IX86 check. + (pthread_testcancel): Include SEH code only if MSC is not + compiling as C++. + (_pthread_cancel_self): Include SEH code only if MSC is not + compiling as C++. + 2000-01-06 Ross Johnson * Makefile: Remove inconsistencies in 'cl' args diff --git a/FAQ b/FAQ index 426e92c..f6da212 100644 --- a/FAQ +++ b/FAQ @@ -14,6 +14,10 @@ Q 3 How do I use pthread.dll for Win32 (Visual C++ 5.0) Q 4 Cancelation doesn't work for me, why? +Q 5 Thread won't block after two calls to mutex_lock + +Q 6 How do I generate libpthread.a for use with Mingw32? + ============================================================================= Q 1 Should I use Cygwin or Mingw32 as a development environment? @@ -253,3 +257,67 @@ a thread is going to block on a Win32 handle. These are: Regards. Ross +------------------------------------------------------------------------------ + +Q 5 Thread won't block after two calls to mutex_lock +--- + +A 5 +--- + +> i was testing this pthread for win32 in my prog. +> when i checked if it was blocking mutex_lock calls, i was surprised when it +> didnt lock +> +> pthread_mutex_t DBlock; +> +> pthread_mutex_init( &DBlock, NULL ); +> pthread_mutex_lock( &DBlock ); +> pthread_mutex_lock( &DBlock ); +> +> ^^ these two calls didnt block + +POSIX leaves the result "undefined" for a thread that tries +to recursively lock the same mutex (one that it owns already). +That means the actual semantics are left up to the +implementation, but should not be relied upon for code that +will be ported to different POSIX threads implementations. + +In the pthreads-win32 implementation a thread won't deadlock +itself by relocking the mutex. Subsequent calls to +pthread_mutex_lock() as in your example above increment +the lock count but the thread continues on. Consequently, +the thread must ensure that it unlocks the mutex once for +each lock operation. That is, pthreads-win32 mutexes are +always recursive. + +You may want to look at the other synchronisation devices +available in the library, such as condition variables or +read-write locks. + +Ross + +------------------------------------------------------------------------------ + +Q 6 How do I generate libpthread.a for use with Mingw32? +--- + +A 6 +--- + +> I'm lacking the libpthread.a that +> used to come with the pre-compiled package. The last time this +> library appeared was in 1999-08-12. Without this library I cannot +> use the pre-compiled dll. + +You can create libpthread.a from the .def file, should work along these +lines: + +$(DLLTOOL) --as $(AS) -k --dllname libpthread.dll --output-lib +libpthread.a --def $(srcdir)/libpthread.def + +Where DLLTOOL is i686-pc-cygwin-dlltool +and AS i686-pc-cygwin-as. + +Thomas Sailer + diff --git a/GNUmakefile b/GNUmakefile index f0d8982..4c94cc7 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,69 +1,71 @@ -# -# Pthreads-win32 - POSIX Threads Library for Win32 -# Copyright (C) 1998 -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Library General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library 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 -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this library; if not, write to the Free -# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -# MA 02111-1307, USA -# - -RM = erase - -CC = g++ - -AR = ar - -LD = gcc -mdll - -OPT = -g -O2 - -## Mingw32 -CFLAGS = $(OPT) -I. -DHAVE_CONFIG_H -Wall - -## Cygwin G++ -#CFLAGS = $(OPT) -fhandle-exceptions -I. -DHAVE_CONFIG_H -Wall - -OBJS = attr.o cancel.o cleanup.o condvar.o create.o dll.o errno.o \ - exit.o fork.o global.o misc.o mutex.o private.o rwlock.o \ - sched.o semaphore.o signal.o sync.o tsd.o - -INCL = implement.h semaphore.h pthread.h windows.h - -DLL = pthread.dll - -LIB = libpthread32.a - - -all: $(LIB) - -$(LIB): $(DLL) - dlltool --def $(DLL:.dll=.def) --output-lib $@ --dllname $(DLL) - -.SUFFIXES: .dll - -$(DLL): $(OBJS) - $(LD) -o $@ $^ -Wl,--base-file,$*.base - dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@ - $(LD) -o $@ $^ -Wl,--base-file,$*.base,$*.exp - dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@ - $(LD) -o $@ $^ -Wl,$*.exp - -clean: - -$(RM) *~ - -$(RM) $(LIB) - -$(RM) *.o - -$(RM) *.exe - -$(RM) $(DLL) - -$(RM) $(DLL:.dll=.base) - -$(RM) $(DLL:.dll=.exp) +# +# Pthreads-win32 - POSIX Threads Library for Win32 +# Copyright (C) 1998 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA +# + +GLANG = c++ + +RM = erase + +CC = gcc + +AR = ar + +LD = gcc -mdll + +OPT = -g -O2 -x $(GLANG) + +## Mingw32 +CFLAGS = $(OPT) -I. -DHAVE_CONFIG_H -Wall + +## Cygwin G++ +#CFLAGS = $(OPT) -fhandle-exceptions -I. -DHAVE_CONFIG_H -Wall + +OBJS = attr.o cancel.o cleanup.o condvar.o create.o dll.o errno.o \ + exit.o fork.o global.o misc.o mutex.o private.o rwlock.o \ + sched.o semaphore.o signal.o sync.o tsd.o + +INCL = implement.h semaphore.h pthread.h windows.h + +DLL = pthread.dll + +LIB = libpthread32.a + + +all: $(LIB) + +$(LIB): $(DLL) + dlltool --def $(DLL:.dll=.def) --output-lib $@ --dllname $(DLL) + +.SUFFIXES: .dll + +$(DLL): $(OBJS) + $(LD) -o $@ $^ -Wl,--base-file,$*.base + dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@ + $(LD) -o $@ $^ -Wl,--base-file,$*.base,$*.exp + dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@ + $(LD) -o $@ $^ -Wl,$*.exp + +clean: + -$(RM) *~ + -$(RM) $(LIB) + -$(RM) *.o + -$(RM) *.exe + -$(RM) $(DLL) + -$(RM) $(DLL:.dll=.base) + -$(RM) $(DLL:.dll=.exp) diff --git a/Makefile b/Makefile index b5b10e5..1264af9 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,9 @@ DEVROOT=e: DLLDEST=$(DEVROOT)\dll LIBDEST=$(DEVROOT)\lib -CLIB=/MD +#CLIB = /MD +CLIB = /MT +CFLAGS = #/EHsc /TP OBJ=attr.obj \ cancel.obj \ @@ -46,10 +48,14 @@ install: all copy pthread.lib $(LIBDEST) pthread.dll: $(OBJ) pthread.def - cl /LDd /Zi $(CLIB) $(OBJ) /Fepthread.dll pthread.def + cl /LD /Zi $(CFLAGS) $(OBJ) /Fepthread.dll /link \ + /nodefaultlib:libcmt \ + /implib:pthread.lib \ + msvcrt.lib \ + /def:pthread.def .c.obj:: - cl /W3 $(CLIB) /nologo /Yd /Zi /I. \ + cl /W3 $(CLIB) $(CFLAGS) /nologo /Yd /Zi /I. \ /D_WIN32_WINNT=0x400 \ /DSTDCALL=_stdcall \ -c $< diff --git a/README.WinCE b/README.WinCE index 2d4212e..a2cd8c2 100644 --- a/README.WinCE +++ b/README.WinCE @@ -2,14 +2,5 @@ WinCE port ---------- (See the file WinCE-PORT for a detailed explanation.) -In config.h: - -you need to define the following which are undefined by default: - -#define NEED_DUPLICATEHANDLE -#define NEED_CREATETHREAD -#define NEED_ERRNO -#define NEED_CALLOC -#define NEED_FTIME -#define NEED_SEM - +Make sure you define "WINCE" amongst your compiler flags (eg. -DWINCE). +The config.h file will define all the necessary defines for you. diff --git a/TODO b/TODO index fabce6d..32cd822 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,20 @@ -- Check behaviour of calling pthread_exit from main(). - The main thread should wait for other threads to exit - before calling exit. +==== +Automate the build/test cycle so that I can +expand to test both library and applications in different +environments and cross-environments. + +Eg. + Applications | SEH | C++ | G++ | C | GCC | + Library | | | | | | + ----------------+-----+-----+-----+-----+-----+ + SEH | X | X | X | X | X | + ----------------+-----+-----+-----+-----+-----+ + C++ (MSC) | X | X | X | X | X | + ----------------+-----+-----+-----+-----+-----+ + G++ (GNU) | ? | ? | X | ? | X | + ----------------+-----+-----+-----+-----+-----+ + +'?' indicates combinations that may not be doable. + +==== + diff --git a/attr.c b/attr.c index fa7de12..84c35a5 100644 --- a/attr.c +++ b/attr.c @@ -84,7 +84,7 @@ pthread_attr_setstacksize(pthread_attr_t *attr, { #ifdef _POSIX_THREAD_ATTR_STACKSIZE - /* Verify that the stack size is within range. */ + /* Verify that the stack size is within range. */ if (stacksize < PTHREAD_STACK_MIN) { return EINVAL; @@ -324,7 +324,12 @@ pthread_attr_init(pthread_attr_t *attr) } #ifdef _POSIX_THREAD_ATTR_STACKSIZE - attr_result->stacksize = PTHREAD_STACK_MIN; + /* + * Default to zero size. Unless changed explicitly this + * will allow Win32 to set the size to that of the + * main thread. + */ + attr_result->stacksize = 0; #endif #ifdef _POSIX_THREAD_ATTR_STACKADDR diff --git a/cancel.c b/cancel.c index b687c78..c072d44 100644 --- a/cancel.c +++ b/cancel.c @@ -30,7 +30,7 @@ static void _pthread_cancel_self(void) { -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__cplusplus) DWORD exceptionInformation[3]; @@ -44,7 +44,7 @@ _pthread_cancel_self(void) 3, exceptionInformation); -#else /* _MSC_VER */ +#else /* _MSC_VER && ! __cplusplus */ # ifdef __cplusplus @@ -52,7 +52,7 @@ _pthread_cancel_self(void) # endif /* __cplusplus */ -#endif /* _MSC_VER */ +#endif /* _MSC_VER && ! __cplusplus */ /* Never reached */ } @@ -72,11 +72,13 @@ _pthread_cancel_thread(pthread_t thread) if (WaitForSingleObject(threadH, 0) == WAIT_TIMEOUT) { +#if defined(_M_IX86) || defined(_X86_) CONTEXT context; context.ContextFlags = CONTEXT_CONTROL; GetThreadContext(threadH, &context); context.Eip = (DWORD) _pthread_cancel_self; SetThreadContext(threadH, &context); +#endif ResumeThread(threadH); } @@ -292,7 +294,7 @@ pthread_testcancel (void) * Canceling! */ -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__cplusplus) DWORD exceptionInformation[3]; @@ -306,7 +308,7 @@ pthread_testcancel (void) 3, exceptionInformation); -#else /* _MSC_VER */ +#else /* _MSC_VER && ! __cplusplus */ #ifdef __cplusplus @@ -314,7 +316,7 @@ pthread_testcancel (void) #endif /* __cplusplus */ -#endif /* _MSC_VER */ +#endif /* _MSC_VER && ! __cplusplus */ } } /* pthread_testcancel */ diff --git a/cleanup.c b/cleanup.c index b92d502..14ed0af 100644 --- a/cleanup.c +++ b/cleanup.c @@ -2,8 +2,9 @@ * cleanup.c * * Description: - * This translation unit implements routines associated cleaning up - * threads. + * This translation unit implements routines associated + * with cleaning up threads. + * * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright (C) 1998 @@ -33,6 +34,12 @@ #include "pthread.h" #include "implement.h" +/* + * The functions pthread_pop_cleanup and pthread_push_cleanup + * are implemented here for applications written in C with no + * SEH or C++ destructor support. + */ + _pthread_cleanup_t * pthread_pop_cleanup (int execute) /* @@ -60,7 +67,7 @@ pthread_pop_cleanup (int execute) * ------------------------------------------------------ */ { - _pthread_cleanup_t *cleanup; + _pthread_cleanup_t *cleanup = NULL; cleanup = (_pthread_cleanup_t *) pthread_getspecific (_pthread_cleanupKey); @@ -69,7 +76,7 @@ pthread_pop_cleanup (int execute) if (execute && (cleanup->routine != NULL)) { -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__cplusplus) __try { @@ -87,7 +94,7 @@ pthread_pop_cleanup (int execute) */ } -#else /* _MSC_VER */ +#else /* _MSC_VER && ! __cplusplus */ #ifdef __cplusplus @@ -114,7 +121,7 @@ pthread_pop_cleanup (int execute) */ (*cleanup->routine) (cleanup->arg); -#endif /* __cplusplus */ +#endif /* __cplusplus && ! __cplusplus */ #endif /* _MSC_VER */ diff --git a/condvar.c b/condvar.c index 69ce69f..98f1f23 100644 --- a/condvar.c +++ b/condvar.c @@ -540,7 +540,7 @@ cond_wait_cleanup(void * args) pthread_cond_t cv = cleanup_args->cv; int * resultPtr = cleanup_args->resultPtr; int lock_result; - int lastWaiter; + int lastWaiter = FALSE; if ((lock_result = pthread_mutex_lock (&(cv->waitersLock))) == 0) { @@ -590,8 +590,6 @@ cond_timedwait (pthread_cond_t * cond, const struct timespec *abstime) { int result = 0; - int internal_result = 0; - int lastWaiter = FALSE; pthread_cond_t cv; cond_wait_cleanup_args_t cleanup_args; diff --git a/config.h b/config.h index 41f703f..acea758 100644 --- a/config.h +++ b/config.h @@ -23,3 +23,19 @@ /* Define if you don't have Win32 semaphores. (eg. WinCE) */ #undef NEED_SEM + +/* Define if you need to convert string parameters to unicode. (eg. WinCE) */ +#undef NEED_UNICODE_CONSTS + +/* + * Target specific groups + */ +#ifdef WINCE +#define NEED_DUPLICATEHANDLE +#define NEED_CREATETHREAD +#define NEED_ERRNO +#define NEED_CALLOC +#define NEED_FTIME +#define NEED_SEM +#define NEED_UNICODE_CONSTS +#endif diff --git a/config.h.in b/config.h.in index 41f703f..acea758 100644 --- a/config.h.in +++ b/config.h.in @@ -23,3 +23,19 @@ /* Define if you don't have Win32 semaphores. (eg. WinCE) */ #undef NEED_SEM + +/* Define if you need to convert string parameters to unicode. (eg. WinCE) */ +#undef NEED_UNICODE_CONSTS + +/* + * Target specific groups + */ +#ifdef WINCE +#define NEED_DUPLICATEHANDLE +#define NEED_CREATETHREAD +#define NEED_ERRNO +#define NEED_CALLOC +#define NEED_FTIME +#define NEED_SEM +#define NEED_UNICODE_CONSTS +#endif diff --git a/create.c b/create.c index ac1384f..48d0984 100644 --- a/create.c +++ b/create.c @@ -68,6 +68,7 @@ pthread_create (pthread_t * tid, */ { pthread_t thread; + HANDLE threadH = 0; int result = EAGAIN; int run = TRUE; ThreadParms *parms = NULL; @@ -90,8 +91,7 @@ pthread_create (pthread_t * tid, goto FAIL0; } - if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == - NULL) + if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL) { goto FAIL0; } @@ -117,7 +117,7 @@ pthread_create (pthread_t * tid, /* * Default stackSize */ - stackSize = 0; + stackSize = PTHREAD_STACK_MIN; } thread->state = run @@ -126,20 +126,40 @@ pthread_create (pthread_t * tid, thread->keys = NULL; + /* + * Threads must be started in suspended mode and resumed if necessary + * after _beginthreadex returns us the handle. Otherwise we set up a + * race condition between the creating and the created threads. + * Note that we also retain a local copy of the handle for use + * by us in case thread->threadH gets NULLed later but before we've + * finished with it here. + */ + #if ! defined (__MINGW32__) || defined (__MSVCRT__) - thread->threadH = (HANDLE) + thread->threadH = threadH = (HANDLE) _beginthreadex ( (void *) NULL, /* No security info */ (unsigned) stackSize, /* default stack size */ (unsigned (PT_STDCALL *) (void *)) _pthread_threadStart, parms, - (unsigned) run ? 0 : CREATE_SUSPENDED, + (unsigned) CREATE_SUSPENDED, (unsigned *) &(thread->thread)); + if (threadH != 0 && run) + { + ResumeThread(threadH); + } + #else /* __MINGW32__ && ! __MSVCRT__ */ - thread->threadH = (HANDLE) + /* + * This lock will force pthread_threadStart() to wait until we have + * the thread handle. + */ + (void) pthread_mutex_lock(&thread->cancelLock); + + thread->threadH = threadH = (HANDLE) _beginthread ( (void (*) (void *)) _pthread_threadStart, (unsigned) stackSize, /* default stack size */ @@ -148,23 +168,25 @@ pthread_create (pthread_t * tid, /* * Make the return code match _beginthreadex's. */ - if (thread->threadH == (HANDLE)-1L) + if (threadH == (HANDLE) -1L) { - thread->threadH = 0; + thread->threadH = threadH = 0; } else if (! run) { - /* + /* * beginthread does not allow for create flags, so we do it now. * Note that beginthread itself creates the thread in SUSPENDED * mode, and then calls ResumeThread to start it. */ - SuspendThread (thread->threadH); + SuspendThread (threadH); } + (void) pthread_mutex_unlock(&thread->cancelLock); + #endif /* __MINGW32__ && ! __MSVCRT__ */ - result = (thread->threadH != 0) ? 0 : EAGAIN; + result = (threadH != 0) ? 0 : EAGAIN; /* * Fall Through Intentionally diff --git a/dll.c b/dll.c index b0d4d2a..ef724bf 100644 --- a/dll.c +++ b/dll.c @@ -88,8 +88,14 @@ DllMain ( _pthread_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); _pthread_try_enter_critical_section = (BOOL (PT_STDCALL *)(LPCRITICAL_SECTION)) + +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress(_pthread_h_kernel32, + (const TCHAR *)TEXT("TryEnterCriticalSection")); +#else GetProcAddress(_pthread_h_kernel32, (LPCSTR) "TryEnterCriticalSection"); +#endif if (_pthread_try_enter_critical_section != NULL) { diff --git a/implement.h b/implement.h index 4012301..76adb1f 100644 --- a/implement.h +++ b/implement.h @@ -239,7 +239,7 @@ struct ThreadKeyAssoc { }; -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__cplusplus) /* * -------------------------------------------------------------- * MAKE_SOFTWARE_EXCEPTION diff --git a/misc.c b/misc.c index f2f5695..aa78752 100644 --- a/misc.c +++ b/misc.c @@ -383,19 +383,19 @@ pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout) pthread_t _pthread_new (void) { - pthread_t new; + pthread_t t; - new = (pthread_t) calloc (1, sizeof (*new)); + t = (pthread_t) calloc (1, sizeof (*t)); - if (new != NULL) + if (t != NULL) { - new->detachState = PTHREAD_CREATE_JOINABLE; - new->cancelState = PTHREAD_CANCEL_ENABLE; - new->cancelType = PTHREAD_CANCEL_DEFERRED; - new->cancelLock = PTHREAD_MUTEX_INITIALIZER; + t->detachState = PTHREAD_CREATE_JOINABLE; + t->cancelState = PTHREAD_CANCEL_ENABLE; + t->cancelType = PTHREAD_CANCEL_DEFERRED; + t->cancelLock = PTHREAD_MUTEX_INITIALIZER; } - return new; + return t; } diff --git a/mutex.c b/mutex.c index bef116e..448ad2a 100644 --- a/mutex.c +++ b/mutex.c @@ -22,7 +22,7 @@ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA */ - + /* errno.h or a replacement file is included by pthread.h */ //#include @@ -125,11 +125,12 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) #error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet. - mx->mutex = CreateMutex ( - NULL, - FALSE, - ????); - result = (mx->mutex == 0) ? EAGAIN : 0; + mx->mutex = CreateMutex(NULL, FALSE, "FIXME FIXME FIXME"); + + if (mx->mutex == 0) + { + result = EAGAIN; + } #else @@ -149,6 +150,20 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) * Create a critical section. */ InitializeCriticalSection(&mx->cs); + + /* + * Check that it works ok - since InitializeCriticalSection doesn't + * return success or failure. + */ + if (TryEnterCriticalSection(&mx->cs)) + { + LeaveCriticalSection(&mx->cs); + } + else + { + DeleteCriticalSection(&mx->cs); + result = EAGAIN; + } } else { @@ -163,12 +178,16 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) if (mx->mutex == 0) { result = EAGAIN; - mx = NULL; - goto FAIL0; } } } + if (result != 0 && mx != NULL) + { + free(mx); + mx = NULL; + } + FAIL0: *mutex = mx; diff --git a/private.c b/private.c index 5af936b..f374e27 100644 --- a/private.c +++ b/private.c @@ -187,7 +187,7 @@ _pthread_threadStart (ThreadParms * threadParms) #ifdef _MSC_VER - DWORD ei[3]; + DWORD ei[] = {0,0,0}; #endif @@ -197,13 +197,24 @@ _pthread_threadStart (ThreadParms * threadParms) start = threadParms->start; arg = threadParms->arg; + free (threadParms); + #if defined (__MINGW32__) && ! defined (__MSVCRT__) - /* beginthread does not return the thread id, and so we do it here. */ + /* + * beginthread does not return the thread id and is running + * before it returns us the thread handle, and so we do it here. + */ self->thread = GetCurrentThreadId (); + if (pthread_mutex_lock(&self->cancelLock) == 0) + { + /* + * We got the lock which means that our creator has + * our thread handle. Unlock and continue on. + */ + (void) pthread_mutex_unlock(&self->cancelLock); + } #endif - free (threadParms); - pthread_setspecific (_pthread_selfThreadKey, self); #ifdef _MSC_VER @@ -231,6 +242,7 @@ _pthread_threadStart (ThreadParms * threadParms) break; default: status = PTHREAD_CANCELED; + break; } } else @@ -366,7 +378,9 @@ _pthread_tkAssocCreate (ThreadKeyAssoc ** assocP, * key on which to create an association. * Returns: * 0 - if successful, - * -1 - general error + * ENOMEM - not enough memory to create assoc or other object + * EINVAL - an internal error occurred + * ENOSYS - an internal error occurred * ------------------------------------------------------------------- */ { @@ -382,12 +396,11 @@ _pthread_tkAssocCreate (ThreadKeyAssoc ** assocP, if (assoc == NULL) { - result = -1; + result = ENOMEM; goto FAIL0; } - if ((result = pthread_mutex_init (&(assoc->lock), NULL)) != - 0) + if ((result = pthread_mutex_init (&(assoc->lock), NULL)) != 0) { goto FAIL1; } @@ -398,8 +411,7 @@ _pthread_tkAssocCreate (ThreadKeyAssoc ** assocP, /* * Register assoc with key */ - if ((result = pthread_mutex_lock (&(key->threadsLock))) != - 0) + if ((result = pthread_mutex_lock (&(key->threadsLock))) != 0) { goto FAIL2; } @@ -793,7 +805,7 @@ _pthread_get_exception_services_code(void) #else - return NULL; + return (DWORD) NULL; #endif } diff --git a/pthread.h b/pthread.h index bed1ae3..822152c 100644 --- a/pthread.h +++ b/pthread.h @@ -282,8 +282,12 @@ struct timespec { #ifdef __MINGW32__ #define PT_STDCALL #else +#ifdef __cplusplus +#define PT_STDCALL __cdecl +#else #define PT_STDCALL __stdcall #endif +#endif #ifdef __cplusplus extern "C" @@ -420,8 +424,12 @@ extern "C" * simply simulating keys. * * PTHREADS_STACK_MIN - * artibrarily chose 1K. By default, WIN32 - * selects 1Meg stacks. + * POSIX specifies 0 which is also the value WIN32 + * interprets as allowing the system to + * set the size to that of the main thread. The + * maximum stack size in Win32 is 1Meg. WIN32 + * allocates more stack as required up to the 1Meg + * limit. * * PTHREAD_THREADS_MAX * Not documented by WIN32. Wrote a test program @@ -431,7 +439,7 @@ extern "C" */ #define PTHREAD_DESTRUCTOR_ITERATIONS 4 #define PTHREAD_KEYS_MAX 64 -#define PTHREAD_STACK_MIN 1024 +#define PTHREAD_STACK_MIN 0 #define PTHREAD_THREADS_MAX 2019 @@ -584,7 +592,7 @@ struct _pthread_cleanup_t #endif /* !_MSC_VER && ! __cplusplus */ }; -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__cplusplus) /* * WIN32 SEH version of cancel cleanup. */ @@ -609,7 +617,7 @@ struct _pthread_cleanup_t } \ } -#else /* _MSC_VER */ +#else /* _MSC_VER && ! __cplusplus */ #ifndef __cplusplus @@ -703,9 +711,9 @@ struct _pthread_cleanup_t cleanup.execute( _execute ); \ } -#endif /* !__cplusplus */ +#endif /* !__cplusplus) */ -#endif /* _MSC_VER */ +#endif /* _MSC_VER && ! __cplusplus */ /* * =============== @@ -958,12 +966,14 @@ int * _errno( void ); rand() -#ifdef _MSC_VER +/* FIXME: This is only required if the library was built using SEH */ /* * Get internal SEH tag */ DWORD _pthread_get_exception_services_code(void); +#if defined(_MSC_VER) && !defined(__cplusplus) + /* * Redefine the SEH __except keyword to ensure that applications * propagate our internal exceptions up to the library's internal handlers. @@ -972,9 +982,12 @@ DWORD _pthread_get_exception_services_code(void); __except((GetExceptionCode() == _pthread_get_exception_services_code()) \ ? EXCEPTION_CONTINUE_SEARCH : (E)) -#endif +#endif /* _MSC_VER && ! __cplusplus */ #ifdef __cplusplus + +/* FIXME: This is only required if the library was built using C++EH */ + /* * Internal exceptions */ diff --git a/rwlock.c b/rwlock.c index fd3f1f7..a4cdd5f 100644 --- a/rwlock.c +++ b/rwlock.c @@ -182,7 +182,7 @@ pthread_rwlock_destroy(pthread_rwlock_t *rwlock) } else { - rw->rw_magic = (int) NULL; + rw->rw_magic = 0; (void) pthread_mutex_unlock(&(rw->rw_lock)); (void) pthread_cond_destroy(&(rw->rw_condreaders)); (void) pthread_cond_destroy(&(rw->rw_condwriters)); diff --git a/sched.c b/sched.c index 88889de..a4451ce 100644 --- a/sched.c +++ b/sched.c @@ -128,6 +128,22 @@ int pthread_getschedparam(pthread_t thread, int *policy, return 0; } + +/* + * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and + * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine. + * + * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5 + * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny: + * highest priority use smaller numbers) and the following happens: + * + * sched_get_priority_min() returns 5 + * sched_get_priority_max() returns 1 + */ + +#define sched_Max(a,b) ((a)<(b)?(b):(a)) +#define sched_Min(a,b) ((a)>(b)?(b):(a)) + int sched_get_priority_max(int policy) { if (policy < SCHED_MIN || policy > SCHED_MAX) @@ -135,8 +151,13 @@ int sched_get_priority_max(int policy) return EINVAL; } +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) + /* WinCE? */ + return sched_Max(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#else /* This is independent of scheduling policy in Win32. */ - return THREAD_PRIORITY_HIGHEST; + return sched_Max(THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_HIGHEST); +#endif } int sched_get_priority_min(int policy) @@ -146,8 +167,13 @@ int sched_get_priority_min(int policy) return EINVAL; } +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) + /* WinCE? */ + return sched_Min(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#else /* This is independent of scheduling policy in Win32. */ - return THREAD_PRIORITY_LOWEST; + return sched_Min(THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_HIGHEST); +#endif } int sched_yield(void) diff --git a/signal.c b/signal.c index f944e0b..ba0edeb 100644 --- a/signal.c +++ b/signal.c @@ -23,7 +23,7 @@ * MA 02111-1307, USA */ -/* errno.h or a replacement file is included by pthread.h */ +/* errno.h or a replacement file is included by pthread.h */ //#include #include "pthread.h" diff --git a/tests/ChangeLog b/tests/ChangeLog index 8e65a35..902a809 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,17 @@ +2000-07-25 Ross Johnson + + * runtest.bat: modified to work under W98. + + * runall.bat: Add new tests; modified to work under W98. + It was ok under NT. + + * Makefile: Add new tests. + + * exception1.c: New; Test passing exceptions back to the + application and retaining library internal exceptions. + + * join0.c: New; Test a single join. + 2000-01-06 Ross Johnson * cleanup1.c: New; Test cleanup handler executes (when thread is diff --git a/tests/Makefile b/tests/Makefile index ef1d30f..5931855 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -39,12 +39,13 @@ COPYFILES = $(HDR) $(LIB) $(DLL) TESTS = loadfree \ mutex1 condvar1 condvar2 exit1 create1 equal1 \ exit2 exit3 \ - join1 join2 mutex2 mutex3 \ + join0 join1 join2 mutex2 mutex3 \ count1 once1 tsd1 self1 self2 cancel1 eyal1 \ condvar3 condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \ errno1 \ rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 \ - context1 cancel3 cancel4 cleanup1 cleanup2 cleanup3 + context1 cancel3 cancel4 cleanup1 cleanup2 cleanup3 \ + exception1 PASSES = $(TESTS:%=%.pass) @@ -63,6 +64,7 @@ mutex3.pass: create1.pass equal1.pass: create1.pass exit2.pass: create1.pass exit3.pass: create1.pass +join0.pass: create1.pass join1.pass: create1.pass join2.pass: create1.pass count1.pass: join1.pass @@ -90,6 +92,7 @@ cancel4.pass: cancel3.pass cleanup1.pass: cancel4.pass cleanup2.pass: cleanup1.pass cleanup3.pass: cleanup2.pass +exception1.pass: cancel4.pass %.pass: %.exe $(LIB) $(DLL) $(HDR) $* diff --git a/tests/cancel2.c b/tests/cancel2.c index 1a10c64..44d1b77 100644 --- a/tests/cancel2.c +++ b/tests/cancel2.c @@ -48,7 +48,7 @@ * Create NUMTHREADS threads in addition to the Main thread. */ enum { - NUMTHREADS = 4 + NUMTHREADS = 1 }; typedef struct bag_t_ bag_t; @@ -113,7 +113,6 @@ mythread(void * arg) /* * Should not get into here. */ - printf("SEH code=%x, MyCode=%x\n", GetExceptionCode(), _pthread_get_exception_services_code()); result += 100; } diff --git a/tests/cancel3.c b/tests/cancel3.c index ff1d286..cb6f3d2 100644 --- a/tests/cancel3.c +++ b/tests/cancel3.c @@ -65,7 +65,7 @@ static pthread_mutex_t waitLock = PTHREAD_MUTEX_INITIALIZER; void * mythread(void * arg) { - int result = 0; + int result = ((int)PTHREAD_CANCELED + 1); bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); @@ -85,7 +85,7 @@ mythread(void * arg) for (bag->count = 0; bag->count < 100; bag->count++) Sleep(100); - return result; + return (void *) result; } int diff --git a/tests/cancel4.c b/tests/cancel4.c index 9ce6880..59c2f8e 100644 --- a/tests/cancel4.c +++ b/tests/cancel4.c @@ -68,7 +68,7 @@ static bag_t threadbag[NUMTHREADS + 1]; void * mythread(void * arg) { - int result = 0; + int result = ((int)PTHREAD_CANCELED + 1); bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); diff --git a/tests/ccl.bat b/tests/ccl.bat index 473ff42..d80ea03 100644 --- a/tests/ccl.bat +++ b/tests/ccl.bat @@ -1,9 +1,9 @@ -REM Generate preprocessor output -REM cl /E /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c ..\%1.c > ..\%1.e - -REM Generate object file -cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c ..\%1.c - -REM Generate executable -cl /Feaout.exe /Zi %1.obj .\pthread.lib -del %1.obj > nul: +REM Generate preprocessor output +REM cl /E /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c ..\%1.c > ..\%1.e + +REM Generate object file +cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c ..\%1.c + +REM Generate executable +cl /Feaout.exe /Zi %1.obj .\pthread.lib +del %1.obj > nul: diff --git a/tests/join1.c b/tests/join1.c index f206c0b..c29e5e6 100644 --- a/tests/join1.c +++ b/tests/join1.c @@ -9,12 +9,14 @@ void * func(void * arg) { - Sleep(1000); + int i = (int) arg; + + Sleep(i * 500); - pthread_exit(arg); + pthread_exit(arg); - /* Never reached. */ - exit(1); + /* Never reached. */ + exit(1); } int @@ -30,6 +32,9 @@ main(int argc, char * argv[]) assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); } + /* Some threads will finish before they are joined, some after. */ + Sleep(1000); + for (i = 0; i < 4; i++) { assert(pthread_join(id[i], (void *) &result) == 0); diff --git a/tests/loadfree.c b/tests/loadfree.c index 3aba61b..b9b14c3 100644 --- a/tests/loadfree.c +++ b/tests/loadfree.c @@ -28,7 +28,7 @@ int main() { HINSTANCE hinst; - assert((hinst = LoadLibrary("pthread")) != 0); + assert((hinst = LoadLibrary("pthread")) != (HINSTANCE) 0); Sleep(100); diff --git a/tests/runall.bat b/tests/runall.bat index ace1962..f2f492b 100644 --- a/tests/runall.bat +++ b/tests/runall.bat @@ -1,64 +1,66 @@ -@echo off - -if NOT x%1==x-f goto noforce -if EXIST *.pass echo y | erase *.pass > nul: -if EXIST *.fail echo y | erase *.fail > nul: -if EXIST *.notrun echo y | erase *.notrun > nul: - -:noforce -call runtest cl loadfree _ -call runtest cl mutex1 _ -call runtest cl mutex2 _ -call runtest cl exit1 _ -call runtest cl condvar1 _ -call runtest cl self1 _ -call runtest cl condvar2 condvar1 -call runtest cl create1 mutex2 -call runtest cl mutex3 create1 -call runtest cl equal1 create1 -call runtest cl exit2 create1 -call runtest cl exit3 create1 -call runtest cl join1 create1 -call runtest cl join2 create1 -call runtest cl count1 join1 -call runtest cl once1 create1 -call runtest cl tsd1 join1 -call runtest cl self2 create1 -call runtest cl cancel1 self2 -call runtest cl cancel2 cancel1 -call runtest cl eyal1 tsd1 -call runtest cl condvar3 create1 -call runtest cl condvar4 create1 -call runtest cl condvar5 condvar4 -call runtest cl condvar6 condvar5 -call runtest cl errno1 mutex3 -call runtest cl rwlock1 condvar6 -call runtest cl rwlock2 rwlock1 -call runtest cl rwlock3 rwlock2 -call runtest cl rwlock4 rwlock3 -call runtest cl rwlock5 rwlock4 -call runtest cl rwlock6 rwlock5 -call runtest cl context1 cancel2 -call runtest cl cancel3 context1 -call runtest cl cancel4 cancel3 -call runtest cl cleanup1 cancel4 -call runtest cl cleanup2 cleanup1 -call runtest cl cleanup3 cleanup2 -call runtest cl condvar7 cleanup1 -call runtest cl condvar8 condvar7 -call runtest cl condvar9 condvar8 - -if NOT EXIST *.notrun goto skip1 -echo The following tests did not run (because prerequisite didn't pass?): -for %%f in (*.notrun) do echo %%f -goto skip2 -:skip1 -echo All tests ran. -:skip2 -if NOT EXIST *.fail goto skip3 -echo The following tests failed: -for %%f in (*.fail) do echo %%f -goto skip4 -:skip3 -echo No tests failed. -:skip4 +@echo off + +if NOT x%1==x-f goto noforce +if EXIST *.pass echo y | erase *.pass > nul: +if EXIST *.fail echo y | erase *.fail > nul: +if EXIST *.notrun echo y | erase *.notrun > nul: + +:noforce +call runtest cl loadfree _ +call runtest cl mutex1 _ +call runtest cl mutex2 _ +call runtest cl exit1 _ +call runtest cl condvar1 _ +call runtest cl self1 _ +call runtest cl condvar2 condvar1 +call runtest cl create1 mutex2 +call runtest cl mutex3 create1 +call runtest cl equal1 create1 +call runtest cl exit2 create1 +call runtest cl exit3 create1 +call runtest cl join0 create1 +call runtest cl join1 create1 +call runtest cl join2 create1 +call runtest cl count1 join1 +call runtest cl once1 create1 +call runtest cl tsd1 join1 +call runtest cl self2 create1 +call runtest cl cancel1 self2 +call runtest cl cancel2 cancel1 +call runtest cl eyal1 tsd1 +call runtest cl condvar3 create1 +call runtest cl condvar4 create1 +call runtest cl condvar5 condvar4 +call runtest cl condvar6 condvar5 +call runtest cl errno1 mutex3 +call runtest cl rwlock1 condvar6 +call runtest cl rwlock2 rwlock1 +call runtest cl rwlock3 rwlock2 +call runtest cl rwlock4 rwlock3 +call runtest cl rwlock5 rwlock4 +call runtest cl rwlock6 rwlock5 +call runtest cl context1 cancel2 +call runtest cl cancel3 context1 +call runtest cl cancel4 cancel3 +call runtest cl cleanup1 cancel4 +call runtest cl cleanup2 cleanup1 +call runtest cl cleanup3 cleanup2 +call runtest cl condvar7 cleanup1 +call runtest cl condvar8 condvar7 +call runtest cl condvar9 condvar8 +call runtest cl exception1 cancel4 + +if NOT EXIST *.notrun goto skip1 +echo The following tests did not run (because prerequisite didn't pass?): +for %%f in (*.notrun) do echo %%f +goto skip2 +:skip1 +echo All tests ran. +:skip2 +if NOT EXIST *.fail goto skip3 +echo The following tests failed: +for %%f in (*.fail) do echo %%f +goto skip4 +:skip3 +echo No tests failed. +:skip4 diff --git a/tests/runtest.bat b/tests/runtest.bat index dc36666..1129b9b 100644 --- a/tests/runtest.bat +++ b/tests/runtest.bat @@ -1,69 +1,81 @@ -@echo off - -REM Usage: runtest cl|gcc testname prerequisit testarg ... - -if %3==_ goto noprereq -if NOT EXIST %3.pass goto needprereq - -:noprereq -if EXIST %2.fail goto forcetest -if EXIST %2.pass goto bypass - -:forcetest -if EXIST %2.fail erase %2.fail - -REM Make sure we start with only those files we expect to need -if exist tmp\*.* echo y | erase tmp\*.* > nul: -rmdir tmp -mkdir tmp - -copy ..\pthread.dll tmp > nul: -copy ..\pthread.h tmp > nul: -copy ..\semaphore.h tmp > nul: -copy ..\sched.h tmp > nul: -copy test.h tmp > nul: -copy ..\pthread.lib tmp > nul: -copy ..\libpthread32.a tmp > nul: - -cd tmp - -REM Compile the test case -REM produces aout.exe using the compiler given as %1 -call ..\c%1.bat %2 > ..\%2.%1log - -if ERRORLEVEL 1 goto cleanup - -REM erase ..\%2.%1log - -echo TEST: %2 [%1] - -REM Run the test case -if EXIST %2.pass erase %2.pass -if EXIST %2.fail erase %2.fail -if EXIST %2.notrun erase %2.notrun -aout.exe %4 %5 %6 %7 %8 %9 - -set RESULT=%ERRORLEVEL% - -if %RESULT% NEQ 0 echo Failed [%RESULT%] > ..\%2.fail -if %RESULT% EQU 0 echo Passed > ..\%2.pass - -:cleanup - -cd .. - -REM Clean up -if exist tmp\*.* echo y | erase tmp\*.* > nul: - -if EXIST %2.fail echo Failed [%RESULT%] -if EXIST %2.pass echo Passed [%RESULT%] - -:bypass -goto end - -:needprereq -echo Test %2 requires %3 to pass before it can run. -echo No Prereq > ..\%2.notrun -goto end - -:end +@echo off + +REM Usage: runtest cl testname prerequisit testarg ... +REM or: runtest gcc testname prerequisit testarg ... + +if %3==_ goto noprereq +if NOT EXIST %3.pass goto needprereq + +:noprereq +if EXIST %2.fail goto forcetest +if EXIST %2.pass goto bypass + +:forcetest +if EXIST %2.fail erase %2.fail + +REM Make sure we start with only those files we expect to need +if not exist tmp\*.* goto skip1 +echo y | erase tmp\*.* > nul: +rmdir tmp +mkdir tmp +:skip1 + +copy ..\pthread.dll tmp > nul: +copy ..\pthread.h tmp > nul: +copy ..\semaphore.h tmp > nul: +copy ..\sched.h tmp > nul: +copy test.h tmp > nul: +copy ..\pthread.lib tmp > nul: +REM copy ..\libpthread32.a tmp > nul: + +cd tmp + +REM Compile the test case +REM produces aout.exe using the compiler given as %1 +call ..\c%1.bat %2 > ..\%2.%1log + +if ERRORLEVEL 1 goto cleanup + +REM erase ..\%2.%1log + +echo TEST: %2 [%1] + +REM Run the test case +if EXIST %2.pass erase %2.pass +if EXIST %2.fail erase %2.fail +if EXIST %2.notrun erase %2.notrun +aout.exe %4 %5 %6 %7 %8 %9 + +set RESULT=1 +if ERRORLEVEL 0 set RESULT=0 + +REM set RESULT=%ERRORLEVEL% + +if %RESULT%==0 goto passed +echo Failed [%RESULT%] > ..\%2.fail +goto cleanup + +:passed +echo Passed > ..\%2.pass + +:cleanup + +cd .. + +REM Clean up +if not exist tmp\*.* goto skip2 +echo y | erase tmp\*.* > nul: +:skip2 + +if EXIST %2.fail echo Failed [%RESULT%] +if EXIST %2.pass echo Passed [%RESULT%] + +:bypass +goto end + +:needprereq +echo Test %2 requires %3 to pass before it can run. +echo No Prereq > ..\%2.notrun +goto end + +:end diff --git a/tsd.c b/tsd.c index 5183cd7..1381ce2 100644 --- a/tsd.c +++ b/tsd.c @@ -71,9 +71,6 @@ pthread_key_create (pthread_key_t * key, void (*destructor) (void *)) } else if (((*key)->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES) { - /* - * Create system key - */ result = EAGAIN; free (*key); @@ -86,6 +83,13 @@ pthread_key_create (pthread_key_t * key, void (*destructor) (void *)) * Therefore, need a lock that allows multiple threads * to gain exclusive access to the key->threads list */ +#if 1 + /* + * The mutex will only be created when it is first locked. + */ + (*key)->threadsLock = PTHREAD_MUTEX_INITIALIZER; + (*key)->destructor = destructor; +#else result = pthread_mutex_init (&((*key)->threadsLock), NULL); if (result != 0) @@ -95,7 +99,11 @@ pthread_key_create (pthread_key_t * key, void (*destructor) (void *)) free (*key); *key = NULL; } - (*key)->destructor = destructor; + else + { + (*key)->destructor = destructor; + } +#endif } return (result); @@ -134,6 +142,7 @@ pthread_key_delete (pthread_key_t key) if (key != NULL) { if (key->threads != NULL && + key->destructor != NULL && pthread_mutex_lock (&(key->threadsLock)) == 0) { /* @@ -194,25 +203,24 @@ pthread_setspecific (pthread_key_t key, const void *value) /* * ------------------------------------------------------ * DOCPUBLIC - * This function initializes an unnamed semaphore. the - * initial value of the semaphore is 'value' + * This function sets the value of the thread specific + * key in the calling thread. * * PARAMETERS - * sem - * pointer to an instance of sem_t + * key + * an instance of pthread_key_t + * value + * the value to set key to * * * DESCRIPTION - * This function initializes an unnamed semaphore. The - * initial value of the semaphore is set to 'value'. + * This function sets the value of the thread specific + * key in the calling thread. * * RESULTS - * 0 successfully created semaphore, - * EINVAL 'sem' is not a valid semaphore, - * ENOSPC a required resource has been exhausted, - * ENOSYS semaphores are not supported, - * EPERM the process lacks appropriate privilege - * ENOENT the thread couldn't find it's own handle + * 0 successfully set value + * EAGAIN could not set value + * ENOENT SERIOUS!! * * ------------------------------------------------------ */ @@ -229,9 +237,9 @@ pthread_setspecific (pthread_key_t key, const void *value) */ self = pthread_self (); if (self == NULL) - { - return ENOENT; - } + { + return ENOENT; + } } else { @@ -284,20 +292,21 @@ pthread_setspecific (pthread_key_t key, const void *value) /* * create an association if not found */ - result = (assoc == NULL) - ? _pthread_tkAssocCreate (&assoc, self, key) - : 0; - } - else - { - result = 0; + if (assoc == NULL) + { + result = _pthread_tkAssocCreate (&assoc, self, key); + } } if (result == 0) { - TlsSetValue (key->key, (LPVOID) value); + if ( ! TlsSetValue (key->key, (LPVOID) value)) + { + result = EAGAIN; + } } } + return (result); } /* pthread_setspecific */ -- cgit v1.2.3