diff options
38 files changed, 474 insertions, 332 deletions
| diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 0d650e1..334b945 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -128,3 +128,7 @@ Vladimir Kliatchko	vladimir at kliatchko dot com  					reimplemented pthread_once with the same form  					as described by A.Terekhov (later version 2);  					implementation of MCS (Mellor-Crummey/Scott) locks. +Ramiro Polla		ramiro.polla at gmail.com +					static library auto init/cleanup on application +					start/exit via RT hooks (MSC and GCC compilers only). +					
\ No newline at end of file @@ -1,105 +1,50 @@ -2009-03-03  Stephan O'Farrill <stephan dot ofarrill at gmail dot com> - -	* pthread_attr_getschedpolicy.c: Add "const" to function parameter -	in accordance with SUSv3 (POSIX). -	* pthread_attr_getinheritsched.c: Likewise. -	* pthread_mutexattr_gettype.c: Likewise. - - -2008-06-06  Robert Kindred  <RKindred at SwRI dot edu> - -        * ptw32_throw.c (ptw32_throw): Remove possible reference to NULL -        pointer. (At the same time made the switch block conditionally -        included only if exitCode is needed - RPJ.) -        * pthread_testcancel.c (pthread_testcancel): Remove duplicate and -        misplaced pthread_mutex_unlock(). - -2008-02-21  Sebastian Gottschalk  <seppig_relay at gmx dot de> - -        * pthread_attr_getdetachstate.c (pthread_attr_getdetachstate): -        Remove potential and superfluous null pointer assignment. - -2007-11-22  Ivan Pizhenko  <ivanp4 at ua dot fm> - -        * pthread.h (gmtime_r): gmtime returns 0 if tm represents a time -        prior to 1/1/1970. Notice this to prevent raising an exception. -        * pthread.h (localtime_r): Likewise for localtime. - -2007-07-14  Marcel Ruff  <mr at marcelruff dot info> - -        * errno.c (_errno): Fix test for pthread_self() success. -        * need_errno.h: Remove unintentional line wrap from #if line. - -2007-07-14  Mike Romanchuk  <mromanchuk at empirix dot com> - -        * pthread.h (timespec): Fix tv_sec type. - -2007-01-07  Sinan Kaya <sinan.kaya at siemens dot com> - -        * need_errno.h: Fix declaration of _errno - the local version of -        _errno() is used, e.g. by WinCE. - -2007-01-06  Ross Johnson <ross.johnson at homemail dot com dot au> - -        * ptw32_semwait.c: Add check for invalid sem_t after acquiring the -        sem_t state guard mutex and before affecting changes to sema state. -                 -2007-01-06  Marcel Ruff <mr at marcelruff dot info> - -        * error.c: Fix reference to pthread handle exitStatus member for -        builds that use NEED_ERRNO (i.e. WINCE). -        * context.h: Add support for ARM processor (WinCE). -        * mutex.c (process.h): Exclude for WINCE. -        * create.c: Likewise. -        * exit.c: Likewise. -        * implement.h: Likewise. -        * pthread_detach.c (signal.h): Exclude for WINCE. -        * pthread_join.c: Likewise. -        * pthread_kill.c: Likewise. -        * pthread_rwlock_init.c (errno.h): Remove - included by pthread.h. -        * pthread_rwlock_destroy.c: Likewise. -        * pthread_rwlock_rdlock.c: Likewise. -        * pthread_rwlock_timedrdlock.c: Likewise. -        * pthread_rwlock_timedwrlock.c: Likewise. -        * pthread_rwlock_tryrdlock.c: Likewise. -        * pthread_rwlock_trywrlock.c: likewise. -        * pthread_rwlock_unlock.c: Likewise. -        * pthread_rwlock_wrlock.c: Likewise. -        * pthread_rwlockattr_destroy.c: Likewise. -        * pthread_rwlockattr_getpshared.c: Likewise. -        * pthread_rwlockattr_init.c: Likewise. -        * pthread_rwlockattr_setpshared.c: Likewise. - -2007-01-06  Romano Paolo Tenca <rotenca at telvia dot it> - -        * pthread_cond_destroy.c: Replace sem_wait() with non-cancelable -        ptw32_semwait() since pthread_cond_destroy() is not a cancelation -        point. -        * implement.h (ptw32_spinlock_check_need_init): Add prototype. -        * ptw32_MCS_lock.c: Reverse order of includes. - -2007-01-06  Eric Berge <eric dot berge at quantum dot com> - -        * pthread_cond_destroy.c: Add LeaveCriticalSection before returning -        after errors. - -2007-01-04  Ross Johnson <ross.johnson at homemail dot com dot au> - -        * ptw32_InterlockedCompareExchange.c: Conditionally skip for -        Win64 as not required. -        * pthread_win32_attach_detach_np.c (pthread_win32_process_attach_np): -        Test for InterlockedCompareExchange is not required for Win64. -        * context.h: New file. Included by pthread_cancel.h and any tests -        that need it (e.g. context1.c). -        * pthread_cancel.c: Architecture-dependent context macros moved -        to context.h. - -2007-01-04  Kip Streithorst <KSTREITH at ball dot com> - -        * implement.h (PTW32_INTERLOCKED_COMPARE_EXCHANGE): Add Win64 -        support. +2010-06-19  Ross Johnson <ross.johnson at homemail.com.au> + +		* ptw32_MCS_lock.c (ptw32_mcs_node_substitute): Fix variable +		names to avoid using C++ keyword ("new"). +		* implement.h (ptw32_mcs_node_substitute): Likewise. +		* pthread_barrier_wait.c: Fix signed/unsigned comparison warning. + +2010-06-18  Ramiro Polla  <ramiro.polla at gmail.com > + +		* autostatic.c: New file; call pthread_win32_process_*() +		libary init/cleanup routines automatically on application start +		when statically linked. +		* pthread.c (autostatic.c): Included. +		* pthread.h (declspec): Remove import/export defines if compiler +		is MINGW. +		* sched.h (declspec): Likewise. +		* semaphore.h (declspec): Likewise. +		* need_errno.h (declspec): Likewise. +		* Makefile (autostatic.obj): Add for small static builds. +		* GNUmakefile (autostatic.o): Likewise. +		* NEWS (Version 2.9.0): Add changes. +		* README.NONPORTABLE (pthread_win32_process_*): Update +		description. + +2010-06-15  Ramiro Polla  <ramiro.polla at gmail.com > + +		* Makefile: Remove linkage with the winsock library by default. +		* GNUmakefile: Likewise. +		* pthread_getspecific.c: Likewise by removing calls to WSA +		functions. +		* config.h (RETAIN_WSALASTERROR): Can be defined if necessary. + +2010-01-26  Ross Johnson <ross.johnson at homemail.com.au> + +		* ptw32_MCS_lock.c (ptw32_mcs_node_substitute): New routine +		to allow relocating the lock owners thread-local node to somewhere +		else, e.g. to global space so that another thread can release the +		lock. Used in pthread_barrier_wait. +		(ptw32_mcs_lock_try_acquire): New routine. +		* pthread_barrier_init: Only one semaphore is used now. +		* pthread_barrier_wait: Added an MCS guard lock with the last thread +		to leave the barrier releasing the lock. This removes a deadlock bug +		observed when there are greater than barrier-count threads +		attempting to cross. +		* pthread_barrier_destroy: Added an MCS guard lock. -2006-12-20  Ross Johnson <ross.johnson at homemail dot com dot au> +2006-12-20  Ross Johnson <ross.johnson at homemail.com.au>          * sem_destroy.c: Fix the race involving invalidation of the sema;          fix incorrect return of EBUSY resulting from the mutex trylock diff --git a/GNUmakefile b/GNUmakefile index 6c48fd2..652edb8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -63,7 +63,8 @@ DOPT	= $(CLEANUP) -g -O0  XOPT	=  RCFLAGS		= --include-dir=. -LFLAGS		= -lwsock32 +# Uncomment this if config.h defines RETAIN_WSALASTERROR +#LFLAGS		= -lwsock32  # ----------------------------------------------------------------------  # The library can be built with some alternative behaviour to @@ -170,6 +171,7 @@ SMALL_STATIC_OBJS	= \  		pthread_cond_wait.o \  		create.o \  		dll.o \ +		autostatic.o \  		errno.o \  		pthread_exit.o \  		fork.o \ @@ -436,6 +438,8 @@ GCE_LIB	= libpthreadGCE$(DLL_VER).a  GCED_LIB= libpthreadGCE$(DLL_VERD).a  GCE_INLINED_STAMP = pthreadGCE$(DLL_VER).stamp  GCED_INLINED_STAMP = pthreadGCE$(DLL_VERD).stamp +GCE_STATIC_STAMP = libpthreadGCE$(DLL_VER).stamp +GCED_STATIC_STAMP = libpthreadGCE$(DLL_VERD).stamp  GC_DLL 	= pthreadGC$(DLL_VER).dll  GCD_DLL	= pthreadGC$(DLL_VERD).dll @@ -30,6 +30,8 @@ OPTIMD	=  CFLAGS	= /W3 /MD /nologo /I. /D_WIN32_WINNT=0x400 /DHAVE_CONFIG_H  CFLAGSD	= /Zi $(CFLAGS) +# Uncomment this if config.h defines RETAIN_WSALASTERROR +#XLIBS = wsock32.lib  # Default cleanup style  CLEANUP	= __CLEANUP_C @@ -57,6 +59,7 @@ DLL_OBJS	= \  		condvar.obj \  		create.obj \  		dll.obj \ +		autostatic.obj \  		errno.obj \  		exit.obj \  		fork.obj \ @@ -114,6 +117,7 @@ SMALL_STATIC_OBJS	= \  		pthread_cond_wait.obj \  		create.obj \  		dll.obj \ +		autostatic.obj \  		errno.obj \  		pthread_exit.obj \  		fork.obj \ @@ -466,12 +470,12 @@ install: $(DLLS)  $(DLLS): $(DLL_OBJS)  	cl /LDd /Zi /nologo $(DLL_OBJS) \  		/link /nodefaultlib:libcmt /implib:$*.lib \ -		msvcrt.lib wsock32.lib /out:$@ +		msvcrt.lib ${XLIBS} /out:$@  $(INLINED_STAMPS): $(DLL_INLINED_OBJS)  	cl /LDd /Zi /nologo $(DLL_INLINED_OBJS) \  		/link /nodefaultlib:libcmt /implib:$*.lib \ -		msvcrt.lib wsock32.lib /out:$*.dll +		msvcrt.lib ${XLIBS} /out:$*.dll  $(STATIC_STAMPS): $(DLL_INLINED_OBJS)  	if exist $*.lib del $*.lib @@ -1,6 +1,7 @@ -RELEASE 2.9.0 +CURRENT CVS HEAD Version +RELEASE 2.9.0 pending  ------------- -(2008-??-??) +(2010-??-??)  General  ------- @@ -20,8 +21,29 @@ identifying changes in version.rc to differentiate your build.  Testing and verification  ------------------------ -This release has been tested on UP and SMP architectures. Thanks to Tim -Theisen for running the Win32 SMP tests. +The current CVS head version has been tested on an SMP architecture +(AMD Phenom 9750 Quad Core) by running the MinGW32 (GCC) builds against +the full test suite, stress tests and benchmarks. + +New Features +------------ +Dependence on the winsock library is now discretionary via +#define RETAIN_WSALASTERROR in config.h. It is undefined by default unless +WINCE is defined (because I (RJ) am unsure of the dependency there). +- Ramiro Polla + +(MSC and GNU builds) The statically linked library now automatically +initialises and cleans up on program start/exit, i.e. statically linked +applications need not call the routines pthread_win32_process_attach_np() +and pthread_win32_process_detach_np() explicitly. The per-thread routine +pthread_win32_thread_detach_np() is also called at program exit to cleanup +POSIX resources acquired by the primary Windows native thread (if I (RJ) +understand the process correctly). Other Windows native threads that call +POSIX API routines may need to call the thread detach routine on thread +exit if the application depends on reclaimed POSIX resources or running +POSIX TSD (TLS) destructors. +See README.NONPORTABLE for descriptions of these routines. +- Ramiro Polla  Bug fixes  --------- @@ -39,12 +61,19 @@ Various modifications to build and test for Win64.  - Kip Streithorst  Various fixes to the QueueUserAPCEx async cancellation helper DLL -and pthreads code cleanups. +(this is a separate download) and pthreads code cleanups.  - Sebastian Gottschalk  Removed potential NULL pointer reference.  - Robert Kindred +Removed the requirement that applications restrict the number of threads +calling pthread_barrier_wait() [on the same barrier] to just the barrier +count in order to avoid contention and dead lock. Also reduced the +contention between barrier_wait and barrier_destroy. This change will +have slowed barriers down slightly but halves the number of semaphores +consumed per barrier to one. +- Ross Johnson  RELEASE 2.8.0  ------------- diff --git a/README.NONPORTABLE b/README.NONPORTABLE index 192fef6..12095ce 100644 --- a/README.NONPORTABLE +++ b/README.NONPORTABLE @@ -156,19 +156,24 @@ pthread_win32_thread_detach_np (void);  	These functions contain the code normally run via dllMain  	when the library is used as a dll but which need to be  	called explicitly by an application when the library -	is statically linked. +	is statically linked. As of version 2.9.0 of the library, static +	builds using either MSC or GCC will call pthread_win32_process_* +	automatically at application startup and exit respectively. -	You will need to call pthread_win32_process_attach_np() before -	you can call any pthread routines when statically linking. +	Otherwise, you will need to call pthread_win32_process_attach_np() +	before you can call any pthread routines when statically linking.  	You should call pthread_win32_process_detach_np() before  	exiting your application to clean up.  	pthread_win32_thread_attach_np() is currently a no-op, but  	pthread_win32_thread_detach_np() is needed to clean up  	the implicit pthread handle that is allocated to a Win32 thread if -	it calls certain pthreads routines. Call this routine when the +	it calls any pthreads routines. Call this routine when the  	Win32 thread exits. +	Threads created through pthread_create() do not	need to call +	pthread_win32_thread_detach_np(). +  	These functions invariably return TRUE except for  	pthread_win32_process_attach_np() which will return FALSE  	if pthreads-win32 initialisation fails. @@ -52,6 +52,12 @@  /* Define if you don't have the GetProcessAffinityMask() */  #undef NEED_PROCESS_AFFINITY_MASK +/* Define if your version of Windows TLSGetValue() clears WSALastError + * and calling SetLastError() isn't enough restore it. You'll also need to + * link against wsock32.lib (or libwsock32.a for MinGW). + */ +#undef RETAIN_WSALASTERROR +  /*  # ----------------------------------------------------------------------  # The library can be built with some alternative behaviour to better @@ -103,6 +109,8 @@  /* #define NEED_SEM */  #define NEED_UNICODE_CONSTS  #define NEED_PROCESS_AFFINITY_MASK +/* This may not be needed */ +#define RETAIN_WSALASTERROR  #endif  #ifdef _UWIN @@ -49,7 +49,7 @@ pthread_cond_t ptw32_cond_list_tail = NULL;  int ptw32_concurrency = 0; -/* What features have been auto-detected */ +/* What features have been auto-detaected */  int ptw32_features = 0;  BOOL ptw32_smp_system = PTW32_TRUE;  /* Safer if assumed true initially. */ diff --git a/implement.h b/implement.h index 69930ef..00f153f 100644 --- a/implement.h +++ b/implement.h @@ -11,7 +11,7 @@   *      Copyright(C) 1998 John E. Bossom   *      Copyright(C) 1999,2005 Pthreads-win32 contributors   *  - *      Contact Email: rpj@callisto.canberra.edu.au + *      Contact Email: Ross.Johnson@homemail.com.au   *    *      The current list of contributors is contained   *      in the file CONTRIBUTORS included with the source @@ -151,9 +151,6 @@ struct ptw32_thread_t_    int implicit:1;    void *keys;    void *nextAssoc; -#ifdef _POSIX_CXX09_EXTENSIONS -  int refs;			/* C++ Thread Support Library extension */ -#endif  }; @@ -252,13 +249,31 @@ struct pthread_spinlock_t_    } u;  }; +/* + * MCS lock queue node - see ptw32_MCS_lock.c + */ +struct ptw32_mcs_node_t_ +{ +  struct ptw32_mcs_node_t_ **lock;        /* ptr to tail of queue */ +  struct ptw32_mcs_node_t_  *next;        /* ptr to successor in queue */ +  LONG                       readyFlag;   /* set after lock is released by +                                             predecessor */ +  LONG                       nextFlag;    /* set after 'next' ptr is set by +                                             successor */ +}; + +typedef struct ptw32_mcs_node_t_   ptw32_mcs_local_node_t; +typedef struct ptw32_mcs_node_t_  *ptw32_mcs_lock_t; + +  struct pthread_barrier_t_  {    unsigned int nCurrentBarrierHeight;    unsigned int nInitialBarrierHeight; -  int iStep;    int pshared; -  sem_t semBarrierBreeched[2]; +  sem_t semBarrierBreeched; +  void * lock; /* MCS lock */ +  ptw32_mcs_local_node_t proxynode;  };  struct pthread_barrierattr_t_ @@ -276,7 +291,6 @@ struct pthread_key_t_  typedef struct ThreadParms ThreadParms; -typedef struct ThreadKeyAssoc ThreadKeyAssoc;  struct ThreadParms  { @@ -327,22 +341,7 @@ struct pthread_rwlockattr_t_    int pshared;  }; -/* - * MCS lock queue node - see ptw32_MCS_lock.c - */ -struct ptw32_mcs_node_t_ -{ -  struct ptw32_mcs_node_t_ **lock;        /* ptr to tail of queue */ -  struct ptw32_mcs_node_t_  *next;        /* ptr to successor in queue */ -  LONG                       readyFlag;   /* set after lock is released by -                                             predecessor */ -  LONG                       nextFlag;    /* set after 'next' ptr is set by -                                             successor */ -}; - -typedef struct ptw32_mcs_node_t_   ptw32_mcs_local_node_t; -typedef struct ptw32_mcs_node_t_  *ptw32_mcs_lock_t; - +typedef struct ThreadKeyAssoc ThreadKeyAssoc;  struct ThreadKeyAssoc  { @@ -380,17 +379,16 @@ struct ThreadKeyAssoc     *      general lock (guarding the row) and the thread's general     *      lock (guarding the column). This avoids the need for a     *      dedicated lock for each association, which not only consumes -   *      more handles but requires that: before the lock handle can -   *      be released - both the key must be deleted and the thread -   *      must have called the destructor. The two-lock arrangement -   *      allows the resources to be freed as soon as either thread or -   *      key is concluded. +   *      more handles but requires that the lock resources persist +   *      until both the key is deleted and the thread has called the +   *      destructor. The two-lock arrangement allows those resources +   *      to be freed as soon as either thread or key is concluded.     * -   *      To avoid deadlock: whenever both locks are required, the key -   *      and thread locks are always acquired in the order: key lock -   *      then thread lock. An exception to this exists when a thread -   *      calls the destructors, however this is done carefully to -   *      avoid deadlock. +   *      To avoid deadlock, whenever both locks are required both the +   *      key and thread locks are acquired consistently in the order +   *      "key lock then thread lock". An exception to this exists +   *      when a thread calls the destructors, however, this is done +   *      carefully (but inelegantly) to avoid deadlock.     *     *      An association is created when a thread first calls     *      pthread_setspecific() on a key that has a specified @@ -424,7 +422,7 @@ struct ThreadKeyAssoc     *     *      nextThread     *              The pthread_key_t->threads attribute is the head of -   *              a chain of assoctiations that runs through the +   *              a chain of associations that runs through the     *              nextThreads link. This chain provides the 1 to many     *              relationship between a pthread_key_t and all the      *              PThreads that have called pthread_setspecific for @@ -460,7 +458,7 @@ struct ThreadKeyAssoc   *      This macro constructs a software exception code following   *      the same format as the standard Win32 error codes as defined   *      in WINERROR.H - *  Values are 32 bit values layed out as follows: + *  Values are 32 bit values laid out as follows:   *   *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0   *  +---+-+-+-----------------------+-------------------------------+ @@ -569,7 +567,6 @@ extern "C"    int ptw32_cond_check_need_init (pthread_cond_t * cond);    int ptw32_mutex_check_need_init (pthread_mutex_t * mutex);    int ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock); -  int ptw32_spinlock_check_need_init (pthread_spinlock_t * spinlock);    PTW32_INTERLOCKED_LONG WINAPI      ptw32_InterlockedCompareExchange (PTW32_INTERLOCKED_LPLONG location, @@ -623,8 +620,12 @@ extern "C"    void ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node); +  int ptw32_mcs_lock_try_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node); +    void ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node); +  void ptw32_mcs_node_substitute (ptw32_mcs_local_node_t * new_node, ptw32_mcs_local_node_t * old_node); +  #ifdef NEED_FTIME    void ptw32_timespec_to_filetime (const struct timespec *ts, FILETIME * ft);    void ptw32_filetime_to_timespec (const FILETIME * ft, struct timespec *ts); @@ -662,10 +663,8 @@ extern "C"  #       endif  #   endif  #else -#   ifndef WINCE  #       include <process.h>  #   endif -#endif  /* @@ -673,22 +672,8 @@ extern "C"   * See ptw32_InterlockedCompareExchange.c   */  #ifndef PTW32_INTERLOCKED_COMPARE_EXCHANGE -#  ifdef _WIN64 -     /* -      * InterlockedCompareExchange is an intrinsic function in Win64. -      */ -#    define PTW32_INTERLOCKED_COMPARE_EXCHANGE _InterlockedCompareExchange -#  else -     /* -      * The routine pthread_win32_process_attach_np() in pthread_win32_attach_detach_np.c -      * checks at runtime that InterlockedCompareExchange is supported within -      * KERNEL32.DLL (or COREDLL.DLL for WinCE). This allows the same -      * dll to run on all Win32 versions from Win95 onwards. Not sure if this -      * is required for WinCE, but should work just the same anyway. -      */  #    define PTW32_INTERLOCKED_COMPARE_EXCHANGE ptw32_interlocked_compare_exchange  #  endif -#endif  #ifndef PTW32_INTERLOCKED_EXCHANGE  #define PTW32_INTERLOCKED_EXCHANGE InterlockedExchange diff --git a/manual/pthread_barrier_init.html b/manual/pthread_barrier_init.html index 065c129..f581358 100644 --- a/manual/pthread_barrier_init.html +++ b/manual/pthread_barrier_init.html @@ -32,8 +32,7 @@ barrier referenced by <I>barrier</I> and release any resources used  by the barrier. The effect of subsequent use of the barrier is  undefined until the barrier is reinitialized by another call to  <B>pthread_barrier_init</B> . An implementation may use this function -to set <I>barrier</I> to an invalid value. The results are undefined -if <B>pthread_barrier_destroy</B> is called when any thread is +to set <I>barrier</I> to an invalid value. An error code is returned if <B>pthread_barrier_destroy</B> is called when any thread is  blocked on the barrier, or if this function is called with an  uninitialized barrier.   </P> @@ -139,10 +138,8 @@ that these routines are implemented and may be used.</P>  <DL>  	<DD STYLE="margin-left: 0cm; margin-bottom: 0.5cm">In  	<B><SPAN LANG="en-GB"><SPAN LANG="en-GB">pthreads-win32</SPAN></SPAN></B>, -	<A HREF="pthread_barrier_wait.html"></A><A HREF="pthread_barrier_wait.html"><B>pthread_barrier_wait</B>(3)</A><A HREF="pthread_barrier_wait.html"></A> -	may deadlock if the number of running threads able to wait on the -	barrier object exceeds the value given as the <I><SPAN LANG="en-GB"><SPAN LANG="en-GB">count</SPAN></SPAN></I> -	parameter in <B>pthread_barrier_init</B>.  +	the behaviour of threads which enter <A HREF="pthread_barrier_wait.html"><B>pthread_barrier_wait</B>(3)</A> +	while the barrier is being destroyed is undefined.   	</DD></DL>  <H2>  <A HREF="#toc9" NAME="sect9">See Also</A></H2> diff --git a/manual/pthread_barrier_wait.html b/manual/pthread_barrier_wait.html index 693d8bd..f407aa5 100644 --- a/manual/pthread_barrier_wait.html +++ b/manual/pthread_barrier_wait.html @@ -103,13 +103,7 @@ that this routine is implemented and may be used.</P>  </P>  <H2><A HREF="#toc11" NAME="sect11">Known Bugs</A></H2>  <DL> -	<DD STYLE="margin-left: 0cm; margin-bottom: 0.5cm">In -	<B><SPAN LANG="en-GB">pthreads-win32</SPAN></B>, -	<B>pthread_barrier_wait</B> may deadlock if the number of running -	threads able to wait on the barrier object exceeds the value given -	as the <I><SPAN LANG="en-GB">count</SPAN></I> parameter in -	<A HREF="pthread_barrier_init.html"><B>pthread_barrier_init(3)</B></A>. -		</DD></DL> +	None.</DL>  <H2>  <A HREF="#toc9" NAME="sect9">See Also</A></H2>  <P><A HREF="pthread_barrier_init.html"><B>pthread_barrier_destroy</B>(3)</A>, diff --git a/manual/pthread_win32_attach_detach_np.html b/manual/pthread_win32_attach_detach_np.html index 57f0339..f8cfc36 100644 --- a/manual/pthread_win32_attach_detach_np.html +++ b/manual/pthread_win32_attach_detach_np.html @@ -27,9 +27,9 @@ statically linking the library.</P>  <P><B>BOOL pthread_win32_thread_attach_np (void);</B></P>  <P><B>BOOL pthread_win32_thread_detach_np (void);</B></P>  <H2><A HREF="#toc2" NAME="sect2">Description</A></H2> -<P>These functions contain the code normally run via <B>dllMain</B> +<P>These functions contain the code normally run via <b>dllMain</b>  when the library is used as a dll but which need to be called -explicitly by an application when the library is statically linked.</P> +explicitly by an application when the library is statically linked. As of version 2.9.0,  the  static library built using either MSC or GCC includes RT hooks which will call the pthread_win32_process_*_np routines automatically on  start/exit of the application.</P>  <P>You will need to call <B>pthread_win32_process_attach_np</B>  before you can call any pthread routines when statically linking. You  should call <B>pthread_win32_process_detach_np</B> before exiting diff --git a/need_errno.h b/need_errno.h index a28955a..6099479 100644 --- a/need_errno.h +++ b/need_errno.h @@ -59,8 +59,7 @@ extern "C" {  #endif  #endif -/* declare reference to errno */ -#ifndef PTW32_STATIC_LIB +#if !defined(PTW32_STATIC_LIB)  #  ifdef PTW32_BUILD  #    define PTW32_DLLPORT __declspec (dllexport)  #  else @@ -49,6 +49,7 @@  #include "condvar.c"  #include "create.c"  #include "dll.c" +#include "autostatic.c"  #include "errno.c"  #include "exit.c"  #include "fork.c" @@ -528,12 +528,12 @@ extern "C"  #endif  /* - * When building the DLL code, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the DLL, + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library,   * do NOT define PTW32_BUILD, and then the variables/functions will   * be imported correctly.   */ -#ifndef PTW32_STATIC_LIB +#if !defined(PTW32_STATIC_LIB)  #  ifdef PTW32_BUILD  #    define PTW32_DLLPORT __declspec (dllexport)  #  else diff --git a/pthread_barrier_destroy.c b/pthread_barrier_destroy.c index 9302ba7..baed212 100644 --- a/pthread_barrier_destroy.c +++ b/pthread_barrier_destroy.c @@ -37,31 +37,67 @@  #include "pthread.h"  #include "implement.h" -  int  pthread_barrier_destroy (pthread_barrier_t * barrier)  {    int result = 0;    pthread_barrier_t b; +  ptw32_mcs_local_node_t node;    if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID)      {        return EINVAL;      } +  if (0 != ptw32_mcs_lock_try_acquire((ptw32_mcs_lock_t *)&(*barrier)->lock, &node)) +    { +      return EBUSY; +    } +    b = *barrier; -  *barrier = NULL; -  if (0 == (result = sem_destroy (&(b->semBarrierBreeched[0])))) +  if (b->nCurrentBarrierHeight < b->nInitialBarrierHeight)      { -      if (0 == (result = sem_destroy (&(b->semBarrierBreeched[1])))) +      result = EBUSY; +    } +  else  	{ +      if (0 == (result = sem_destroy (&(b->semBarrierBreeched)))) +        { +          *barrier = (pthread_barrier_t) PTW32_OBJECT_INVALID; +          /* +           * Release the lock before freeing b. +           * +           * FIXME: There may be successors which, when we release the lock, +           * will be linked into b->lock, which will be corrupted at some +           * point with undefined results for the application. To fix this +           * will require changing pthread_barrier_t from a pointer to +           * pthread_barrier_t_ to an instance. This is a change to the ABI +           * and will require a major version number increment. +           */ +          ptw32_mcs_lock_release(&node);  	  (void) free (b);  	  return 0;  	} -      (void) sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0); +      else +        { +          /* +           * This should not ever be reached. +           * Restore the barrier to working condition before returning. +           */ +          (void) sem_init (&(b->semBarrierBreeched), b->pshared, 0); +        } + +      if (result != 0) +        { +          /* +           * The barrier still exists and is valid +           * in the event of any error above. +           */ +          result = EBUSY; +        }      } -  *barrier = b; +  ptw32_mcs_lock_release(&node);    return (result);  } diff --git a/pthread_barrier_init.c b/pthread_barrier_init.c index dc1b50c..618bfae 100644 --- a/pthread_barrier_init.c +++ b/pthread_barrier_init.c @@ -55,25 +55,13 @@ pthread_barrier_init (pthread_barrier_t * barrier,  		    ? (*attr)->pshared : PTHREAD_PROCESS_PRIVATE);        b->nCurrentBarrierHeight = b->nInitialBarrierHeight = count; -      b->iStep = 0; +      b->lock = 0; -      /* -       * Two semaphores are used in the same way as two stepping -       * stones might be used in crossing a stream. Once all -       * threads are safely on one stone, the other stone can -       * be moved ahead, and the threads can start moving to it. -       * If some threads decide to eat their lunch before moving -       * then the other threads have to wait. -       */ -      if (0 == sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0)) -	{ -	  if (0 == sem_init (&(b->semBarrierBreeched[1]), b->pshared, 0)) +      if (0 == sem_init (&(b->semBarrierBreeched), b->pshared, 0))  	    {  	      *barrier = b;  	      return 0;  	    } -	  (void) sem_destroy (&(b->semBarrierBreeched[0])); -	}        (void) free (b);      } diff --git a/pthread_barrier_wait.c b/pthread_barrier_wait.c index 01ae297..182b779 100644 --- a/pthread_barrier_wait.c +++ b/pthread_barrier_wait.c @@ -42,57 +42,62 @@ int  pthread_barrier_wait (pthread_barrier_t * barrier)  {    int result; -  int step;    pthread_barrier_t b; +  ptw32_mcs_local_node_t node; +    if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID)      {        return EINVAL;      } -  b = *barrier; -  step = b->iStep; +  ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&(*barrier)->lock, &node); -  if (0 == InterlockedDecrement ((long *) &(b->nCurrentBarrierHeight))) +  b = *barrier; +  if (--b->nCurrentBarrierHeight == 0)      { -      /* Must be done before posting the semaphore. */ -      b->nCurrentBarrierHeight = b->nInitialBarrierHeight; +      /* +       * We are the last thread to arrive at the barrier before it releases us. +       * Move our MCS local node to the global scope barrier handle so that the +       * last thread out (not necessarily us) can release the lock. +       */ +      ptw32_mcs_node_substitute(&b->proxynode, &node);        /* -       * There is no race condition between the semaphore wait and post -       * because we are using two alternating semas and all threads have -       * entered barrier_wait and checked nCurrentBarrierHeight before this -       * barrier's sema can be posted. Any threads that have not quite -       * entered sem_wait below when the multiple_post has completed -       * will nevertheless continue through the semaphore (barrier) -       * and will not be left stranded. +       * Any threads that have not quite entered sem_wait below when the +       * multiple_post has completed will nevertheless continue through +       * the semaphore (barrier).         */        result = (b->nInitialBarrierHeight > 1 -		? sem_post_multiple (&(b->semBarrierBreeched[step]), +                ? sem_post_multiple (&(b->semBarrierBreeched),  				     b->nInitialBarrierHeight - 1) : 0);      }    else      { +      ptw32_mcs_lock_release(&node);        /*         * Use the non-cancelable version of sem_wait(). +       * +       * It is possible that all nInitialBarrierHeight-1 threads are +       * at this point when the last thread enters the barrier, resets +       * nCurrentBarrierHeight = nInitialBarrierHeight and leaves. +       * If pthread_barrier_destroy is called at that moment then the +       * barrier will be destroyed along with the semas.         */ -      result = ptw32_semwait (&(b->semBarrierBreeched[step])); +      result = ptw32_semwait (&(b->semBarrierBreeched));      } +  if ((PTW32_INTERLOCKED_LONG)InterlockedIncrement((LPLONG)&b->nCurrentBarrierHeight) +		  == (PTW32_INTERLOCKED_LONG)b->nInitialBarrierHeight) +    {    /* -   * The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD. -   * This also sets up the alternate semaphore as the next barrier. +       * We are the last thread to cross this barrier     */ +      ptw32_mcs_lock_release(&b->proxynode);    if (0 == result)      { -      result = ((PTW32_INTERLOCKED_LONG) step == -		PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) -						    & (b->iStep), -						    (PTW32_INTERLOCKED_LONG) -						    (1L - step), -						    (PTW32_INTERLOCKED_LONG) -						    step) ? -		PTHREAD_BARRIER_SERIAL_THREAD : 0); +          result = PTHREAD_BARRIER_SERIAL_THREAD; +        }      }    return (result); diff --git a/pthread_cancel.c b/pthread_cancel.c index 7d519ee..de2c5a9 100644 --- a/pthread_cancel.c +++ b/pthread_cancel.c @@ -113,16 +113,8 @@ pthread_cancel (pthread_t thread)      };    /* -   * FIXME!! -   * -   * Can a thread cancel itself? -   * -   * The standard doesn't -   * specify an error to be returned if the target -   * thread is itself. -   * -   * If it may, then we need to ensure that a thread can't -   * deadlock itself trying to cancel itself asyncronously +   * For self cancellation we need to ensure that a thread can't +   * deadlock itself trying to cancel itself asynchronously     * (pthread_cancel is required to be an async-cancel     * safe function).     */ diff --git a/pthread_getspecific.c b/pthread_getspecific.c index b05ff41..5ee1641 100644 --- a/pthread_getspecific.c +++ b/pthread_getspecific.c @@ -72,12 +72,15 @@ pthread_getspecific (pthread_key_t key)    else      {        int lasterror = GetLastError (); +#if defined(RETAIN_WSALASTERROR)        int lastWSAerror = WSAGetLastError (); - +#endif        ptr = TlsGetValue (key->key);        SetLastError (lasterror); +#if defined(RETAIN_WSALASTERROR)        WSASetLastError (lastWSAerror); +#endif      }    return ptr; diff --git a/pthread_join.c b/pthread_join.c index 3804327..72a3a74 100644 --- a/pthread_join.c +++ b/pthread_join.c @@ -104,7 +104,7 @@ pthread_join (pthread_t thread, void **value_ptr)    LeaveCriticalSection (&ptw32_thread_reuse_lock); -  if (0 == result) +  if (result == 0)      {        /*          * The target thread is joinable and can't be reused before we join it. @@ -124,7 +124,7 @@ pthread_join (pthread_t thread, void **value_ptr)  	  /*  	   * Pthread_join is a cancelation point.  	   * If we are canceled then our target thread must not be -	   * detached (destroyed) by us. This is guarranteed because +	   * detached (destroyed). This is guarranteed because  	   * pthreadCancelableWait will not return if we  	   * are canceled.  	   */ diff --git a/pthread_once.c b/pthread_once.c index 96d45f2..4da54fc 100644 --- a/pthread_once.c +++ b/pthread_once.c @@ -41,7 +41,7 @@  static void PTW32_CDECL  ptw32_once_on_init_cancel (void * arg)  { -  /* when the initting thread is cancelled we have to release the lock */ +  /* when the initing thread is cancelled we have to release the lock */    ptw32_mcs_local_node_t *node = (ptw32_mcs_local_node_t *)arg;    ptw32_mcs_lock_release(node);  } diff --git a/pthread_win32_attach_detach_np.c b/pthread_win32_attach_detach_np.c index 5bbd925..7911fe1 100644 --- a/pthread_win32_attach_detach_np.c +++ b/pthread_win32_attach_detach_np.c @@ -283,7 +283,7 @@ pthread_win32_thread_detach_np ()         */        ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); -      if (sp != NULL) +      if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle.  	{  	  ptw32_callUserDestroyRoutines (sp->ptHandle); @@ -291,16 +291,10 @@ pthread_win32_thread_detach_np ()  	  sp->state = PThreadStateLast;  	  /*  	   * If the thread is joinable at this point then it MUST be joined -	   * or detached explicitly by the application because it's -	   * detachState cannot be changed from this point on. +	   * or detached explicitly by the application.  	   */  	  (void) pthread_mutex_unlock (&sp->cancelLock); -	  /* -	   * No race condition here because detachState will not be changed -	   * elsewhere now that thread state is PThreadStateLast (set above -	   * behind mutex). -	   */  	  if (sp->detachState == PTHREAD_CREATE_DETACHED)  	    {  	      ptw32_threadDestroy (sp->ptHandle); diff --git a/ptw32_MCS_lock.c b/ptw32_MCS_lock.c index 6b797c5..80e0f5a 100644 --- a/ptw32_MCS_lock.c +++ b/ptw32_MCS_lock.c @@ -89,8 +89,8 @@   * }   */ -#include "pthread.h"  #include "implement.h" +#include "pthread.h"  /*   * ptw32_mcs_flag_set -- notify another thread about an event. @@ -159,8 +159,8 @@ ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node)    node->next = 0; /* initially, no successor */    /* queue for the lock */ -  pred = (ptw32_mcs_local_node_t *)PTW32_INTERLOCKED_EXCHANGE((LPLONG)lock, -						              (LONG)node); +  pred = (ptw32_mcs_local_node_t *)PTW32_INTERLOCKED_EXCHANGE((PTW32_INTERLOCKED_LPLONG)lock, +						              (PTW32_INTERLOCKED_LONG)node);    if (0 != pred)      { @@ -184,7 +184,8 @@ ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node)  {    ptw32_mcs_lock_t *lock = node->lock;    ptw32_mcs_local_node_t *next = (ptw32_mcs_local_node_t *) -    InterlockedExchangeAdd((LPLONG)&node->next, 0); /* MBR fence */ +    InterlockedExchangeAdd((LPLONG)&node->next, +                           (LONG)0); /* MBR fence */    if (0 == next)      { @@ -208,3 +209,55 @@ ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node)    /* pass the lock */    ptw32_mcs_flag_set(&next->readyFlag);  } + +/* +  * ptw32_mcs_lock_try_acquire + */ +INLINE int +ptw32_mcs_lock_try_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node) +{ +  node->lock = lock; +  node->nextFlag = 0; +  node->readyFlag = 0; +  node->next = 0; /* initially, no successor */ + +  return ((PTW32_INTERLOCKED_LPLONG)PTW32_INTERLOCKED_COMPARE_EXCHANGE( +                                      (PTW32_INTERLOCKED_LPLONG)lock, +                                      (PTW32_INTERLOCKED_LONG)node, +                                      (PTW32_INTERLOCKED_LONG)0) +               == (PTW32_INTERLOCKED_LPLONG)0) ? 0 : EBUSY; +} + +/* + * ptw32_mcs_node_substitute -- move an MCS lock local node, usually from thread + * space to, for example, global space so that another thread can release + * the lock on behalf of the current lock owner. + * + * Example: used in pthread_barrier_wait where we want the last thread out of + * the barrier to release the lock owned by the last thread to enter the barrier + * (the one that releases all threads but not necessarily the last to leave). + * + * Should only be called by the thread that has the lock. + */ +INLINE void +ptw32_mcs_node_substitute (ptw32_mcs_local_node_t * new_node, ptw32_mcs_local_node_t * old_node) +{ +  new_node->lock = old_node->lock; +  new_node->nextFlag = 0; /* Not needed - used only in initial Acquire */ +  new_node->readyFlag = 0; /* Not needed - we were waiting on this */ +  new_node->next = 0; + +  if ((ptw32_mcs_local_node_t *)PTW32_INTERLOCKED_COMPARE_EXCHANGE((PTW32_INTERLOCKED_LPLONG)new_node->lock, +                                                                   (PTW32_INTERLOCKED_LONG)new_node, +                                                                   (PTW32_INTERLOCKED_LONG)old_node) != old_node) +    { +      /* +       * A successor has queued after us, so wait for them to link to us +       */ +      while (old_node->next == 0) +        { +          Sleep(0); +        } +      new_node->next = old_node->next; +    } +} @@ -71,12 +71,12 @@  #endif  /* - * When building the DLL code, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the DLL, + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library,   * do NOT define PTW32_BUILD, and then the variables/functions will   * be imported correctly.   */ -#ifndef PTW32_STATIC_LIB +#if !defined(PTW32_STATIC_LIB)  #  ifdef PTW32_BUILD  #    define PTW32_DLLPORT __declspec (dllexport)  #  else diff --git a/semaphore.h b/semaphore.h index a3330a6..52438c7 100644 --- a/semaphore.h +++ b/semaphore.h @@ -70,12 +70,12 @@  #endif  /* - * When building the DLL code, you should define PTW32_BUILD so that - * the variables/functions are exported correctly. When using the DLL, + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library,   * do NOT define PTW32_BUILD, and then the variables/functions will   * be imported correctly.   */ -#ifndef PTW32_STATIC_LIB +#if !defined(PTW32_STATIC_LIB)  #  ifdef PTW32_BUILD  #    define PTW32_DLLPORT __declspec (dllexport)  #  else diff --git a/tests/Bmakefile b/tests/Bmakefile index 9a2c2b4..169f42c 100644 --- a/tests/Bmakefile +++ b/tests/Bmakefile @@ -40,6 +40,7 @@ MKDIR	= mkdir  TOUCH	= echo Passed >  ECHO	= @echo +# The next path is relative to $BUILD_DIR  QAPC	= ..\QueueUserAPCEx\User\quserex.dll  CPHDR	= pthread.h semaphore.h sched.h @@ -96,7 +97,7 @@ PASSES=   loadfree.pass \  	  self2.pass  \  	  cancel1.pass  cancel2.pass  \  	  semaphore4.pass  semaphore4t.pass  semaphore5.pass  \ -	  barrier1.pass  barrier2.pass  barrier3.pass  barrier4.pass  barrier5.pass  \ +	  barrier1.pass  barrier2.pass  barrier3.pass  barrier4.pass  barrier5.pass barrier6.pass \  	  tsd1.pass  tsd2.pass  delay1.pass  delay2.pass  eyal1.pass  \  	  condvar3.pass  condvar3_1.pass  condvar3_2.pass  condvar3_3.pass  \  	  condvar4.pass  condvar5.pass  condvar6.pass  \ @@ -114,7 +115,8 @@ PASSES=   loadfree.pass \  	  cancel9.pass  create3.pass  stress1.pass  BENCHRESULTS = \ -	  benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench +	  benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench \ +	  benchtest6.bench  help:  	@ $(ECHO) Run one of the following command lines: @@ -191,7 +193,7 @@ BCX-bench:  	@ $(CC) /P $(EHFLAGS) $(CFLAGS) $(INCLUDES) $<  $(COPYFILES): -	@ $(ECHO) Copying $@ +	@ $(ECHO) Copying $(BUILD_DIR)\$@  	@ $(CP) $(BUILD_DIR)\$@ .  pthread.dll: $(CPDLL) @@ -221,11 +223,13 @@ benchtest2.bench:  benchtest3.bench:  benchtest4.bench:  benchtest5.bench: +benchtest6.bench:  barrier1.pass: semaphore4.pass  barrier2.pass: barrier1.pass  barrier3.pass: barrier2.pass  barrier4.pass: barrier3.pass  barrier5.pass: barrier4.pass +barrier6.pass: barrier5.pass  cancel1.pass: create1.pass  cancel2.pass: cancel1.pass  cancel3.pass: context1.pass diff --git a/tests/ChangeLog b/tests/ChangeLog index 30f6ccb..1bdcc43 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,22 @@ +2010-06-19  Ross Johnson <Ross dot Johnson at homemail dot com dot au> + +	* Makefile (STATICRESULTS): Add all tests into suite for static +	library. +	* GNUmakefile (STATICTESTS): Likewise, except for openmp1.c which +	has a DLL dependency. + +2010-02-04  Ross Johnson <Ross dot Johnson at homemail dot com dot au> + +	* openmp1.c: New; for libgomp compatibility (OpenMP). +	* barrier5.c: Rewrite after changes to barriers. +	* barrier6.c: New. +	* benchtest6.c: New; timing barriers. +	* GNUMakefile: Update for new tests. +	* Makefile: Ditto. +	* BMakefile: Ditto. +	* once3.c: Improve cancelation testing. +	* stress1.c: Fix comment. +  2007-01-04  Ross Johnson <Ross dot Johnson at homemail dot com dot au>          * context1.c: Include context.h from library sources and remove diff --git a/tests/GNUmakefile b/tests/GNUmakefile index 1762b6c..c431f2f 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -44,15 +44,15 @@ CAT	= cat  MKDIR	= mkdir  TOUCH	= echo Passed >  ECHO	= @echo -MAKE	= make +MAKE	= make -k  #  # Mingw32  #  XXCFLAGS	=  -XXLIBS	= -lws2_32 +XXLIBS	= -lws2_32 -lgomp  #CFLAGS	= -O3 -UNDEBUG -Wall $(XXCFLAGS) -CFLAGS	= -g -UNDEBUG -Wall $(XXCFLAGS) +CFLAGS	= -O3 -fopenmp -UNDEBUG -Wall $(XXCFLAGS)  BUILD_DIR	= ..  INCLUDES	= -I. @@ -67,6 +67,7 @@ GCX	= $(TEST)$(DLL_VER)  HDR	= pthread.h semaphore.h sched.h  LIB	= libpthread$(GCX).a  DLL	= pthread$(GCX).dll +# The next path is relative to $BUILD_DIR  QAPC	= ../QueueUserAPCEx/User/quserex.dll  COPYFILES	= $(HDR) $(LIB) $(DLL) $(QAPC) @@ -74,7 +75,8 @@ COPYFILES	= $(HDR) $(LIB) $(DLL) $(QAPC)  # If a test case returns a non-zero exit code to the shell, make will  # stop. -TESTS	= sizes loadfree \ +TESTS	= \ +	  sizes loadfree \  	  self1 mutex5 mutex1 mutex1e mutex1n mutex1r \  	  semaphore1 semaphore2 semaphore3 \  	  condvar1 condvar1_1 condvar1_2 condvar2 condvar2_1 exit1 \ @@ -90,8 +92,8 @@ TESTS	= sizes loadfree \  	  once1 once2 once3 once4 self2 \  	  cancel1 cancel2 \  	  semaphore4 semaphore4t semaphore5 \ -	  barrier1 barrier2 barrier3 barrier4 barrier5 \ -	  tsd1 tsd2 delay1 delay2 eyal1 \ +	  barrier1 barrier2 barrier3 barrier4 barrier5 barrier6 \ +	  tsd1 tsd2 openmp1 delay1 delay2 eyal1 \  	  condvar3 condvar3_1 condvar3_2 condvar3_3 \  	  condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \  	  errno1 \ @@ -109,10 +111,39 @@ STRESSTESTS = \  	stress1  BENCHTESTS = \ -	benchtest1 benchtest2 benchtest3 benchtest4 benchtest5 +	benchtest1 benchtest2 benchtest3 benchtest4 benchtest5 benchtest6  STATICTESTS = \ -	self1 +	  sizes \ +	  self1 mutex5 mutex1 mutex1e mutex1n mutex1r \ +	  semaphore1 semaphore2 semaphore3 \ +	  condvar1 condvar1_1 condvar1_2 condvar2 condvar2_1 exit1 \ +	  create1 create2 reuse1 reuse2 equal1 \ +	  kill1 valid1 valid2 \ +	  exit2 exit3 exit4 exit5 \ +	  join0 join1 detach1 join2 join3 \ +	  mutex2 mutex2r mutex2e mutex3 mutex3r mutex3e \ +	  mutex4 mutex6 mutex6n mutex6e mutex6r \ +	  mutex6s mutex6es mutex6rs \ +	  mutex7 mutex7n mutex7e mutex7r mutex8 mutex8n mutex8e mutex8r \ +	  count1 \ +	  once1 once2 once3 once4 self2 \ +	  cancel1 cancel2 \ +	  semaphore4 semaphore4t semaphore5 \ +	  barrier1 barrier2 barrier3 barrier4 barrier5 barrier6 \ +	  tsd1 tsd2 delay1 delay2 eyal1 \ +	  condvar3 condvar3_1 condvar3_2 condvar3_3 \ +	  condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \ +	  errno1 \ +	  rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 rwlock7 rwlock8 \ +	  rwlock2_t rwlock3_t rwlock4_t rwlock5_t rwlock6_t rwlock6_t2 \ +	  context1 cancel3 cancel4 cancel5 cancel6a cancel6d \ +	  cancel7 cancel8 \ +	  cleanup0 cleanup1 cleanup2 cleanup3 \ +	  priority1 priority2 inherit1 \ +	  spin1 spin2 spin3 spin4 \ +	  exception1 exception2 exception3 \ +	  cancel9 create3 stress1  PASSES		= $(TESTS:%=%.pass)  BENCHRESULTS	= $(BENCHTESTS:%=%.bench) @@ -184,12 +215,14 @@ benchtest2.bench:  benchtest3.bench:  benchtest4.bench:  benchtest5.bench: +benchtest6.bench:  barrier1.pass: semaphore4.pass  barrier2.pass: barrier1.pass  barrier3.pass: barrier2.pass  barrier4.pass: barrier3.pass  barrier5.pass: barrier4.pass +barrier6.pass: barrier5.pass  cancel1.pass: create1.pass  cancel2.pass: cancel1.pass  cancel2_1.pass: cancel2.pass @@ -277,6 +310,7 @@ once1.pass: create1.pass  once2.pass: once1.pass  once3.pass: once2.pass  once4.pass: once3.pass +openmp1.pass: tsd2.pass  priority1.pass: join1.pass  priority2.pass: priority1.pass barrier3.pass  reuse1.pass: create2.pass @@ -345,7 +379,7 @@ sizes.pass: sizes.exe  	@ $(CC) -S $(CFLAGS) -o $@ $< $(INCLUDES)  $(COPYFILES): -	@ $(ECHO) Copying $@ +	@ $(ECHO) Copying $(BUILD_DIR)/$@  	@ $(CP) $(BUILD_DIR)/$@ .  benchlib.o: benchlib.c @@ -366,6 +400,7 @@ clean:  	- $(RM) *.e  	- $(RM) *.i  	- $(RM) *.o +	- $(RM) *.so  	- $(RM) *.obj  	- $(RM) *.pdb  	- $(RM) *.exe diff --git a/tests/Makefile b/tests/Makefile index 57fd2f4..c3342be 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -40,6 +40,7 @@ MKDIR	= mkdir  TOUCH	= echo Passed >  ECHO	= @echo +# The next path is relative to $BUILD_DIR  QAPC	= ..\QueueUserAPCEx\User\quserex.dll  CPHDR	= pthread.h semaphore.h sched.h @@ -67,7 +68,7 @@ VCXFLAGS	= /GX /TP /D__CLEANUP_C  CPLIB	= $(VCLIB)  CPDLL	= $(VCDLL) -CFLAGS= $(OPTIM) /W3 /WX /MD /nologo /Zi +CFLAGS= $(OPTIM) /W3 /WX /MD /nologo /Yd /Zi  LFLAGS= /INCREMENTAL:NO  INCLUDES=-I.  BUILD_DIR=.. @@ -100,7 +101,7 @@ PASSES= sizes.pass  loadfree.pass \  	  self2.pass  \  	  cancel1.pass  cancel2.pass  \  	  semaphore4.pass  semaphore4t.pass  semaphore5.pass  \ -	  barrier1.pass  barrier2.pass  barrier3.pass  barrier4.pass  barrier5.pass  \ +	  barrier1.pass  barrier2.pass  barrier3.pass  barrier4.pass  barrier5.pass  barrier6.pass  \  	  tsd1.pass  tsd2.pass  delay1.pass  delay2.pass  eyal1.pass  \  	  condvar3.pass  condvar3_1.pass  condvar3_2.pass  condvar3_3.pass  \  	  condvar4.pass  condvar5.pass  condvar6.pass  \ @@ -119,13 +120,50 @@ PASSES= sizes.pass  loadfree.pass \  	  cancel9.pass  create3.pass  stress1.pass  BENCHRESULTS = \ -	  benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench +	  benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench \ +	  benchtest6.bench  STRESSRESULTS = \  	  stress1.stress  STATICRESULTS = \ -	  self1.pass +	  sizes.pass  \ +	  self1.pass  mutex5.pass  \ +	  mutex1.pass  mutex1n.pass  mutex1e.pass  mutex1r.pass  \ +	  semaphore1.pass  semaphore2.pass  semaphore3.pass  \ +	  mutex2.pass  mutex3.pass  \ +	  mutex2r.pass  mutex2e.pass  mutex3r.pass  mutex3e.pass  \ +	  condvar1.pass  condvar1_1.pass  condvar1_2.pass  condvar2.pass  condvar2_1.pass  \ +	  exit1.pass  create1.pass  create2.pass  reuse1.pass  reuse2.pass  equal1.pass  \ +	  kill1.pass  valid1.pass  valid2.pass  \ +	  exit2.pass  exit3.pass  exit4.pass  exit5.pass  \ +	  join0.pass  join1.pass  detach1.pass  join2.pass join3.pass  \ +	  mutex4.pass  mutex6.pass  mutex6n.pass  mutex6e.pass  mutex6r.pass  \ +	  mutex6s.pass  mutex6es.pass  mutex6rs.pass  \ +	  mutex7.pass  mutex7n.pass  mutex7e.pass  mutex7r.pass  \ +	  mutex8.pass  mutex8n.pass  mutex8e.pass  mutex8r.pass  \ +	  count1.pass  \ +	  once1.pass  once2.pass  once3.pass  once4.pass  \ +	  self2.pass  \ +	  cancel1.pass  cancel2.pass  \ +	  semaphore4.pass  semaphore4t.pass  semaphore5.pass  \ +	  barrier1.pass  barrier2.pass  barrier3.pass  barrier4.pass  barrier5.pass  barrier6.pass  \ +	  tsd1.pass  tsd2.pass  delay1.pass  delay2.pass  eyal1.pass  \ +	  condvar3.pass  condvar3_1.pass  condvar3_2.pass  condvar3_3.pass  \ +	  condvar4.pass  condvar5.pass  condvar6.pass  \ +	  condvar7.pass  condvar8.pass  condvar9.pass  \ +	  errno1.pass  \ +	  rwlock1.pass  rwlock2.pass  rwlock3.pass  rwlock4.pass  \ +	  rwlock5.pass  rwlock6.pass  rwlock7.pass  rwlock8.pass  \ +	  rwlock2_t.pass  rwlock3_t.pass  rwlock4_t.pass  rwlock5_t.pass  rwlock6_t.pass  rwlock6_t2.pass  \ +	  context1.pass  \ +	  cancel3.pass  cancel4.pass  cancel5.pass  cancel6a.pass  cancel6d.pass  \ +	  cancel7.pass  cancel8.pass  \ +	  cleanup0.pass  cleanup1.pass  cleanup2.pass  cleanup3.pass  \ +	  priority1.pass priority2.pass inherit1.pass  \ +	  spin1.pass  spin2.pass  spin3.pass  spin4.pass  \ +	  exception1.pass  exception2.pass  exception3.pass  \ +	  cancel9.pass  create3.pass  stress1.pass  help:  	@ $(ECHO) Run one of the following command lines: @@ -245,7 +283,7 @@ VC-static:  	@ $(CC) /P $(EHFLAGS) $(CFLAGS) $(INCLUDES) $<  $(COPYFILES): -	@ $(ECHO) Copying $@ +	@ $(ECHO) Copying $(BUILD_DIR)\$@  	@ $(CP) $(BUILD_DIR)\$@ .  pthread.dll: $(CPDLL) @@ -274,12 +312,14 @@ benchtest2.bench:  benchtest3.bench:  benchtest4.bench:  benchtest5.bench: +benchtest6.bench:  barrier1.pass: semaphore4.pass  barrier2.pass: barrier1.pass  barrier3.pass: barrier2.pass  barrier4.pass: barrier3.pass  barrier5.pass: barrier4.pass +barrier6.pass: barrier5.pass  cancel1.pass: create1.pass  cancel2.pass: cancel1.pass  cancel3.pass: context1.pass diff --git a/tests/SIZES.GC b/tests/SIZES.GC index ae09a84..9252581 100755 --- a/tests/SIZES.GC +++ b/tests/SIZES.GC @@ -1,20 +1,21 @@  Sizes of pthreads-win32 structs  ------------------------------- -                    pthread_t_  124 +                     pthread_t    8
 +                ptw32_thread_t  140
                 pthread_attr_t_   28 -                        sem_t_    4 -              pthread_mutex_t_   44 +                        sem_t_   12
 +              pthread_mutex_t_   24
            pthread_mutexattr_t_    8             pthread_spinlock_t_    8 -            pthread_barrier_t_   24 +            pthread_barrier_t_   36
          pthread_barrierattr_t_    4                  pthread_key_t_   16                 pthread_cond_t_   32             pthread_condattr_t_    4               pthread_rwlock_t_   28           pthread_rwlockattr_t_    4 -               pthread_once_t_    8 +               pthread_once_t_   16
                 ptw32_cleanup_t   12 +             ptw32_mcs_node_t_   16
                     sched_param    4  ------------------------------- - diff --git a/tests/SIZES.GCE b/tests/SIZES.GCE index f36d0d2..a9ea64d 100755 --- a/tests/SIZES.GCE +++ b/tests/SIZES.GCE @@ -1,20 +1,21 @@  Sizes of pthreads-win32 structs  ------------------------------- -                    pthread_t_   60 +                     pthread_t    8
 +                ptw32_thread_t   76
                 pthread_attr_t_   28 -                        sem_t_    4 -              pthread_mutex_t_   44 +                        sem_t_   12
 +              pthread_mutex_t_   24
            pthread_mutexattr_t_    8             pthread_spinlock_t_    8 -            pthread_barrier_t_   24 +            pthread_barrier_t_   36
          pthread_barrierattr_t_    4                  pthread_key_t_   16                 pthread_cond_t_   32             pthread_condattr_t_    4               pthread_rwlock_t_   28           pthread_rwlockattr_t_    4 -               pthread_once_t_    8 +               pthread_once_t_   16
                 ptw32_cleanup_t   12 +             ptw32_mcs_node_t_   16
                     sched_param    4  ------------------------------- - diff --git a/tests/Wmakefile b/tests/Wmakefile index 83cd34b..a4b64a3 100644 --- a/tests/Wmakefile +++ b/tests/Wmakefile @@ -68,7 +68,10 @@ LFLAGS=  INCLUDES= -i=.  BUILD_DIR=.. -COPYFILES	= $(CPHDR) $(CPLIB) $(CPDLL) +# The next path is relative to $BUILD_DIR +QAPC	= ..\QueueUserAPCEx\User\quserex.dll + +COPYFILES	= $(CPHDR) $(CPLIB) $(CPDLL) $(QAPC)  TEST		=  EHFLAGS	= @@ -188,7 +191,7 @@ sizes.pass: sizes.exe  	@ $(CC) /P $(EHFLAGS) $(CFLAGS) $(INCLUDES) $<  $(COPYFILES): .SYMBOLIC -	@ $(ECHO) Copying $@ +	@ $(ECHO) Copying $(BUILD_DIR)\$@  	@ $(CP) $(BUILD_DIR)\$@ .  pthread.dll: diff --git a/tests/barrier5.c b/tests/barrier5.c index 5b598c9..851398c 100644 --- a/tests/barrier5.c +++ b/tests/barrier5.c @@ -33,47 +33,36 @@   *   * --------------------------------------------------------------------------   * - * Declare a single barrier object, set up a sequence of - * barrier points to prove lockstepness, and then destroy it. - * + * Set up a series of barriers at different heights and test various numbers + * of threads accessing, especially cases where there are more threads than the + * barrier height (count), i.e. test contention when the barrier is released.   */  #include "test.h"  enum { -  NUMTHREADS = 16, -  BARRIERS = 10000 +  NUMTHREADS = 15, +  HEIGHT = 10, +  BARRIERMULTIPLE = 1000  };  pthread_barrier_t barrier = NULL;  pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; - -int barrierReleases[BARRIERS + 1]; +LONG totalThreadCrossings;  void * -func(void * barrierHeight) +func(void * crossings)  { -  int i;    int result;    int serialThreads = 0; -  for (i = 1; i < BARRIERS; i++) +  while ((LONG)crossings >= (LONG)InterlockedIncrement((LPLONG)&totalThreadCrossings))      {        result = pthread_barrier_wait(&barrier); -      assert(pthread_mutex_lock(&mx) == 0); -      barrierReleases[i]++; -      assert(pthread_mutex_unlock(&mx) == 0); -      /* -       * Confirm the correct number of releases from the previous -       * barrier. We can't do the current barrier yet because there may -       * still be threads waking up. -       */        if (result == PTHREAD_BARRIER_SERIAL_THREAD)          {            serialThreads++; -          assert(barrierReleases[i - 1] == (int) barrierHeight); -          barrierReleases[i + 1] = 0;          }        else if (result != 0)          { @@ -92,20 +81,23 @@ main()    int i, j;    int result;    int serialThreadsTotal; +  LONG Crossings;    pthread_t t[NUMTHREADS + 1];    for (j = 1; j <= NUMTHREADS; j++)      { -      printf("Barrier height = %d\n", j); +      int height = j<HEIGHT?j:HEIGHT; + +      totalThreadCrossings = 0; +      Crossings = height * BARRIERMULTIPLE; -      barrierReleases[0] = j; -      barrierReleases[1] = 0; +      printf("Threads=%d, Barrier height=%d\n", j, height); -      assert(pthread_barrier_init(&barrier, NULL, j) == 0); +      assert(pthread_barrier_init(&barrier, NULL, height) == 0);        for (i = 1; i <= j; i++)          { -          assert(pthread_create(&t[i], NULL, func, (void *) j) == 0); +          assert(pthread_create(&t[i], NULL, func, (void *) Crossings) == 0);          }        serialThreadsTotal = 0; @@ -115,9 +107,7 @@ main()            serialThreadsTotal += result;          } -      assert(serialThreadsTotal == BARRIERS - 1); -      assert(barrierReleases[BARRIERS - 1] == j); -      assert(barrierReleases[BARRIERS] == 0); +      assert(serialThreadsTotal == BARRIERMULTIPLE);        assert(pthread_barrier_destroy(&barrier) == 0);      } diff --git a/tests/once3.c b/tests/once3.c index 51d2daa..c706f80 100644 --- a/tests/once3.c +++ b/tests/once3.c @@ -34,7 +34,7 @@   * --------------------------------------------------------------------------   *   * Create several pthread_once objects and channel several threads - * through each. Make the init_routine cancelable and cancel them + * through each. Make the init_routine cancelable and cancel them with   * waiters waiting.   *   * Depends on API functions: @@ -45,6 +45,8 @@   *      pthread_once()   */ +/* #define ASSERT_TRACE */ +  #include "test.h"  #define NUM_THREADS 100 /* Targeting each once control */ @@ -66,6 +68,7 @@ myfunc(void)  {    EnterCriticalSection(&numOnce.cs);    numOnce.i++; +  assert(numOnce.i > 0);    LeaveCriticalSection(&numOnce.cs);    /* Simulate slow once routine so that following threads pile up behind it */    Sleep(10); @@ -78,11 +81,11 @@ mythread(void * arg)  {    /*     * Cancel every thread. These threads are deferred cancelable only, so -   * only the thread performing the init_routine will see it (there are +   * only the thread performing the once routine (my_func) will see it (there are     * no other cancelation points here). The result will be that every thread -   * eventually cancels only when it becomes the new initter. +   * eventually cancels only when it becomes the new once thread.     */ -  pthread_cancel(pthread_self()); +  assert(pthread_cancel(pthread_self()) == 0);    assert(pthread_once(&once[(int) arg], myfunc) == 0);    EnterCriticalSection(&numThreads.cs);    numThreads.i++; diff --git a/tests/self1.c b/tests/self1.c index 59498d9..aa08328 100644 --- a/tests/self1.c +++ b/tests/self1.c @@ -54,7 +54,7 @@ main(int argc, char * argv[])  	 */  	pthread_t self; -#ifdef PTW32_STATIC_LIB +#if defined(PTW32_STATIC_LIB) && !(defined(_MSC_VER) || defined(__MINGW32__))  	pthread_win32_process_attach_np();  #endif @@ -62,7 +62,7 @@ main(int argc, char * argv[])  	assert(self.p != NULL); -#ifdef PTW32_STATIC_LIB +#if defined(PTW32_STATIC_LIB) && !(defined(_MSC_VER) || defined(__MINGW32__))  	pthread_win32_process_detach_np();  #endif  	return 0; diff --git a/tests/stress1.c b/tests/stress1.c index efaf445..3588361 100644 --- a/tests/stress1.c +++ b/tests/stress1.c @@ -54,7 +54,7 @@   * - Master and slave do battle continuously until main tells them to stop.   * - Afterwards, the CV must be successfully destroyed (will return an   * error if there are waiters (including any internal semaphore waiters, - * which, if there are, cannot not be real waiters). + * which, if there are, cannot be real waiters).   *   * Environment:   * -  @@ -97,7 +97,7 @@ static int timeoutCount = 0;  static int signalsTakenCount = 0;  static int signalsSent = 0;  static int bias = 0; -static int timeout = 10;
 // Must be > 0 +static int timeout = 10; // Must be > 0  enum {    CTL_STOP     = -1 diff --git a/tests/test.h b/tests/test.h index 3132c69..56fa335 100644 --- a/tests/test.h +++ b/tests/test.h @@ -56,7 +56,7 @@  #endif -char * error_string[] = { +const char * error_string[] = {    "ZERO_or_EOK",    "EPERM",    "ENOFILE_or_ENOENT", @@ -99,7 +99,7 @@ char * error_string[] = {    "ENOLCK",    "ENOSYS",    "ENOTEMPTY", -  "EILSEQ", +  "EILSEQ"  };  /* | 
