diff options
-rw-r--r-- | ANNOUNCE | 124 | ||||
-rw-r--r-- | ChangeLog | 23 | ||||
-rw-r--r-- | FAQ | 254 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | README.NONPORTABLE | 6 | ||||
-rw-r--r-- | cancel.c | 132 | ||||
-rw-r--r-- | condvar.c | 16 | ||||
-rw-r--r-- | misc.c | 15 | ||||
-rw-r--r-- | mutex.c | 80 | ||||
-rw-r--r-- | private.c | 11 | ||||
-rw-r--r-- | pthread.h | 4 | ||||
-rw-r--r-- | rwlock.c | 540 | ||||
-rw-r--r-- | signal.c | 12 | ||||
-rw-r--r-- | tests/ChangeLog | 16 | ||||
-rw-r--r-- | tests/GNUmakefile | 18 | ||||
-rw-r--r-- | tests/Makefile | 14 | ||||
-rw-r--r-- | tests/cleanup0.c | 8 | ||||
-rw-r--r-- | tests/cleanup1.c | 7 | ||||
-rw-r--r-- | tests/cleanup2.c | 6 | ||||
-rw-r--r-- | tests/cleanup3.c | 6 | ||||
-rw-r--r-- | tests/condvar7.c | 6 | ||||
-rw-r--r-- | tests/condvar8.c | 12 | ||||
-rw-r--r-- | tests/condvar9.c | 12 |
23 files changed, 676 insertions, 652 deletions
@@ -27,10 +27,10 @@ announcement for the list of contributors. Changes since the last snapshot
-------------------------------
-Cleanup code default style. (IMPORTANT - with apologies for the length)
+Cleanup code default style. (IMPORTANT)
----------------------------------------------------------------------
Previously, if not defined, the cleanup style was determined automatically
-from the compiler used, and one of the following was defined accordingly:
+from the compiler/language, and one of the following was defined accordingly:
__CLEANUP_SEH MSVC only
__CLEANUP_CXX C++, including MSVC++, GNU G++
@@ -46,13 +46,14 @@ caught by a handler in the thread startup routine, so that the the correct stack unwinding occurs regardless of where the thread
is when it's canceled or exits via pthread_exit().
-In this snapshot, unless the build explicitly defines (e.g. via a
-compiler option) __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then
+In this and future snapshots, unless the build explicitly defines (e.g.
+via a compiler option) __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then
the build NOW always defaults to __CLEANUP_C style cleanup. This style
uses setjmp/longjmp in the cancelation and pthread_exit implementations,
and therefore won't do stack unwinding even when linked to applications
-that have it (e.g. C++ apps). This is for consistency with most/all
-commercial Unix POSIX threads implementations.
+that have it (e.g. C++ apps). This is for consistency with most
+current commercial Unix POSIX threads implementations. Compaq's TRU64
+may be an exception (no pun intended) and possible future trend.
Although it was not clearly documented before, it is still necessary to
build your application using the same __CLEANUP_* define as was
@@ -62,7 +63,11 @@ defines require the following library versions: __CLEANUP_SEH pthreadVSE.dll
__CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll
- __CLEANUP_C pthreadVC.dll or pthreadGC.dll
+ __CLEANUP_C pthreadVC.dll or pthreadGC.dll
+
+E.g. regardless of whether your app is C or C++, if you link with
+pthreadVC.lib or libpthreadGC.a, then you must define __CLEANUP_C.
+
THE POINT OF ALL THIS IS: if you have not been defining one of these
explicitly, then the defaults as described at the top of this
@@ -72,14 +77,14 @@ THIS NOW CHANGES, as has been explained above, but to try to make this clearer here's an example:
If you were building your application with MSVC++ i.e. using C++
-exceptions (rather than SEH) and not explicitly defining one of
-__CLEANUP_*, then __CLEANUP_C++ was defined for you in pthread.h.
+exceptions and not explicitly defining one of __CLEANUP_*, then
+__CLEANUP_C++ was automatically defined for you in pthread.h.
You should have been linking with pthreadVCE.dll, which does
stack unwinding.
If you now build your application as you had before, pthread.h will now
-set __CLEANUP_C as the default style, and you will need to link
-with pthreadVC.dll. Stack unwinding will now NOT occur when a thread
+automatically set __CLEANUP_C as the default style, and you will need to
+link with pthreadVC.dll. Stack unwinding will now NOT occur when a thread
is canceled, or the thread calls pthread_exit().
Your application will now most likely behave differently to previous
@@ -132,34 +137,37 @@ is not available on i386 CPUs. This library (from snapshot 20010712 onwards) is therefore no longer supported on i386
processor platforms.
-rwlocks
--------
-Rwlockattr functions have been added.
+New routines
+------------
+For source code portability only, rwlocks cannot be process shared yet.
+ pthread_rwlockattr_init()
+ pthread_rwlockattr_destroy()
+ pthread_rwlockattr_setpshared()
+ pthread_rwlockattr_getpshared()
-Restored pthread_rwlock_wrlock() as a cancelation point as permitted
-by POSIX 1003.1j. (Was prematurely disabled in the last snapshot.)
+As defined in the new POSIX standard, and the Single Unix Spec version 3:
+ sem_timedwait()
+ pthread_mutex_timedlock()
-First attempt at removing inclusion of windows.h in pthread.h
--------------------------------------------------------------
-This is done to prevent conflicts reported by some people.
+pthread.h no longer includes windows.h
+--------------------------------------
+This was done to prevent conflicts.
-Succeeded for all MSVC and the GNU C builds, but not yet for
-GNU C++. One unresolved error from the linker prevents the later.
-Only HANDLE and DWORD need to be defined in pthread.h. Safeguards
-are used to avoid redefinition errors in application builds.
+HANDLE, DWORD, and NULL are temporarily defined within pthread.h if
+they are not already.
Bug fixes
---------
-Fixed potential NULL pointer dereferences in pthread_mutexattr_init,
+* Fixed potential NULL pointer dereferences in pthread_mutexattr_init,
pthread_mutexattr_getpshared, pthread_barrierattr_init,
pthread_barrierattr_getpshared, and pthread_condattr_getpshared.
- Scott McCaskill <scott@magruder.org>
-Removed potential race condition in pthread_mutex_trylock and
+* Removed potential race condition in pthread_mutex_trylock and
pthread_mutex_lock;
- Alexander Terekhov <TEREKHOV@de.ibm.com>
-The behaviour of pthread_mutex_trylock in relation to
+* The behaviour of pthread_mutex_trylock in relation to
recursive mutexes was inconsistent with commercial implementations.
Trylock would return EBUSY if the lock was owned already by the
calling thread regardless of mutex type. Trylock now increments the
@@ -168,6 +176,22 @@ return EDEADLK rather than EBUSY for ERRORCHECK mutexes. This is consistent with Solaris.
- Thomas Pfaff <tpfaff@gmx.net>
+* Found a fix for the library and workaround for applications for
+the known bug #2, i.e. where __CLEANUP_CXX or __CLEANUP_SEH is defined.
+See the "Known Bugs in this snapshot" section below.
+
+This could be made transparent to applications by replacing the macros that
+define the current C++ and SEH versions of pthread_cleanup_push/pop
+with the C version, but AFAIK cleanup handlers would not then run in the
+correct sequence with destructors and exception cleanup handlers when
+an exception occurs.
+
+* Cancelation once started in a thread cannot now be inadvertantly
+double canceled. That is, once a thread begins it's cancelation run,
+cancelation is disabled and a subsequent cancel request will
+return an error (ESRCH).
+
+
---------------------------
Known bugs in this snapshot
---------------------------
@@ -182,6 +206,34 @@ Known bugs in this snapshot 2. Cancellation problems in optimised code
- Milan Gardian
+ Workaround [rpj - 2 Feb 2002]
+ -----------------------------
+ The problem disappears when /Ob0 is used, i.e. /O2 /Ob0 works OK.
+
+ So the inlining optimisation is interfering with the way that cleanup
+ handlers are run. In order to confirm this, the following use of pragmas
+ gets around the problem but I don't know how to make it transparent, in say,
+ pthread.h where pthread_cleanup_push is a macro that expands (in the C++ case) to
+ a local object instantiation with handlerFunc as the destructor (see pthread.h):
+
+ #pragma inline_depth(0)
+ pthread_cleanup_push(handlerFunc, (void *) &arg);
+
+ /* ... */
+
+ pthread_cleanup_pop(0);
+ #pragma inline_depth(8)
+
+ The pragma is also needed (and now used) within the library itself wherever
+ cleanup handlers are used (condvar.c and rwlock.c).
+
+ Use of these pragmas allows compiler optimisation /O2 to be used for
+ both the library and applications.
+ [/rpj]
+
+ Original problem description
+ ----------------------------
+
The cancellation (actually, cleanup-after-cancel) tests fail when using VC
(professional) optimisation switches (/O1 or /O2) in pthreads library. I
have not investigated which concrete optimisation technique causes this
@@ -309,7 +361,8 @@ The following functions are implemented: pthread_mutex_init
pthread_mutex_destroy
pthread_mutex_lock
- pthread_mutex_trylock
+ pthread_mutex_trylock
+ pthread_mutex_timedlock
pthread_mutex_unlock
---------------------------
@@ -370,6 +423,7 @@ The following functions are implemented: sem_post
sem_wait
sem_trywait
+ sem_timedwait
sem_open (returns an error ENOSYS)
sem_close (returns an error ENOSYS)
sem_unlink (returns an error ENOSYS)
@@ -410,7 +464,9 @@ The following functions are implemented: pthread_mutexattr_getkind_np
pthread_mutexattr_setkind_np (types: PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_ERRORCHECK_NP,
- PTHREAD_MUTEX_RECURSIVE_NP)
+ PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ADAPTIVE_NP,
+ PTHREAD_MUTEX_TIMED_NP)
pthread_num_processors_np
pthread_win32_process_attach_np (Required when statically linking the library)
pthread_win32_process_detach_np (Required when statically linking the library)
@@ -532,21 +588,15 @@ MSVC using C setjmp/longjmp works. Distribute pthreadVC.dll with your applicatio Mingw32:
-You need gcc-2.95.2-1 modified as per pthreads-win32 FAQ answer (6), with
-binutils-19990818-1 and msvcrt runtime-2000-03-27. Mingw32 must use
-the thread-safe MSVCRT library (see the FAQ). You need to distribute
-the gcc.dll DLL from Mingw32 with your application.
+See FAQ Questions 6 and 10.
Mingw using C++ EH works. Distribute pthreadGCE.dll with your application.
Mingw using C setjmp/longjmp works. Distribute pthreadGC.dll with your application.
Cygwin: (http://sourceware.cygnus.com/cygwin/)
-Cygwin aims to provide a complete POSIX environment on top of Win32, including
-threads. When this is complete, developers using Cygwin will not need
-pthreads-win32. At this time, Cygwin has preliminary support for multithreaded
-development, however, this is not turned on by default. We have not tested
-pthreads-win32 against Cygwin.
+Developers using Cygwin will not need pthreads-win32 since it has POSIX threads
+support. Refer to its documentation for details and extent.
UWIN:
@@ -1,3 +1,26 @@ +2002-02-02 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * cancel.c: Rearranged some code and introduced checks
+ to disable cancelation at the start of a thread's cancelation
+ run to prevent double cancelation. The main problem
+ arises if a thread is canceling and then receives a subsequent
+ async cancel request.
+ * private.c: Likewise.
+ * condvar.c: Place pragmas around cleanup_push/pop to turn
+ off inline optimisation (/Obn where n>0 - MSVC only). Various
+ optimisation switches in MSVC turn this on, which interferes with
+ the way that cleanup handlers are run in C++ EH and SEH
+ code. Application code compiled with inline optimisation must
+ also wrap cleanup_push/pop blocks with the pragmas, e.g.
+ #pragma inline_depth(0)
+ pthread_cleanup_push(...)
+ ...
+ pthread_cleanup_pop(...)
+ #pragma inline_depth(8)
+ * rwlock.c: Likewise.
+ * mutex.c: Remove attempts to inline some functions.
+ * signal.c: Modify misleading comment.
+
2002-02-01 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* semaphore.c (sem_trywait): Fix missing errno return
@@ -48,6 +48,8 @@ See the file "ANNOUNCE" for more information including standards conformance details and list of supported routines.
+------------------------------------------------------------------------------
+
Q 2 Which of the several dll versions do I use?
--- or,
What are all these pthread*.dll and pthread*.lib files?
@@ -91,6 +93,8 @@ There are a couple of reasons: behaviour under these conditions.
+------------------------------------------------------------------------------
+
Q 3 What is the library naming convention?
---
@@ -141,6 +145,8 @@ The GNU library archive file names have changed to: libpthreadGC.a
+------------------------------------------------------------------------------
+
Q 4 Cleanup code default style or: it used to work when I built
--- the library myself, but now it doesn't - why?
@@ -208,13 +214,16 @@ __CLEANUP_C++ explicitly using a compiler option and link with pthreadVCE.dll as you did before.
+------------------------------------------------------------------------------
+
Q 5 Why is the default library version now less exception-friendly?
---
-Because no commercial Unix POSIX threads implementation allows you to
-choose to have stack unwinding. Therefore, providing it in pthread-win32
-as a default is dangerous. We still provide the choice but
-you must now consciously make it.
+Because most commercial Unix POSIX threads implementations don't allow you to
+choose to have stack unwinding. (Compaq's TRU64 Unix is possibly an exception.)
+
+Therefore, providing it in pthread-win32 as a default could be dangerous. We
+still provide the choice but you must now consciously make it.
WHY NOT REMOVE THE EXCEPTIONS VERSIONS OF THE LIBRARY ALTOGETHER?
There are a few reasons:
@@ -231,122 +240,26 @@ There are a few reasons: nearly as visible to people who may have a use for it.
+------------------------------------------------------------------------------
+
Q 6 Should I use Cygwin or Mingw32 as a development environment?
---
Important: see Q7 also.
-In short, use Mingw32 with the MSVCRT library to build applications that use
-the DLL. Cygwin's own internal support for POSIX threads is growing. Consult
-that project's documentation for more information.
-
-Date: Mon, 07 Dec 1998 15:11:37 +0100
-From: Anders Norlander <anorland@hem2.passagen.se>
-To: Ross Johnson <rpj@ise.canberra.edu.au>
-Cc: pthreads-win32 <pthreads-win32@air.net.au>
-Subject: Re: pthreads-win32: TryEnterCriticalSection patch (fwd)
-
-Ross Johnson wrote:
->
-> Anders,
->
-> You said you're using GCC. Is that from cygwin32 or mingw32? What is your
-> environment (so I can perhaps help other people out)? We have problems
-> with cygwin32 et al that have been built on Win95. They're missing
-> _{begin,end}threadex.
-
-Ross,
-
-I use mingw32 when compiling pthreads-win32, but unlike most people I
-use MSVCRT as the C library instead of CRTDLL. For those that don't
-feel like configuring and building the necessary components themselves,
-Mumit Khan has released an add on for mingw32 to make it use MSVCRT40.
-It is available at his ftp site, follow the minw32 links at
-http://www.xraylith.wisc.edu/~khan/software/gnu-win32/
-
-For cygwin it is a completely different matter. I suppose
-pthreads-win32 uses _beginthreadex and _endthreadex because the Win32
-docs say that programs calling functions in the C library should not
-use CreateThread and ExitThread. However, this applies only to
-Microsoft's (and possibly others) multithreaded C libraries that need
-to keep track of per thread data, it does not apply to cygwin.
-This code solves the problem:
-
-/* Check for old and new versions of cygwin */
-#if defined(__CYGWIN32__) || defined(__CYGWIN__)
-/* Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE
- in order to avoid warnings because of return type */
-#define _beginthreadex(security, stack_size, start_proc, arg, flags,
-pid) \
-CreateThread(security, stack_size, (LPTHREAD_START_ROUTINE) start_proc,
-\
- arg, flags, pid)
-#define _endthreadex ExitThread
-#endif
-
-I would be extremely careful using threads with cygwin, since it is
-not (yet) threadsafe.
-
-Regards,
-Anders
+Use Mingw32 with the MSVCRT library to build applications that use
+the pthreads DLL.
+
+Cygwin's own internal support for POSIX threads is growing.
+Consult that project's documentation for more information.
------------------------------------------------------------------------------
Q 7 Now that pthreads-win32 builds under Mingw32, why do I get
--- memory access violations (segfaults)?
-Note: issue resolved.
-The latest Mingw32 package has thread-safe exception handling.
-Make sure you also read A 6 below to get a fully working build.
-
-
-The following email exchange describes the problem. Until this issue
-is resolved people without the Microsoft compiler can obtain the current
-MSVC prebuilt DLL (pthread.{dll,lib,h}) at:
-
-ftp://sources.redhat.com/pub/pthreads-win32/dll-latest
-
-Date: Wed, 10 Feb 1999 13:21:01 -0000
-From: "Ruland, Kevin" <Kevin.Ruland@anheuser-busch.com>
-Reply-To: POSIX threads on Win32 <pthreads-win32@air.net.au>
-To: 'POSIX threads on Win32' <pthreads-win32@air.net.au>
-Subject: Mingw32 exceptions not thread safe.
-
-Hello everyone.
-
-I asked Mumit Khan, maintainer of egcs for mingw and assorted guru, about
-the Known Problem listed below.
-
-> Known problems
-> --------------
->
-> There is an unresolved bug which shows up as a segmentation fault
-> (memory access violation) when the library is built using g++. Build
-> the test program "eyal1.c" and run with an argument of "2" or
-> greater. The argument is the number of threads to run, excluding the
-> main thread, so the bug appears with 2 or more worker threads.
->
-> Kevin Ruland has traced the exception to the try/catch blocks in
-> ptw32_threadStart().
->
-
-The official word is:
-
-<Quote Mumit Khan [khan@xraylith.wisc.edu]>
-EGCS-1.1.1 for win32 (either cygwin or crtdll/msvc runtimes) do not have
-thread-safe exception support.
-
-For Cygwin, it'll happen when Cygwin runtime has mature thread safety and
-pthread is fully integrated. Then it's just a matter of rebuilding GCC (or
-just libgcc in this) with thread safe EH support.
-
-For Mingw crtdll/msvc, someone needs to write the thread-wrapper for win32
-threads. Anyone who knows win32 threads should be able to do this without
-much trouble at all. It's low on my priority list, so unless someone else
-volunteers, it'll have to wait.
-<\Quote>
-
-Kevin
+The latest Mingw32 package has thread-safe exception handling (see Q10).
+Also, see Q6 above.
------------------------------------------------------------------------------
@@ -362,7 +275,9 @@ Q 8 How do I use pthread.dll for Win32 (Visual C++ 5.0) > Thank you,
>
-You should have a .dll, .lib, .def, and three .h files.
+You should have a .dll, .lib, .def, and three .h files. It is recommended
+that you use pthreadVC.dll, rather than pthreadVCE.dll or pthreadVSE.dll
+(see Q2 above).
The .dll can go in any directory listed in your PATH environment
variable, so putting it into C:\WINDOWS should work.
@@ -467,123 +382,12 @@ Ross ------------------------------------------------------------------------------
-Q 10 Thread won't block after two calls to mutex_lock
-----
-
-> 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 10 How do I create thread-safe applications using
+---- pthreadGCE.dll, libpthreadw32.a and Mingw32?
-------------------------------------------------------------------------------
-
-Q 11 How do I generate pthreadGCE.dll and libpthreadw32.a for use with Mingw32?
-----
-
-Once you've followed Thomas Pfaff's instructions below to fix
-Mingw32, then you can simply run "make" to build the library and dll.
-
-
-From - Sat Dec 9 22:56:10 2000
-From: "Thomas Pfaff" <tpfaff@gmx.net>
-To: <mingw-users@lists.sourceforge.net>, <pthreads-win32@sources.redhat.com>
-Subject: mingw32 DLLs, threads and exceptions HOWTO
-Date: Thu, 7 Dec 2000 11:12:43 +0100
-
-Dear all,
-
-this is a summary that should help users to have thread safe exception
-handling over DLL exported functions.
-If you don't care about c++ exceptions you can stop reading here.
-
-The first time i struggled with c++ exceptions was when i tried to throw an
-exception in a dll exported function where the exception handler resides in
-the program module.
-Instead of catching the exception the program stopped with an abnormal
-termination.
-The reason was that the exception code is in libgcc.a. Since this is a
-static library the code and some static variables are both in the dll and in
-the program module, each module runs in its own context.
-It was Franco Bez that pointed me in the right direction, that is convert
-libgcc.a into a dll.
-
-That done i tried to build the pthreads-win32 library, but some tests failed
-with an access violation. Due to the fact that the dll was not build
-was -mthreads support, eh_context_static instead of eh_context_specific (the
-mthreads version) was used for exception handling.
-I did a rebuild of the gcc dll with -mthreads, now all tests are passed
-(except a nonportable exception test that relies on a MSVC feature).
-
-To build the gcc dll i did the following steps.
-
-1. create a temporary directory libgcc
-2. copy libgcc.a from gcc-2.95.2\lib\gcc-lib\i386-mingw32\gcc-2.95.2 to that
-directory
-3. ar -x libgcc.a
-4. create a directory tmp and move __main.o, _exit.o and __dummy.o in that
-directory
-5. build the dll
-gcc -shared -mthreads -o gcc.dll *.o
-strip gcc.dll
-Move this dll into your gcc\bin directory
-6. Move _chkstk.o and frame.o to the tmp directory, otherwise you break the
-builtin alloca.
-7. Build the import library libgcc.a
-dllwrap --export-all --dllname=gcc.dll --output-def=libgcc.def --output-lib=
-libgcc.a *.o
-ar -q libgcc.a tmp/*.o
-strip --strip-debug libgcc.a
-ranlib libgcc.a
-8. save your old libgcc.a, copy the new libgcc.a into
-gcc-2.95.2\lib\gcc-lib\i386-mingw32\gcc-2.95.2
-
-I am using gcc-2.95.2-1 with Mumits patched binutils-19990818-1and msvcrt
-runtime-2000-03-27.
-I don't know if this is still required with the current binutils and gcc
-since i have seen no sources until now.
-
-I believe that these steps are at least necessary if you are trying to use
-the pthreads-win32 library (which is required if you want to use gtk+ on
-win32).
-They will make mingw32 a real replacement for MSVC (at least for me).
-
-What is left:
-
-1. Include the mingwm10.dll function into the gcc.dll to have only one dll
-left.
-2. make -mthreads and -fnative-struct default compiler options.
-3. convert libstdc++ to a dll by adding the declspec dllexport and dllimport
-to every class definition.
-
-Regards,
- Thomas
+See Thomas Pfaff's email at:
+http://sources.redhat.com/ml/pthreads-win32/2002/msg00000.html
------------------------------------------------------------------------------
@@ -13,6 +13,8 @@ LIBDEST=$(DEVROOT) DLLS = pthreadVCE.dll pthreadVSE.dll pthreadVC.dll
+OPTIM = /O2
+
# C++ Exceptions
VCEFLAGS = /GX /TP /DPtW32NoCatchWarn /D__CLEANUP_CXX
#Structured Exceptions
@@ -20,8 +22,8 @@ VSEFLAGS = /D__CLEANUP_SEH #C cleanup code
VCFLAGS = /D__CLEANUP_C
-#CFLAGS = /W3 /MT /nologo /Yd /Zi /I. /D_WIN32_WINNT=0x400 /DPTW32_BUILD /DTEST_ICE
-CFLAGS = /W3 /MT /nologo /Yd /Zi /I. /D_WIN32_WINNT=0x400 /DPTW32_BUILD
+#CFLAGS = $(OPTIM) /W3 /MT /nologo /Yd /Zi /I. /D_WIN32_WINNT=0x400 /DPTW32_BUILD /DTEST_ICE
+CFLAGS = $(OPTIM) /W3 /MT /nologo /Yd /Zi /I. /D_WIN32_WINNT=0x400 /DPTW32_BUILD
OBJ= attr.obj \
barrier.obj \
diff --git a/README.NONPORTABLE b/README.NONPORTABLE index a4e21f3..b6e6768 100644 --- a/README.NONPORTABLE +++ b/README.NONPORTABLE @@ -65,9 +65,9 @@ int pthread_num_processors_np This routine (found on HPUX systems) returns the number of processors - in the system. This implementations actually returns the number of - processors available to the process, which can be a different (lower) - value depending on the process's affinity mask. + in the system. This implementation actually returns the number of + processors available to the process, which can be a lower number + than the system's number, depending on the process's affinity mask. BOOL pthread_win32_process_attach_np (void); @@ -41,17 +41,17 @@ #if defined(_ALPHA_) #define PROGCTR(Context) ((Context).Fir) #endif - + #if defined(_PPC_) #define PROGCTR(Context) ((Context).Iar) #endif - + #if !defined(PROGCTR) #error Module contains CPU-specific code; modify and recompile. -#endif +#endif -static void +static INLINE void ptw32_cancel_self(void) { ptw32_throw(PTW32_EPS_CANCEL); @@ -60,31 +60,35 @@ ptw32_cancel_self(void) } +#if 0 /* * ptw32_cancel_thread implements asynchronous cancellation. */ -static INLINE void +static INLINE void ptw32_cancel_thread(pthread_t thread) { HANDLE threadH = thread->threadH; - (void) pthread_mutex_lock(&thread->cancelLock); - SuspendThread(threadH); - if (WaitForSingleObject(threadH, 0) == WAIT_TIMEOUT) + if (WaitForSingleObject(threadH, 0) == WAIT_TIMEOUT ) { CONTEXT context; + + (void) pthread_mutex_lock(&thread->cancelLock); + + thread->state = PThreadStateCanceling; + thread->cancelState = PTHREAD_CANCEL_DISABLE; context.ContextFlags = CONTEXT_CONTROL; GetThreadContext(threadH, &context); PROGCTR(context) = (DWORD) ptw32_cancel_self; SetThreadContext(threadH, &context); + + (void) pthread_mutex_unlock(&thread->cancelLock); ResumeThread(threadH); } - - (void) pthread_mutex_unlock(&thread->cancelLock); } - +#endif int pthread_setcancelstate (int state, int *oldstate) @@ -99,11 +103,11 @@ pthread_setcancelstate (int state, int *oldstate) * PARAMETERS * state, * oldstate - * PTHREAD_CANCEL_ENABLE - * cancellation is enabled, + * PTHREAD_CANCEL_ENABLE + * cancellation is enabled, * - * PTHREAD_CANCEL_DISABLE - * cancellation is disabled + * PTHREAD_CANCEL_DISABLE + * cancellation is disabled * * * DESCRIPTION @@ -114,15 +118,15 @@ pthread_setcancelstate (int state, int *oldstate) * * NOTES: * 1) Use to disable cancellation around 'atomic' code that - * includes cancellation points + * includes cancellation points * * COMPATIBILITY ADDITIONS * If 'oldstate' is NULL then the previous state is not returned * but the function still succeeds. (Solaris) * * RESULTS - * 0 successfully set cancelability type, - * EINVAL 'state' is invalid + * 0 successfully set cancelability type, + * EINVAL 'state' is invalid * * ------------------------------------------------------ */ @@ -152,10 +156,12 @@ pthread_setcancelstate (int state, int *oldstate) /* * Check if there is a pending asynchronous cancel */ - if (self->cancelState == PTHREAD_CANCEL_ENABLE + if (state == PTHREAD_CANCEL_ENABLE && self->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS && WaitForSingleObject(self->cancelEvent, 0) == WAIT_OBJECT_0) { + self->state = PThreadStateCanceling; + self->cancelState = PTHREAD_CANCEL_DISABLE; ResetEvent(self->cancelEvent); (void) pthread_mutex_unlock(&self->cancelLock); ptw32_throw(PTW32_EPS_CANCEL); @@ -183,11 +189,11 @@ pthread_setcanceltype (int type, int *oldtype) * PARAMETERS * type, * oldtype - * PTHREAD_CANCEL_DEFERRED - * only deferred cancelation is allowed, + * PTHREAD_CANCEL_DEFERRED + * only deferred cancelation is allowed, * - * PTHREAD_CANCEL_ASYNCHRONOUS - * Asynchronous cancellation is allowed + * PTHREAD_CANCEL_ASYNCHRONOUS + * Asynchronous cancellation is allowed * * * DESCRIPTION @@ -198,15 +204,15 @@ pthread_setcanceltype (int type, int *oldtype) * * NOTES: * 1) Use with caution; most code is not safe for use - * with asynchronous cancelability. + * with asynchronous cancelability. * * COMPATIBILITY ADDITIONS * If 'oldtype' is NULL then the previous type is not returned * but the function still succeeds. (Solaris) * * RESULTS - * 0 successfully set cancelability type, - * EINVAL 'type' is invalid + * 0 successfully set cancelability type, + * EINVAL 'type' is invalid * * ------------------------------------------------------ */ @@ -237,9 +243,11 @@ pthread_setcanceltype (int type, int *oldtype) * Check if there is a pending asynchronous cancel */ if (self->cancelState == PTHREAD_CANCEL_ENABLE - && self->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS + && type == PTHREAD_CANCEL_ASYNCHRONOUS && WaitForSingleObject(self->cancelEvent, 0) == WAIT_OBJECT_0) { + self->state = PThreadStateCanceling; + self->cancelState = PTHREAD_CANCEL_DISABLE; ResetEvent(self->cancelEvent); (void) pthread_mutex_unlock(&self->cancelLock); ptw32_throw(PTW32_EPS_CANCEL); @@ -261,7 +269,7 @@ pthread_testcancel (void) * This function creates a deferred cancellation point * in the calling thread. The call has no effect if the * current cancelability state is - * PTHREAD_CANCEL_DISABLE + * PTHREAD_CANCEL_DISABLE * * PARAMETERS * N/A @@ -271,30 +279,37 @@ pthread_testcancel (void) * This function creates a deferred cancellation point * in the calling thread. The call has no effect if the * current cancelability state is - * PTHREAD_CANCEL_DISABLE + * PTHREAD_CANCEL_DISABLE * * NOTES: * 1) Cancellation is asynchronous. Use pthread_join - * to wait for termination of thread if necessary + * to wait for termination of thread if necessary * * RESULTS - * N/A + * N/A * * ------------------------------------------------------ */ { pthread_t self = pthread_self(); + (void) pthread_mutex_lock(&self->cancelLock); + if (self != NULL - && self->cancelState == PTHREAD_CANCEL_ENABLE + && self->cancelState != PTHREAD_CANCEL_DISABLE && WaitForSingleObject (self->cancelEvent, 0) == WAIT_OBJECT_0 ) { /* * Canceling! */ + self->state = PThreadStateCanceling; + self->cancelState = PTHREAD_CANCEL_DISABLE; + (void) pthread_mutex_unlock(&self->cancelLock); ptw32_throw(PTW32_EPS_CANCEL); } + + (void) pthread_mutex_unlock(&self->cancelLock); } /* pthread_testcancel */ int @@ -306,18 +321,18 @@ pthread_cancel (pthread_t thread) * * PARAMETERS * thread - * reference to an instance of pthread_t + * reference to an instance of pthread_t * * * DESCRIPTION * This function requests cancellation of 'thread'. * NOTE: cancellation is asynchronous; use pthread_join to - * wait for termination of 'thread' if necessary. + * wait for termination of 'thread' if necessary. * * RESULTS - * 0 successfully requested cancellation, - * ESRCH no thread found corresponding to 'thread', - * ENOMEM implicit self thread create failed. + * 0 successfully requested cancellation, + * ESRCH no thread found corresponding to 'thread', + * ENOMEM implicit self thread create failed. * ------------------------------------------------------ */ { @@ -355,37 +370,56 @@ pthread_cancel (pthread_t thread) /* * Lock for async-cancel safety. */ - (void) pthread_mutex_lock(&self->cancelLock); + (void) pthread_mutex_lock(&thread->cancelLock); if (thread->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS - && thread->cancelState == PTHREAD_CANCEL_ENABLE ) + && thread->cancelState == PTHREAD_CANCEL_ENABLE + && thread->state < PThreadStateCanceling ) { if (cancel_self) { - (void) pthread_mutex_unlock(&self->cancelLock); + thread->state = PThreadStateCanceling; + thread->cancelState = PTHREAD_CANCEL_DISABLE; + + (void) pthread_mutex_unlock(&thread->cancelLock); ptw32_throw(PTW32_EPS_CANCEL); /* Never reached */ } - - ptw32_cancel_thread(thread); + else + { + HANDLE threadH = thread->threadH; + + SuspendThread(threadH); + + if (WaitForSingleObject(threadH, 0) == WAIT_TIMEOUT ) + { + CONTEXT context; + + thread->state = PThreadStateCanceling; + thread->cancelState = PTHREAD_CANCEL_DISABLE; + context.ContextFlags = CONTEXT_CONTROL; + GetThreadContext(threadH, &context); + PROGCTR(context) = (DWORD) ptw32_cancel_self; + SetThreadContext(threadH, &context); + (void) pthread_mutex_unlock(&thread->cancelLock); + ResumeThread(threadH); + } + } } else { /* * Set for deferred cancellation. */ - if (!SetEvent (thread->cancelEvent)) + if ( thread->state >= PThreadStateCanceling + || !SetEvent (thread->cancelEvent)) { result = ESRCH; } - } - (void) pthread_mutex_unlock(&self->cancelLock); + (void) pthread_mutex_unlock(&thread->cancelLock); + } return (result); - } - - - @@ -920,6 +920,9 @@ ptw32_cond_timedwait (pthread_cond_t * cond, */ cleanup_args.signaled = 0; +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif pthread_cleanup_push(ptw32_cond_wait_cleanup, (void *) &cleanup_args); /* @@ -935,13 +938,13 @@ ptw32_cond_timedwait (pthread_cond_t * cond, * timeout, or * thread cancellation * - * Note: + * Note: * * sem_timedwait is a cancellation point, - * hence providing the mechanism for making - * pthread_cond_wait a cancellation point. + * hence providing the mechanism for making + * pthread_cond_wait a cancellation point. * We use the cleanup mechanism to ensure we - * re-lock the mutex and adjust (to)unblock(ed) waiters + * re-lock the mutex and adjust (to)unblock(ed) waiters * counts if we are cancelled, timed out or signalled. */ if (sem_timedwait(&(cv->semBlockQueue), abstime) != 0) @@ -959,6 +962,9 @@ ptw32_cond_timedwait (pthread_cond_t * cond, * Always cleanup */ pthread_cleanup_pop(1); +#ifdef _MSC_VER +#pragma inline_depth(8) +#endif /* * "result" can be modified by the cleanup handler. @@ -969,7 +975,7 @@ ptw32_cond_timedwait (pthread_cond_t * cond, static INLINE int -ptw32_cond_unblock (pthread_cond_t * cond, +ptw32_cond_unblock (pthread_cond_t * cond, int unblockAll) /* * Notes. @@ -355,9 +355,20 @@ ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout) if (self != NULL && !self->implicit) { /* - * Thread started with pthread_create + * Thread started with pthread_create. + * Make sure we haven't been async-canceled in the meantime. */ - ptw32_throw(PTW32_EPS_CANCEL); + (void) pthread_mutex_lock(&self->cancelLock); + if (self->state < PThreadStateCanceling) + { + self->state = PThreadStateCanceling; + self->cancelState = PTHREAD_CANCEL_DISABLE; + (void) pthread_mutex_unlock(&self->cancelLock); + ptw32_throw(PTW32_EPS_CANCEL); + + /* Never reached */ + } + (void) pthread_mutex_unlock(&self->cancelLock); } /* Should never get to here. */ @@ -91,7 +91,7 @@ ptw32_mutex_check_need_init(pthread_mutex_t *mutex) return(result); } -INLINE int +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) { int result = 0; @@ -138,20 +138,20 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) mx->lock_idx = PTW32_MUTEX_LOCK_IDX_INIT; mx->recursive_count = 0; mx->kind = (attr == NULL || *attr == NULL - ? PTHREAD_MUTEX_DEFAULT - : (*attr)->kind); + ? PTHREAD_MUTEX_DEFAULT + : (*attr)->kind); mx->ownerThread = NULL; if ( 0 != sem_init( &mx->wait_sema, 0, 0 )) - { - result = EAGAIN; - free(mx); - mx = NULL; - } + { + result = EAGAIN; + free(mx); + mx = NULL; + } else - { - InitializeCriticalSection( &mx->wait_cs ); - } + { + InitializeCriticalSection( &mx->wait_cs ); + } } *mutex = mx; @@ -762,7 +762,7 @@ ptw32_timed_semwait (sem_t * sem, const struct timespec * abstime) } /* ptw32_timed_semwait */ -INLINE int +int pthread_mutex_lock(pthread_mutex_t *mutex) { int result = 0; @@ -829,7 +829,7 @@ pthread_mutex_lock(pthread_mutex_t *mutex) } -INLINE int +int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime) { int result = 0; @@ -907,27 +907,27 @@ pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime) EnterCriticalSection(&mx->wait_cs); /* - * If we timeout, it is up to us to adjust lock_idx to say - * we're no longer waiting. If the mutex was also unlocked - * while we were timing out, and we simply return ETIMEDOUT, - * then wait_sema would be left in a state that is not consistent - * with the state of lock_idx. - * + * If we timeout, it is up to us to adjust lock_idx to say + * we're no longer waiting. If the mutex was also unlocked + * while we were timing out, and we simply return ETIMEDOUT, + * then wait_sema would be left in a state that is not consistent + * with the state of lock_idx. + * * We must check to see if wait_sema has just been posted - * but we can't just call sem_getvalue - we must compete for - * the semaphore using sem_trywait(), otherwise we would need - * additional critical sections elsewhere, which would make the - * logic too inefficient. - * - * If sem_trywait returns EAGAIN then either wait_sema - * was given directly to another waiting thread or - * another thread has called sem_*wait() before us and - * taken the lock. Then we MUST decrement lock_idx and return - * ETIMEDOUT. - * - * Otherwise we MUST return success (because we have effectively - * acquired the lock that would have been ours had we not - * timed out), and NOT decrement lock_idx. + * but we can't just call sem_getvalue - we must compete for + * the semaphore using sem_trywait(), otherwise we would need + * additional critical sections elsewhere, which would make the + * logic too inefficient. + * + * If sem_trywait returns EAGAIN then either wait_sema + * was given directly to another waiting thread or + * another thread has called sem_*wait() before us and + * taken the lock. Then we MUST decrement lock_idx and return + * ETIMEDOUT. + * + * Otherwise we MUST return success (because we have effectively + * acquired the lock that would have been ours had we not + * timed out), and NOT decrement lock_idx. * * We can almost guarrantee that EAGAIN is the only * possible error, so no need to test errno. @@ -945,10 +945,10 @@ pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime) case 2: /* abstime had passed before we started to wait. */ { /* - * If we timeout, it is up to us to adjust lock_idx to say - * we're no longer waiting. wait_sema has not been touched. - */ - (void) InterlockedDecrement( &mx->lock_idx ); + * If we timeout, it is up to us to adjust lock_idx to say + * we're no longer waiting. wait_sema has not been touched. + */ + (void) InterlockedDecrement( &mx->lock_idx ); result = ETIMEDOUT; break; } @@ -966,7 +966,7 @@ pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime) } -INLINE int +int pthread_mutex_unlock(pthread_mutex_t *mutex) { int result = 0; @@ -979,7 +979,7 @@ pthread_mutex_unlock(pthread_mutex_t *mutex) mx = *mutex; - /* + /* * If the thread calling us holds the mutex then there is no * race condition. If another thread holds the * lock then we shouldn't be in here. @@ -1020,7 +1020,7 @@ pthread_mutex_unlock(pthread_mutex_t *mutex) return(result); } -INLINE int +int pthread_mutex_trylock(pthread_mutex_t *mutex) { int result = 0; @@ -272,6 +272,8 @@ ptw32_threadStart (void * vthreadParms) pthread_setspecific (ptw32_selfThreadKey, self); + self->state = PThreadStateRunning; + #ifdef __CLEANUP_SEH __try @@ -366,7 +368,7 @@ ptw32_threadStart (void * vthreadParms) * We want to run the user's terminate function if supplied. * That function may call pthread_exit() or be canceled, which will * be handled by the outer try block. - * + * * ptw32_terminate() will be called if there is no user * supplied function. */ @@ -408,6 +410,9 @@ ptw32_threadStart (void * vthreadParms) * and release the exception out of thread scope. */ status = self->exitStatus = PTHREAD_CANCELED; + (void) pthread_mutex_lock(&self->cancelLock); + self->state = PThreadStateException; + (void) pthread_mutex_unlock(&self->cancelLock); (void) pthread_mutex_destroy(&self->cancelLock); (void) set_terminate(ptw32_oldTerminate); ptw32_callUserDestroyRoutines(self); @@ -428,6 +433,10 @@ ptw32_threadStart (void * vthreadParms) #endif /* __CLEANUP_C */ #endif /* __CLEANUP_SEH */ + (void) pthread_mutex_lock(&self->cancelLock); + self->state = PThreadStateLast; + (void) pthread_mutex_unlock(&self->cancelLock); + (void) pthread_mutex_destroy(&self->cancelLock); @@ -495,9 +495,13 @@ struct pthread_once_t_ enum { + /* Compatibility with LinuxThreads */ PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_RECURSIVE_NP, PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, @@ -95,21 +95,21 @@ pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) if (rwlock == NULL) { - return EINVAL; + return EINVAL; } if (attr != NULL && *attr != NULL) { - result = EINVAL; /* Not supported */ - goto DONE; + result = EINVAL; /* Not supported */ + goto DONE; } rwl = (pthread_rwlock_t) calloc(1, sizeof(*rwl)); if (rwl == NULL) { - result = ENOMEM; - goto DONE; + result = ENOMEM; + goto DONE; } rwl->nSharedAccessCount = 0; @@ -119,19 +119,19 @@ pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) result = pthread_mutex_init(&rwl->mtxExclusiveAccess, NULL); if (result != 0) { - goto FAIL0; + goto FAIL0; } result = pthread_mutex_init(&rwl->mtxSharedAccessCompleted, NULL); if (result != 0) { - goto FAIL1; + goto FAIL1; } result = pthread_cond_init(&rwl->cndSharedAccessCompleted, NULL); if (result != 0) { - goto FAIL2; + goto FAIL2; } rwl->nMagic = PTW32_RWLOCK_MAGIC; @@ -163,92 +163,92 @@ pthread_rwlock_destroy(pthread_rwlock_t *rwlock) if (rwlock == NULL || *rwlock == NULL) { - return EINVAL; + return EINVAL; } if (*rwlock != PTHREAD_RWLOCK_INITIALIZER) { - rwl = *rwlock; - - if (rwl->nMagic != PTW32_RWLOCK_MAGIC) - { - return EINVAL; - } - - if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0) - { - return result; - } - - if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - return result; - } - - /* - * Check whether any threads own/wait for the lock (wait for ex.access); - * report "BUSY" if so. - */ - if (rwl->nExclusiveAccessCount > 0 - || rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount) - { - result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); - result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - result2 = EBUSY; - } - else - { - rwl->nMagic = 0; - - if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) - { - pthread_mutex_unlock(&rwl->mtxExclusiveAccess); - return result; - } - - if ((result = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))) != 0) - { - return result; - } - - *rwlock = NULL; /* Invalidate rwlock before anything else */ - result = pthread_cond_destroy(&(rwl->cndSharedAccessCompleted)); - result1 = pthread_mutex_destroy(&(rwl->mtxSharedAccessCompleted)); - result2 = pthread_mutex_destroy(&(rwl->mtxExclusiveAccess)); - (void) free(rwl); - } + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } + + /* + * Check whether any threads own/wait for the lock (wait for ex.access); + * report "BUSY" if so. + */ + if (rwl->nExclusiveAccessCount > 0 + || rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount) + { + result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); + result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + result2 = EBUSY; + } + else + { + rwl->nMagic = 0; + + if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + pthread_mutex_unlock(&rwl->mtxExclusiveAccess); + return result; + } + + if ((result = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + *rwlock = NULL; /* Invalidate rwlock before anything else */ + result = pthread_cond_destroy(&(rwl->cndSharedAccessCompleted)); + result1 = pthread_mutex_destroy(&(rwl->mtxSharedAccessCompleted)); + result2 = pthread_mutex_destroy(&(rwl->mtxExclusiveAccess)); + (void) free(rwl); + } } else { - /* - * See notes in ptw32_rwlock_check_need_init() above also. - */ - EnterCriticalSection(&ptw32_rwlock_test_init_lock); - - /* - * Check again. - */ - if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) - { - /* - * This is all we need to do to destroy a statically - * initialised rwlock that has not yet been used (initialised). - * If we get to here, another thread - * waiting to initialise this rwlock will get an EINVAL. - */ - *rwlock = NULL; - } - else - { - /* - * The rwlock has been initialised while we were waiting - * so assume it's in use. - */ - result = EBUSY; - } - - LeaveCriticalSection(&ptw32_rwlock_test_init_lock); + /* + * See notes in ptw32_rwlock_check_need_init() above also. + */ + EnterCriticalSection(&ptw32_rwlock_test_init_lock); + + /* + * Check again. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised rwlock that has not yet been used (initialised). + * If we get to here, another thread + * waiting to initialise this rwlock will get an EINVAL. + */ + *rwlock = NULL; + } + else + { + /* + * The rwlock has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + + LeaveCriticalSection(&ptw32_rwlock_test_init_lock); } return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); @@ -265,7 +265,7 @@ pthread_rwlockattr_init (pthread_rwlockattr_t * attr) * * PARAMETERS * attr - * pointer to an instance of pthread_rwlockattr_t + * pointer to an instance of pthread_rwlockattr_t * * * DESCRIPTION @@ -273,8 +273,8 @@ pthread_rwlockattr_init (pthread_rwlockattr_t * attr) * attributes. * * RESULTS - * 0 successfully initialized attr, - * ENOMEM insufficient memory for attr. + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. * * ------------------------------------------------------ */ @@ -296,7 +296,7 @@ pthread_rwlockattr_init (pthread_rwlockattr_t * attr) *attr = rwa; return(result); -} /* pthread_rwlockattr_init */ +} /* pthread_rwlockattr_init */ int @@ -309,7 +309,7 @@ pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr) * * PARAMETERS * attr - * pointer to an instance of pthread_rwlockattr_t + * pointer to an instance of pthread_rwlockattr_t * * * DESCRIPTION @@ -317,11 +317,11 @@ pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr) * no longer be used. * * NOTES: - * 1) Does not affect rwlockss created using 'attr' + * 1) Does not affect rwlockss created using 'attr' * * RESULTS - * 0 successfully released attr, - * EINVAL 'attr' is invalid. + * 0 successfully released attr, + * EINVAL 'attr' is invalid. * * ------------------------------------------------------ */ @@ -341,12 +341,12 @@ pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr) } return(result); -} /* pthread_rwlockattr_destroy */ +} /* pthread_rwlockattr_destroy */ int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, - int *pshared) + int *pshared) /* * ------------------------------------------------------ * DOCPUBLIC @@ -355,16 +355,16 @@ pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, * * PARAMETERS * attr - * pointer to an instance of pthread_rwlockattr_t + * pointer to an instance of pthread_rwlockattr_t * * pshared - * will be set to one of: + * will be set to one of: * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. * * * DESCRIPTION @@ -372,15 +372,15 @@ pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, * processes if pthread_rwlock_t variable is allocated * in memory shared by these processes. * NOTES: - * 1) pshared rwlocks MUST be allocated in shared - * memory. - * 2) The following macro is defined if shared rwlocks - * are supported: - * _POSIX_THREAD_PROCESS_SHARED + * 1) pshared rwlocks MUST be allocated in shared + * memory. + * 2) The following macro is defined if shared rwlocks + * are supported: + * _POSIX_THREAD_PROCESS_SHARED * * RESULTS - * 0 successfully retrieved attribute, - * EINVAL 'attr' is invalid, + * 0 successfully retrieved attribute, + * EINVAL 'attr' is invalid, * * ------------------------------------------------------ */ @@ -400,7 +400,7 @@ pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, return (result); -} /* pthread_rwlockattr_getpshared */ +} /* pthread_rwlockattr_getpshared */ int @@ -415,16 +415,16 @@ pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, * * PARAMETERS * attr - * pointer to an instance of pthread_rwlockattr_t + * pointer to an instance of pthread_rwlockattr_t * * pshared - * must be one of: + * must be one of: * - * PTHREAD_PROCESS_SHARED - * May be shared if in shared memory + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory * - * PTHREAD_PROCESS_PRIVATE - * Cannot be shared. + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. * * DESCRIPTION * Rwlocks creatd with 'attr' can be shared between @@ -432,17 +432,17 @@ pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, * in memory shared by these processes. * * NOTES: - * 1) pshared rwlocks MUST be allocated in shared - * memory. + * 1) pshared rwlocks MUST be allocated in shared + * memory. * - * 2) The following macro is defined if shared rwlocks - * are supported: - * _POSIX_THREAD_PROCESS_SHARED + * 2) The following macro is defined if shared rwlocks + * are supported: + * _POSIX_THREAD_PROCESS_SHARED * * RESULTS - * 0 successfully set attribute, - * EINVAL 'attr' or pshared is invalid, - * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, * * ------------------------------------------------------ */ @@ -454,24 +454,24 @@ pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, (pshared == PTHREAD_PROCESS_PRIVATE))) { if (pshared == PTHREAD_PROCESS_SHARED) - { + { #if !defined( _POSIX_THREAD_PROCESS_SHARED ) - result = ENOSYS; - pshared = PTHREAD_PROCESS_PRIVATE; + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; #else - result = 0; + result = 0; #endif /* _POSIX_THREAD_PROCESS_SHARED */ - } + } else - { - result = 0; - } + { + result = 0; + } (*attr)->pshared = pshared; } @@ -482,7 +482,7 @@ pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, return (result); -} /* pthread_rwlockattr_setpshared */ +} /* pthread_rwlockattr_setpshared */ int @@ -493,7 +493,7 @@ pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) if (rwlock == NULL || *rwlock == NULL) { - return EINVAL; + return EINVAL; } /* @@ -504,42 +504,42 @@ pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { - result = ptw32_rwlock_check_need_init(rwlock); + result = ptw32_rwlock_check_need_init(rwlock); - if (result != 0 && result != EBUSY) - { - return result; - } + if (result != 0 && result != EBUSY) + { + return result; + } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return EINVAL; + return EINVAL; } if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0) { - return result; + return result; } if (++rwl->nSharedAccessCount == INT_MAX) { - if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - return result; - } + if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; - if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - return result; - } + if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } } return (pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))); @@ -565,7 +565,7 @@ pthread_rwlock_wrlock(pthread_rwlock_t * rwlock) if (rwlock == NULL || *rwlock == NULL) { - return EINVAL; + return EINVAL; } /* @@ -576,69 +576,75 @@ pthread_rwlock_wrlock(pthread_rwlock_t * rwlock) */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { - result = ptw32_rwlock_check_need_init(rwlock); + result = ptw32_rwlock_check_need_init(rwlock); - if (result != 0 && result != EBUSY) - { - return result; - } + if (result != 0 && result != EBUSY) + { + return result; + } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return EINVAL; + return EINVAL; } if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0) { - return result; + return result; } if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) { - (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - return result; + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; } if (rwl->nExclusiveAccessCount == 0) { - if (rwl->nCompletedSharedAccessCount > 0) - { - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; - } - - if (rwl->nSharedAccessCount > 0) - { - rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; - - /* - * This routine may be a cancelation point - * according to POSIX 1003.1j section 18.1.2. - */ - pthread_cleanup_push(ptw32_rwlock_cancelwrwait, (void*)rwl); - - do - { - result = pthread_cond_wait(&(rwl->cndSharedAccessCompleted), - &(rwl->mtxSharedAccessCompleted)); - } - while (result == 0 && rwl->nCompletedSharedAccessCount < 0); - - pthread_cleanup_pop ((result != 0) ? 1 : 0); - - if (result == 0) - { - rwl->nSharedAccessCount = 0; - } - } + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } + + if (rwl->nSharedAccessCount > 0) + { + rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; + + /* + * This routine may be a cancelation point + * according to POSIX 1003.1j section 18.1.2. + */ +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif + pthread_cleanup_push(ptw32_rwlock_cancelwrwait, (void*)rwl); + + do + { + result = pthread_cond_wait(&(rwl->cndSharedAccessCompleted), + &(rwl->mtxSharedAccessCompleted)); + } + while (result == 0 && rwl->nCompletedSharedAccessCount < 0); + + pthread_cleanup_pop ((result != 0) ? 1 : 0); +#ifdef _MSC_VER +#pragma inline_depth(8) +#endif + + if (result == 0) + { + rwl->nSharedAccessCount = 0; + } + } } if (result == 0) { - rwl->nExclusiveAccessCount++; + rwl->nExclusiveAccessCount++; } return result; @@ -652,44 +658,44 @@ pthread_rwlock_unlock(pthread_rwlock_t * rwlock) if (rwlock == NULL || *rwlock == NULL) { - return(EINVAL); + return(EINVAL); } if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { - /* - * Assume any race condition here is harmless. - */ - return 0; + /* + * Assume any race condition here is harmless. + */ + return 0; } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return EINVAL; + return EINVAL; } if (rwl->nExclusiveAccessCount == 0) { - if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) - { - return result; - } + if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + return result; + } - if (++rwl->nCompletedSharedAccessCount == 0) - { - result = pthread_cond_signal(&(rwl->cndSharedAccessCompleted)); - } + if (++rwl->nCompletedSharedAccessCount == 0) + { + result = pthread_cond_signal(&(rwl->cndSharedAccessCompleted)); + } - result1 = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); + result1 = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); } else { - rwl->nExclusiveAccessCount--; + rwl->nExclusiveAccessCount--; - result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); - result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted)); + result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); } @@ -704,7 +710,7 @@ pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock) if (rwlock == NULL || *rwlock == NULL) { - return EINVAL; + return EINVAL; } /* @@ -715,42 +721,42 @@ pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock) */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { - result = ptw32_rwlock_check_need_init(rwlock); + result = ptw32_rwlock_check_need_init(rwlock); - if (result != 0 && result != EBUSY) - { - return result; - } + if (result != 0 && result != EBUSY) + { + return result; + } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return EINVAL; + return EINVAL; } if ((result = pthread_mutex_trylock(&(rwl->mtxExclusiveAccess))) != 0) { - return result; + return result; } if (++rwl->nSharedAccessCount == INT_MAX) { - if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - return result; - } + if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; - if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - return result; - } + if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } } return (pthread_mutex_unlock(&rwl->mtxExclusiveAccess)); @@ -764,7 +770,7 @@ pthread_rwlock_trywrlock(pthread_rwlock_t * rwlock) if (rwlock == NULL || *rwlock == NULL) { - return EINVAL; + return EINVAL; } /* @@ -775,61 +781,61 @@ pthread_rwlock_trywrlock(pthread_rwlock_t * rwlock) */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { - result = ptw32_rwlock_check_need_init(rwlock); + result = ptw32_rwlock_check_need_init(rwlock); - if (result != 0 && result != EBUSY) - { - return result; - } + if (result != 0 && result != EBUSY) + { + return result; + } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { - return EINVAL; + return EINVAL; } if ((result = pthread_mutex_trylock(&(rwl->mtxExclusiveAccess))) != 0) { - return result; + return result; } if ((result = pthread_mutex_trylock(&(rwl->mtxSharedAccessCompleted))) != 0) { - result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - return ((result1 != 0) ? result1 : result); + result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return ((result1 != 0) ? result1 : result); } if (rwl->nExclusiveAccessCount == 0) { - if (rwl->nCompletedSharedAccessCount > 0) - { - rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; - rwl->nCompletedSharedAccessCount = 0; - } - - if (rwl->nSharedAccessCount > 0) - { - if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) - { - (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); - return result; - } - - if ((result = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))) == 0) - { - result = EBUSY; - } - } - else - { - rwl->nExclusiveAccessCount = 1; - } + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } + + if (rwl->nSharedAccessCount > 0) + { + if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)); + return result; + } + + if ((result = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))) == 0) + { + result = EBUSY; + } + } + else + { + rwl->nExclusiveAccessCount = 1; + } } else { - result = EBUSY; + result = EBUSY; } return result; @@ -27,8 +27,8 @@ */ /* - * Strategy for implementing pthread_kill() - * ======================================== + * Possible future strategy for implementing pthread_kill() + * ======================================================== * * Win32 does not implement signals. * Signals are simply software interrupts. @@ -124,10 +124,10 @@ pthread_sigmask(int how, sigset_t const *set, sigset_t *oset) if (set != NULL) { unsigned int i; - + /* FIXME: this code assumes that sigmask is an even multiple of - the size of a long integer. */ - + the size of a long integer. */ + unsigned long *src = (unsigned long const *) set; unsigned long *dest = (unsigned long *) &(thread->sigmask); @@ -167,7 +167,7 @@ int sigwait(const sigset_t *set, } int sigaction(int signum, - const struct sigaction *act, + const struct sigaction *act, struct sigaction *oldact) { } diff --git a/tests/ChangeLog b/tests/ChangeLog index 91f823e..3e3ee9c 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,19 @@ +2002-02-02 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * mutex8: New test.
+ * mutex8n: New test.
+ * mutex8e: New test.
+ * mutex8r: New test.
+ * cancel6a: New test.
+ * cancel6d: New test.
+ * cleanup0.c: Add pragmas for inline optimisation control.
+ * cleanup1.c: Add pragmas for inline optimisation control.
+ * cleanup2.c: Add pragmas for inline optimisation control.
+ * cleanup3.c: Add pragmas for inline optimisation control.
+ * condvar7.c: Add pragmas for inline optimisation control.
+ * condvar8.c: Add pragmas for inline optimisation control.
+ * condvar9.c: Add pragmas for inline optimisation control.
+
2002-01-30 Ross Johnson <rpj@special.ise.canberra.edu.au>
* cleanup1.c (): Must be declared __cdecl when compiled
diff --git a/tests/GNUmakefile b/tests/GNUmakefile index 0bf4102..c18e444 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -16,11 +16,11 @@ MAKE = make # # Mingw32 # -GLANG = c++ +GLANG = c++ CC = gcc XXCFLAGS = -#CFLAGS = -g -O0 -mthreads -UNDEBUG -Wall -x $(GLANG) -#CFLAGS = -O3 -mthreads -UNDEBUG -Wall -x $(GLANG) +#CFLAGS = -g -O0 -mthreads -UNDEBUG -Wall -x $(GLANG) +#CFLAGS = -O3 -mthreads -UNDEBUG -Wall -x $(GLANG) CFLAGS = -g -O0 -UNDEBUG -Wall $(XXCFLAGS) BUILD_DIR = .. INCLUDES = -I. @@ -40,13 +40,13 @@ TESTS = loadfree \ condvar1 condvar2 condvar2_1 exit1 create1 equal1 \ exit2 exit3 \ join0 join1 join2 mutex2 mutex3 mutex4 mutex6 mutex6n mutex6e mutex6r \ - mutex7 mutex7n mutex7e mutex7r \ + mutex7 mutex7n mutex7e mutex7r mutex8 mutex8n mutex8e mutex8r \ count1 once1 tsd1 self2 cancel1 cancel2 eyal1 \ condvar3 condvar3_1 condvar3_2 condvar3_3 \ condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \ errno1 \ rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 rwlock7 \ - context1 cancel3 cancel4 cancel5 \ + context1 cancel3 cancel4 cancel5 cancel6a cancel6d \ cleanup0 cleanup1 cleanup2 cleanup3 \ priority1 priority2 inherit1 \ spin1 spin2 spin3 spin4 \ @@ -65,7 +65,7 @@ default: @ $(ECHO) nmake clean GC (to test using GC dll with C (no EH) applications) @ $(ECHO) nmake clean GCX (to test using GC dll with C++ (EH) applications) @ $(ECHO) nmake clean GCE-bench (to benchtest using GNU C dll with C++ exception handling) - @ $(ECHO) nmake clean GC-bench (to benchtest using GNU C dll with C cleanup code) + @ $(ECHO) nmake clean GC-bench (to benchtest using GNU C dll with C cleanup code) auto: @ $(MAKE) clean GCE @@ -109,6 +109,8 @@ cancel2_1.pass: cancel2.pass cancel3.pass: context1.pass cancel4.pass: cancel3.pass cancel5.pass: cancel3.pass +cancel6a.pass: cancel3.pass +cancel6d.pass: cancel3.pass cleanup0.pass: cancel5.pass cleanup1.pass: cleanup0.pass cleanup2.pass: cleanup1.pass @@ -159,6 +161,10 @@ mutex7.pass: mutex6.pass mutex7n.pass: mutex6n.pass mutex7e.pass: mutex6e.pass mutex7r.pass: mutex6r.pass +mutex8.pass: mutex7.pass +mutex8n.pass: mutex7n.pass +mutex8e.pass: mutex7e.pass +mutex8r.pass: mutex7r.pass once1.pass: create1.pass priority1.pass: join1.pass priority2.pass: priority1.pass diff --git a/tests/Makefile b/tests/Makefile index 74c9b8b..5f160cb 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -10,6 +10,8 @@ ECHO = @echo CPHDR = pthread.h semaphore.h sched.h
+OPTIM = /O2
+
# C++ Exceptions
VCEFLAGS = /GX /TP /DPtW32NoCatchWarn /D__CLEANUP_CXX
VCELIB = pthreadVCE.lib
@@ -25,7 +27,7 @@ VCDLL = pthreadVC.dll # C++ Exceptions in application - using VC version of pthreads dll
VCXFLAGS = /GX /TP /D__CLEANUP_C
-CFLAGS= /W3 /WX /MT /nologo /Yd /Zi -D_WIN32_WINNT=0x400
+CFLAGS= $(OPTIM) /W3 /WX /MT /nologo /Yd /Zi -D_WIN32_WINNT=0x400
LFLAGS= /INCREMENTAL:NO
INCLUDES=-I.
BUILD_DIR=..
@@ -47,6 +49,7 @@ PASSES= loadfree.pass \ join0.pass join1.pass join2.pass \
mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.pass \
mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \
+ mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass \
count1.pass once1.pass tsd1.pass \
self2.pass \
cancel1.pass cancel2.pass \
@@ -57,7 +60,7 @@ PASSES= loadfree.pass \ errno1.pass \
rwlock1.pass rwlock2.pass rwlock3.pass rwlock4.pass rwlock5.pass rwlock6.pass rwlock7.pass \
context1.pass \
- cancel3.pass cancel4.pass cancel5.pass \
+ cancel3.pass cancel4.pass cancel5.pass cancel6a.pass cancel6d.pass \
cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \
priority1.pass priority2.pass inherit1.pass \
spin1.pass spin2.pass spin3.pass spin4.pass \
@@ -152,6 +155,7 @@ clean: - $(RM) *.obj
- $(RM) *.pdb
- $(RM) *.o
+ - $(RM) *.asm
- $(RM) *.exe
- $(RM) *.pass
- $(RM) *.bench
@@ -171,6 +175,8 @@ cancel2.pass: cancel1.pass cancel3.pass: context1.pass
cancel4.pass: cancel3.pass
cancel5.pass: cancel3.pass
+cancel6a.pass: cancel3.pass
+cancel6d.pass: cancel3.pass
cleanup0.pass: cancel5.pass
cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
@@ -221,6 +227,10 @@ mutex7.pass: mutex6.pass mutex7n.pass: mutex6n.pass
mutex7e.pass: mutex6e.pass
mutex7r.pass: mutex6r.pass
+mutex8.pass: mutex7.pass
+mutex8n.pass: mutex7n.pass
+mutex8e.pass: mutex7e.pass
+mutex8r.pass: mutex7r.pass
once1.pass: create1.pass
priority1.pass: join1.pass
priority2.pass: priority1.pass
diff --git a/tests/cleanup0.c b/tests/cleanup0.c index ef7c6bb..9cd9c5c 100644 --- a/tests/cleanup0.c +++ b/tests/cleanup0.c @@ -109,11 +109,17 @@ mythread(void * arg) assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif pthread_cleanup_push(increment_pop_count, (void *) &pop_count); Sleep(100); pthread_cleanup_pop(1); +#ifdef _MSC_VER +#pragma inline_depth(8) +#endif return (void *) result; } @@ -176,7 +182,7 @@ main() fprintf(stderr, "Thread %d: started %d: result %d\n", i, threadbag[i].started, - result); + result); fflush(stderr); } failed = (failed || fail); diff --git a/tests/cleanup1.c b/tests/cleanup1.c index 2b2ffe4..52a67c7 100644 --- a/tests/cleanup1.c +++ b/tests/cleanup1.c @@ -89,6 +89,7 @@ static void #ifdef __CLEANUP_C __cdecl #endif + increment_pop_count(void * arg) { int * c = (int *) arg; @@ -112,6 +113,9 @@ mythread(void * arg) assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif pthread_cleanup_push(increment_pop_count, (void *) &pop_count); /* * We don't have true async cancelation - it relies on the thread @@ -123,6 +127,9 @@ mythread(void * arg) Sleep(100); pthread_cleanup_pop(0); +#ifdef _MSC_VER +#pragma inline_depth(8) +#endif return (void *) result; } diff --git a/tests/cleanup2.c b/tests/cleanup2.c index 373275b..4d1fafe 100644 --- a/tests/cleanup2.c +++ b/tests/cleanup2.c @@ -103,11 +103,17 @@ mythread(void * arg) assert(bag->started == 0); bag->started = 1; +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif pthread_cleanup_push(increment_pop_count, (void *) &pop_count); sched_yield(); pthread_cleanup_pop(1); +#ifdef _MSC_VER +#pragma inline_depth(8) +#endif return (void *) result; } diff --git a/tests/cleanup3.c b/tests/cleanup3.c index 0b88da1..2d44f79 100644 --- a/tests/cleanup3.c +++ b/tests/cleanup3.c @@ -104,6 +104,9 @@ mythread(void * arg) assert(bag->started == 0); bag->started = 1; +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif pthread_cleanup_push(increment_pop_count, (void *) &pop_count); sched_yield(); @@ -111,6 +114,9 @@ mythread(void * arg) pop_count--; pthread_cleanup_pop(0); +#ifdef _MSC_VER +#pragma inline_depth(8) +#endif return (void *) result; } diff --git a/tests/condvar7.c b/tests/condvar7.c index 8eb5879..0e52c64 100644 --- a/tests/condvar7.c +++ b/tests/condvar7.c @@ -116,12 +116,18 @@ mythread(void * arg) assert(pthread_mutex_lock(&cvthing.lock) == 0); +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); while (! (cvthing.shared > 0)) assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); pthread_cleanup_pop(0); +#ifdef _MSC_VER +#pragma inline_depth(8) +#endif assert(cvthing.shared > 0); diff --git a/tests/condvar8.c b/tests/condvar8.c index cef458a..6f2b458 100644 --- a/tests/condvar8.c +++ b/tests/condvar8.c @@ -116,12 +116,18 @@ mythread(void * arg) assert(pthread_mutex_lock(&cvthing.lock) == 0); +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); while (! (cvthing.shared > 0)) assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); pthread_cleanup_pop(0); +#ifdef _MSC_VER +#pragma inline_depth(8) +#endif assert(cvthing.shared > 0); @@ -211,9 +217,9 @@ main() failed = !threadbag[i].started; if (failed) - { - fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); - } + { + fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); + } } /* diff --git a/tests/condvar9.c b/tests/condvar9.c index 48f4320..e06df17 100644 --- a/tests/condvar9.c +++ b/tests/condvar9.c @@ -121,12 +121,18 @@ mythread(void * arg) * pthread_cond_timedwait is a cancelation point and we * going to cancel one deliberately. */ +#ifdef _MSC_VER +#pragma inline_depth(0) +#endif pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); while (! (cvthing.shared > 0)) assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); pthread_cleanup_pop(0); +#ifdef _MSC_VER +#pragma inline_depth(8) +#endif assert(cvthing.shared > 0); @@ -218,9 +224,9 @@ main() failed = !threadbag[i].started; if (failed) - { - fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); - } + { + fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); + } } /* |