diff options
| -rw-r--r-- | ChangeLog | 90 | ||||
| -rw-r--r-- | FAQ | 68 | ||||
| -rw-r--r-- | GNUmakefile | 140 | ||||
| -rw-r--r-- | Makefile | 12 | ||||
| -rw-r--r-- | README.WinCE | 13 | ||||
| -rw-r--r-- | TODO | 23 | ||||
| -rw-r--r-- | attr.c | 9 | ||||
| -rw-r--r-- | cancel.c | 14 | ||||
| -rw-r--r-- | cleanup.c | 19 | ||||
| -rw-r--r-- | condvar.c | 4 | ||||
| -rw-r--r-- | config.h | 16 | ||||
| -rw-r--r-- | config.h.in | 16 | ||||
| -rw-r--r-- | create.c | 44 | ||||
| -rw-r--r-- | dll.c | 6 | ||||
| -rw-r--r-- | implement.h | 2 | ||||
| -rw-r--r-- | misc.c | 16 | ||||
| -rw-r--r-- | mutex.c | 35 | ||||
| -rw-r--r-- | private.c | 34 | ||||
| -rw-r--r-- | pthread.h | 31 | ||||
| -rw-r--r-- | rwlock.c | 2 | ||||
| -rw-r--r-- | sched.c | 30 | ||||
| -rw-r--r-- | signal.c | 2 | ||||
| -rw-r--r-- | tests/ChangeLog | 14 | ||||
| -rw-r--r-- | tests/Makefile | 7 | ||||
| -rw-r--r-- | tests/cancel2.c | 3 | ||||
| -rw-r--r-- | tests/cancel3.c | 4 | ||||
| -rw-r--r-- | tests/cancel4.c | 2 | ||||
| -rw-r--r-- | tests/ccl.bat | 18 | ||||
| -rw-r--r-- | tests/join1.c | 13 | ||||
| -rw-r--r-- | tests/loadfree.c | 2 | ||||
| -rw-r--r-- | tests/runall.bat | 130 | ||||
| -rw-r--r-- | tests/runtest.bat | 150 | ||||
| -rw-r--r-- | tsd.c | 63 | 
33 files changed, 695 insertions, 337 deletions
| @@ -1,8 +1,64 @@ -2000-07-25  Ross Johnson  <rpj@setup1.ise.canberra.edu.au> +2000-07-25  Ross Johnson  <rpj@special.ise.canberra.edu.au> + +	* sched.c (sched_get_priority_max): Handle different WinCE and +	Win32 priority values together. +	(sched_get_priority_min): Ditto. +	- Tristan Savatier <tristan@mpegtv.com> + +	* 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  <rpj@special.ise.canberra.edu.au> + +	* 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  <rpj@special.ise.canberra.edu.au> + +	* FAQ: Added Q5 and Q6. +  2000-07-21  Ross Johnson  <rpj@setup1.ise.canberra.edu.au>  	* 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  <rpj@special.ise.canberra.edu.au> + +	* 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  <rpj@special.ise.canberra.edu.au> + +	* 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  <rpj@special.ise.canberra.edu.au> + +	* 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  <rpj@special.ise.canberra.edu.au>  	* Makefile: Remove inconsistencies in 'cl' args @@ -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 <sailer@ife.ee.ethz.ch> + 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)
 @@ -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. @@ -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. + +==== + @@ -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 @@ -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 */ @@ -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 */ @@ -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; @@ -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 @@ -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 @@ -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 @@ -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;  } @@ -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 <errno.h> @@ -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; @@ -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  } @@ -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   */ @@ -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)); @@ -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) @@ -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 <errno.h>  #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  <rpj@special.ise.canberra.edu.au> + +	* 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  <rpj@special.ise.canberra.edu.au>  	* 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
 @@ -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 */ | 
