summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>2002-02-11 01:53:22 +0000
committerrpj <rpj>2002-02-11 01:53:22 +0000
commite6f1797e9e9925ae7f9dda54806ef8f52ae3ed07 (patch)
treec513bf622584d48383ce9d167159c81baa71b3f9
parent1cf6fdda9842e5b728cdce93683292f4380a4572 (diff)
Splitting files. See ChangeLog file for details.
-rw-r--r--ANNOUNCE1460
-rw-r--r--CONTRIBUTORS74
-rw-r--r--ChangeLog7327
-rw-r--r--FAQ786
-rw-r--r--GNUmakefile64
-rw-r--r--Makefile454
-rw-r--r--Nmakefile48
-rw-r--r--Nmakefile.tests392
-rw-r--r--README838
-rw-r--r--README.CV6072
-rw-r--r--TODO14
-rw-r--r--condvar.c1259
-rw-r--r--condvar_attr_destroy.c86
-rw-r--r--condvar_attr_getpshared.c97
-rw-r--r--condvar_attr_init.c87
-rw-r--r--condvar_attr_setpshared.c117
-rw-r--r--condvar_check_need_init.c94
-rw-r--r--condvar_destroy.c222
-rw-r--r--condvar_init.c143
-rw-r--r--condvar_signal.c355
-rw-r--r--condvar_wait.c527
-rw-r--r--misc.c420
-rw-r--r--nonportable.c299
-rw-r--r--np_delay.c155
-rw-r--r--np_getw32threadhandle.c53
-rw-r--r--np_mutexattr_setkind.c57
-rw-r--r--np_num_processors.c56
-rw-r--r--np_win32_attach.c162
-rw-r--r--pthread.c7
-rw-r--r--pthread.def324
-rw-r--r--pthread.dsp438
-rw-r--r--pthread.dsw58
-rw-r--r--pthread_equal.c76
-rw-r--r--pthread_getconcurrency.c45
-rw-r--r--pthread_once.c131
-rw-r--r--pthread_self.c124
-rw-r--r--pthread_setconcurrency.c53
-rw-r--r--ptw32_calloc.c54
-rw-r--r--ptw32_new.c69
-rw-r--r--tests/ChangeLog6
-rw-r--r--w32_CancelableWait.c168
41 files changed, 12214 insertions, 11057 deletions
diff --git a/ANNOUNCE b/ANNOUNCE
index 6141400..4a238d8 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,730 +1,730 @@
- PTHREADS-WIN32 SNAPSHOT 2002-??-??
- ----------------------------------
- Web Site: http://sources.redhat.com/pthreads-win32/
- FTP Site: ftp://sources.redhat.com/pub/pthreads-win32
- Coordinator: Ross Johnson <rpj@ise.canberra.edu.au>
-
-
-We are pleased to announce the availability of a new snapshot of
-Pthreads-win32, an Open Source Software implementation of the
-Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's
-Win32 environment. Some functions from POSIX 1003.1b are also
-supported including semaphores. Other related functions include
-the set of read-write lock functions.
-
-Parts of the implementation also comply with the Open Group's
-Single Unix specification for compatibility with major Unix
-implementations and Linux.
-
-Pthreads-win32 is free software, distributed under the GNU Lesser
-General Public License (LGPL).
-
-Please see the 'Acknowledgements' section at the end of this
-announcement for the list of contributors.
-
-
--------------------------------
-Changes since the last snapshot
--------------------------------
-
-Cleanup code default style. (IMPORTANT)
-----------------------------------------------------------------------
-Previously, if not defined, the cleanup style was determined automatically
-from the compiler/language, and one of the following was defined accordingly:
-
- __CLEANUP_SEH MSVC only
- __CLEANUP_CXX C++, including MSVC++, GNU G++
- __CLEANUP_C C, including GNU GCC, not MSVC
-
-These defines determine the style of cleanup (see pthread.h) and,
-most importantly, the way that cancelation and thread exit (via
-pthread_exit) is performed (see the routine ptw32_throw() in private.c).
-
-In short, the exceptions versions of the library throw an exception
-when a thread is canceled or exits (via pthread_exit()), which is
-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 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
-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
-used for the version of the library that you link with, so that the
-correct parts of pthread.h are included. That is, the possible
-defines require the following library versions:
-
- __CLEANUP_SEH pthreadVSE.dll
- __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.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
-section were being used.
-
-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 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
-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
-versions, and in non-obvious ways. Most likely is that locally
-instantiated objects may not be destroyed or cleaned up after a thread
-is canceled.
-
-If you want the same behaviour as before, then you must now define
-__CLEANUP_C++ explicitly using a compiler option and link with
-pthreadVCE.dll as you did before.
-
-
-WHY ARE WE MAKING THE DEFAULT STYLE 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 unless
-you consciously choose to do otherwise, your pthreads applications will
-now run or crash in similar ways irrespective of the threads platform
-you use. Or at least this is the hope.
-
-
-WHY NOT REMOVE THE EXCEPTIONS VERSIONS OF THE LIBRARY ALTOGETHER?
-There are a few reasons:
-- because there are well respected POSIX threads people who believe
- that POSIX threads implementations should be exceptions aware and
- do the expected thing in that context. (There are equally respected
- people who believe it should not be easily accessible, if it's there
- at all, for unconditional conformity to other implementations.)
-- because pthreads-win32 is one of the few implementations that has
- the choice, perhaps the only freely available one, and so offers
- a laboratory to people who may want to explore the effects;
-- although the code will always be around somewhere for anyone who
- wants it, once it's removed from the current version it will not be
- nearly as visible to people who may have a use for it.
-
-Source module splitting
------------------------
-In order to enable smaller image sizes to be generated
-for applications that link statically with the library,
-most routines have been separated out into individual
-source code files.
-
-This is being done in such a way as to be backward compatible.
-The old source files are reused to congregate the individual
-routine files into larger translation units (via a bunch of
-# includes) so that the compiler can still optimise wherever
-possible, e.g. through inlining, which can only be done
-within the same translation unit.
-
-It is also possible to build the entire library by compiling
-the single file named "pthread.c", which just #includes all
-the secondary congregation source files. The compiler
-may be able to use this to do more inlining of routines.
-
-Although the GNU compiler is able to produce libraries with
-the necessary separation (the -ffunction-segments switch),
-AFAIK, the MSVC and other compilers don't have this feature.
-
-Finally, since I use makefiles and command-line compilation,
-I don't know what havoc this reorganisation may wreak amongst
-IDE project file users. You should be able to continue
-using your existing project files without modification.
-
-New non-portable function
--------------------------
-pthread_num_processors_np(): Returns the number of processors
-in the system that are available to the process, as determined
-from the processor affinity mask.
-
-Platform dependence
--------------------
-As Win95 doesn't provide one, the library now contains
-it's own InterlockedCompareExchange() routine, which is used
-whenever Windows doesn't provide it. InterlockedCompareExchange()
-is used to implement spinlocks and barriers, and also in mutexes.
-This routine relies on the CMPXCHG machine instruction which
-is not available on i386 CPUs. This library (from snapshot
-20010712 onwards) is therefore no longer supported on i386
-processor platforms.
-
-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()
-
-As defined in the new POSIX standard, and the Single Unix Spec version 3:
- sem_timedwait()
- pthread_mutex_timedlock()
-
-pthread.h no longer includes windows.h
---------------------------------------
-[Not yet for G++]
-
-This was done to prevent conflicts.
-
-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,
-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
-pthread_mutex_lock;
-- Alexander Terekhov <TEREKHOV@de.ibm.com>
-
-* 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
-recursion count and returns 0 for RECURSIVE mutexes, and will
-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
----------------------------
-
-1. Under MS VC++ (only tested with version 6.0), a term_func
- set via the standard C++ set_terminate() function is not called
- for some reason. The code in private.c ptw32_threadStart()
- retrieves and calls the user supplied terminate routine, which
- works as expected under MinGW32 g++, but doesn't run under
- MS VC++ 6.0, presumably because set_terminate() returns NULL.
-
-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,
- but if you want to use inlining optimisation you can be much more
- specific about where it's switched off and on by using a pragma.
-
- So the inlining optimisation is interfering with the way that cleanup
- handlers are run. It appears to relate to auto-inlining of class methods
- since this is the only auto inlining that is performed at /O1 optimisation
- (functions with the "inline" qualifier are also inlined, but the problem
- doesn't appear to involve any such functions in the library or testsuite).
-
- In order to confirm the inlining culprit, the following use of pragmas
- eliminate the problem but I don't know how to make it transparent, putting
- it in, say, pthread.h where pthread_cleanup_push defined as a macro.
-
- #pragma inline_depth(0)
- pthread_cleanup_push(handlerFunc, (void *) &arg);
-
- /* ... */
-
- pthread_cleanup_pop(0);
- #pragma inline_depth()
-
- Note the empty () value after the pop macro. This resets depth to the
- default. Or you can specify a non-zero depth here.
-
- 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 optimisations /O1 and /O2 to be
- used for either or both the library and applications.
-
- Experimenting further, I found that wrapping the actual cleanup handler
- function with #pragma auto_inline(off|on) does NOT work.
-
- MSVC6.0 doesn't appear to support the C99 standard's _Pragma directive,
- however, later versions may. This form is embeddable inside #define
- macros, which would be ideal because it would mean that it could be added
- to the push/pop macro definitions in pthread.h and hidden from the
- application programmer.
-
- [/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
- problem (/Og, /Oi, /Ot, /Oy, /Ob1, /Gs, /Gf, /Gy, etc.), but here is a
- summary of builds and corresponding failures:
-
- * pthreads VSE (optimised tests): OK
- * pthreads VCE (optimised tests): Failed "cleanup1" test (runtime)
-
- * pthreads VSE (DLL in CRT, optimised tests): OK
- * pthreads VCE (DLL in CRT, optimised tests): Failed "cleanup1" test
- (runtime)
-
- Please note that while in VSE version of the pthreads library the
- optimisation does not really have any impact on the tests (they pass OK), in
- VCE version addition of optimisation (/O2 in this case) causes the tests to
- fail uniformly - either in "cleanup0" or "cleanup1" test cases.
-
- Please note that all the tests above use default pthreads DLL (no
- optimisations, linked with either static or DLL CRT, based on test type).
- Therefore the problem lies not within the pthreads DLL but within the
- compiled client code (the application using pthreads -> involvement of
- "pthread.h").
-
- I think the message of this section is that usage of VCE version of pthreads
- in applications relying on cancellation/cleanup AND using optimisations for
- creation of production code is highly unreliable for the current version of
- the pthreads library.
-
-
-Caveats
--------
-
-1. Due to what is believed to be a C++ compliance error in VC++,
-if your application contains catch(...) blocks in your POSIX threads
-then you will need to replace the "catch(...)" with the macro
-"PtW32Catch", eg.
-
- #ifdef PtW32Catch
- PtW32Catch {
- ...
- }
- #else
- catch(...) {
- ...
- }
- #endif
-
-Otherwise neither pthreads cancelation nor pthread_exit() will work
-reliably.
-
-
-Level of standards conformance
-------------------------------
-
-The following POSIX 1003.1c/1b/1j options are defined:
-
- _POSIX_THREADS
- _POSIX_THREAD_SAFE_FUNCTIONS
- _POSIX_THREAD_ATTR_STACKSIZE
- _POSIX_THREAD_PRIORITY_SCHEDULING
- _POSIX_SEMAPHORES
- _POSIX_READER_WRITER_LOCKS
- _POSIX_SPIN_LOCKS
- _POSIX_BARRIERS
-
-
-The following POSIX 1003.1c options are not defined:
-
- _POSIX_THREAD_ATTR_STACKADDR
- _POSIX_THREAD_PRIO_INHERIT
- _POSIX_THREAD_PRIO_PROTECT
- _POSIX_THREAD_PROCESS_SHARED
-
-
-The following functions are implemented:
-
- ---------------------------
- PThreads
- ---------------------------
- pthread_attr_init
- pthread_attr_destroy
- pthread_attr_getdetachstate
- pthread_attr_getstackaddr
- pthread_attr_getstacksize
- pthread_attr_setdetachstate
- pthread_attr_setstackaddr
- pthread_attr_setstacksize
-
- pthread_create
- pthread_detach
- pthread_equal
- pthread_exit
- pthread_join
- pthread_once
- pthread_self
-
- pthread_cancel
- pthread_cleanup_pop
- pthread_cleanup_push
- pthread_setcancelstate
- pthread_setcanceltype
- pthread_testcancel
-
- ---------------------------
- Thread Specific Data
- ---------------------------
- pthread_key_create
- pthread_key_delete
- pthread_setspecific
- pthread_getspecific
-
- ---------------------------
- Mutexes
- ---------------------------
- pthread_mutexattr_init
- pthread_mutexattr_destroy
- pthread_mutexattr_getpshared
- pthread_mutexattr_setpshared
- pthread_mutexattr_gettype
- pthread_mutexattr_settype (types: PTHREAD_MUTEX_DEFAULT
- PTHREAD_MUTEX_NORMAL
- PTHREAD_MUTEX_ERRORCHECK
- PTHREAD_MUTEX_RECURSIVE )
- pthread_mutex_init
- pthread_mutex_destroy
- pthread_mutex_lock
- pthread_mutex_trylock
- pthread_mutex_timedlock
- pthread_mutex_unlock
-
- ---------------------------
- Condition Variables
- ---------------------------
- pthread_condattr_init
- pthread_condattr_destroy
- pthread_condattr_getpshared
- pthread_condattr_setpshared
-
- pthread_cond_init
- pthread_cond_destroy
- pthread_cond_wait
- pthread_cond_timedwait
- pthread_cond_signal
- pthread_cond_broadcast
-
- ---------------------------
- Read/Write Locks - POSIX 1j
- ---------------------------
- pthread_rwlock_init
- pthread_rwlock_destroy
- pthread_rwlock_tryrdlock
- pthread_rwlock_trywrlock
- pthread_rwlock_rdlock
- pthread_rwlock_rwlock
- pthread_rwlock_unlock
- pthread_rwlockattr_init
- pthread_rwlockattr_destroy
- pthread_rwlockattr_getpshared
- pthread_rwlockattr_setpshared
-
- ---------------------------
- Spin Locks - POSIX 1j
- ---------------------------
- pthread_spin_init
- pthread_spin_destroy
- pthread_spin_lock
- pthread_spin_unlock
- pthread_spin_trylock
-
- ---------------------------
- Barriers - POSIX 1j
- ---------------------------
- pthread_barrier_init
- pthread_barrier_destroy
- pthread_barrier_wait
- pthread_barrierattr_init
- pthread_barrierattr_destroy
- pthread_barrierattr_getpshared
- pthread_barrierattr_setpshared
-
- ---------------------------
- Semaphores - POSIX 1b
- ---------------------------
- sem_init
- sem_destroy
- 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)
- sem_getvalue (returns an error ENOSYS)
-
- ---------------------------
- RealTime Scheduling
- ---------------------------
- pthread_attr_getschedparam
- pthread_attr_setschedparam
- pthread_attr_getinheritsched
- pthread_attr_setinheritsched
- pthread_attr_getschedpolicy (only supports SCHED_OTHER)
- pthread_attr_setschedpolicy (only supports SCHED_OTHER)
- pthread_getschedparam
- pthread_setschedparam
- pthread_getconcurrency
- pthread_setconcurrency
- pthread_attr_getscope
- pthread_attr_setscope (only supports PTHREAD_SCOPE_SYSTEM)
- sched_get_priority_max (POSIX 1b)
- sched_get_priority_min (POSIX 1b)
- sched_rr_get_interval (POSIX 1b - returns an error ENOTSUP)
- sched_setscheduler (POSIX 1b - only supports SCHED_OTHER)
- sched_getscheduler (POSIX 1b - only supports SCHED_OTHER)
- sched_yield (POSIX 1b)
-
- ---------------------------
- Signals
- ---------------------------
- pthread_sigmask
-
- ---------------------------
- Non-portable routines (see the README.NONPORTABLE file for usage)
- ---------------------------
- pthread_getw32threadhandle_np
- pthread_delay_np
- pthread_mutexattr_getkind_np
- pthread_mutexattr_setkind_np (types: PTHREAD_MUTEX_FAST_NP,
- PTHREAD_MUTEX_ERRORCHECK_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)
- pthread_win32_thread_attach_np (Required when statically linking the library)
- pthread_win32_thread_detach_np (Required when statically linking the library)
-
- ---------------------------
- Static Initializers
- ---------------------------
- PTHREAD_ONCE_INIT
- PTHREAD_MUTEX_INITIALIZER
- PTHREAD_COND_INITIALIZER
- PTHREAD_RWLOCK_INITIALIZER
- PTHREAD_SPINLOCK_INITIALIZER
-
- ---------------------------
- Thread-Safe C Runtime Library (macros)
- ---------------------------
- strtok_r
- asctime_r
- ctime_r
- gmtime_r
- localtime_r
- rand_r
-
-
-The following functions are not implemented:
-
- ---------------------------
- RealTime Scheduling
- ---------------------------
- pthread_mutex_getprioceiling
- pthread_mutex_setprioceiling
- pthread_mutex_attr_getprioceiling
- pthread_mutex_attr_getprotocol
- pthread_mutex_attr_setprioceiling
- pthread_mutex_attr_setprotocol
-
- ---------------------------
- Fork Handlers
- ---------------------------
- pthread_atfork
-
- ---------------------------
- Stdio
- ---------------------------
- flockfile
- ftrylockfile
- funlockfile
- getc_unlocked
- getchar_unlocked
- putc_unlocked
- putchar_unlocked
-
- ---------------------------
- Thread-Safe C Runtime Library
- ---------------------------
- readdir_r
- getgrgid_r
- getgrnam_r
- getpwuid_r
- getpwnam_r
-
- ---------------------------
- Signals
- ---------------------------
- pthread_kill
- sigtimedwait
- sigwait
- sigwaitinfo
-
-
-The library includes two non-API functions for creating cancellation
-points in applications and libraries:
-
- pthreadCancelableWait
- pthreadCancelableTimedWait
-
-
-Availability
-------------
-
-The prebuilt DLL, export libs (for both MSVC and Mingw32), and the header
-files (pthread.h, semaphore.h, sched.h) are available along with the
-complete source code.
-
-The source code can be found at:
-
- ftp://sources.redhat.com/pub/pthreads-win32
-
-and as individual source code files at
-
- ftp://sources.redhat.com/pub/pthreads-win32/source
-
-The pre-built DLL, export libraries and include files can be found at:
-
- ftp://sources.redhat.com/pub/pthreads-win32/dll-latest
-
-
-
-Mailing List
-------------
-
-There is a mailing list for discussing pthreads on Win32. To join,
-send email to:
-
- pthreads-win32-subscribe@sourceware.cygnus.com
-
-
-Application Development Environments
-------------------------------------
-
-See the README file for more information.
-
-MSVC:
-MSVC using SEH works. Distribute pthreadVSE.dll with your application.
-MSVC using C++ EH works. Distribute pthreadVCE.dll with your application.
-MSVC using C setjmp/longjmp works. Distribute pthreadVC.dll with your application.
-
-
-Mingw32:
-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/)
-Developers using Cygwin will not need pthreads-win32 since it has POSIX threads
-support. Refer to its documentation for details and extent.
-
-
-UWIN:
-UWIN is a complete Unix-like environment for Windows from AT&T. Pthreads-win32
-doesn't currently support UWIN (and vice versa), but that may change in the
-future.
-
-Generally:
-For convenience, the following pre-built files are available on the FTP site
-(see Availability above):
-
- pthread.h - for POSIX 1c threads
- semaphore.h - for POSIX 1b semaphores
- sched.h - for POSIX 1b scheduling
- pthreadVCE.dll - built with MSVC++ compiler using C++ EH
- pthreadVCE.lib
- pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp
- pthreadVC.lib
- pthreadVSE.dll - built with MSVC compiler using SEH
- pthreadVSE.lib
- pthreadGCE.dll - built with Mingw32 G++ 2.95.2-1
- pthreadGC.dll - built with Mingw32 GCC 2.95.2-1 using setjmp/longjmp
- libpthreadGCE.a - derived from pthreadGCE.dll
- libpthreadGC.a - derived from pthreadGC.dll
- gcc.dll - needed if distributing applications that use pthreadGCE.dll
-
-These are the only files you need in order to build POSIX threads
-applications for Win32 using either MSVC or Mingw32.
-
-See the FAQ file in the source tree for additional information.
-
-
-Documentation
--------------
-
-Currently, there is no documentation included in the package apart
-from the copious comments in the source code.
-
-For POSIX Thread API programming, several reference books are
-available:
-
- Programming with POSIX Threads
- David R. Butenhof
- Addison-Wesley (pub)
-
- Pthreads Programming
- By Bradford Nichols, Dick Buttlar & Jacqueline Proulx Farrell
- O'Reilly (pub)
-
-On the web: see the links at the bottom of the pthreads-win32 site:
-
- http://sources.redhat.com/pthreads-win32/
-
-
-Acknowledgements
-----------------
-
-This library is based substantially on a Win32 pthreads
-implementation contributed by John Bossom <John.Bossom@cognos.com>.
-
-The implementation of Condition Variables uses algorithms developed
-by Alexander Terekhov and Louis Thomas.
-
-The implementation of POSIX mutexes has been improved by Thomas Pfaff.
-
-The implementation of read/write locks was contributed by
-Aurelio Medina and improved by Alexander Terekhov.
-
-Many others have contributed significant time and effort to solve critical
-problems in order to make the library workable, robust and reliable.
-
-There is also a separate CONTRIBUTORS file. This file and others are
-on the web site:
-
- http://sources.redhat.com/pthreads-win32
-
-As much as possible, the ChangeLog file acknowledges contributions to the
-code base in more detail.
-
-Enjoy!
-
-Ross Johnson
+ PTHREADS-WIN32 SNAPSHOT 2002-??-??
+ ----------------------------------
+ Web Site: http://sources.redhat.com/pthreads-win32/
+ FTP Site: ftp://sources.redhat.com/pub/pthreads-win32
+ Coordinator: Ross Johnson <rpj@ise.canberra.edu.au>
+
+
+We are pleased to announce the availability of a new snapshot of
+Pthreads-win32, an Open Source Software implementation of the
+Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's
+Win32 environment. Some functions from POSIX 1003.1b are also
+supported including semaphores. Other related functions include
+the set of read-write lock functions.
+
+Parts of the implementation also comply with the Open Group's
+Single Unix specification for compatibility with major Unix
+implementations and Linux.
+
+Pthreads-win32 is free software, distributed under the GNU Lesser
+General Public License (LGPL).
+
+Please see the 'Acknowledgements' section at the end of this
+announcement for the list of contributors.
+
+
+-------------------------------
+Changes since the last snapshot
+-------------------------------
+
+Cleanup code default style. (IMPORTANT)
+----------------------------------------------------------------------
+Previously, if not defined, the cleanup style was determined automatically
+from the compiler/language, and one of the following was defined accordingly:
+
+ __CLEANUP_SEH MSVC only
+ __CLEANUP_CXX C++, including MSVC++, GNU G++
+ __CLEANUP_C C, including GNU GCC, not MSVC
+
+These defines determine the style of cleanup (see pthread.h) and,
+most importantly, the way that cancelation and thread exit (via
+pthread_exit) is performed (see the routine ptw32_throw() in private.c).
+
+In short, the exceptions versions of the library throw an exception
+when a thread is canceled or exits (via pthread_exit()), which is
+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 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
+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
+used for the version of the library that you link with, so that the
+correct parts of pthread.h are included. That is, the possible
+defines require the following library versions:
+
+ __CLEANUP_SEH pthreadVSE.dll
+ __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.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
+section were being used.
+
+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 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
+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
+versions, and in non-obvious ways. Most likely is that locally
+instantiated objects may not be destroyed or cleaned up after a thread
+is canceled.
+
+If you want the same behaviour as before, then you must now define
+__CLEANUP_C++ explicitly using a compiler option and link with
+pthreadVCE.dll as you did before.
+
+
+WHY ARE WE MAKING THE DEFAULT STYLE 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 unless
+you consciously choose to do otherwise, your pthreads applications will
+now run or crash in similar ways irrespective of the threads platform
+you use. Or at least this is the hope.
+
+
+WHY NOT REMOVE THE EXCEPTIONS VERSIONS OF THE LIBRARY ALTOGETHER?
+There are a few reasons:
+- because there are well respected POSIX threads people who believe
+ that POSIX threads implementations should be exceptions aware and
+ do the expected thing in that context. (There are equally respected
+ people who believe it should not be easily accessible, if it's there
+ at all, for unconditional conformity to other implementations.)
+- because pthreads-win32 is one of the few implementations that has
+ the choice, perhaps the only freely available one, and so offers
+ a laboratory to people who may want to explore the effects;
+- although the code will always be around somewhere for anyone who
+ wants it, once it's removed from the current version it will not be
+ nearly as visible to people who may have a use for it.
+
+Source module splitting
+-----------------------
+In order to enable smaller image sizes to be generated
+for applications that link statically with the library,
+most routines have been separated out into individual
+source code files.
+
+This is being done in such a way as to be backward compatible.
+The old source files are reused to congregate the individual
+routine files into larger translation units (via a bunch of
+# includes) so that the compiler can still optimise wherever
+possible, e.g. through inlining, which can only be done
+within the same translation unit.
+
+It is also possible to build the entire library by compiling
+the single file named "pthread.c", which just #includes all
+the secondary congregation source files. The compiler
+may be able to use this to do more inlining of routines.
+
+Although the GNU compiler is able to produce libraries with
+the necessary separation (the -ffunction-segments switch),
+AFAIK, the MSVC and other compilers don't have this feature.
+
+Finally, since I use makefiles and command-line compilation,
+I don't know what havoc this reorganisation may wreak amongst
+IDE project file users. You should be able to continue
+using your existing project files without modification.
+
+New non-portable function
+-------------------------
+pthread_num_processors_np(): Returns the number of processors
+in the system that are available to the process, as determined
+from the processor affinity mask.
+
+Platform dependence
+-------------------
+As Win95 doesn't provide one, the library now contains
+it's own InterlockedCompareExchange() routine, which is used
+whenever Windows doesn't provide it. InterlockedCompareExchange()
+is used to implement spinlocks and barriers, and also in mutexes.
+This routine relies on the CMPXCHG machine instruction which
+is not available on i386 CPUs. This library (from snapshot
+20010712 onwards) is therefore no longer supported on i386
+processor platforms.
+
+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()
+
+As defined in the new POSIX standard, and the Single Unix Spec version 3:
+ sem_timedwait()
+ pthread_mutex_timedlock()
+
+pthread.h no longer includes windows.h
+--------------------------------------
+[Not yet for G++]
+
+This was done to prevent conflicts.
+
+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,
+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
+pthread_mutex_lock;
+- Alexander Terekhov <TEREKHOV@de.ibm.com>
+
+* 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
+recursion count and returns 0 for RECURSIVE mutexes, and will
+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
+---------------------------
+
+1. Under MS VC++ (only tested with version 6.0), a term_func
+ set via the standard C++ set_terminate() function is not called
+ for some reason. The code in private.c ptw32_threadStart()
+ retrieves and calls the user supplied terminate routine, which
+ works as expected under MinGW32 g++, but doesn't run under
+ MS VC++ 6.0, presumably because set_terminate() returns NULL.
+
+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,
+ but if you want to use inlining optimisation you can be much more
+ specific about where it's switched off and on by using a pragma.
+
+ So the inlining optimisation is interfering with the way that cleanup
+ handlers are run. It appears to relate to auto-inlining of class methods
+ since this is the only auto inlining that is performed at /O1 optimisation
+ (functions with the "inline" qualifier are also inlined, but the problem
+ doesn't appear to involve any such functions in the library or testsuite).
+
+ In order to confirm the inlining culprit, the following use of pragmas
+ eliminate the problem but I don't know how to make it transparent, putting
+ it in, say, pthread.h where pthread_cleanup_push defined as a macro.
+
+ #pragma inline_depth(0)
+ pthread_cleanup_push(handlerFunc, (void *) &arg);
+
+ /* ... */
+
+ pthread_cleanup_pop(0);
+ #pragma inline_depth()
+
+ Note the empty () value after the pop macro. This resets depth to the
+ default. Or you can specify a non-zero depth here.
+
+ 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 optimisations /O1 and /O2 to be
+ used for either or both the library and applications.
+
+ Experimenting further, I found that wrapping the actual cleanup handler
+ function with #pragma auto_inline(off|on) does NOT work.
+
+ MSVC6.0 doesn't appear to support the C99 standard's _Pragma directive,
+ however, later versions may. This form is embeddable inside #define
+ macros, which would be ideal because it would mean that it could be added
+ to the push/pop macro definitions in pthread.h and hidden from the
+ application programmer.
+
+ [/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
+ problem (/Og, /Oi, /Ot, /Oy, /Ob1, /Gs, /Gf, /Gy, etc.), but here is a
+ summary of builds and corresponding failures:
+
+ * pthreads VSE (optimised tests): OK
+ * pthreads VCE (optimised tests): Failed "cleanup1" test (runtime)
+
+ * pthreads VSE (DLL in CRT, optimised tests): OK
+ * pthreads VCE (DLL in CRT, optimised tests): Failed "cleanup1" test
+ (runtime)
+
+ Please note that while in VSE version of the pthreads library the
+ optimisation does not really have any impact on the tests (they pass OK), in
+ VCE version addition of optimisation (/O2 in this case) causes the tests to
+ fail uniformly - either in "cleanup0" or "cleanup1" test cases.
+
+ Please note that all the tests above use default pthreads DLL (no
+ optimisations, linked with either static or DLL CRT, based on test type).
+ Therefore the problem lies not within the pthreads DLL but within the
+ compiled client code (the application using pthreads -> involvement of
+ "pthread.h").
+
+ I think the message of this section is that usage of VCE version of pthreads
+ in applications relying on cancellation/cleanup AND using optimisations for
+ creation of production code is highly unreliable for the current version of
+ the pthreads library.
+
+
+Caveats
+-------
+
+1. Due to what is believed to be a C++ compliance error in VC++,
+if your application contains catch(...) blocks in your POSIX threads
+then you will need to replace the "catch(...)" with the macro
+"PtW32Catch", eg.
+
+ #ifdef PtW32Catch
+ PtW32Catch {
+ ...
+ }
+ #else
+ catch(...) {
+ ...
+ }
+ #endif
+
+Otherwise neither pthreads cancelation nor pthread_exit() will work
+reliably.
+
+
+Level of standards conformance
+------------------------------
+
+The following POSIX 1003.1c/1b/1j options are defined:
+
+ _POSIX_THREADS
+ _POSIX_THREAD_SAFE_FUNCTIONS
+ _POSIX_THREAD_ATTR_STACKSIZE
+ _POSIX_THREAD_PRIORITY_SCHEDULING
+ _POSIX_SEMAPHORES
+ _POSIX_READER_WRITER_LOCKS
+ _POSIX_SPIN_LOCKS
+ _POSIX_BARRIERS
+
+
+The following POSIX 1003.1c options are not defined:
+
+ _POSIX_THREAD_ATTR_STACKADDR
+ _POSIX_THREAD_PRIO_INHERIT
+ _POSIX_THREAD_PRIO_PROTECT
+ _POSIX_THREAD_PROCESS_SHARED
+
+
+The following functions are implemented:
+
+ ---------------------------
+ PThreads
+ ---------------------------
+ pthread_attr_init
+ pthread_attr_destroy
+ pthread_attr_getdetachstate
+ pthread_attr_getstackaddr
+ pthread_attr_getstacksize
+ pthread_attr_setdetachstate
+ pthread_attr_setstackaddr
+ pthread_attr_setstacksize
+
+ pthread_create
+ pthread_detach
+ pthread_equal
+ pthread_exit
+ pthread_join
+ pthread_once
+ pthread_self
+
+ pthread_cancel
+ pthread_cleanup_pop
+ pthread_cleanup_push
+ pthread_setcancelstate
+ pthread_setcanceltype
+ pthread_testcancel
+
+ ---------------------------
+ Thread Specific Data
+ ---------------------------
+ pthread_key_create
+ pthread_key_delete
+ pthread_setspecific
+ pthread_getspecific
+
+ ---------------------------
+ Mutexes
+ ---------------------------
+ pthread_mutexattr_init
+ pthread_mutexattr_destroy
+ pthread_mutexattr_getpshared
+ pthread_mutexattr_setpshared
+ pthread_mutexattr_gettype
+ pthread_mutexattr_settype (types: PTHREAD_MUTEX_DEFAULT
+ PTHREAD_MUTEX_NORMAL
+ PTHREAD_MUTEX_ERRORCHECK
+ PTHREAD_MUTEX_RECURSIVE )
+ pthread_mutex_init
+ pthread_mutex_destroy
+ pthread_mutex_lock
+ pthread_mutex_trylock
+ pthread_mutex_timedlock
+ pthread_mutex_unlock
+
+ ---------------------------
+ Condition Variables
+ ---------------------------
+ pthread_condattr_init
+ pthread_condattr_destroy
+ pthread_condattr_getpshared
+ pthread_condattr_setpshared
+
+ pthread_cond_init
+ pthread_cond_destroy
+ pthread_cond_wait
+ pthread_cond_timedwait
+ pthread_cond_signal
+ pthread_cond_broadcast
+
+ ---------------------------
+ Read/Write Locks - POSIX 1j
+ ---------------------------
+ pthread_rwlock_init
+ pthread_rwlock_destroy
+ pthread_rwlock_tryrdlock
+ pthread_rwlock_trywrlock
+ pthread_rwlock_rdlock
+ pthread_rwlock_rwlock
+ pthread_rwlock_unlock
+ pthread_rwlockattr_init
+ pthread_rwlockattr_destroy
+ pthread_rwlockattr_getpshared
+ pthread_rwlockattr_setpshared
+
+ ---------------------------
+ Spin Locks - POSIX 1j
+ ---------------------------
+ pthread_spin_init
+ pthread_spin_destroy
+ pthread_spin_lock
+ pthread_spin_unlock
+ pthread_spin_trylock
+
+ ---------------------------
+ Barriers - POSIX 1j
+ ---------------------------
+ pthread_barrier_init
+ pthread_barrier_destroy
+ pthread_barrier_wait
+ pthread_barrierattr_init
+ pthread_barrierattr_destroy
+ pthread_barrierattr_getpshared
+ pthread_barrierattr_setpshared
+
+ ---------------------------
+ Semaphores - POSIX 1b
+ ---------------------------
+ sem_init
+ sem_destroy
+ 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)
+ sem_getvalue (returns an error ENOSYS)
+
+ ---------------------------
+ RealTime Scheduling
+ ---------------------------
+ pthread_attr_getschedparam
+ pthread_attr_setschedparam
+ pthread_attr_getinheritsched
+ pthread_attr_setinheritsched
+ pthread_attr_getschedpolicy (only supports SCHED_OTHER)
+ pthread_attr_setschedpolicy (only supports SCHED_OTHER)
+ pthread_getschedparam
+ pthread_setschedparam
+ pthread_getconcurrency
+ pthread_setconcurrency
+ pthread_attr_getscope
+ pthread_attr_setscope (only supports PTHREAD_SCOPE_SYSTEM)
+ sched_get_priority_max (POSIX 1b)
+ sched_get_priority_min (POSIX 1b)
+ sched_rr_get_interval (POSIX 1b - returns an error ENOTSUP)
+ sched_setscheduler (POSIX 1b - only supports SCHED_OTHER)
+ sched_getscheduler (POSIX 1b - only supports SCHED_OTHER)
+ sched_yield (POSIX 1b)
+
+ ---------------------------
+ Signals
+ ---------------------------
+ pthread_sigmask
+
+ ---------------------------
+ Non-portable routines (see the README.NONPORTABLE file for usage)
+ ---------------------------
+ pthread_getw32threadhandle_np
+ pthread_delay_np
+ pthread_mutexattr_getkind_np
+ pthread_mutexattr_setkind_np (types: PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_ERRORCHECK_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)
+ pthread_win32_thread_attach_np (Required when statically linking the library)
+ pthread_win32_thread_detach_np (Required when statically linking the library)
+
+ ---------------------------
+ Static Initializers
+ ---------------------------
+ PTHREAD_ONCE_INIT
+ PTHREAD_MUTEX_INITIALIZER
+ PTHREAD_COND_INITIALIZER
+ PTHREAD_RWLOCK_INITIALIZER
+ PTHREAD_SPINLOCK_INITIALIZER
+
+ ---------------------------
+ Thread-Safe C Runtime Library (macros)
+ ---------------------------
+ strtok_r
+ asctime_r
+ ctime_r
+ gmtime_r
+ localtime_r
+ rand_r
+
+
+The following functions are not implemented:
+
+ ---------------------------
+ RealTime Scheduling
+ ---------------------------
+ pthread_mutex_getprioceiling
+ pthread_mutex_setprioceiling
+ pthread_mutex_attr_getprioceiling
+ pthread_mutex_attr_getprotocol
+ pthread_mutex_attr_setprioceiling
+ pthread_mutex_attr_setprotocol
+
+ ---------------------------
+ Fork Handlers
+ ---------------------------
+ pthread_atfork
+
+ ---------------------------
+ Stdio
+ ---------------------------
+ flockfile
+ ftrylockfile
+ funlockfile
+ getc_unlocked
+ getchar_unlocked
+ putc_unlocked
+ putchar_unlocked
+
+ ---------------------------
+ Thread-Safe C Runtime Library
+ ---------------------------
+ readdir_r
+ getgrgid_r
+ getgrnam_r
+ getpwuid_r
+ getpwnam_r
+
+ ---------------------------
+ Signals
+ ---------------------------
+ pthread_kill
+ sigtimedwait
+ sigwait
+ sigwaitinfo
+
+
+The library includes two non-API functions for creating cancellation
+points in applications and libraries:
+
+ pthreadCancelableWait
+ pthreadCancelableTimedWait
+
+
+Availability
+------------
+
+The prebuilt DLL, export libs (for both MSVC and Mingw32), and the header
+files (pthread.h, semaphore.h, sched.h) are available along with the
+complete source code.
+
+The source code can be found at:
+
+ ftp://sources.redhat.com/pub/pthreads-win32
+
+and as individual source code files at
+
+ ftp://sources.redhat.com/pub/pthreads-win32/source
+
+The pre-built DLL, export libraries and include files can be found at:
+
+ ftp://sources.redhat.com/pub/pthreads-win32/dll-latest
+
+
+
+Mailing List
+------------
+
+There is a mailing list for discussing pthreads on Win32. To join,
+send email to:
+
+ pthreads-win32-subscribe@sourceware.cygnus.com
+
+
+Application Development Environments
+------------------------------------
+
+See the README file for more information.
+
+MSVC:
+MSVC using SEH works. Distribute pthreadVSE.dll with your application.
+MSVC using C++ EH works. Distribute pthreadVCE.dll with your application.
+MSVC using C setjmp/longjmp works. Distribute pthreadVC.dll with your application.
+
+
+Mingw32:
+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/)
+Developers using Cygwin will not need pthreads-win32 since it has POSIX threads
+support. Refer to its documentation for details and extent.
+
+
+UWIN:
+UWIN is a complete Unix-like environment for Windows from AT&T. Pthreads-win32
+doesn't currently support UWIN (and vice versa), but that may change in the
+future.
+
+Generally:
+For convenience, the following pre-built files are available on the FTP site
+(see Availability above):
+
+ pthread.h - for POSIX 1c threads
+ semaphore.h - for POSIX 1b semaphores
+ sched.h - for POSIX 1b scheduling
+ pthreadVCE.dll - built with MSVC++ compiler using C++ EH
+ pthreadVCE.lib
+ pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp
+ pthreadVC.lib
+ pthreadVSE.dll - built with MSVC compiler using SEH
+ pthreadVSE.lib
+ pthreadGCE.dll - built with Mingw32 G++ 2.95.2-1
+ pthreadGC.dll - built with Mingw32 GCC 2.95.2-1 using setjmp/longjmp
+ libpthreadGCE.a - derived from pthreadGCE.dll
+ libpthreadGC.a - derived from pthreadGC.dll
+ gcc.dll - needed if distributing applications that use pthreadGCE.dll
+
+These are the only files you need in order to build POSIX threads
+applications for Win32 using either MSVC or Mingw32.
+
+See the FAQ file in the source tree for additional information.
+
+
+Documentation
+-------------
+
+Currently, there is no documentation included in the package apart
+from the copious comments in the source code.
+
+For POSIX Thread API programming, several reference books are
+available:
+
+ Programming with POSIX Threads
+ David R. Butenhof
+ Addison-Wesley (pub)
+
+ Pthreads Programming
+ By Bradford Nichols, Dick Buttlar & Jacqueline Proulx Farrell
+ O'Reilly (pub)
+
+On the web: see the links at the bottom of the pthreads-win32 site:
+
+ http://sources.redhat.com/pthreads-win32/
+
+
+Acknowledgements
+----------------
+
+This library is based substantially on a Win32 pthreads
+implementation contributed by John Bossom <John.Bossom@cognos.com>.
+
+The implementation of Condition Variables uses algorithms developed
+by Alexander Terekhov and Louis Thomas.
+
+The implementation of POSIX mutexes has been improved by Thomas Pfaff.
+
+The implementation of read/write locks was contributed by
+Aurelio Medina and improved by Alexander Terekhov.
+
+Many others have contributed significant time and effort to solve critical
+problems in order to make the library workable, robust and reliable.
+
+There is also a separate CONTRIBUTORS file. This file and others are
+on the web site:
+
+ http://sources.redhat.com/pthreads-win32
+
+As much as possible, the ChangeLog file acknowledges contributions to the
+code base in more detail.
+
+Enjoy!
+
+Ross Johnson
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index eb61b7d..b844556 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,37 +1,37 @@
-Contributors (in approximate order of appearance)
-
-[See also the ChangeLog file where individuals are
-attributed in log entries. Likewise in the FAQ file.]
-
-Ben Elliston bje@cygnus.com
-Ross Johnson rpj@ise.canberra.edu.au
-Robert Colquhoun rjc@trump.net.au
-John E. Bossom John.Bossom@cognos.com
-Anders Norlander anorland@hem2.passagen.se
-Tor Lillqvist tml@iki.fi
-Kevin Ruland Kevin.Ruland@anheuser-busch.com
-Mike Russo miker@eai.com
-Mark E. Armstrong avail@pacbell.net
-Lorin Hochstein lmh@xiphos.ca
-Peter Slacik Peter.Slacik@tatramed.sk
-Mumit Khan khan@xraylith.wisc.edu
-Aurelio Medina aureliom@crt.com
-Milan Gardian mg@tatramed.sk
-Graham Dumpleton Graham.Dumpleton@ra.pad.otc.telstra.com.au
-Tristan Savatier tristan@mpegtv.com
-Erik Hensema erik@hensema.xs4all.nl
-Rich Peters rpeters@micro-magic.com
-Todd Owen towen@lucidcalm.dropbear.id.au
-Jason Nye jnye@nbnet.nb.ca
-Fred Forester fforest@eticomm.net
-Kevin D. Clark kclark@cabletron.com
-David Baggett dmb@itasoftware.com
-Paul Redondo paul@matchvision.com
-Scott McCaskill scott@3dfx.om
-Thomas Pfaff tpfaff@gmx.net
-Franco Bez franco.bez@gmx.de
-Alexander Terekhov TEREKHOV@de.ibm.com
-Louis Thomas lthomas@arbitrade.com
-David Korn dgk@research.att.com
-Phil Frisbie, Jr. phil@hawksoft.com
-
+Contributors (in approximate order of appearance)
+
+[See also the ChangeLog file where individuals are
+attributed in log entries. Likewise in the FAQ file.]
+
+Ben Elliston bje@cygnus.com
+Ross Johnson rpj@ise.canberra.edu.au
+Robert Colquhoun rjc@trump.net.au
+John E. Bossom John.Bossom@cognos.com
+Anders Norlander anorland@hem2.passagen.se
+Tor Lillqvist tml@iki.fi
+Kevin Ruland Kevin.Ruland@anheuser-busch.com
+Mike Russo miker@eai.com
+Mark E. Armstrong avail@pacbell.net
+Lorin Hochstein lmh@xiphos.ca
+Peter Slacik Peter.Slacik@tatramed.sk
+Mumit Khan khan@xraylith.wisc.edu
+Aurelio Medina aureliom@crt.com
+Milan Gardian mg@tatramed.sk
+Graham Dumpleton Graham.Dumpleton@ra.pad.otc.telstra.com.au
+Tristan Savatier tristan@mpegtv.com
+Erik Hensema erik@hensema.xs4all.nl
+Rich Peters rpeters@micro-magic.com
+Todd Owen towen@lucidcalm.dropbear.id.au
+Jason Nye jnye@nbnet.nb.ca
+Fred Forester fforest@eticomm.net
+Kevin D. Clark kclark@cabletron.com
+David Baggett dmb@itasoftware.com
+Paul Redondo paul@matchvision.com
+Scott McCaskill scott@3dfx.om
+Thomas Pfaff tpfaff@gmx.net
+Franco Bez franco.bez@gmx.de
+Alexander Terekhov TEREKHOV@de.ibm.com
+Louis Thomas lthomas@arbitrade.com
+David Korn dgk@research.att.com
+Phil Frisbie, Jr. phil@hawksoft.com
+
diff --git a/ChangeLog b/ChangeLog
index 8c7c0da..3b68aad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3638 +1,3689 @@
-2002-02-07 Alexander Terekhov<TEREKHOV@de.ibm.com>
-
- * nonportable.c (pthread_delay_np): Make a true
- cancelation point. Deferred cancels will interrupt the
- wait.
-
-2002-02-07 Ross Johnson <rpj@setup1.ise.canberra.edu.au
-
- * misc.c (ptw32_new): Add creation of cancelEvent so that
- implicit POSIX threads (Win32 threads with a POSIX face)
- are cancelable; mainly so that pthread_delay_np doesn't fail
- if called from the main thread.
- * create.c (pthread_create): Remove creation of cancelEvent
- from here; now in ptw32_new().
-
- Reduce executable size.
- -----------------------
- When linking with the static library, only those
- routines actually called, either directly or indirectly
- should be included.
-
- [Gcc has the -ffunction-segments option to do this but MSVC
- doesn't have this feature as far as I can determine. Other
- compilers are undetermined as well. - rpj]
-
- * barrier.c: All routines are now in separate compilation units;
- This file is used to congregate the separate modules for
- potential inline optimisation and backward build compatibility.
- * cancel.c: Likewise.
- * barrier_attr_destroy.c: Separated routine from cancel.c.
- * barrier_attr_getpshared.c: Likewise.
- * barrier_attr_init.c: Likewise.
- * barrier_attr_setpshared.c: Likewise.
- * barrier_destroy.c: Likewise.
- * barrier_init.c: Likewise.
- * barrier_wait.c: Likewise.
- * cancel_cancel.c: Likewise.
- * cancel_setcancelstate.c: Likewise.
- * cancel_setcanceltype.c: Likewise.
- * cancel_testcancel.c: Likewise.
-
-2002-02-04 Max Woodbury <mtew@cds.duke.edu>
-
- Reduced name space pollution.
- -----------------------------
- When the appropriate symbols are defined, the headers
- will restrict the definitions of new names. In particular,
- it must be possible to NOT include the <windows.h>
- header and related definitions with some combination
- of symbol definitions. Secondly, it should be possible
- that additional definitions should be limited to POSIX
- compliant symbols by the definition of appropriate symbols.
-
- * pthread.h: POSIX conditionals.
- * sched.h: POSIX conditionals.
- * semaphore.h: POSIX conditionals.
-
- * semaphore.c: Included <limits.h>.
- (sem_init): Changed magic 0x7FFFFFFFL to INT_MAX.
- (sem_getvalue): Trial version.
-
- Reduce executable size.
- -----------------------
- When linking with the static library, only those
- routines actually called, either directly or indirectly
- should be included.
-
- [Gcc has the -ffunction-segments option to do this but MSVC
- doesn't have this feature as far as I can determine. Other
- compilers are undetermined as well. - rpj]
-
- * semaphore.c: All routines are now in separate compilation units;
- This file is used to congregate the separate modules for
- potential inline optimisation and backward build compatibility.
- * semaphore_close.c: Separated routine from semaphore.c.
- * semaphore_decrease.c: Likewise.
- * semaphore_destroy.c: Likewise.
- * semaphore_getvalue.c: Likewise.
- * semaphore_increase.c: Likewise.
- * semaphore_init.c: Likewise.
- * semaphore_open.c: Likewise.
- * semaphore_post.c: Likewise.
- * semaphore_postmultiple.c: Likewise.
- * semaphore_timedwait.c: Likewise.
- * semaphore_trywait.c: Likewise.
- * semaphore_unlink.c: Likewise.
- * semaphore_wait.c: Likewise.
-
-2002-02-04 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- The following extends the idea above to the rest of pthreads-win32 - rpj
-
- * attr.c: All routines are now in separate compilation units;
- This file is used to congregate the separate modules for
- potential inline optimisation and backward build compatibility.
- * attr_destroy.c: Separated routine from attr.c.
- * attr_getdetachstate.c: Likewise.
- * attr_getscope.c: Likewise.
- * attr_getstackaddr.c: Likewise.
- * attr_getstacksize.c: Likewise.
- * attr_init.c: Likewise.
- * attr_is_attr.c: Likewise.
- * attr_setdetachstate.c: Likewise.
- * attr_setscope.c: Likewise.
- * attr_setstackaddr.c: Likewise.
- * attr_setstacksize.c: Likewise.
-
- * pthread.c: Agregation of agregate modules for super-inlineability.
-
-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
- for systems that define NEED_SEM (e.g. early WinCE).
- * mutex.c (pthread_mutex_timedlock): Return ENOTSUP
- for systems that define NEED_SEM since they don't
- have sem_trywait().
-
-2002-01-27 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * mutex.c (pthread_mutex_timedlock): New function suggested by
- Alexander Terekhov. The logic required to implement this
- properly came from Alexander, with some collaboration
- with Thomas Pfaff.
- (pthread_mutex_unlock): Wrap the waiters check and sema
- post in a critical section to prevent a race with
- pthread_mutex_timedlock.
- (ptw32_timed_semwait): New function;
- returns a special result if the absolute timeout parameter
- represents a time already passed when called; used by
- pthread_mutex_timedwait(). Have deliberately not reused
- the name "ptw32_sem_timedwait" because they are not the same
- routine.
- * condvar.c (ptw32_cond_timedwait): Use the new sem_timedwait()
- instead of ptw32_sem_timedwait(), which now has a different
- function. See previous.
- * implement.h: Remove prototype for ptw32_sem_timedwait.
- See next.
- (pthread_mutex_t_): Add critical section element for access
- to lock_idx during mutex post-timeout processing.
- * semaphore.h (sem_timedwait): See next.
- * semaphore.c (sem_timedwait): See next.
- * private.c (ptw32_sem_timedwait): Move to semaphore.c
- and rename as sem_timedwait().
-
-2002-01-18 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * sync.c (pthread_join): Was getting the exit code from the
- calling thread rather than the joined thread if
- defined(__MINGW32__) && !defined(__MSVCRT__).
-
-2002-01-15 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * pthread.h: Unless the build explicitly defines __CLEANUP_SEH,
- __CLEANUP_CXX, or __CLEANUP_C, then the build defaults to
- __CLEANUP_C style cleanup. This style uses setjmp/longjmp
- in the cancelation and thread exit implementations and therefore
- won't do stack unwinding if linked to applications that have it
- (e.g. C++ apps). This is currently consistent with most/all
- commercial Unix POSIX threads implementations.
-
- * spin.c (pthread_spin_init): Edit renamed function call.
- * nonportable.c (pthread_num_processors_np): New.
- (pthread_getprocessors_np): Renamed to ptw32_getprocessors
- and moved to private.c.
- * private.c (pthread_getprocessors): Moved here from
- nonportable.c.
- * pthread.def (pthread_getprocessors_np): Removed
- from export list.
-
- * rwlock.c (pthread_rwlockattr_init): New.
- (pthread_rwlockattr_destroy): New.
- (pthread_rwlockattr_getpshared): New.
- (pthread_rwlockattr_setpshared): New.
-
-2002-01-14 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * attr.c (pthread_attr_setscope): Fix struct pointer
- indirection error introduced 2002-01-04.
- (pthread_attr_getscope): Likewise.
-
-2002-01-12 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * pthread.dsp (SOURCE): Add missing source files.
-
-2002-01-08 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * mutex.c (pthread_mutex_trylock): use
- ptw32_interlocked_compare_exchange function pointer
- rather than ptw32_InterlockedCompareExchange() directly
- to retain portability to non-iX86 processors,
- e.g. WinCE etc. The pointer will point to the native
- OS version of InterlockedCompareExchange() if the
- OS supports it (see ChangeLog entry of 2001-10-17).
-
-2002-01-07 Thomas Pfaff <tpfaff@gmx.net>, Alexander Terekhov <TEREKHOV@de.ibm.com>
-
- * mutex.c (pthread_mutex_init): Remove critical
- section calls.
- (pthread_mutex_destroy): Likewise.
- (pthread_mutex_unlock): Likewise.
- (pthread_mutex_trylock): Likewise; uses
- ptw32_InterlockedCompareExchange() to avoid need for
- critical section; library is no longer i386 compatible;
- recursive mutexes now increment the lock count rather
- than return EBUSY; errorcheck mutexes return EDEADLCK
- rather than EBUSY. This behaviour is consistent with the
- Solaris pthreads implementation.
- * implement.h (pthread_mutex_t_): Remove critical
- section element - no longer needed.
-
-
-2002-01-04 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * attr.c (pthread_attr_setscope): Add more error
- checking and actually store the scope value even
- though it's not really necessary.
- (pthread_attr_getscope): Return stored value.
- * implement.h (pthread_attr_t_): Add new scope element.
- * ANNOUNCE: Fix out of date comment next to
- pthread_attr_setscope in conformance section.
-
-2001-12-21 Alexander Terekhov <TEREKHOV@de.ibm.com>
-
- * mutex.c (pthread_mutex_lock): Decrementing lock_idx was
- not thread-safe.
- (pthread_mutex_trylock): Likewise.
-
-2001-10-26 prionx@juno.com
-
- * semaphore.c (sem_init): Fix typo and missing bracket
- in conditionally compiled code. Only older versions of
- WinCE require this code, hence it doesn't normally get
- tested; somehow when sem_t reverted to an opaque struct
- the calloc NULL check was left in the conditionally included
- section.
- (sem_destroy): Likewise, the calloced sem_t wasn't being freed.
-
-2001-10-25 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * GNUmakefile (libwsock32): Add to linker flags for
- WSAGetLastError() and WSASetLastError().
- * Makefile (wsock32.lib): Likewise.
- * create.c: Minor mostly inert changes.
- * implement.h (PTW32_MAX): Move into here and renamed
- from sched.h.
- (PTW32_MIN): Likewise.
- * GNUmakefile (TEST_ICE): Define if testing internal
- implementation of InterlockedCompareExchange.
- * Makefile (TEST_ICE): Likewise.
- * private.c (TEST_ICE): Likewise.
-
-2001-10-24 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * attr.c (pthread_attr_setstacksize): Quell warning
- from LCC by conditionally compiling the stacksize
- validity check. LCC correctly warns that the condition
- (stacksize < PTHREAD_STACK_MIN) is suspicious
- because STACK_MIN is 0 and stacksize is of type
- size_t (or unsigned int).
-
-2001-10-17 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * barrier.c: Move _LONG and _LPLONG defines into
- implement.h; rename to PTW32_INTERLOCKED_LONG and
- PTW32_INTERLOCKED_LPLONG respectively.
- * spin.c: Likewise; ptw32_interlocked_compare_exchange used
- in place of InterlockedCompareExchange directly.
- * global.c (ptw32_interlocked_compare_exchange): Add
- prototype for this new routine pointer to be used when
- InterlockedCompareExchange isn't supported by Windows.
- * nonportable.c (pthread_win32_process_attach_np): Check for
- support of InterlockedCompareExchange in kernel32 and assign its
- address to ptw32_interlocked_compare_exchange if it exists, or
- our own ix86 specific implementation ptw32_InterlockedCompareExchange.
- *private.c (ptw32_InterlockedCompareExchange): An
- implementation of InterlockedCompareExchange() which is
- specific to ix86; written directly in assembler for either
- MSVC or GNU C; needed because Windows 95 doesn't support
- InterlockedCompareExchange().
-
- * sched.c (sched_get_priority_min): Extend to return
- THREAD_PRIORITY_IDLE.
- (sched_get_priority_max): Extend to return
- THREAD_PRIORITY_CRITICAL.
-
-2001-10-15 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * spin.c (pthread_spin_lock): PTHREAD_SPINLOCK_INITIALIZER
- was causing a program fault.
- (pthread_spin_init): Could have alloced memory
- without freeing under some error conditions.
-
- * mutex.c (pthread_mutex_init): Move memory
- allocation of mutex struct after checking for
- PROCESS_SHARED.
-
-2001-10-12 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * spin.c (pthread_spin_unlock): Was not returning
- EPERM if the spinlock was not locked, for multi CPU
- machines.
-
-2001-10-08 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * spin.c (pthread_spin_trylock): Was not returning
- EBUSY for multi CPU machines.
-
-2001-08-24 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * condvar.c (pthread_cond_destroy): Remove cv element
- that is no longer used.
- * implement.h: Likewise.
-
-2001-08-23 Alexander Terekhov <TEREKHOV@de.ibm.com>
-
- * condvar.c (pthread_cond_destroy): fix bug with
- respect to deadlock in the case of concurrent
- _destroy/_unblock; a condition variable can be destroyed
- immediately after all the threads that are blocked on
- it are awakened.
-
-2001-08-23 Phil Frisbie, Jr. <phil@hawksoft.com>
-
- * tsd.c (pthread_getspecific): Preserve the last
- winsock error [from WSAGetLastError()].
-
-2001-07-18 Scott McCaskill <scott@magruder.org>
-
- * mutex.c (pthread_mutexattr_init): Return ENOMEM
- immediately and don't dereference the NULL pointer
- if calloc fails.
- (pthread_mutexattr_getpshared): Don't dereference
- a pointer that is possibly NULL.
- * barrier.c (pthread_barrierattr_init): Likewise
- (pthread_barrierattr_getpshared): Don't dereference
- a pointer that is possibly NULL.
- * condvar.c (pthread_condattr_getpshared): Don't dereference
- a pointer that is possibly NULL.
-
-2001-07-15 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * rwlock.c (pthread_rwlock_wrlock): Is allowed to be
- a cancelation point; re-enable deferred cancelability
- around the CV call.
-
-2001-07-10 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * barrier.c: Still more revamping. The exclusive access
- mutex isn't really needed so it has been removed and replaced
- by an InterlockedDecrement(). nSerial has been removed.
- iStep is now dual-purpose. The process shared attribute
- is now stored in the barrier struct.
- * implement.h (pthread_barrier_t_): Lost some/gained one
- elements.
- * private.c (ptw32_threadStart): Removed some comments.
-
-2001-07-10 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * barrier.c: Revamped to fix the race condition. Two alternating
- semaphores are used instead of the PulseEvent. Also improved
- overall throughput by returning PTHREAD_BARRIER_SERIAL_THREAD
- to the first waking thread.
- * implement.h (pthread_barrier_t_): Revamped.
-
-2001-07-09 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * barrier.c: Fix several bugs in all routines. Now passes
- tests/barrier5.c which is fairly rigorous. There is still
- a non-optimal work-around for a race condition between
- the barrier breeched event signal and event wait. Basically
- the last (signalling) thread to hit the barrier yields
- to allow any other threads, which may have lost the race,
- to complete.
-
-2001-07-07 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * barrier.c: Changed synchronisation mechanism to a
- Win32 manual reset Event and use PulseEvent to signal
- waiting threads. If the implementation continued to use
- a semaphore it would require a second semaphore and
- some management to use them alternately as barriers. A
- single semaphore allows threads to cascade from one barrier
- through the next, leaving some threads blocked at the first.
- * implement.h (pthread_barrier_t_): As per above.
- * general: Made a number of other routines inlinable.
-
-2001-07-07 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * spin.c: Revamped and working; included static initialiser.
- Now beta level.
- * barrier.c: Likewise.
- * condvar.c: Macro constant change; inline auto init routine.
- * mutex.c: Likewise.
- * rwlock.c: Likewise.
- * private.c: Add support for spinlock initialiser.
- * global.c: Likewise.
- * implement.h: Likewise.
- * pthread.h (PTHREAD_SPINLOCK_INITIALIZER): Fix typo.
-
-2001-07-05 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * barrier.c: Remove static initialisation - irrelevent
- for this object.
- * pthread.h (PTHREAD_BARRIER_INITIALIZER): Removed.
- * rwlock.c (pthread_rwlock_wrlock): This routine is
- not a cancelation point - disable deferred
- cancelation around call to pthread_cond_wait().
-
-2001-07-05 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * spin.c: New module implementing spin locks.
- * barrier.c: New module implementing barriers.
- * pthread.h (_POSIX_SPIN_LOCKS): defined.
- (_POSIX_BARRIERS): Defined.
- (pthread_spin_*): Defined.
- (pthread_barrier*): Defined.
- (PTHREAD_BARRIER_SERIAL_THREAD): Defined.
- * implement.h (pthread_spinlock_t_): Defined.
- (pthread_barrier_t_): Defined.
- (pthread_barrierattr_t_): Defined.
-
- * mutex.c (pthread_mutex_lock): Return with the error
- if an auto-initialiser initialisation fails.
-
- * nonportable.c (pthread_getprocessors_np): New; gets the
- number of available processors for the current process.
-
-2001-07-03 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * pthread.h (_POSIX_READER_WRITER_LOCKS): Define it
- if not already defined.
-
-2001-07-01 Alexander Terekhov <TEREKHOV@de.ibm.com>
-
- * condvar.c: Fixed lost signal bug reported by Timur Aydin
- (taydin@snet.net).
- [RPJ (me) didn't translate the original algorithm
- correctly.]
- * semaphore.c: Added sem_post_multiple; this is a useful
- routine, but it doesn't appear to be standard. For now it's
- not an exported function.
-
-2001-06-25 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * create.c (pthread_create): Add priority inheritance
- attributes.
- * mutex.c (pthread_mutex_lock): Remove some overhead for
- PTHREAD_MUTEX_NORMAL mutex types. Specifically, avoid
- calling pthread_self() and pthread_equal() to check/set
- the mutex owner. Introduce a new pseudo owner for this
- type. Test results suggest increases in speed of up to
- 90% for non-blocking locks.
- This is the default type of mutex used internally by other
- synchronising objects, ie. condition variables and
- read-write locks. The test rwlock7.c shows about a
- 30-35% speed increase over snapshot 2001-06-06. The
- price of this is that the application developer
- must ensure correct behaviour, or explicitly set the
- mutex to a safer type such as PTHREAD_MUTEX_ERRORCHECK.
- For example, PTHREAD_MUTEX_NORMAL (or PTHREAD_MUTEX_DEFAULT)
- type mutexes will not return an error if a thread which is not
- the owner calls pthread_mutex_unlock. The call will succeed
- in unlocking the mutex if it is currently locked, but a
- subsequent unlock by the true owner will then fail with EPERM.
- This is however consistent with some other implementations.
- (pthread_mutex_unlock): Likewise.
- (pthread_mutex_trylock): Likewise.
- (pthread_mutex_destroy): Likewise.
- * attr.c (pthread_attr_init): PTHREAD_EXPLICIT_SCHED is the
- default inheritance attribute; THREAD_PRIORITY_NORMAL is
- the default priority for new threads.
- * sched.c (pthread_attr_setschedpolicy): Added routine.
- (pthread_attr_getschedpolicy): Added routine.
- (pthread_attr_setinheritsched): Added routine.
- (pthread_attr_getinheritsched): Added routine.
- * pthread.h (sched_rr_set_interval): Added as a macro;
- returns -1 with errno set to ENOSYS.
-
-2001-06-23 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- *sched.c (pthread_attr_setschedparam): Add priority range
- check.
- (sched_setscheduler): New function; checks for a valid
- pid and policy; checks for permission to set information
- in the target process; expects pid to be a Win32 process ID,
- not a process handle; the only scheduler policy allowed is
- SCHED_OTHER.
- (sched_getscheduler): Likewise, but checks for permission
- to query.
- * pthread.h (SCHED_*): Moved to sched.h as defined in the
- POSIX standard.
- * sched.h (SCHED_*): Moved from pthread.h.
- (pid_t): Defined if necessary.
- (sched_setscheduler): Defined.
- (sched_getscheduler): Defined.
- * pthread.def (sched_setscheduler): Exported.
- (sched_getscheduler): Likewise.
-
-2001-06-23 Ralf Brese <Ralf.Brese@pdb4.siemens.de>
-
- * create.c (pthread_create): Set thread priority from
- thread attributes.
-
-2001-06-18 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * Made organisational-only changes to UWIN additions.
- * dll.c (dllMain): Moved UWIN process attach code
- to pthread_win32_process_attach_np(); moved
- instance of pthread_count to global.c.
- * global.c (pthread_count): Moved from dll.c.
- * nonportable.c (pthread_win32_process_attach_np):
- Moved _UWIN code to here from dll.c.
- * implement.h (pthread_count): Define extern int.
- * create.c (pthread_count): Remove extern int.
- * private.c (pthread_count): Likewise.
- * exit.c (pthread_count): Likewise.
-
-2001-06-18 David Korn <dgk@research.att.com>
-
- * dll.c: Added changes necessary to work with UWIN.
- * create.c: Likewise.
- * pthread.h: Likewise.
- * misc.c: Likewise.
- * exit.c: Likewise.
- * private.c: Likewise.
- * implement.h: Likewise.
- There is some room at the start of struct pthread_t_
- to implement the signal semantics in UWIN's posix.dll
- although this is not yet complete.
- * Nmakefile: Compatible with UWIN's Nmake utility.
- * Nmakefile.tests: Likewise - for running the tests.
-
-2001-06-08 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * semaphore.h (sem_t): Fixed for compile and test.
- * implement.h (sem_t_): Likewise.
- * semaphore.c: Likewise.
- * private.c (ptw32_sem_timedwait): Updated to use new
- opaque sem_t.
-
-2001-06-06 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * semaphore.h (sem_t): Is now an opaque pointer;
- moved actual definition to implement.h.
- * implement.h (sem_t_): Move here from semaphore.h;
- was the definition of sem_t.
- * semaphore.c: Wherever necessary, changed use of sem
- from that of a pointer to a pointer-pointer; added
- extra checks for a valid sem_t; NULL sem_t when
- it is destroyed; added extra checks when creating
- and destroying sem_t elements in the NEED_SEM
- code branches; changed from using a pthread_mutex_t
- ((*sem)->mutex) to CRITICAL_SECTION ((*sem)->sem_lock_cs)
- in NEED_SEM branches for access serialisation.
-
-2001-06-06 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * mutex.c (pthread_mutexattr_init): Remove
- ptw32_mutex_default_kind.
-
-2001-06-05 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * nonportable.c (pthread_mutex_setdefaultkind_np):
- Remove - should not have been included in the first place.
- (pthread_mutex_getdefaultkind_np): Likewise.
- * global.c (ptw32_mutex_default_kind): Likewise.
- * mutex.c (pthread_mutex_init): Remove use of
- ptw32_mutex_default_kind.
- * pthread.h (pthread_mutex_setdefaultkind_np): Likewise.
- (pthread_mutex_getdefaultkind_np): Likewise.
- * pthread.def (pthread_mutexattr_setkind_np): Added.
- (pthread_mutexattr_getkind_np): Likewise.
-
- * README: Many changes that should have gone in before
- the last snapshot.
- * README.NONPORTABLE: New - referred to by ANNOUNCE
- but never created; documents the non-portable routines
- included in the library - moved from README with new
- routines added.
- * ANNOUNCE (pthread_mutexattr_setkind_np): Added to
- compliance list.
- (pthread_mutexattr_getkind_np): Likewise.
-
-2001-06-04 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * condvar.c: Add original description of the algorithm as
- developed by Terekhov and Thomas, plus reference to
- README.CV.
-
-2001-06-03 Alexander Terekhov <TEREKHOV@de.ibm.com>, Louis Thomas <lthomas@arbitrade.com>
-
- * condvar.c (pthread_cond_init): Completely revamped.
- (pthread_cond_destroy): Likewise.
- (ptw32_cond_wait_cleanup): Likewise.
- (ptw32_cond_timedwait): Likewise.
- (ptw32_cond_unblock): New general signaling routine.
- (pthread_cond_signal): Now calls ptw32_cond_unblock.
- (pthread_cond_broadcast): Likewise.
- * implement.h (pthread_cond_t_): Revamped.
- * README.CV: New; explanation of the above changes.
-
-2001-05-30 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * pthread.h (rand_r): Fake using _seed argument to quell
- compiler warning (compiler should optimise this away later).
-
- * GNUmakefile (OPT): Leave symbolic information out of the library
- and increase optimisation level - for smaller faster prebuilt
- dlls.
-
-2001-05-29 Milan Gardian <Milan.Gardian@LEIBINGER.com>
-
- * Makefile: fix typo.
- * pthreads.h: Fix problems with stdcall/cdecl conventions, in particular
- remove the need for PT_STDCALL everywhere; remove warning supression.
- * (errno): Fix the longstanding "inconsistent dll linkage" problem
- with errno; now also works with /MD debugging libs -
- warnings emerged when compiling pthreads library with /MD (or /MDd)
- compiler switch, instead of /MT (or /MTd) (i.e. when compiling pthreads
- using Multithreaded DLL CRT instead of Multithreaded statically linked
- CRT).
- * create.c (pthread_create): Likewise; fix typo.
- * private.c (ptw32_threadStart): Eliminate use of terminate() which doesn't
- throw exceptions.
- * Remove unnecessary #includes from a number of modules -
- [I had to #include malloc.h in implement.h for gcc - rpj].
-
-2001-05-29 Thomas Pfaff <tpfaff@gmx.net>
-
- * pthread.h (PTHREAD_MUTEX_DEFAULT): New; equivalent to
- PTHREAD_MUTEX_DEFAULT_NP.
- * (PTHREAD_MUTEX_NORMAL): Similarly.
- * (PTHREAD_MUTEX_ERRORCHECK): Similarly.
- * (PTHREAD_MUTEX_RECURSIVE): Similarly.
- * (pthread_mutex_setdefaultkind_np): New; Linux compatibility stub
- for pthread_mutexattr_settype.
- * (pthread_mutexattr_getkind_np): New; Linux compatibility stub
- for pthread_mutexattr_gettype.
- * mutex.c (pthread_mutexattr_settype): New; allow
- the following types of mutex:
- PTHREAD_MUTEX_DEFAULT_NP
- PTHREAD_MUTEX_NORMAL_NP
- PTHREAD_MUTEX_ERRORCHECK_NP
- PTHREAD_MUTEX_RECURSIVE_NP
- * Note that PTHREAD_MUTEX_DEFAULT is equivalent to
- PTHREAD_MUTEX_NORMAL - ie. mutexes should no longer
- be recursive by default, and a thread will deadlock if it
- tries to relock a mutex it already owns. This is inline with
- other pthreads implementations.
- * (pthread_mutex_lock): Process the lock request
- according to the mutex type.
- * (pthread_mutex_init): Eliminate use of Win32 mutexes as the
- basis of POSIX mutexes - instead, a combination of one critical section
- and one semaphore are used in conjunction with Win32 Interlocked* routines.
- * (pthread_mutex_destroy): Likewise.
- * (pthread_mutex_lock): Likewise.
- * (pthread_mutex_trylock): Likewise.
- * (pthread_mutex_unlock): Likewise.
- * Use longjmp/setjmp to implement cancelation when building the library
- using a C compiler which doesn't support exceptions, e.g. gcc -x c (note
- that gcc -x c++ uses exceptions).
- * Also fixed some of the same typos and eliminated PT_STDCALL as
- Milan Gardian's patches above.
-
-2001-02-07 Alexander Terekhov <TEREKHOV@de.ibm.com>
-
- * rwlock.c: Revamped.
- * implement.h (pthread_rwlock_t_): Redefined.
- This implementation does not have reader/writer starvation problem.
- Rwlock attempts to behave more like a normal mutex with
- races and scheduling policy determining who is more important;
- It also supports recursive locking,
- has less synchronization overhead (no broadcasts at all,
- readers are not blocked on any condition variable) and seem to
- be faster than the current implementation [W98 appears to be
- approximately 15 percent faster at least - on top of speed increase
- from Thomas Pfaff's changes to mutex.c - rpj].
-
-2000-12-29 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * Makefile: Back-out "for" loops which don't work.
-
- * GNUmakefile: Remove the fake.a target; add the "realclean"
- target; don't remove built libs under the "clean" target.
-
- * config.h: Add a guard against multiple inclusion.
-
- * semaphore.h: Add some defines from config.h to make
- semaphore.h independent of config.h when building apps.
-
- * pthread.h (_errno): Back-out previous fix until we know how to
- fix it properly.
-
- * implement.h (lockCount): Add missing element to pthread_mutex_t_.
-
- * sync.c (pthread_join): Spelling fix in comment.
-
- * private.c (ptw32_threadStart): Reset original termination
- function (C++).
- (ptw32_threadStart): Cleanup detached threads early in case
- the library is statically linked.
- (ptw32_callUserDestroyRoutines): Remove [SEH] __try block from
- destructor call so that unhandled exceptions will be passed through
- to the system; call terminate() from [C++] try block for the same
- reason.
-
- * tsd.c (pthread_getspecific): Add comment.
-
- * mutex.c (pthread_mutex_init): Initialise new elements in
- pthread_mutex_t.
- (pthread_mutex_unlock): Invert "pthread_equal()" test.
-
-2000-12-28 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * semaphore.c (mode_t): Use ifndef HAVE_MODE_T to include definition.
-
- * config.h.in (HAVE_MODE_T): Added.
- (_UWIN): Start adding defines for the UWIN package.
-
- * private.c (ptw32_threadStart): Unhandled exceptions are
- now passed through to the system to deal with. This is consistent
- with normal Windows behaviour. C++ applications may use
- set_terminate() to override the default behaviour which is
- to call ptw32_terminate(). Ptw32_terminate() cleans up some
- POSIX thread stuff before calling the system default function
- which calls abort(). The users termination function should conform
- to standard C++ semantics which is to not return. It should
- exit the thread (call pthread_exit()) or exit the application.
- * private.c (ptw32_terminate): Added as the default set_terminate()
- function. It calls the system default function after cleaning up
- some POSIX thread stuff.
-
- * implement.h (ptw32_try_enter_critical_section): Move
- declaration.
- * global.c (ptw32_try_enter_critical_section): Moved
- from dll.c.
- * dll.c: Move process and thread attach/detach code into
- functions in nonportable.c.
- * nonportable.c (pthread_win32_process_attach_np): Process
- attach code from dll.c is now available to static linked
- applications.
- * nonportable.c (pthread_win32_process_detach_np): Likewise.
- * nonportable.c (pthread_win32_thread_attach_np): Likewise.
- * nonportable.c (pthread_win32_thread_detach_np): Likewise.
-
- * pthread.h: Add new non-portable prototypes for static
- linked applications.
-
- * GNUmakefile (OPT): Increase optimisation flag and remove
- debug info flag.
-
- * pthread.def: Add new non-portable exports for static
- linked applications.
-
-2000-12-11 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * FAQ: Update Answer 6 re getting a fully working
- Mingw32 built library.
-
-2000-10-10 Steven Reddie <smr@essemer.com.au>
-
- * misc.c (pthread_self): Restore Win32 "last error"
- cleared by TlsGetValue() call in
- pthread_getspecific()
-
-2000-09-20 Arthur Kantor <akantor@bexusa.com>
-
- * mutex.c (pthread_mutex_lock): Record the owner
- of the mutex. This requires also keeping count of
- recursive locks ourselves rather than leaving it
- to Win32 since we need to know when to NULL the
- thread owner when the mutex is unlocked.
- (pthread_mutex_trylock): Likewise.
- (pthread_mutex_unlock): Check that the calling
- thread owns the mutex, decrement the recursive
- lock count, and NULL the owner if zero. Return
- EPERM if the mutex is owned by another thread.
- * implement.h (pthread_mutex_t_): Add ownerThread
- and lockCount members.
-
-2000-09-13 Jef Gearhart <jgearhart@tpssys.com>
-
- * mutex.c (pthread_mutex_init): Call
- TryEnterCriticalSection through the pointer
- rather than directly so that the dll can load
- on Windows versions that can't resolve the
- function, eg. Windows 95
-
-2000-09-09 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * pthread.h (ctime_r): Fix arg.
-
-2000-09-08 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * GNUmakefile(_WIN32_WINNT=0x400): Define in CFLAGS;
- doesn't seem to be needed though.
-
- * cancel.c (pthread_cancel): Must get "self" through
- calling pthread_self() which will ensure a POSIX thread
- struct is built for non-POSIX threads; return an error
- if this fails
- - Ollie Leahy <ollie@mpt.ie>
- (pthread_setcancelstate): Likewise.
- (pthread_setcanceltype): Likewise.
- * misc.c (ptw32_cancelable_wait): Likewise.
-
- * private.c (ptw32_tkAssocCreate): Remove unused #if 0
- wrapped code.
-
- * pthread.h (ptw32_get_exception_services_code):
- Needed to be forward declared unconditionally.
-
-2000-09-06 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * cancel.c (pthread_cancel): If called from the main
- thread "self" would be NULL; get "self" via pthread_self()
- instead of directly from TLS so that an implicit
- pthread object is created.
-
- * misc.c (pthread_equal): Strengthen test for NULLs.
-
-2000-09-02 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * condvar.c (ptw32_cond_wait_cleanup): Ensure that all
- waking threads check if they are the last, and notify
- the broadcaster if so - even if an error occurs in the
- waiter.
-
- * semaphore.c (_decrease_semaphore): Should be
- a call to ptw32_decrease_semaphore.
- (_increase_semaphore): Should be a call to
- ptw32_increase_semaphore.
-
- * misc.c (ptw32_cancelable_wait): Renamed from
- CancelableWait.
- * rwlock.c (_rwlock_check*): Renamed to
- ptw32_rwlock_check*.
- * mutex.c (_mutex_check*): Renamed to ptw32_mutex_check*.
- * condvar.c (cond_timed*): Renamed to ptw32_cond_timed*.
- (_cond_check*): Renamed to ptw32_cond_check*.
- (cond_wait_cleanup*): Rename to ptw32_cond_wait_cleanup*.
- (ptw32_cond_timedwait): Add comments.
-
-2000-08-22 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * private.c (ptw32_throw): Fix exception test;
- move exceptionInformation declaration.
-
- * tsd.c (pthread_key_create): newkey wrongly declared.
-
- * pthread.h: Fix comment block.
-
-2000-08-18 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * mutex.c (pthread_mutex_destroy): Check that the mutex isn't
- held; invalidate the mutex as early as possible to avoid
- contention; not perfect - FIXME!
-
- * rwlock.c (pthread_rwlock_init): Remove redundant assignment
- to "rw".
- (pthread_rwlock_destroy): Invalidate the rwlock before
- freeing up any of it's resources - to avoid contention.
-
- * private.c (ptw32_tkAssocCreate): Change assoc->lock
- to use a dynamically initialised mutex - only consumes
- a W32 mutex or critical section when first used,
- not before.
-
- * mutex.c (pthread_mutex_init): Remove redundant assignment
- to "mx".
- (pthread_mutexattr_destroy): Set attribute to NULL
- before freeing it's memory - to avoid contention.
-
- * implement.h (PTW32_EPS_CANCEL/PTW32_EPS_EXIT):
- Must be defined for all compilers - used as generic
- exception selectors by ptw32_throw().
-
- * Several: Fix typos from scripted edit session
- yesterday.
-
- * nonportable.c (pthread_mutexattr_setforcecs_np):
- Moved this function from mutex.c.
- (pthread_getw32threadhandle_np): New function to
- return the win32 thread handle that the POSIX
- thread is using.
- * mutex.c (pthread_mutexattr_setforcecs_np):
- Moved to new file "nonportable.c".
-
- * pthread.h (PTW32_BUILD): Only redefine __except
- and catch compiler keywords if we aren't building
- the library (ie. PTW32_BUILD is not defined) -
- this is safer than defining and then undefining
- if not building the library.
- * implement.h: Remove __except and catch undefines.
- * Makefile (CFLAGS): Define PTW32_BUILD.
- * GNUmakefile (CFLAGS): Define PTW32_BUILD.
-
- * All appropriate: Change Pthread_exception* to
- ptw32_exception* to be consistent with internal
- identifier naming.
-
- * private.c (ptw32_throw): New function to provide
- a generic exception throw for all internal
- exceptions and EH schemes.
- (ptw32_threadStart): pthread_exit() value is now
- returned via the thread structure exitStatus
- element.
- * exit.c (pthread_exit): pthread_exit() value is now
- returned via the thread structure exitStatus
- element.
- * cancel.c (ptw32_cancel_self): Now uses ptw32_throw.
- (pthread_setcancelstate): Ditto.
- (pthread_setcanceltype): Ditto.
- (pthread_testcancel): Ditto.
- (pthread_cancel): Ditto.
- * misc.c (CancelableWait): Ditto.
- * exit.c (pthread_exit): Ditto.
- * All applicable: Change PTW32_ prefix to
- PTW32_ prefix to remove leading underscores
- from private library identifiers.
-
-2000-08-17 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * All applicable: Change _pthread_ prefix to
- ptw32_ prefix to remove leading underscores
- from private library identifiers (single
- and double leading underscores are reserved in the
- ANSI C standard for compiler implementations).
-
- * tsd.c (pthread_create_key): Initialise temporary
- key before returning it's address to avoid race
- conditions.
-
-2000-08-13 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * errno.c: Add _MD precompile condition; thus far
- had no effect when using /MD compile option but I
- thnk it should be there.
-
- * exit.c: Add __cplusplus to various #if lines;
- was compiling SEH code even when VC++ had
- C++ compile options.
-
- * private.c: ditto.
-
- * create.c (pthread_create): Add PT_STDCALL macro to
- function pointer arg in _beginthread().
-
- * pthread.h: PT_STDCALL really does need to be defined
- in both this and impliment.h; don't set it to __cdecl
- - this macro is only used to extend function pointer
- casting for functions that will be passed as parameters.
- (~PThreadCleanup): add cast and group expression.
- (_errno): Add _MD compile conditional.
- (PtW32NoCatchWarn): Change pragma message.
-
- * implement.h: Move and change PT_STDCALL define.
-
- * need_errno.h: Add _MD to compilation conditional.
-
- * GNUmakefile: Substantial rewrite for new naming
- convention; set for nil optimisation (turn it up
- when we have a working library build; add target
- "fake.a" to build a libpthreadw32.a from the VC++
- built DLL pthreadVCE.dll.
-
- * pthread.def (LIBRARY): Don't specify in the .def
- file - it is specified on the linker command line
- since we now use the same .def file for variously
- named .dlls.
-
- * Makefile: Substantial rewrite for new naming
- convention; default nmake target only issues a
- help message; run nmake with specific target
- corresponding to the EH scheme being used.
-
- * README: Update information; add naming convention
- explanation.
-
- * ANNOUNCE: Update information.
-
-2000-08-12 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * pthread.h: Add compile-time message when using
- MSC_VER compiler and C++ EH to warn application
- programmers to use PtW32Catch instead of catch(...)
- if they want cancelation and pthread_exit to work.
-
- * implement.h: Remove #include <semaphore.h>; we
- use our own local semaphore.h.
-
-2000-08-10 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * cleanup.c (pthread_pop_cleanup): Remove _pthread
- prefix from __except and catch keywords; implement.h
- now simply undefines ptw32__except and
- ptw32_catch if defined; VC++ was not textually
- substituting ptw32_catch etc back to catch as
- it was redefined; the reason for using the prefixed
- version was to make it clear that it was not using
- the pthread.h redefined catch keyword.
-
- * private.c (ptw32_threadStart): Ditto.
- (ptw32_callUserDestroyRoutines): Ditto.
-
- * implement.h (ptw32__except): Remove #define.
- (ptw32_catch): Remove #define.
-
- * GNUmakefile (pthread.a): New target to build
- libpthread32.a from pthread.dll using dlltool.
-
- * buildlib.bat: Duplicate cl commands with args to
- build C++ EH version of pthread.dll; use of .bat
- files is redundant now that nmake compatible
- Makefile is included; used as a kludge only now.
-
- * Makefile: Localise some macros and fix up the clean:
- target to extend it and work properly.
-
- * CONTRIBUTORS: Add contributors.
-
- * ANNOUNCE: Updated.
-
- * README: Updated.
-
-2000-08-06 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * pthread.h: Remove #warning - VC++ doesn't accept it.
-
-2000-08-05 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * pthread.h (PtW32CatchAll): Add macro. When compiling
- applications using VC++ with C++ EH rather than SEH
- 'PtW32CatchAll' must be used in place of any 'catch( ... )'
- if the application wants pthread cancelation or
- pthread_exit() to work.
-
-2000-08-03 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * pthread.h: Add a base class ptw32_exception for
- library internal exceptions and change the "catch"
- re-define macro to use it.
-
-2000-08-02 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * GNUmakefile (CFLAGS): Add -mthreads.
- Add new targets to generate cpp and asm output.
-
- * sync.c (pthread_join): Remove dead code.
-
-2000-07-25 Tristan Savatier <tristan@mpegtv.com>
-
- * sched.c (sched_get_priority_max): Handle different WinCE and
- Win32 priority values together.
- (sched_get_priority_min): Ditto.
-
-2000-07-25 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * create.c (pthread_create): Force new threads to wait until
- pthread_create has the new thread's handle; we also retain
- a local copy of the handle for internal use until
- pthread_create returns.
-
- * private.c (ptw32_threadStart): Initialise ei[].
- (ptw32_threadStart): When beginthread is used to start the
- thread, force waiting until the creator thread had the
- thread handle.
-
- * cancel.c (ptw32_cancel_thread): Include context switch
- code for defined(_X86_) environments in addition to _M_IX86.
-
- * rwlock.c (pthread_rwlock_destroy): Assignment changed
- to avoid compiler warning.
-
- * private.c (ptw32_get_exception_services_code): Cast
- NULL return value to avoid compiler warning.
-
- * cleanup.c (pthread_pop_cleanup): Initialise "cleanup" variable
- to avoid compiler warnings.
-
- * misc.c (ptw32_new): Change "new" variable to "t" to avoid
- confusion with the C++ keyword of the same name.
-
- * condvar.c (cond_wait_cleanup): Initialise lastWaiter variable.
- (cond_timedwait): Remove unused local variables. to avoid
- compiler warnings.
-
- * dll.c (dllMain): Remove 2000-07-21 change - problem
- appears to be in pthread_create().
-
-2000-07-22 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * tsd.c (pthread_key_create): If a destructor was given
- and the pthread_mutex_init failed, then would try to
- reference a NULL pointer (*key); eliminate this section of
- code by using a dynamically initialised mutex
- (PTHREAD_MUTEX_INITIALIZER).
-
- * tsd.c (pthread_setspecific): Return an error if
- unable to set the value; simplify cryptic conditional.
-
- * tsd.c (pthread_key_delete): Locking threadsLock relied
- on mutex_lock returning an error if the key has no destructor.
- ThreadsLock is only initialised if the key has a destructor.
- Making this mutex a static could reduce the number of mutexes
- used by an application since it is actually created only at
- first use and it's often destroyed soon after.
-
-2000-07-22 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * FAQ: Added Q5 and Q6.
-
-2000-07-21 David Baggett <dmb@itasoftware.com>
-
- * dll.c: Include resource leakage work-around. This is a
- partial FIXME which doesn't stop all leakage. The real
- problem needs to be found and fixed.
-
-2000-07-21 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
-
- * create.c (pthread_create): Set threadH to 0 (zero)
- everywhere. Some assignments were using NULL. Maybe
- it should be NULL everywhere - need to check. (I know
- they are nearly always the same thing - but not by
- definition.)
-
- * misc.c (pthread_self): Try to catch NULL thread handles
- at the point where they might be generated, even though
- they should always be valid at this point.
-
- * tsd.c (pthread_setspecific): return an error value if
- pthread_self() returns NULL.
-
- * sync.c (pthread_join): return an error value if
- pthread_self() returns NULL.
-
- * signal.c (pthread_sigmask): return an error value if
- pthread_self() returns NULL.
-
-2000-03-02 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * attr.c (pthread_attr_init): Set default stacksize to zero (0)
- rather than PTHREAD_STACK_MIN even though these are now the same.
-
- * pthread.h (PTHREAD_STACK_MIN): Lowered to 0.
-
-2000-01-28 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * mutex.c (pthread_mutex_init): Free mutex if it has been alloced;
- if critical sections can be used instead of Win32 mutexes, test
- that the critical section works and return an error if not.
-
-2000-01-07 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * cleanup.c (pthread_pop_cleanup): Include SEH code only if MSC is not
- compiling as C++.
- (pthread_push_cleanup): Include SEH code only if MSC is not
- compiling as C++.
-
- * pthread.h: Include SEH code only if MSC is not
- compiling as C++.
-
- * implement.h: Include SEH code only if MSC is not
- compiling as C++.
-
- * cancel.c (ptw32_cancel_thread): Add _M_IX86 check.
- (pthread_testcancel): Include SEH code only if MSC is not
- compiling as C++.
- (ptw32_cancel_self): Include SEH code only if MSC is not
- compiling as C++.
-
-2000-01-06 Erik Hensema <erik.hensema@group2000.nl>
-
- * Makefile: Remove inconsistencies in 'cl' args
-
-2000-01-04 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * private.c (ptw32_get_exception_services_code): New; returns
- value of EXCEPTION_PTW32_SERVICES.
- (ptw32_processInitialize): Remove initialisation of
- ptw32_exception_services which is no longer needed.
-
- * pthread.h (ptw32_exception_services): Remove extern.
- (ptw32_get_exception_services_code): Add function prototype;
- use this to return EXCEPTION_PTW32_SERVICES value instead of
- using the ptw32_exception_services variable which I had
- trouble exporting through pthread.def.
-
- * global.c (ptw32_exception_services): Remove declaration.
-
-1999-11-22 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * implement.h: Forward declare ptw32_new();
-
- * misc.c (ptw32_new): New; alloc and initialise a new pthread_t.
- (pthread_self): New thread struct is generated by new routine
- ptw32_new().
-
- * create.c (pthread_create): New thread struct is generated
- by new routine ptw32_new().
-
-1999-11-21 Ross Johnson <rpj@special.ise.canberra.edu.au>
-
- * global.c (ptw32_exception_services): Declare new variable.
-
- * private.c (ptw32_threadStart): Destroy thread's
- cancelLock mutex; make 'catch' and '__except' usageimmune to
- redfinitions in pthread.h.
- (ptw32_processInitialize): Init new constant ptw32_exception_services.
-
- * create.c (pthread_create): Initialise thread's cancelLock
- mutex.
-
- * cleanup.c (pthread_pop_cleanup): Make 'catch' and '__except'
- usage immune to redfinition s in pthread.h.
-
- * private.c: Ditto.
-
- * pthread.h (catch): Redefine 'catch' so that C++ applications
- won't catch our internal exceptions.
- (__except): ditto for __except.
-
- * implement.h (ptw32_catch): Define internal version
- of 'catch' because 'catch' is redefined by pthread.h.
- (__except): ditto for __except.
- (struct pthread_t_): Add cancelLock mutex for async cancel
- safety.
-
-1999-11-21 Jason Nye <jnye@nbnet.nb.ca>, Erik Hensema <erik.hensema@group2000.nl>
-
- * cancel.c (ptw32_cancel_self): New; part of the async
- cancellation implementation.
- (ptw32_cancel_thread): Ditto; this function is X86
- processor specific.
- (pthread_setcancelstate): Add check for pending async
- cancel request and cancel the calling thread if
- required; add async-cancel safety lock.
- (pthread_setcanceltype): Ditto.
-
-1999-11-13 Erik Hensema <erik.hensema@group2000.nl>
-
- * configure.in (AC_OUTPUT): Put generated output into GNUmakefile
- rather than Makefile. Makefile will become the MSC nmake compatible
- version
-
-1999-11-13 John Bossom (John.Bossom@cognos.com>
-
- * misc.c (pthread_self): Add a note about GetCurrentThread
- returning a pseudo-handle
-
-1999-11-10 Todd Owen <towen@lucidcalm.dropbear.id.au>
-
- * dll.c (dllMain): Free kernel32 ASAP.
- If TryEnterCriticalSection is not being used, then free
- the kernel32.dll handle now, rather than leaving it until
- DLL_PROCESS_DETACH.
-
- Note: this is not a pedantic exercise in freeing unused
- resources! It is a work-around for a bug in Windows 95
- (see microsoft knowledge base article, Q187684) which
- does Bad Things when FreeLibrary is called within
- the DLL_PROCESS_DETACH code, in certain situations.
- Since w95 just happens to be a platform which does not
- provide TryEnterCriticalSection, the bug will be
- effortlessly avoided.
-
-1999-11-10 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * sync.c (pthread_join): Make it a deferred cancelation point.
-
- * misc.c (pthread_self): Explicitly initialise implicitly
- created thread state to default values.
-
-1999-11-05 Tristan Savatier <tristan@mpegtv.com>
-
- * pthread.h (winsock.h): Include unconditionally.
- (ETIMEDOUT): Change fallback value to that defined by winsock.h.
-
- * general: Patched for portability to WinCE. The details are
- described in the file WinCE-PORT. Follow the instructions
- in README.WinCE to make the appropriate changes in config.h.
-
-1999-10-30 Erik Hensema <erik.hensema@group2000.nl>
-
- * create.c (pthread_create): Explicitly initialise thread state to
- default values.
-
- * cancel.c (pthread_setcancelstate): Check for NULL 'oldstate'
- for compatibility with Solaris pthreads;
- (pthread_setcanceltype): ditto:
-
-1999-10-23 Erik Hensema <erik.hensema@group2000.nl>
-
- * pthread.h (ctime_r): Fix incorrect argument "_tm"
-
-1999-10-21 Aurelio Medina <aureliom@crt.com>
-
- * pthread.h (_POSIX_THREADS): Only define it if it isn't
- already defined. Projects may need to define this on
- the CC command line under Win32 as it doesn't have unistd.h
-
-1999-10-17 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * rwlock.c (pthread_rwlock_destroy): Add cast to remove compile
- warning.
-
- * condvar.c (pthread_cond_broadcast): Only release semaphores
- if there are waiting threads.
-
-1999-10-15 Lorin Hochstein <lmh@xiphos.ca>, Peter Slacik <Peter.Slacik@tatramed.sk>
-
- * condvar.c (cond_wait_cleanup): New static cleanup handler for
- cond_timedwait;
- (cond_timedwait): pthread_cleanup_push args changed;
- canceling a thread while it's in pthread_cond_wait
- will now decrement the waiters count and cleanup if it's the
- last waiter.
-
-1999-10-15 Graham Dumpleton <Graham.Dumpleton@ra.pad.otc.telstra.com.au>
-
- * condvar.c (cond_wait_cleanup): the last waiter will now reset the CV's
- wasBroadcast flag
-
-Thu Sep 16 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * rwlock.c (pthread_rwlock_destroy): Add serialisation.
- (_rwlock_check_need_init): Check for detroyed rwlock.
- * rwlock.c: Check return codes from _rwlock_check_need_init();
- modify comments; serialise access to rwlock objects during
- operations; rename rw_mutex to rw_lock.
- * implement.h: Rename rw_mutex to rw_lock.
- * mutex.c (pthread_mutex_destroy): Add serialisation.
- (_mutex_check_need_init): Check for detroyed mutex.
- * condvar.c (pthread_cond_destroy): Add serialisation.
- (_cond_check_need_init): Check for detroyed condvar.
- * mutex.c: Modify comments.
- * condvar.c: Modify comments.
-
-1999-08-10 Aurelio Medina <aureliom@crt.com>
-
- * implement.h (pthread_rwlock_t_): Add.
- * pthread.h (pthread_rwlock_t): Add.
- (PTHREAD_RWLOCK_INITIALIZER): Add.
- Add rwlock function prototypes.
- * rwlock.c: New module.
- * pthread.def: Add new rwlock functions.
- * private.c (ptw32_processInitialize): initialise
- ptw32_rwlock_test_init_lock critical section.
- * global.c (ptw32_rwlock_test_init_lock): Add.
-
- * mutex.c (pthread_mutex_destroy): Don't free mutex memory
- if mutex is PTHREAD_MUTEX_INITIALIZER and has not been
- initialised yet.
-
-1999-08-08 Milan Gardian <mg@tatramed.sk>
-
- * mutex.c (pthread_mutex_destroy): Free mutex memory.
-
-1999-08-22 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * exit.c (pthread_exit): Fix reference to potentially
- uninitialised pointer.
-
-1999-08-21 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * private.c (ptw32_threadStart): Apply fix of 1999-08-19
- this time to C++ and non-trapped C versions. Ommitted to
- do this the first time through.
-
-1999-08-19 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * private.c (ptw32_threadStart): Return exit status from
- the application thread startup routine.
- - Milan Gardian <mg@tatramed.sk>
-
-1999-08-18 John Bossom <john.Bossom@cognos.com>
-
- * exit.c (pthread_exit): Put status into pthread_t->exitStatus
- * private.c (ptw32_threadStart): Set pthread->exitStatus
- on exit of try{} block.
- * sync.c (pthread_join): use pthread_exitStatus value if the
- thread exit doesn't return a value (for Mingw32 CRTDLL
- which uses endthread instead of _endthreadex).
-
-Tue Aug 17 20:17:58 CDT 1999 Mumit Khan <khan@xraylith.wisc.edu>
-
- * create.c (pthread_create): Add CRTDLL suppport.
- * exit.c (pthread_exit): Likewise.
- * private.c (ptw32_threadStart): Likewise.
- (ptw32_threadDestroy): Likewise.
- * sync.c (pthread_join): Likewise.
- * tests/join1.c (main): Warn about partial support for CRTDLL.
-
-Tue Aug 17 20:00:08 1999 Mumit Khan <khan@xraylith.wisc.edu>
-
- * Makefile.in (LD): Delete entry point.
- * acconfig.h (STDCALL): Delete unused macro.
- * configure.in: Remove test for STDCALL.
- * config.h.in: Regenerate.
- * errno.c (_errno): Fix self type.
- * pthread.h (PT_STDCALL): Move from here to
- * implement.h (PT_STDCALL): here.
- (ptw32_threadStart): Fix prototype.
- * private.c (ptw32_threadStart): Likewise.
-
-1999-08-14 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * exit.c (pthread_exit): Don't call pthread_self() but
- get thread handle directly from TSD for efficiency.
-
-1999-08-12 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * private.c (ptw32_threadStart): ei[] only declared if _MSC_VER.
-
- * exit.c (pthread_exit): Check for implicitly created threads
- to avoid raising an unhandled exception.
-
-1999-07-12 Peter Slacik <Peter.Slacik@tatramed.sk>
-
- * condvar.c (pthread_cond_destroy): Add critical section.
- (cond_timedwait): Add critical section; check for timeout
- waiting on semaphore.
- (pthread_cond_broadcast): Add critical section.
-
-1999-07-09 Lorin Hochstein <lmh@xiphos.ca>, John Bossom <John.Bossom@Cognos.COM>
-
- The problem was that cleanup handlers were not executed when
- pthread_exit() was called.
-
- * implement.h (pthread_t_): Add exceptionInformation element for
- C++ per-thread exception information.
- (general): Define and rename exceptions.
-
-1999-07-09 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * misc.c (CancelableWait): PTW32_EPS_CANCEL (SEH) and
- ptw32_exception_cancel (C++) used to identify the exception.
-
- * cancel.c (pthread_testcancel): PTW32_EPS_CANCEL (SEH) and
- ptw32_exception_cancel (C++) used to identify the exception.
-
- * exit.c (pthread_exit): throw/raise an exception to return to
- ptw32_threadStart() to exit the thread. PTW32_EPS_EXIT (SEH)
- and ptw32_exception_exit (C++) used to identify the exception.
-
- * private.c (ptw32_threadStart): Add pthread_exit exception trap;
- clean up and exit the thread directly rather than via pthread_exit().
-
-Sun May 30 00:25:02 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * semaphore.h (mode_t): Conditionally typedef it.
-
-Fri May 28 13:33:05 1999 Mark E. Armstrong <avail@pacbell.net>
-
- * condvar.c (pthread_cond_broadcast): Fix possible memory fault
-
-Thu May 27 13:08:46 1999 Peter Slacik <Peter.Slacik@tatramed.sk>
-
- * condvar.c (pthread_cond_broadcast): Fix logic bug
-
-Thu May 27 13:08:46 1999 Bossom, John <John.Bossom@Cognos.COM>
-
- * condvar.c (pthread_cond_broadcast): optimise sem_post loop
-
-Fri May 14 12:13:18 1999 Mike Russo <miker@eai.com>
-
- * attr.c (pthread_attr_setdetachstate): Fix logic bug
-
-Sat May 8 09:42:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.def (sem_open): Add.
- (sem_close): Add.
- (sem_unlink): Add.
- (sem_getvalue): Add.
-
- * FAQ (Question 3): Add.
-
-Thu Apr 8 01:16:23 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * semaphore.c (sem_open): New function; returns an error (ENOSYS).
- (sem_close): ditto.
- (sem_unlink): ditto.
- (sem_getvalue): ditto.
-
- * semaphore.h (_POSIX_SEMAPHORES): define.
-
-Wed Apr 7 14:09:52 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * errno.c (_REENTRANT || _MT): Invert condition.
-
- * pthread.h (_errno): Conditionally include prototype.
-
-Wed Apr 7 09:37:00 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * *.c (comments): Remove individual attributions - these are
- documented sufficiently elsewhere.
-
- * implement.h (pthread.h): Remove extraneous include.
-
-Sun Apr 4 11:05:57 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * sched.c (sched.h): Include.
-
- * sched.h: New file for POSIX 1b scheduling.
-
- * pthread.h: Move opaque structures to implement.h; move sched_*
- prototypes out and into sched.h.
-
- * implement.h: Add opaque structures from pthread.h.
-
- * sched.c (sched_yield): New function.
-
- * condvar.c (ptw32_sem_*): Rename to sem_*; except for
- ptw32_sem_timedwait which is an private function.
-
-Sat Apr 3 23:28:00 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * Makefile.in (OBJS): Add errno.o.
-
-Fri Apr 2 11:08:50 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h (ptw32_sem_*): Remove prototypes now defined in
- semaphore.h.
-
- * pthread.h (sempahore.h): Include.
-
- * semaphore.h: New file for POSIX 1b semaphores.
-
- * semaphore.c (ptw32_sem_timedwait): Moved to private.c.
-
- * pthread.h (ptw32_sem_t): Change to sem_t.
-
- * private.c (ptw32_sem_timedwait): Moved from semaphore.c;
- set errno on error.
-
- * pthread.h (pthread_t_): Add per-thread errno element.
-
-Fri Apr 2 11:08:50 1999 John Bossom <jebossom@cognos.com>
-
- * semaphore.c (ptw32_sem_*): Change to sem_*; these functions
- will be exported from the library; set errno on error.
-
- * errno.c (_errno): New file. New function.
-
-Fri Mar 26 14:11:45 1999 Tor Lillqvist <tml@iki.fi>
-
- * semaphore.c (ptw32_sem_timedwait): Check for negative
- milliseconds.
-
-Wed Mar 24 11:32:07 1999 John Bossom <jebossom@cognos.com>
-
- * misc.c (CancelableWait): Initialise exceptionInformation[2].
- (pthread_self): Get a real Win32 thread handle for implicit threads.
-
- * cancel.c (pthread_testcancel): Initialise exceptionInformation[2].
-
- * implement.h (SE_INFORMATION): Fix values.
-
- * private.c (ptw32_threadDestroy): Close the thread handle.
-
-Fri Mar 19 12:57:27 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * cancel.c (comments): Update and cleanup.
-
-Fri Mar 19 09:12:59 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * private.c (ptw32_threadStart): status returns PTHREAD_CANCELED.
-
- * pthread.h (PTHREAD_CANCELED): defined.
-
-Tue Mar 16 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * all: Add GNU LGPL and Copyright and Warranty.
-
-Mon Mar 15 00:20:13 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * condvar.c (pthread_cond_init): fix possible uninitialised use
- of cv.
-
-Sun Mar 14 21:01:59 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * condvar.c (pthread_cond_destroy): don't do full cleanup if
- static initialised cv has never been used.
- (cond_timedwait): check result of auto-initialisation.
-
-Thu Mar 11 09:01:48 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.h (pthread_mutex_t): revert to (pthread_mutex_t *);
- define a value to serve as PTHREAD_MUTEX_INITIALIZER.
- (pthread_mutex_t_): remove staticinit and valid elements.
- (pthread_cond_t): revert to (pthread_cond_t_ *);
- define a value to serve as PTHREAD_COND_INITIALIZER.
- (pthread_cond_t_): remove staticinit and valid elements.
-
- * mutex.c (pthread_mutex_t args): adjust indirection of references.
- (all functions): check for PTHREAD_MUTEX_INITIALIZER value;
- check for NULL (invalid).
-
- * condvar.c (pthread_cond_t args): adjust indirection of references.
- (all functions): check for PTHREAD_COND_INITIALIZER value;
- check for NULL (invalid).
-
-Wed Mar 10 17:18:12 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * misc.c (CancelableWait): Undo changes from Mar 8 and 7.
-
-Mon Mar 8 11:18:59 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * misc.c (CancelableWait): Ensure cancelEvent handle is the lowest
- indexed element in the handles array. Enhance test for abandoned
- objects.
-
- * pthread.h (PTHREAD_MUTEX_INITIALIZER): Trailing elements not
- initialised are set to zero by the compiler. This avoids the
- problem of initialising the opaque critical section element in it.
- (PTHREAD_COND_INITIALIZER): Ditto.
-
- * semaphore.c (ptw32_sem_timedwait): Check sem == NULL earlier.
-
-Sun Mar 7 12:31:14 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * condvar.c (pthread_cond_init): set semaphore initial value
- to 0, not 1. cond_timedwait was returning signaled immediately.
-
- * misc.c (CancelableWait): Place the cancel event handle first
- in the handle table for WaitForMultipleObjects. This ensures that
- the cancel event is recognised and acted apon if both objects
- happen to be signaled together.
-
- * private.c (ptw32_cond_test_init_lock): Initialise and destroy.
-
- * implement.h (ptw32_cond_test_init_lock): Add extern.
-
- * global.c (ptw32_cond_test_init_lock): Add declaration.
-
- * condvar.c (pthread_cond_destroy): check for valid initialised CV;
- flag destroyed CVs as invalid.
- (pthread_cond_init): pthread_cond_t is no longer just a pointer.
- This is because PTHREAD_COND_INITIALIZER needs state info to reside
- in pthread_cond_t so that it can initialise on first use. Will work on
- making pthread_cond_t (and other objects like it) opaque again, if
- possible, later.
- (cond_timedwait): add check for statically initialisation of
- CV; initialise on first use.
- (pthread_cond_signal): check for valid CV.
- (pthread_cond_broadcast): check for valid CV.
- (_cond_check_need_init): Add.
-
- * pthread.h (PTHREAD_COND_INITIALIZER): Fix.
- (pthread_cond_t): no longer a pointer to pthread_cond_t_.
- (pthread_cond_t_): add 'staticinit' and 'valid' elements.
-
-Sat Mar 6 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h: Undate comments.
-
-Sun Feb 21 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.h (PTHREAD_MUTEX_INITIALIZER): missing braces around
- cs element initialiser.
-
-1999-02-21 Ben Elliston <bje@cygnus.com>
-
- * pthread.h (pthread_exit): The return type of this function is
- void, not int.
-
- * exit.c (pthread_exit): Do not return 0.
-
-Sat Feb 20 16:03:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * dll.c (DLLMain): Expand TryEnterCriticalSection support test.
-
- * mutex.c (pthread_mutex_trylock): The check for
- ptw32_try_enter_critical_section == NULL should have been
- removed long ago.
-
-Fri Feb 19 16:03:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * sync.c (pthread_join): Fix pthread_equal() test.
-
- * mutex.c (pthread_mutex_trylock): Check mutex != NULL before
- using it.
-
-Thu Feb 18 16:17:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * misc.c (pthread_equal): Fix inverted result.
-
- * Makefile.in: Use libpthread32.a as the name of the DLL export
- library instead of pthread.lib.
-
- * condvar.c (pthread_cond_init): cv could have been used unitialised;
- initialise.
-
- * create.c (pthread_create): parms could have been used unitialised;
- initialise.
-
- * pthread.h (struct pthread_once_t_): Remove redefinition.
-
-Sat Feb 13 03:03:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.h (struct pthread_once_t_): Replaced.
-
- * misc.c (pthread_once): Replace with John Bossom's version;
- has lighter weight serialisation; fixes problem of not holding
- competing threads until after the init_routine completes.
-
-Thu Feb 11 13:34:14 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * misc.c (CancelableWait): Change C++ exception throw.
-
- * sync.c (pthread_join): Change FIXME comment - issue resolved.
-
-Wed Feb 10 12:49:11 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * configure: Various temporary changes.
- - Kevin Ruland <Kevin.Ruland@anheuser-busch.com>
-
- * README: Update.
-
- * pthread.def (pthread_attr_getstackaddr): uncomment
- (pthread_attr_setstackaddr): uncomment
-
-Fri Feb 5 13:42:30 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * semaphore.c: Comment format changes.
-
-Thu Feb 4 10:07:28 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * global.c: Remove ptw32_exception instantiation.
-
- * cancel.c (pthread_testcancel): Change C++ exception throw.
-
- * implement.h: Remove extern declaration.
-
-Wed Feb 3 13:04:44 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * cleanup.c: Rename ptw32_*_cleanup() to pthread_*_cleanup().
-
- * pthread.def: Ditto.
-
- * pthread.h: Ditto.
-
- * pthread.def (pthread_cleanup_push): Remove from export list;
- the function is defined as a macro under all compilers.
- (pthread_cleanup_pop): Ditto.
-
- * pthread.h: Remove #if defined().
-
-Wed Feb 3 10:13:48 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * sync.c (pthread_join): Check for NULL value_ptr arg;
- check for detached threads.
-
-Tue Feb 2 18:07:43 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * implement.h: Add #include <pthread.h>.
- Change sem_t to ptw32_sem_t.
-
- Various patches by Kevin Ruland <Kevin.Ruland@anheuser-busch.com>
-
- * signal.c (pthread_sigmask): Add and modify casts.
- Reverse LHS/RHS bitwise assignments.
-
- * pthread.h: Remove #include <semaphore.h>.
- (PTW32_ATTR_VALID): Add cast.
- (struct pthread_t_): Add sigmask element.
-
- * dll.c: Add "extern C" for DLLMain.
- (DllMain): Add cast.
-
- * create.c (pthread_create): Set sigmask in thread.
-
- * condvar.c: Remove #include. Change sem_* to ptw32_sem_*.
-
- * attr.c: Changed #include.
-
- * Makefile.in: Additional targets and changes to build the library
- as a DLL.
-
-Fri Jan 29 11:56:28 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * Makefile.in (OBJS): Add semaphore.o to list.
-
- * semaphore.c (ptw32_sem_timedwait): Move from private.c.
- Rename sem_* to ptw32_sem_*.
-
- * pthread.h (pthread_cond_t): Change type of sem_t.
- _POSIX_SEMAPHORES no longer defined.
-
- * semaphore.h: Contents moved to implement.h.
- Removed from source tree.
-
- * implement.h: Add semaphore function prototypes and rename all
- functions to prepend 'ptw32_'. They are
- now private to the pthreads-win32 implementation.
-
- * private.c: Change #warning.
- Move ptw32_sem_timedwait() to semaphore.c.
-
- * cleanup.c: Change #warning.
-
- * misc.c: Remove #include <errno.h>
-
- * pthread.def: Cleanup CVS merge conflicts.
-
- * global.c: Ditto.
-
- * ChangeLog: Ditto.
-
- * cleanup.c: Ditto.
-
-Sun Jan 24 01:34:52 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * semaphore.c (sem_wait): Remove second arg to
- pthreadCancelableWait() call.
-
-Sat Jan 23 17:36:40 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.def: Add new functions to export list.
-
- * pthread.h (PTHREAD_MUTEX_AUTO_CS_NP): New.
- (PTHREAD_MUTEX_FORCE_CS_NP): New.
-
- * README: Updated.
-
-Fri Jan 22 14:31:59 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * Makefile.in (CFLAGS): Remove -fhandle-exceptions. Not needed
- with egcs. Add -g for debugging.
-
- * create.c (pthread_create): Replace __stdcall with PT_STDCALL
- macro. This is a hack and must be fixed.
-
- * misc.c (CancelableWait): Remove redundant statement.
-
- * mutex.c (pthread_mutexattr_init): Cast calloc return value.
-
- * misc.c (CancelableWait): Add cast.
- (pthread_self): Add cast.
-
- * exit.c (pthread_exit): Add cast.
-
- * condvar.c (pthread_condattr_init): Cast calloc return value.
-
- * cleanup.c: Reorganise conditional compilation.
-
- * attr.c (pthread_attr_init): Remove unused 'result'.
- Cast malloc return value.
-
- * private.c (ptw32_callUserDestroyRoutines): Redo conditional
- compilation.
-
- * misc.c (CancelableWait): C++ version uses 'throw'.
-
- * cancel.c (pthread_testcancel): Ditto.
-
- * implement.h (class ptw32_exception): Define for C++.
-
- * pthread.h: Fix C, C++, and Win32 SEH condition compilation
- mayhem around pthread_cleanup_* defines. C++ version now uses John
- Bossom's cleanup handlers.
- (pthread_attr_t): Make 'valid' unsigned.
- Define '_timeb' as 'timeb' for Ming32.
- Define PT_STDCALL as nothing for Mingw32. May be temporary.
-
- * cancel.c (pthread_testcancel): Cast return value.
-
-Wed Jan 20 09:31:28 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.h (pthread_mutexattr_t): Changed to a pointer.
-
- * mutex.c (pthread_mutex_init): Conditionally create Win32 mutex
- - from John Bossom's implementation.
- (pthread_mutex_destroy): Conditionally close Win32 mutex
- - from John Bossom's implementation.
- (pthread_mutexattr_init): Replaced by John Bossom's version.
- (pthread_mutexattr_destroy): Ditto.
- (pthread_mutexattr_getpshared): New function from John Bossom's
- implementation.
- (pthread_mutexattr_setpshared): New function from John Bossom's
- implementation.
-
-Tue Jan 19 18:27:42 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * pthread.h (pthreadCancelableTimedWait): New prototype.
- (pthreadCancelableWait): Remove second argument.
-
- * misc.c (CancelableWait): New static function is
- pthreadCancelableWait() renamed.
- (pthreadCancelableWait): Now just calls CancelableWait() with
- INFINITE timeout.
- (pthreadCancelableTimedWait): Just calls CancelableWait()
- with passed in timeout.
-
-Tue Jan 19 18:27:42 1999 Scott Lightner <scott@curriculum.com>
-
- * private.c (ptw32_sem_timedwait): 'abstime' arg really is
- absolute time. Calculate relative time to wait from current
- time before passing timeout to new routine
- pthreadCancelableTimedWait().
-
-Tue Jan 19 10:27:39 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.h (pthread_mutexattr_setforcecs_np): New prototype.
-
- * mutex.c (pthread_mutexattr_init): Init 'pshared' and 'forcecs'
- attributes to 0.
- (pthread_mutexattr_setforcecs_np): New function (not portable).
-
- * pthread.h (pthread_mutex_t):
- Add 'mutex' element. Set to NULL in PTHREAD_MUTEX_INITIALIZER.
- The pthread_mutex_*() routines will try to optimise performance
- by choosing either mutexes or critical sections as the basis
- for pthread mutexes for each indevidual mutex.
- (pthread_mutexattr_t_): Add 'forcecs' element.
- Some applications may choose to force use of critical sections
- if they know that:-
- the mutex is PROCESS_PRIVATE and,
- either the OS supports TryEnterCriticalSection() or
- pthread_mutex_trylock() will never be called on the mutex.
- This attribute will be setable via a non-portable routine.
-
- Note: We don't yet support PROCESS_SHARED mutexes, so the
- implementation as it stands will default to Win32 mutexes only if
- the OS doesn't support TryEnterCriticalSection. On Win9x, and early
- versions of NT 'forcecs' will need to be set in order to get
- critical section based mutexes.
-
-Sun Jan 17 12:01:26 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.h (PTHREAD_MUTEX_INITIALIZER): Init new 'staticinit'
- value to '1' and existing 'valid' value to '1'.
-
- * global.c (ptw32_mutex_test_init_lock): Add.
-
- * implement.h (ptw32_mutex_test_init_lock.): Add extern.
-
- * private.c (ptw32_processInitialize): Init critical section for
- global lock used by _mutex_check_need_init().
- (ptw32_processTerminate): Ditto (:s/Init/Destroy/).
-
- * dll.c (dllMain): Move call to FreeLibrary() so that it is only
- called once when the process detaches.
-
- * mutex.c (_mutex_check_need_init): New static function to test
- and init PTHREAD_MUTEX_INITIALIZER mutexes. Provides serialised
- access to the internal state of the uninitialised static mutex.
- Called from pthread_mutex_trylock() and pthread_mutex_lock() which
- do a quick unguarded test to check if _mutex_check_need_init()
- needs to be called. This is safe as the test is conservative
- and is repeated inside the guarded section of
- _mutex_check_need_init(). Thus in all calls except the first
- calls to lock static mutexes, the additional overhead to lock any
- mutex is a single memory fetch and test for zero.
-
- * pthread.h (pthread_mutex_t_): Add 'staticinit' member. Mutexes
- initialised by PTHREAD_MUTEX_INITIALIZER aren't really initialised
- until the first attempt to lock it. Using the 'valid'
- flag (which flags the mutex as destroyed or not) to record this
- information would be messy. It is possible for a statically
- initialised mutex such as this to be destroyed before ever being
- used.
-
- * mutex.c (pthread_mutex_trylock): Call _mutex_check_need_init()
- to test/init PTHREAD_MUTEX_INITIALIZER mutexes.
- (pthread_mutex_lock): Ditto.
- (pthread_mutex_unlock): Add check to ensure we don't try to unlock
- an unitialised static mutex.
- (pthread_mutex_destroy): Add check to ensure we don't try to delete
- a critical section that we never created. Allows us to destroy
- a static mutex that has never been locked (and hence initialised).
- (pthread_mutex_init): Set 'staticinit' flag to 0 for the new mutex.
-
-Sun Jan 17 12:01:26 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * private.c (ptw32_sem_timedwait): Move from semaphore.c.
-
- * semaphore.c : Remove redundant #includes.
- (ptw32_sem_timedwait): Move to private.c.
- (sem_wait): Add missing abstime arg to pthreadCancelableWait() call.
-
-Fri Jan 15 23:38:05 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * condvar.c (cond_timedwait): Remove comment.
-
-Fri Jan 15 15:41:28 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * pthread.h: Add new 'abstime' arg to pthreadCancelableWait()
- prototype.
-
- * condvar.c (cond_timedwait): New generalised function called by
- both pthread_cond_wait() and pthread_cond_timedwait(). This is
- essentially pthread_cond_wait() renamed and modified to add the
- 'abstime' arg and call the new ptw32_sem_timedwait() instead of
- sem_wait().
- (pthread_cond_wait): Now just calls the internal static
- function cond_timedwait() with an INFINITE wait.
- (pthread_cond_timedwait): Now implemented. Calls the internal
- static function cond_timedwait().
-
- * implement.h (ptw32_sem_timedwait): New internal function
- prototype.
-
- * misc.c (pthreadCancelableWait): Added new 'abstime' argument
- to allow shorter than INFINITE wait.
-
- * semaphore.c (ptw32_sem_timedwait): New function for internal
- use. This is essentially sem_wait() modified to add the
- 'abstime' arg and call the modified (see above)
- pthreadCancelableWait().
-
-Thu Jan 14 14:27:13 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * cleanup.c: Correct _cplusplus to __cplusplus wherever used.
-
- * Makefile.in: Add CC=g++ and add -fhandle-exceptions to CFLAGS.
- The derived Makefile will compile all units of the package as C++
- so that those which include try/catch exception handling should work
- properly. The package should compile ok if CC=gcc, however, exception
- handling will not be included and thus thread cancellation, for
- example, will not work.
-
- * cleanup.c (ptw32_pop_cleanup): Add #warning to compile this
- file as C++ if using a cygwin32 environment. Perhaps the whole package
- should be compiled using g++ under cygwin.
-
- * private.c (ptw32_threadStart): Change #error directive
- into #warning and bracket for __CYGWIN__ and derivative compilers.
-
-Wed Jan 13 09:34:52 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * build.bat: Delete old binaries before compiling/linking.
-
-Tue Jan 12 09:58:38 1999 Tor Lillqvist <tml@iki.fi>
-
- * dll.c: The Microsoft compiler pragmas probably are more
- appropriately protected by _MSC_VER than by _WIN32.
-
- * pthread.h: Define ETIMEDOUT. This should be returned by
- pthread_cond_timedwait which is not implemented yet as of
- snapshot-1999-01-04-1305. It was implemented in the older version.
- The Microsoft compiler pragmas probably are more appropriately
- protected by _MSC_VER than by _WIN32.
-
- * pthread.def: pthread_mutex_destroy was missing from the def file
-
- * condvar.c (pthread_cond_broadcast): Ensure we only wait on threads
- if there were any waiting on the condition.
- I think pthread_cond_broadcast should do the WaitForSingleObject
- only if cv->waiters > 0? Otherwise it seems to hang, at least in the
- testg thread program from glib.
-
-Tue Jan 12 09:58:38 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * condvar.c (pthread_cond_timedwait): Fix function description
- comments.
-
- * semaphore.c (sem_post): Correct typo in comment.
-
-Mon Jan 11 20:33:19 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.h: Re-arrange conditional compile of pthread_cleanup-*
- macros.
-
- * cleanup.c (ptw32_push_cleanup): Provide conditional
- compile of cleanup->prev.
-
-1999-01-11 Tor Lillqvist <tml@iki.fi>
-
- * condvar.c (pthread_cond_init): Invert logic when testing the
- return value from calloc().
-
-Sat Jan 9 14:32:08 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h: Compile-time switch for CYGWIN derived environments
- to use CreateThread instead of _beginthreadex. Ditto for ExitThread.
- Patch provided by Anders Norlander <anorland@hem2.passagen.se>.
-
-Tue Jan 5 16:33:04 1999 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * cleanup.c (ptw32_pop_cleanup): Add C++ version of __try/__except
- block. Move trailing "}" out of #ifdef _WIN32 block left there by
- (rpj's) mistake.
-
- * private.c: Remove #include <errno.h> which is included by pthread.h.
-
-1998-12-11 Ben Elliston <bje@toilet.to.cygnus.com>
-
- * README: Update info about subscribing to the mailing list.
-
-Mon Jan 4 11:23:40 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * all: No code changes, just cleanup.
- - remove #if 0 /* Pre Bossom */ enclosed code.
- - Remove some redundant #includes.
- * pthread.h: Update implemented/unimplemented routines list.
- * Tag the bossom merge branch getting ready to merge back to main
- trunk.
-
-Tue Dec 29 13:11:16 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h: Move the following struct definitions to pthread.h:
- pthread_t_, pthread_attr_t_, pthread_mutex_t_, pthread_mutex_t_,
- pthread_mutexattr_t_, pthread_key_t_, pthread_cond_t_,
- pthread_condattr_t_, pthread_once_t_.
-
- * pthread.h: Add "_" prefix to pthread_push_cleanup and
- pthread_pop_cleanup internal routines, and associated struct and
- typedefs.
-
- * buildlib.bat: Add compile command for semaphore.c
-
- * pthread.def: Comment out pthread_atfork routine name.
- Now unimplemented.
-
- * tsd.c (pthread_setspecific): Rename tkAssocCreate to
- ptw32_tkAssocCreate.
- (pthread_key_delete): Rename tkAssocDestroy to
- ptw32_tkAssocDestroy.
-
- * sync.c (pthread_join): Rename threadDestroy to ptw32_threadDestroy
-
- * sched.c (is_attr): attr is now **attr (was *attr), so add extra
- NULL pointer test.
- (pthread_attr_setschedparam): Increase redirection for attr which is
- now a **.
- (pthread_attr_getschedparam): Ditto.
- (pthread_setschedparam): Change thread validation and rename "thread"
- Win32 thread Handle element name to match John Bossom's version.
- (pthread_getschedparam): Ditto.
-
- * private.c (ptw32_threadDestroy): Rename call to
- callUserDestroyRoutines() as ptw32_callUserDestroyRoutines()
-
- * misc.c: Add #include "implement.h".
-
- * dll.c: Remove defined(KLUDGE) wrapped code.
-
- * fork.c: Remove redefinition of ENOMEM.
- Remove pthread_atfork() and fork() with #if 0/#endif.
-
- * create.c (pthread_create): Rename threadStart and threadDestroy calls
- to ptw32_threadStart and ptw32_threadDestroy.
-
- * implement.h: Rename "detachedstate" to "detachstate".
-
- * attr.c: Rename "detachedstate" to "detachstate".
-
-Mon Dec 28 09:54:39 1998 John Bossom
-
- * semaphore.c: Initial version.
- * semaphore.h: Initial version.
-
-Mon Dec 28 09:54:39 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.h (pthread_attr_t_): Change to *pthread_attr_t.
-
-Mon Dec 28 09:54:39 1998 John Bossom, Ben Elliston
-
- * attr.c (pthread_attr_setstacksize): Merge with John's version.
- (pthread_attr_getstacksize): Merge with John's version.
- (pthread_attr_setstackaddr): Merge with John's version.
- (pthread_attr_getstackaddr): Merge with John's version.
- (pthread_attr_init): Merge with John's version.
- (pthread_attr_destroy): Merge with John's version.
- (pthread_attr_getdetachstate): Merge with John's version.
- (pthread_attr_setdetachstate): Merge with John's version.
- (is_attr): attr is now **attr (was *attr), so add extra NULL pointer
- test.
-
-Mon Dec 28 09:54:39 1998 Ross Johnson
-
- * implement.h (pthread_attr_t_): Add and rename elements in JEB's
- version to correspond to original, so that it can be used with
- original attr routines.
-
- * pthread.h: Add #endif at end which was truncated in merging.
-
-Sun Dec 20 14:51:58 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * misc.c (pthreadCancelableWait): New function by John Bossom. Non-standard
- but provides a hook that can be used to implement cancellation points in
- applications that use this library.
-
- * pthread.h (pthread_cleanup_pop): C++ (non-WIN32) version uses
- try/catch to emulate John Bossom's WIN32 __try/__finally behaviour.
- In the WIN32 version __finally block, add a test for AbnormalTermination otherwise
- cleanup is only run if the cleanup_pop execute arg is non-zero. Cancellation
- should cause the cleanup to run irrespective of the execute arg.
-
- * condvar.c (pthread_condattr_init): Replaced by John Bossom's version.
- (pthread_condattr_destroy): Replaced by John Bossom's version.
- (pthread_condattr_getpshared): Replaced by John Bossom's version.
- (pthread_condattr_setpshared): Replaced by John Bossom's version.
- (pthread_cond_init): Replaced by John Bossom's version.
- Fix comment (refered to mutex rather than condition variable).
- (pthread_cond_destroy): Replaced by John Bossom's version.
- (pthread_cond_wait): Replaced by John Bossom's version.
- (pthread_cond_timedwait): Replaced by John Bossom's version.
- (pthread_cond_signal): Replaced by John Bossom's version.
- (pthread_cond_broadcast): Replaced by John Bossom's version.
-
-Thu Dec 17 19:10:46 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * tsd.c (pthread_key_create): Replaced by John Bossom's version.
- (pthread_key_delete): Replaced by John Bossom's version.
- (pthread_setspecific): Replaced by John Bossom's version.
- (pthread_getspecific): Replaced by John Bossom's version.
-
-Mon Dec 7 09:44:40 1998 John Bossom
-
- * cancel.c (pthread_setcancelstate): Replaced.
- (pthread_setcanceltype): Replaced.
- (pthread_testcancel): Replaced.
- (pthread_cancel): Replaced.
-
- * exit.c (pthread_exit): Replaced.
-
- * misc.c (pthread_self): Replaced.
- (pthread_equal): Replaced.
-
- * sync.c (pthread_detach): Replaced.
- (pthread_join): Replaced.
-
- * create.c (pthread_create): Replaced.
-
- * private.c (ptw32_processInitialize): New.
- (ptw32_processTerminate): New.
- (ptw32_threadStart): New.
- (ptw32_threadDestroy): New.
- (ptw32_cleanupStack): New.
- (ptw32_tkAssocCreate): New.
- (ptw32_tkAssocDestroy): New.
- (ptw32_callUserDestroyRoutines): New.
-
- * implement.h: Added non-API structures and declarations.
-
- * dll.c (PthreadsEntryPoint): Cast return value of GetProcAddress
- to resolve compile warning from MSVC.
-
- * dll.c (DLLmain): Replaced.
- * dll.c (PthreadsEntryPoint):
- Re-applied Anders Norlander's patch:-
- Initialize ptw32_try_enter_critical_section at startup
- and release kernel32 handle when DLL is being unloaded.
-
-Sun Dec 6 21:54:35 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * buildlib.bat: Fix args to CL when building the .DLL
-
- * cleanup.c (ptw32_destructor_run_all): Fix TSD key management.
- This is a tidy-up before TSD and Thread management is completely
- replaced by John Bossom's code.
-
- * tsd.c (pthread_key_create): Fix TSD key management.
-
- * global.c (ptw32_key_virgin_next): Initialise.
-
- * build.bat: New DOS script to compile and link a pthreads app
- using Microsoft's CL compiler linker.
- * buildlib.bat: New DOS script to compile all the object files
- and create pthread.lib and pthread.dll using Microsoft's CL
- compiler linker.
-
-1998-12-05 Anders Norlander <anorland@hem2.passagen.se>
-
- * implement.h (ptw32_try_enter_critical_section): New extern
- * dll.c (ptw32_try_enter_critical_section): New pointer to
- TryEnterCriticalSection if it exists; otherwise NULL.
- * dll.c (PthreadsEntryPoint):
- Initialize ptw32_try_enter_critical_section at startup
- and release kernel32 handle when DLL is being unloaded.
- * mutex.c (pthread_mutex_trylock): Replaced check for NT with
- a check if ptw32_try_enter_critical_section is valid
- pointer to a function. Call ptw32_try_enter_critical_section
- instead of TryEnterCriticalSection to avoid errors on Win95.
-
-Thu Dec 3 13:32:00 1998 Ross Johnson <rpj@ise.canberra.edu.au>
-
- * README: Correct cygwin32 compatibility statement.
-
-Sun Nov 15 21:24:06 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * cleanup.c (ptw32_destructor_run_all): Declare missing void * arg.
- Fixup CVS merge conflicts.
-
-1998-10-30 Ben Elliston <bje@cygnus.com>
-
- * condvar.c (cond_wait): Fix semantic error. Test for equality
- instead of making an assignment.
-
-Fri Oct 30 15:15:50 1998 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * cleanup.c (ptw32_handler_push): Fixed bug appending new
- handler to list reported by Peter Slacik
- <Peter.Slacik@leibinger.freinet.de>.
- (new_thread): Rename poorly named local variable to
- "new_handler".
-
-Sat Oct 24 18:34:59 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * global.c: Add TSD key management array and index declarations.
-
- * implement.h: Ditto for externs.
-
-Fri Oct 23 00:08:09 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h (PTW32_TSD_KEY_REUSE): Add enum.
-
- * private.c (ptw32_delete_thread): Add call to
- ptw32_destructor_run_all() to clean up the threads keys.
-
- * cleanup.c (ptw32_destructor_run_all): Check for no more dirty
- keys to run destructors on. Assume that the destructor call always
- succeeds and set the key value to NULL.
-
-Thu Oct 22 21:44:44 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * tsd.c (pthread_setspecific): Add key management code.
- (pthread_key_create): Ditto.
- (pthread_key_delete): Ditto.
-
- * implement.h (struct ptw32_tsd_key): Add status member.
-
- * tsd.c: Add description of pthread_key_delete() from the
- standard as a comment.
-
-Fri Oct 16 17:38:47 1998 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * cleanup.c (ptw32_destructor_run_all): Fix and improve
- stepping through the key table.
-
-Thu Oct 15 14:05:01 1998 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * private.c (ptw32_new_thread): Remove init of destructorstack.
- No longer an element of pthread_t.
-
- * tsd.c (pthread_setspecific): Fix type declaration and cast.
- (pthread_getspecific): Ditto.
- (pthread_getspecific): Change error return value to NULL if key
- is not in use.
-
-Thu Oct 15 11:53:21 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * global.c (ptw32_tsd_key_table): Fix declaration.
-
- * implement.h(ptw32_TSD_keys_TlsIndex): Add missing extern.
- (ptw32_tsd_mutex): Ditto.
-
- * create.c (ptw32_start_call): Fix "keys" array declaration.
- Add comment.
-
- * tsd.c (pthread_setspecific): Fix type declaration and cast.
- (pthread_getspecific): Ditto.
-
- * cleanup.c (ptw32_destructor_run_all): Declare missing loop
- counter.
-
-Wed Oct 14 21:09:24 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * private.c (ptw32_new_thread): Increment ptw32_threads_count.
- (ptw32_delete_thread): Decrement ptw32_threads_count.
- Remove some comments.
-
- * exit.c (ptw32_exit): : Fix two pthread_mutex_lock() calls that
- should have been pthread_mutex_unlock() calls.
- (ptw32_vacuum): Remove call to ptw32_destructor_pop_all().
-
- * create.c (pthread_create): Fix two pthread_mutex_lock() calls that
- should have been pthread_mutex_unlock() calls.
-
- * global.c (ptw32_tsd_mutex): Add mutex for TSD operations.
-
- * tsd.c (pthread_key_create): Add critical section.
- (pthread_setspecific): Ditto.
- (pthread_getspecific): Ditto.
- (pthread_key_delete): Ditto.
-
- * sync.c (pthread_join): Fix two pthread_mutex_lock() calls that
- should have been pthread_mutex_unlock() calls.
-
-Mon Oct 12 00:00:44 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h (ptw32_tsd_key_table): New.
-
- * create.c (ptw32_start_call): Initialise per-thread TSD keys
- to NULL.
-
- * misc.c (pthread_once): Correct typo in comment.
-
- * implement.h (ptw32_destructor_push): Remove.
- (ptw32_destructor_pop): Remove.
- (ptw32_destructor_run_all): Rename from ptw32_destructor_pop_all.
- (PTW32_TSD_KEY_DELETED): Add enum.
- (PTW32_TSD_KEY_INUSE): Add enum.
-
- * cleanup.c (ptw32_destructor_push): Remove.
- (ptw32_destructor_pop): Remove.
- (ptw32_destructor_run_all): Totally revamped TSD.
-
- * dll.c (ptw32_TSD_keys_TlsIndex): Initialise.
-
- * tsd.c (pthread_setspecific): Totally revamped TSD.
- (pthread_getspecific): Ditto.
- (pthread_create): Ditto.
- (pthread_delete): Ditto.
-
-Sun Oct 11 22:44:55 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * global.c (ptw32_tsd_key_table): Add new global.
-
- * implement.h (ptw32_tsd_key_t and struct ptw32_tsd_key):
- Add.
- (struct _pthread): Remove destructorstack.
-
- * cleanup.c (ptw32_destructor_run_all): Rename from
- ptw32_destructor_pop_all. The key destructor stack was made
- global rather than per-thread. No longer removes destructor nodes
- from the stack. Comments updated.
-
-1998-10-06 Ben Elliston <bje@cygnus.com>
-
- * condvar.c (cond_wait): Use POSIX, not Win32 mutex calls.
- (pthread_cond_broadcast): Likewise.
- (pthread_cond_signal): Likewise.
-
-1998-10-05 Ben Elliston <bje@cygnus.com>
-
- * pthread.def: Update. Some functions aren't available yet, others
- are macros in <pthread.h>.
-
- * tests/join.c: Remove; useless.
-
-Mon Oct 5 14:25:08 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * pthread.def: New file for building the DLL.
-
-1998-10-05 Ben Elliston <bje@cygnus.com>
-
- * misc.c (pthread_equal): Correct inverted logic bug.
- (pthread_once): Use the POSIX mutex primitives, not Win32. Remove
- irrelevant FIXME comment.
-
- * global.c (PTHREAD_MUTEX_INITIALIZER): Move to pthread.h.
-
- * pthread.h (PTHREAD_MUTEX_INITIALIZER): Define.
- (pthread_mutex_t): Reimplement as a struct containing a valid
- flag. If the flag is ever down upon entry to a mutex operation,
- we call pthread_mutex_create() to initialise the object. This
- fixes the problem of how to handle statically initialised objects
- that can't call InitializeCriticalSection() due to their context.
- (PTHREAD_ONCE_INIT): Define.
-
- * mutex.c (pthread_mutex_init): Set valid flag.
- (pthread_mutex_destroy): Clear valid flag.
- (pthread_mutex_lock): Check and handle the valid flag.
- (pthread_mutex_unlock): Likewise.
- (pthread_mutex_trylock): Likewise.
-
- * tests/mutex3.c: New file; test for the static initialisation
- macro. Passes.
-
- * tests/create1.c: New file; test pthread_create(). Passes.
-
- * tests/equal.c: Poor test; remove.
-
- * tests/equal1.c New file; test pthread_equal(). Passes.
-
- * tests/once1.c: New file; test for pthread_once(). Passes.
-
- * tests/self.c: Remove; rename to self1.c.
-
- * tests/self1.c: This is the old self.c.
-
- * tests/self2.c: New file. Test pthread_self() with a single
- thread. Passes.
-
- * tests/self3.c: New file. Test pthread_self() with a couple of
- threads to ensure their thread IDs differ. Passes.
-
-1998-10-04 Ben Elliston <bje@cygnus.com>
-
- * tests/mutex2.c: Test pthread_mutex_trylock(). Passes.
-
- * tests/mutex1.c: New basic test for mutex functions (it passes).
- (main): Eliminate warning.
-
- * configure.in: Test for __stdcall, not _stdcall. Typo.
-
- * configure: Regenerate.
-
- * attr.c (pthread_attr_setstackaddr): Remove FIXME comment. Win32
- does know about ENOSYS after all.
- (pthread_attr_setstackaddr): Likewise.
-
-1998-10-03 Ben Elliston <bje@cygnus.com>
-
- * configure.in: Test for the `_stdcall' keyword. Define `STDCALL'
- to `_stdcall' if we have it, null otherwise.
-
- * configure: Regenerate.
-
- * acconfig.h (STDCALL): New define.
-
- * config.h.in: Regenerate.
-
- * create.c (ptw32_start_call): Add STDCALL prefix.
-
- * mutex.c (pthread_mutex_init): Correct function signature.
-
- * attr.c (pthread_attr_init): Only zero out the `sigmask' member
- if we have the sigset_t type.
-
- * pthread.h: No need to include <unistd.h>. It doesn't even exist
- on Win32! Again, an artifact of cross-compilation.
- (pthread_sigmask): Only provide if we have the sigset_t type.
-
- * process.h: Remove. This was a stand-in before we started doing
- native compilation under Win32.
-
- * pthread.h (pthread_mutex_init): Make `attr' argument const.
-
-1998-10-02 Ben Elliston <bje@cygnus.com>
-
- * COPYING: Remove.
-
- * COPYING.LIB: Add. This library is under the LGPL.
-
-1998-09-13 Ben Elliston <bje@cygnus.com>
-
- * configure.in: Test for required system features.
-
- * configure: Generate.
-
- * acconfig.h: New file.
-
- * config.h.in: Generate.
-
- * Makefile.in: Renamed from Makefile.
-
- * COPYING: Import from a recent GNU package.
-
- * config.guess: Likewise.
-
- * config.sub: Likewise.
-
- * install-sh: Likewise.
-
- * config.h: Remove.
-
- * Makefile: Likewise.
-
-1998-09-12 Ben Elliston <bje@cygnus.com>
-
- * windows.h: No longer needed; remove.
-
- * windows.c: Likewise.
-
-Sat Sep 12 20:09:24 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * windows.h: Remove error number definitions. These are in <errno.h>
-
- * tsd.c: Add comment explaining rationale for not building
- POSIX TSD on top of Win32 TLS.
-
-1998-09-12 Ben Elliston <bje@cygnus.com>
-
- * {most}.c: Include <errno.h> to get POSIX error values.
-
- * signal.c (pthread_sigmask): Only provide if HAVE_SIGSET_T is
- defined.
-
- * config.h: #undef features, don't #define them. This will be
- generated by autoconf very soon.
-
-1998-08-11 Ben Elliston <bje@cygnus.com>
-
- * Makefile (LIB): Define.
- (clean): Define target.
- (all): Build a library not just the object files.
-
- * pthread.h: Provide a definition for struct timespec if we don't
- already have one.
-
- * windows.c (TlsGetValue): Bug fix.
-
-Thu Aug 6 15:19:22 1998 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * misc.c (pthread_once): Fix arg 1 of EnterCriticalSection()
- and LeaveCriticalSection() calls to pass address-of lock.
-
- * fork.c (pthread_atfork): Typecast (void (*)(void *)) funcptr
- in each ptw32_handler_push() call.
-
- * exit.c (ptw32_exit): Fix attr arg in
- pthread_attr_getdetachstate() call.
-
- * private.c (ptw32_new_thread): Typecast (HANDLE) NULL.
- (ptw32_delete_thread): Ditto.
-
- * implement.h: (PTW32_MAX_THREADS): Add define. This keeps
- changing in an attempt to make thread administration data types
- opaque and cleanup DLL startup.
-
- * dll.c (PthreadsEntryPoint):
- (ptw32_virgins): Remove malloc() and free() calls.
- (ptw32_reuse): Ditto.
- (ptw32_win32handle_map): Ditto.
- (ptw32_threads_mutex_table): Ditto.
-
- * global.c (_POSIX_THREAD_THREADS_MAX): Initialise with
- PTW32_MAX_THREADS.
- (ptw32_virgins): Ditto.
- (ptw32_reuse): Ditto.
- (ptw32_win32handle_map): Ditto.
- (ptw32_threads_mutex_table): Ditto.
-
- * create.c (pthread_create): Typecast (HANDLE) NULL.
- Typecast (unsigned (*)(void *)) start_routine.
-
- * condvar.c (pthread_cond_init): Add address-of operator & to
- arg 1 of pthread_mutex_init() call.
- (pthread_cond_destroy): Add address-of operator & to
- arg 1 of pthread_mutex_destroy() call.
-
- * cleanup.c (ptw32_destructor_pop_all): Add (int) cast to
- pthread_getspecific() arg.
- (ptw32_destructor_pop): Add (void *) cast to "if" conditional.
- (ptw32_destructor_push): Add (void *) cast to
- ptw32_handler_push() "key" arg.
- (malloc.h): Add include.
-
- * implement.h (ptw32_destructor_pop): Add prototype.
-
- * tsd.c (implement.h): Add include.
-
- * sync.c (pthread_join): Remove target_thread_mutex and it's
- initialisation. Rename getdetachedstate to getdetachstate.
- Remove unused variable "exitcode".
- (pthread_detach): Remove target_thread_mutex and it's
- initialisation. Rename getdetachedstate to getdetachstate.
- Rename setdetachedstate to setdetachstate.
-
- * signal.c (pthread_sigmask): Rename SIG_SET to SIG_SETMASK.
- Cast "set" to (long *) in assignment to passify compiler warning.
- Add address-of operator & to thread->attr.sigmask in memcpy() call
- and assignment.
- (pthread_sigmask): Add address-of operator & to thread->attr.sigmask
- in memcpy() call and assignment.
-
- * windows.h (THREAD_PRIORITY_ERROR_RETURN): Add.
- (THREAD_PRIORITY_LOWEST): Add.
- (THREAD_PRIORITY_HIGHEST): Add.
-
- * sched.c (is_attr): Add function.
- (implement.h): Add include.
- (pthread_setschedparam): Rename all instances of "sched_policy"
- to "sched_priority".
- (pthread_getschedparam): Ditto.
-
-Tue Aug 4 16:57:58 1998 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * private.c (ptw32_delete_thread): Fix typo. Add missing ';'.
-
- * global.c (ptw32_virgins): Change types from pointer to
- array pointer.
- (ptw32_reuse): Ditto.
- (ptw32_win32handle_map): Ditto.
- (ptw32_threads_mutex_table): Ditto.
-
- * implement.h(ptw32_virgins): Change types from pointer to
- array pointer.
- (ptw32_reuse): Ditto.
- (ptw32_win32handle_map): Ditto.
- (ptw32_threads_mutex_table): Ditto.
-
- * private.c (ptw32_delete_thread): Fix "entry" should be "thread".
-
- * misc.c (pthread_self): Add extern for ptw32_threadID_TlsIndex.
-
- * global.c: Add comment.
-
- * misc.c (pthread_once): Fix member -> dereferences.
- Change ptw32_once_flag to once_control->flag in "if" test.
-
-Tue Aug 4 00:09:30 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h(ptw32_virgins): Add extern.
- (ptw32_virgin_next): Ditto.
- (ptw32_reuse): Ditto.
- (ptw32_reuse_top): Ditto.
- (ptw32_win32handle_map): Ditto.
- (ptw32_threads_mutex_table): Ditto.
-
- * global.c (ptw32_virgins): Changed from array to pointer.
- Storage allocation for the array moved into dll.c.
- (ptw32_reuse): Ditto.
- (ptw32_win32handle_map): Ditto.
- (ptw32_threads_mutex_table): Ditto.
-
- * dll.c (PthreadsEntryPoint): Set up thread admin storage when
- DLL is loaded.
-
- * fork.c (pthread_atfork): Fix function pointer arg to all
- ptw32_handler_push() calls. Change "arg" arg to NULL in child push.
-
- * exit.c: Add windows.h and process.h includes.
- (ptw32_exit): Add local detachstate declaration.
- (ptw32_exit): Fix incorrect name for pthread_attr_getdetachstate().
-
- * pthread.h (_POSIX_THREAD_ATTR_STACKSIZE): Move from global.c
- (_POSIX_THREAD_ATTR_STACKADDR): Ditto.
-
- * create.c (pthread_create): Fix #if should be #ifdef.
- (ptw32_start_call): Remove usused variables.
-
- * process.h: Create.
-
- * windows.h: Move _beginthreadex and _endthreadex into
- process.h
-
-Mon Aug 3 21:19:57 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * condvar.c (pthread_cond_init): Add NULL attr to
- pthread_mutex_init() call - default attributes will be used.
- (cond_wait): Fix typo.
- (cond_wait): Fix typo - cv was ev.
- (pthread_cond_broadcast): Fix two identical typos.
-
- * cleanup.c (ptw32_destructor_pop_all): Remove _ prefix from
- PTHREAD_DESTRUCTOR_ITERATIONS.
-
- * pthread.h: Move _POSIX_* values into posix.h
-
- * pthread.h: Fix typo in pthread_mutex_init() prototype.
-
- * attr.c (pthread_attr_init): Fix error in priority member init.
-
- * windows.h (THREAD_PRIORITY_NORMAL): Add.
-
- * pthread.h (sched_param): Add missing ';' to struct definition.
-
- * attr.c (pthread_attr_init): Remove obsolete pthread_attr_t
- member initialisation - cancelstate, canceltype, cancel_pending.
- (is_attr): Make arg "attr" a const.
-
- * implement.h (PTW32_HANDLER_POP_LIFO): Remove definition.
- (PTW32_HANDLER_POP_FIFO): Ditto.
- (PTW32_VALID): Add missing newline escape (\).
- (ptw32_handler_node): Make element "next" a pointer.
-
-1998-08-02 Ben Elliston <bje@cygnus.com>
-
- * windows.h: Remove duplicate TlsSetValue() prototype. Add
- TlsGetValue() prototype.
- (FALSE): Define.
- (TRUE): Likewise.
- Add forgotten errno values. Guard against multiple #includes.
-
- * windows.c: New file. Implement stubs for Win32 functions.
-
- * Makefile (SRCS): Remove. Not explicitly needed.
- (CFLAGS): Add -Wall for all warnings with GCC.
-
-Sun Aug 2 19:03:42 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * config.h: Create. This is a temporary stand-in for autoconf yet
- to be done.
- (HAVE_SIGNAL_H): Add.
-
- * pthread.h: Minor rearrangement for temporary config.h.
-
-Fri Jul 31 14:00:29 1998 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * cleanup.c (ptw32_destructor_pop): Implement. Removes
- destructors associated with a key without executing them.
- (ptw32_destructor_pop_all): Add FIXME comment.
-
- * tsd.c (pthread_key_delete): Add call to ptw32_destructor_pop().
-
-Fri Jul 31 00:05:45 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * tsd.c (pthread_key_create): Update to properly associate
- the destructor routine with the key.
- (pthread_key_delete): Add FIXME comment.
-
- * exit.c (ptw32_vacuum): Add call to
- ptw32_destructor_pop_all().
-
- * implement.h (ptw32_handler_pop_all): Add prototype.
- (ptw32_destructor_pop_all): Ditto.
-
- * cleanup.c (ptw32_destructor_push): Implement. This is just a
- call to ptw32_handler_push().
- (ptw32_destructor_pop_all): Implement. This is significantly
- different to ptw32_handler_pop_all().
-
- * Makefile (SRCS): Create. Preliminary.
-
- * windows.h: Create. Contains Win32 definitions for compile
- testing. This is just a standin for the real one.
-
- * pthread.h (SIG_UNBLOCK): Fix typo. Was SIG_BLOCK.
- (windows.h): Add include. Required for CRITICAL_SECTION.
- (pthread_cond_t): Move enum declaration outside of struct
- definition.
- (unistd.h): Add include - may be temporary.
-
- * condvar.c (windows.h): Add include.
-
- * implement.h (PTW32_THIS): Remove - no longer required.
- (PTW32_STACK): Use pthread_self() instead of PTW32_THIS.
-
-Thu Jul 30 23:12:45 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h: Remove ptw32_find_entry() prototype.
-
- * private.c: Extend comments.
- Remove ptw32_find_entry() - no longer needed.
-
- * create.c (ptw32_start_call): Add call to TlsSetValue() to
- store the thread ID.
-
- * dll.c (PthreadsEntryPoint): Implement. This is called
- whenever a process loads the DLL. Used to initialise thread
- local storage.
-
- * implement.h: Add ptw32_threadID_TlsIndex.
- Add ()s around PTW32_VALID expression.
-
- * misc.c (pthread_self): Re-implement using Win32 TLS to store
- the threads own ID.
-
-Wed Jul 29 11:39:03 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * private.c: Corrections in comments.
- (ptw32_new_thread): Alter "if" flow to be more natural.
-
- * cleanup.c (ptw32_handler_push): Same as below.
-
- * create.c (pthread_create): Same as below.
-
- * private.c (ptw32_new_thread): Rename "new" to "new_thread".
- Since when has a C programmer been required to know C++?
-
-Tue Jul 28 14:04:29 1998 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * implement.h: Add PTW32_VALID macro.
-
- * sync.c (pthread_join): Modify to use the new thread
- type and ptw32_delete_thread(). Rename "target" to "thread".
- Remove extra local variable "target".
- (pthread_detach): Ditto.
-
- * signal.c (pthread_sigmask): Move init of "us" out of inner block.
- Fix instance of "this" should have been "us". Rename "us" to "thread".
-
- * sched.c (pthread_setschedparam): Modify to use the new thread
- type.
- (pthread_getschedparam): Ditto.
-
- * private.c (ptw32_find_thread): Fix return type and arg.
-
- * implement.h: Remove PTW32_YES and PTW32_NO.
- (ptw32_new_thread): Add prototype.
- (ptw32_find_thread): Ditto.
- (ptw32_delete_thread): Ditto.
- (ptw32_new_thread_entry): Remove prototype.
- (ptw32_find_thread_entry): Ditto.
- (ptw32_delete_thread_entry): Ditto.
- ( PTW32_NEW, PTW32_INUSE, PTW32_EXITED, PTW32_REUSE):
- Add.
-
-
- * create.c (pthread_create): Minor rename "us" to "new" (I need
- these cues but it doesn't stop me coming out with some major bugs
- at times).
- Load start_routine and arg into the thread so the wrapper can
- call it.
-
- * exit.c (pthread_exit): Fix pthread_this should be pthread_self.
-
- * cancel.c (pthread_setcancelstate): Change
- ptw32_threads_thread_t * to pthread_t and init with
- pthread_this().
- (pthread_setcanceltype): Ditto.
-
- * exit.c (ptw32_exit): Add new pthread_t arg.
- Rename ptw32_delete_thread_entry to ptw32_delete_thread.
- Rename "us" to "thread".
- (pthread_exit): Call ptw32_exit with added thread arg.
-
- * create.c (ptw32_start_call): Insert missing ")".
- Add "us" arg to ptw32_exit() call.
- (pthread_create): Modify to use new thread allocation scheme.
-
- * private.c: Added detailed explanation of the new thread
- allocation scheme.
- (ptw32_new_thread): Totally rewritten to use
- new thread allocation scheme.
- (ptw32_delete_thread): Ditto.
- (ptw32_find_thread): Obsolete.
-
-Mon Jul 27 17:46:37 1998 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * create.c (pthread_create): Start of rewrite. Not completed yet.
-
- * private.c (ptw32_new_thread_entry): Start of rewrite. Not
- complete.
-
- * implement.h (ptw32_threads_thread): Rename, remove thread
- member, add win32handle and ptstatus members.
- (ptw32_t): Add.
-
- * pthread.h: pthread_t is no longer mapped directly to a Win32
- HANDLE type. This is so we can let the Win32 thread terminate and
- reuse the HANDLE while pthreads holds it's own thread ID until
- the last waiting join exits.
-
-Mon Jul 27 00:20:37 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * private.c (ptw32_delete_thread_entry): Destroy the thread
- entry attribute object before deleting the thread entry itself.
-
- * attr.c (pthread_attr_init): Initialise cancel_pending = FALSE.
- (pthread_attr_setdetachstate): Rename "detached" to "detachedstate".
- (pthread_attr_getdetachstate): Ditto.
-
- * exit.c (ptw32_exit): Fix incorrect check for detachedstate.
-
- * implement.h (ptw32_call_t): Remove env member.
-
-Sun Jul 26 13:06:12 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h (ptw32_new_thread_entry): Fix prototype.
- (ptw32_find_thread_entry): Ditto.
- (ptw32_delete_thread_entry): Ditto.
- (ptw32_exit): Add prototype.
-
- * exit.c (ptw32_exit): New function. Called from pthread_exit()
- and ptw32_start_call() to exit the thread. It allows an extra
- argument which is the return code passed to _endthreadex().
- (ptw32_exit): Move thread entry delete call from ptw32_vacuum()
- into here. Add more explanation of thread entry deletion.
- (ptw32_exit): Clarify comment.
-
- * create.c (ptw32_start_call): Change pthread_exit() call to
- ptw32_exit() call.
-
- * exit.c (ptw32_vacuum): Add thread entry deletion code
- moved from ptw32_start_call(). See next item.
- (pthread_exit): Remove longjmp(). Add mutex lock around thread table
- manipulation code. This routine now calls _enthreadex().
-
- * create.c (ptw32_start_call): Remove setjmp() call and move
- cleanup code out. Call pthread_exit(NULL) to terminate the thread.
-
-1998-07-26 Ben Elliston <bje@cygnus.com>
-
- * tsd.c (pthread_getspecific): Update comments.
-
- * mutex.c (pthread_mutexattr_setpshared): Not supported; remove.
- (pthread_mutexattr_getpshared): Likewise.
-
- * pthread.h (pthread_mutexattr_setpshared): Remove prototype.
- (pthread_mutexattr_getpshared): Likewise.
-
-Sun Jul 26 00:09:59 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * sync.c: Rename all instances of ptw32_count_mutex to
- ptw32_table_mutex.
-
- * implement.h: Rename ptw32_count_mutex to
- ptw32_table_mutex.
-
- * global.c: Rename ptw32_count_mutex to
- ptw32_table_mutex.
-
- * create.c (pthread_create): Add critical sections.
- (ptw32_start_call): Rename ptw32_count_mutex to
- ptw32_table_mutex.
-
- * cancel.c (pthread_setcancelstate): Fix indirection bug and rename
- "this" to "us".
-
- * signal.c (pthread_sigmask): Rename "this" to "us" and fix some
- minor syntax errors. Declare "us" and initialise it.
-
- * sync.c (pthread_detach): Rename "this" to "target".
-
- * pthread.h: Converting PTHREAD_* defines to alias the (const int)
- values in global.c.
-
- * global.c: Started converting PTHREAD_* defines to (const int) as
- a part of making the eventual pthreads DLL binary compatible
- through version changes.
-
- * condvar.c (cond_wait): Add cancelation point. This applies the
- point to both pthread_cond_wait() and pthread_cond_timedwait().
-
- * exit.c (pthread_exit): Rename "this" to "us".
-
- * implement.h: Add comment.
-
- * sync.c (pthread_join): I've satisfied myself that pthread_detach()
- does set the detached attribute in the thread entry attributes
- to PTHREAD_CREATE_DETACHED. "if" conditions were changed to test
- that attribute instead of a separate flag.
-
- * create.c (pthread_create): Rename "this" to "us".
- (pthread_create): cancelstate and canceltype are not attributes
- so the copy to thread entry attribute storage was removed.
- Only the thread itself can change it's cancelstate or canceltype,
- ie. the thread must exist already.
-
- * private.c (ptw32_delete_thread_entry): Mutex locks removed.
- Mutexes must be applied at the caller level.
- (ptw32_new_thread_entry): Ditto.
- (ptw32_new_thread_entry): Init cancelstate, canceltype, and
- cancel_pending to default values.
- (ptw32_new_thread_entry): Rename "this" to "new".
- (ptw32_find_thread_entry): Rename "this" to "entry".
- (ptw32_delete_thread_entry): Rename "thread_entry" to "entry".
-
- * create.c (ptw32_start_call): Mutexes changed to
- ptw32_count_mutex. All access to the threads table entries is
- under the one mutex. Otherwise chaos reigns.
-
-Sat Jul 25 23:16:51 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h (ptw32_threads_thread): Move cancelstate and
- canceltype members out of pthread_attr_t into here.
-
- * fork.c (fork): Add comment.
-
-1998-07-25 Ben Elliston <bje@cygnus.com>
-
- * fork.c (fork): Autoconfiscate.
-
-Sat Jul 25 00:00:13 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * create.c (ptw32_start_call): Set thread priority. Ensure our
- thread entry is removed from the thread table but only if
- pthread_detach() was called and there are no waiting joins.
- (pthread_create): Set detach flag in thread entry if the
- thread is created PTHREAD_CREATE_DETACHED.
-
- * pthread.h (pthread_attr_t): Rename member "detachedstate".
-
- * attr.c (pthread_attr_init): Rename attr members.
-
- * exit.c (pthread_exit): Fix indirection mistake.
-
- * implement.h (PTW32_THREADS_TABLE_INDEX): Add.
-
- * exit.c (ptw32_vacuum): Fix incorrect args to
- ptw32_handler_pop_all() calls.
- Make thread entry removal conditional.
-
- * sync.c (pthread_join): Add multiple join and async detach handling.
-
- * implement.h (PTW32_THREADS_TABLE_INDEX): Add.
-
- * global.c (ptw32_threads_mutex_table): Add.
-
- * implement.h (ptw32_once_flag): Remove.
- (ptw32_once_lock): Ditto.
- (ptw32_threads_mutex_table): Add.
-
- * global.c (ptw32_once_flag): Remove.
- (ptw32_once_lock): Ditto.
-
- * sync.c (pthread_join): Fix tests involving new return value
- from ptw32_find_thread_entry().
- (pthread_detach): Ditto.
-
- * private.c (ptw32_find_thread_entry): Failure return code
- changed from -1 to NULL.
-
-Fri Jul 24 23:09:33 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * create.c (pthread_create): Change . to -> in sigmask memcpy() args.
-
- * pthread.h: (pthread_cancel): Add function prototype.
- (pthread_testcancel): Ditto.
-
-1998-07-24 Ben Elliston <bje@cygnus.com>
-
- * pthread.h (pthread_condattr_t): Rename dummy structure member.
- (pthread_mutexattr_t): Likewise.
-
-Fri Jul 24 21:13:55 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * cancel.c (pthread_cancel): Implement.
- (pthread_testcancel): Implement.
-
- * exit.c (pthread_exit): Add comment explaining the longjmp().
-
- * implement.h (ptw32_threads_thread_t): New member cancelthread.
- (PTW32_YES): Define.
- (PTW32_NO): Define.
- (RND_SIZEOF): Remove.
-
- * create.c (pthread_create): Rename cancelability to cancelstate.
-
- * pthread.h (pthread_attr_t): Rename cancelability to cancelstate.
- (PTHREAD_CANCELED): Define.
-
-1998-07-24 Ben Elliston <bje@cygnus.com>
-
- * pthread.h (SIG_BLOCK): Define if not already defined.
- (SIG_UNBLOCK): Likewise.
- (SIG_SETMASK): Likewise.
- (pthread_attr_t): Add signal mask member.
- (pthread_sigmask): Add function prototype.
-
- * signal.c (pthread_sigmask): Implement.
-
- * create.c: #include <string.h> to get a prototype for memcpy().
- (pthread_create): New threads inherit their creator's signal
- mask. Copy the signal mask to the new thread structure if we know
- about signals.
-
-Fri Jul 24 16:33:17 1998 Ross Johnson <rpj@swan.canberra.edu.au>
-
- * fork.c (pthread_atfork): Add all the necessary push calls.
- Local implementation semantics:
- If we get an ENOMEM at any time then ALL handlers
- (including those from previous pthread_atfork() calls) will be
- popped off each of the three atfork stacks before we return.
- (fork): Add all the necessary pop calls. Add the thread cancellation
- and join calls to the child fork.
- Add #includes.
-
- * implement.h: (ptw32_handler_push): Fix return type and stack arg
- type in prototype.
- (ptw32_handler_pop): Fix stack arg type in prototype.
- (ptw32_handler_pop_all): Fix stack arg type in prototype.
-
- * cleanup.c (ptw32_handler_push): Change return type to int and
- return ENOMEM if malloc() fails.
-
- * sync.c (pthread_detach): Use equality test, not assignment.
-
- * create.c (ptw32_start_call): Add call to Win32 CloseHandle()
- if thread is detached.
-
-1998-07-24 Ben Elliston <bje@cygnus.com>
-
- * sync.c (pthread_detach): Close the Win32 thread handle to
- emulate detached (or daemon) threads.
-
-Fri Jul 24 03:00:25 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * sync.c (pthread_join): Save valueptr arg in joinvalueptr for
- pthread_exit() to use.
-
- * private.c (ptw32_new_thread_entry): Initialise joinvalueptr to
- NULL.
-
- * create.c (ptw32_start_call): Rewrite to facilitate joins.
- pthread_exit() will do a longjmp() back to here. Does appropriate
- cleanup and exit/return from the thread.
- (pthread_create): _beginthreadex() now passes a pointer to our
- thread table entry instead of just the call member of that entry.
-
- * implement.h (ptw32_threads_thread): New member
- void ** joinvalueptr.
- (ptw32_call_t): New member jmpbuf env.
-
- * exit.c (pthread_exit): Major rewrite to handle joins and handing
- value pointer to joining thread. Uses longjmp() back to
- ptw32_start_call().
-
- * create.c (pthread_create): Ensure values of new attribute members
- are copied to the thread attribute object.
-
- * attr.c (pthread_attr_destroy): Fix merge conflicts.
- (pthread_attr_getdetachstate): Fix merge conflicts.
- (pthread_attr_setdetachstate): Fix merge conflicts.
-
- * pthread.h: Fix merge conflicts.
-
- * sync.c (pthread_join): Fix merge conflicts.
-
-Fri Jul 24 00:21:21 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * sync.c (pthread_join): Add check for valid and joinable
- thread.
- (pthread_detach): Implement. After checking for a valid and joinable
- thread, it's still a no-op.
-
- * private.c (ptw32_find_thread_entry): Bug prevented returning
- an error value in some cases.
-
- * attr.c (pthread_attr_setdetachedstate): Implement.
- (pthread_attr_getdetachedstate): Implement.
-
- * implement.h: Move more hidden definitions into here from
- pthread.h.
-
-1998-07-24 Ben Elliston <bje@cygnus.com>
-
- * pthread.h (PTHREAD_CREATE_JOINABLE): Define.
- (PTHREAD_CREATE_DETACHED): Likewise.
- (pthread_attr_t): Add new structure member `detached'.
- (pthread_attr_getdetachstate): Add function prototype.
- (pthread_attr_setdetachstate): Likewise.
-
- * sync.c (pthread_join): Return if the target thread is detached.
-
- * attr.c (pthread_attr_init): Initialise cancelability and
- canceltype structure members.
- (pthread_attr_getdetachstate): Implement.
- (pthread_attr_setdetachstate): Likewise.
-
- * implement.h (PTW32_CANCEL_DEFAULTS): Remove. Bit fields
- proved to be too cumbersome. Set the defaults in attr.c using the
- public PTHREAD_CANCEL_* constants.
-
- * cancel.c: New file.
-
- * pthread.h (sched_param): Define this type.
- (pthread_attr_getschedparam): Add function prototype.
- (pthread_attr_setschedparam): Likewise.
- (pthread_setcancelstate): Likewise.
- (pthread_setcanceltype): Likewise.
- (sched_get_priority_min): Likewise.
- (sched_get_priority_max): Likewise.
- (pthread_mutexattr_setprotocol): Remove; not supported.
- (pthread_mutexattr_getprotocol): Likewise.
- (pthread_mutexattr_setprioceiling): Likewise.
- (pthread_mutexattr_getprioceiling): Likewise.
- (pthread_attr_t): Add canceltype member. Update comments.
- (SCHED_OTHER): Define this scheduling policy constant.
- (SCHED_FIFO): Likewise.
- (SCHED_RR): Likewise.
- (SCHED_MIN): Define the lowest possible value for this constant.
- (SCHED_MAX): Likewise, the maximum possible value.
- (PTHREAD_CANCEL_ASYNCHRONOUS): Redefine.
- (PTHREAD_CANCEL_DEFERRED): Likewise.
-
- * sched.c: New file.
- (pthread_setschedparam): Implement.
- (pthread_getschedparam): Implement.
- (sched_get_priority_max): Validate policy argument.
- (sched_get_priority_min): Likewise.
-
- * mutex.c (pthread_mutexattr_setprotocol): Remove; not supported.
- (pthread_mutexattr_getprotocol): Likewise.
- (pthread_mutexattr_setprioceiling): Likewise.
- (pthread_mutexattr_getprioceiling): Likewise.
-
-Fri Jul 24 00:21:21 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * create.c (pthread_create): Arg to ptw32_new_thread_entry()
- changed. See next entry. Move mutex locks out. Changes made yesterday
- and today allow us to start the new thread running rather than
- temporarily suspended.
-
- * private.c (ptw32_new_thread_entry): ptw32_thread_table
- was changed back to a table of thread structures rather than pointers.
- As such we're trading storage for increaded speed. This routine
- was modified to work with the new table. Mutex lock put in around
- global data accesses.
- (ptw32_find_thread_entry): Ditto
- (ptw32_delete_thread_entry): Ditto
-
-Thu Jul 23 23:25:30 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * global.c: New. Global data objects declared here. These moved from
- pthread.h.
-
- * pthread.h: Move implementation hidden definitions into
- implement.h.
-
- * implement.h: Move implementation hidden definitions from
- pthread.h. Add constants to index into the different handler stacks.
-
- * cleanup.c (ptw32_handler_push): Simplify args. Restructure.
- (ptw32_handler_pop): Simplify args. Restructure.
- (ptw32_handler_pop_all): Simplify args. Restructure.
-
-Wed Jul 22 00:16:22 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * attr.c, implement.h, pthread.h, ChangeLog: Resolve CVS merge
- conflicts.
-
- * private.c (ptw32_find_thread_entry): Changes to return type
- to support leaner ptw32_threads_table[] which now only stores
- ptw32_thread_thread_t *.
- (ptw32_new_thread_entry): Internal changes.
- (ptw32_delete_thread_entry): Internal changes to avoid contention.
- Calling routines changed accordingly.
-
- * pthread.h: Modified cleanup macros to use new generic push and pop.
- Added destructor and atfork stacks to ptw32_threads_thread_t.
-
- * cleanup.c (ptw32_handler_push, ptw32_handler_pop,
- ptw32_handler_pop_all): Renamed cleanup push and pop routines
- and made generic to handle destructors and atfork handlers as
- well.
-
- * create.c (ptw32_start_call): New function is a wrapper for
- all new threads. It allows us to do some cleanup when the thread
- returns, ie. that is otherwise only done if the thread is cancelled.
-
- * exit.c (ptw32_vacuum): New function contains code from
- pthread_exit() that we need in the new ptw32_start_call()
- as well.
-
- * implement.h: Various additions and minor changes.
-
- * pthread.h: Various additions and minor changes.
- Change cleanup handler macros to use generic handler push and pop
- functions.
-
- * attr.c: Minor mods to all functions.
- (is_attr): Implemented missing function.
-
- * create.c (pthread_create): More clean up.
-
- * private.c (ptw32_find_thread_entry): Implement.
- (ptw32_delete_thread_entry): Implement.
- (ptw32_new_thread_entry): Implement.
- These functions manipulate the implementations internal thread
- table and are part of general code cleanup and modularisation.
- They replace ptw32_getthreadindex() which was removed.
-
- * exit.c (pthread_exit): Changed to use the new code above.
-
- * pthread.h: Add cancelability constants. Update comments.
-
-1998-07-22 Ben Elliston <bje@cygnus.com>
-
- * attr.c (pthread_setstacksize): Update test of attr argument.
- (pthread_getstacksize): Likewise.
- (pthread_setstackaddr): Likewise.
- (pthread_getstackaddr): Likewise.
- (pthread_attr_init): No need to allocate any storage.
- (pthread_attr_destroy): No need to free any storage.
-
- * mutex.c (is_attr): Not likely to be needed; remove.
- (remove_attr): Likewise.
- (insert_attr): Likewise.
-
- * implement.h (ptw32_mutexattr_t): Moved to a public definition
- in pthread.h. There was little gain in hiding these details.
- (ptw32_condattr_t): Likewise.
- (ptw32_attr_t): Likewise.
-
- * pthread.h (pthread_atfork): Add function prototype.
- (pthread_attr_t): Moved here from implement.h.
-
- * fork.c (pthread_atfork): Preliminary implementation.
- (ptw32_fork): Likewise.
-
-Wed Jul 22 00:16:22 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * cleanup.c (ptw32_cleanup_push): Implement.
- (ptw32_cleanup_pop): Implement.
- (ptw32_do_cancellation): Implement.
- These are private to the implementation. The real cleanup functions
- are macros. See below.
-
- * pthread.h (pthread_cleanup_push): Implement as a macro.
- (pthread_cleanup_pop): Implement as a macro.
- Because these are macros which start and end a block, the POSIX scoping
- requirement is observed. See the comment in the file.
-
- * exit.c (pthread_exit): Refine the code.
-
- * create.c (pthread_create): Code cleanup.
-
- * implement.h (RND_SIZEOF): Add RND_SIZEOF(T) to round sizeof(T)
- up to multiple of DWORD.
- Add function prototypes.
-
- * private.c (ptw32_getthreadindex): "*thread" should have been
- "thread". Detect empty slot fail condition.
-
-1998-07-20 Ben Elliston <bje@cygnus.com>
-
- * misc.c (pthread_once): Implement. Don't use a per-application
- flag and mutex--make `pthread_once_t' contain these elements in
- their structure. The earlier version had incorrect semantics.
-
- * pthread.h (ptw32_once_flag): Add new variable. Remove.
- (ptw32_once_lock): Add new mutex lock to ensure integrity of
- access to ptw32_once_flag. Remove.
- (pthread_once): Add function prototype.
- (pthread_once_t): Define this type.
-
-Mon Jul 20 02:31:05 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * private.c (ptw32_getthreadindex): Implement.
-
- * pthread.h: Add application static data dependent on
- _PTHREADS_BUILD_DLL define. This is needed to avoid allocating
- non-sharable static data within the pthread DLL.
-
- * implement.h: Add ptw32_cleanup_stack_t, ptw32_cleanup_node_t
- and PTW32_HASH_INDEX.
-
- * exit.c (pthread_exit): Begin work on cleanup and de-allocate
- thread-private storage.
-
- * create.c (pthread_create): Add thread to thread table.
- Keep a thread-private copy of the attributes with default values
- filled in when necessary. Same for the cleanup stack. Make
- pthread_create C run-time library friendly by using _beginthreadex()
- instead of CreateThread(). Fix error returns.
-
-Sun Jul 19 16:26:23 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h: Rename pthreads_thread_count to ptw32_threads_count.
- Create ptw32_threads_thread_t struct to keep thread specific data.
-
- * create.c: Rename pthreads_thread_count to ptw32_threads_count.
- (pthread_create): Handle errors from CreateThread().
-
-1998-07-19 Ben Elliston <bje@cygnus.com>
-
- * condvar.c (pthread_cond_wait): Generalise. Moved from here ..
- (cond_wait): To here.
- (pthread_cond_timedwait): Implement; use generalised cond_wait().
-
- * pthread.h (pthread_key_t): Define this type.
- (pthread_key_create): Add function prototype.
- (pthread_setspecific): Likewise.
- (pthread_getspecific): Likwise.
- (pthread_key_delete): Likewise.
-
- * tsd.c (pthread_key_create): Implement.
- (pthread_setspecific): Likewise.
- (pthread_getspecific): Likewise.
- (pthread_key_delete): Likewise.
-
- * mutex.c (pthread_mutex_trylock): Return ENOSYS if this function
- is called on a Win32 platform which is not Windows NT.
-
-1998-07-18 Ben Elliston <bje@cygnus.com>
-
- * condvar.c (pthread_condattr_init): Do not attempt to malloc any
- storage; none is needed now that condattr_t is an empty struct.
- (pthread_condattr_destory): Likewise; do not free storage.
- (pthread_condattr_setpshared): No longer supported; return ENOSYS.
- (pthread_condattr_getpshared): Likewise.
- (pthread_cond_init): Implement with help from Douglas Schmidt.
- Remember to initialise the cv's internal mutex.
- (pthread_cond_wait): Likewise.
- (pthread_cond_signal): Likewise.
- (pthread_cond_broadcast): Likewise.
- (pthread_cond_timedwait): Preliminary implementation, but I need
- to see some API documentation for `WaitForMultipleObject'.
- (pthread_destory): Implement.
-
- * pthread.h (pthread_cond_init): Add function protoype.
- (pthread_cond_broadcast): Likewise.
- (pthread_cond_signal): Likewise.
- (pthread_cond_timedwait): Likewise.
- (pthread_cond_wait): Likewise.
- (pthread_cond_destroy): Likewise.
- (pthread_cond_t): Define this type. Fix for u_int. Do not assume
- that the mutex contained withing the pthread_cond_t structure will
- be a critical section. Use our new POSIX type!
-
- * implement.h (ptw32_condattr_t): Remove shared attribute.
-
-1998-07-17 Ben Elliston <bje@cygnus.com>
-
- * pthread.h (PTHREADS_PROCESS_PRIVATE): Remove.
- (PTHREAD_PROCESS_SHARED): Likewise. No support for mutexes shared
- across processes for now.
- (pthread_mutex_t): Use a Win32 CRITICAL_SECTION type for better
- performance.
-
- * implement.h (ptw32_mutexattr_t): Remove shared attribute.
-
- * mutex.c (pthread_mutexattr_setpshared): This optional function
- is no longer supported, since we want to implement POSIX mutex
- variables using the much more efficient Win32 critical section
- primitives. Critical section objects in Win32 cannot be shared
- between processes.
- (pthread_mutexattr_getpshared): Likewise.
- (pthread_mutexattr_init): No need to malloc any storage; the
- attributes structure is now empty.
- (pthread_mutexattr_destroy): This is now a nop.
- (pthread_mutex_init): Use InitializeCriticalSection().
- (pthread_mutex_destroy): Use DeleteCriticalSection().
- (pthread_mutex_lock): Use EnterCriticalSection().
- (pthread_mutex_trylock): Use TryEnterCriticalSection(). This is
- not supported by Windows 9x, but trylock is a hack anyway, IMHO.
- (pthread_mutex_unlock): Use LeaveCriticalSection().
-
-1998-07-14 Ben Elliston <bje@cygnus.com>
-
- * attr.c (pthread_attr_setstacksize): Implement.
- (pthread_attr_getstacksize): Likewise.
- (pthread_attr_setstackaddr): Likewise.
- (pthread_attr_getstackaddr): Likewise.
- (pthread_attr_init): Likewise.
- (pthread_attr_destroy): Likewise.
-
- * condvar.c (pthread_condattr_init): Add `_cond' to function name.
-
- * mutex.c (pthread_mutex_lock): Add `_mutex' to function name.
- (pthread_mutex_trylock): Likewise.
- (pthread_mutex_unlock): Likewise.
-
- * pthread.h (pthread_condattr_setpshared): Fix typo.
- (pthread_attr_init): Add function prototype.
- (pthread_attr_destroy): Likewise.
- (pthread_attr_setstacksize): Likewise.
- (pthread_attr_getstacksize): Likewise.
- (pthread_attr_setstackaddr): Likewise.
- (pthread_attr_getstackaddr): Likewise.
-
-Mon Jul 13 01:09:55 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h: Wrap in #ifndef _IMPLEMENT_H
-
- * create.c (pthread_create): Map stacksize attr to Win32.
-
- * mutex.c: Include implement.h
-
-1998-07-13 Ben Elliston <bje@cygnus.com>
-
- * condvar.c (pthread_condattr_init): Implement.
- (pthread_condattr_destroy): Likewise.
- (pthread_condattr_setpshared): Likewise.
- (pthread_condattr_getpshared): Likewise.
-
- * implement.h (PTHREAD_THREADS_MAX): Remove trailing semicolon.
- (PTHREAD_STACK_MIN): Specify; needs confirming.
- (ptw32_attr_t): Define this type.
- (ptw32_condattr_t): Likewise.
-
- * pthread.h (pthread_mutex_t): Define this type.
- (pthread_condattr_t): Likewise.
- (pthread_mutex_destroy): Add function prototype.
- (pthread_lock): Likewise.
- (pthread_trylock): Likewise.
- (pthread_unlock): Likewise.
- (pthread_condattr_init): Likewise.
- (pthread_condattr_destroy): Likewise.
- (pthread_condattr_setpshared): Likewise.
- (pthread_condattr_getpshared): Likewise.
-
- * mutex.c (pthread_mutex_init): Implement.
- (pthread_mutex_destroy): Likewise.
- (pthread_lock): Likewise.
- (pthread_trylock): Likewise.
- (pthread_unlock): Likewise.
-
-1998-07-12 Ben Elliston <bje@cygnus.com>
-
- * implement.h (ptw32_mutexattr_t): Define this implementation
- internal type. Application programmers only see a mutex attribute
- object as a void pointer.
-
- * pthread.h (pthread_mutexattr_t): Define this type.
- (pthread_mutexattr_init): Add function prototype.
- (pthread_mutexattr_destroy): Likewise.
- (pthread_mutexattr_setpshared): Likewise.
- (pthread_mutexattr_getpshared): Likewise.
- (pthread_mutexattr_setprotocol): Likewise.
- (pthread_mutexattr_getprotocol): Likewise.
- (pthread_mutexattr_setprioceiling): Likewise.
- (pthread_mutexattr_getprioceiling): Likewise.
- (PTHREAD_PROCESS_PRIVATE): Define.
- (PTHREAD_PROCESS_SHARED): Define.
-
- * mutex.c (pthread_mutexattr_init): Implement.
- (pthread_mutexattr_destroy): Implement.
- (pthread_mutexattr_setprotocol): Implement.
- (pthread_mutexattr_getprotocol): Likewise.
- (pthread_mutexattr_setprioceiling): Likewise.
- (pthread_mutexattr_getprioceiling): Likewise.
- (pthread_mutexattr_setpshared): Likewise.
- (pthread_mutexattr_getpshared): Likewise.
- (insert_attr): New function; very preliminary implementation!
- (is_attr): Likewise.
- (remove_attr): Likewise.
-
-Sat Jul 11 14:48:54 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
-
- * implement.h: Preliminary implementation specific defines.
-
- * create.c (pthread_create): Preliminary implementation.
-
-1998-07-11 Ben Elliston <bje@cygnus.com>
-
- * sync.c (pthread_join): Implement.
-
- * misc.c (pthread_equal): Likewise.
-
- * pthread.h (pthread_join): Add function prototype.
- (pthread_equal): Likewise.
-
-1998-07-10 Ben Elliston <bje@cygnus.com>
-
- * misc.c (pthread_self): Implement.
-
- * exit.c (pthread_exit): Implement.
-
- * pthread.h (pthread_exit): Add function prototype.
- (pthread_self): Likewise.
- (pthread_t): Define this type.
-
-1998-07-09 Ben Elliston <bje@cygnus.com>
-
- * create.c (pthread_create): A dummy stub right now.
-
- * pthread.h (pthread_create): Add function prototype.
+2002-02-10 Ross Johnson <rpj@setup1.ise.canberra.edu.au
+
+ Reduce executable size.
+ -----------------------
+ When linking with the static library, only those
+ routines actually called, either directly or indirectly
+ should be included.
+
+ [Gcc has the -ffunction-segments option to do this but MSVC
+ doesn't have this feature as far as I can determine. Other
+ compilers are undetermined as well. - rpj]
+
+ * nonportable.c: Split file into function segments.
+ * np_delay.c: Separated routine from nonportable.c
+ * np_getw32threadhandle.c: Likewise.
+ * np_mutexattr_setkind.c: Likewise.
+ * np_num_processors.c: Likewise.
+ * np_win32_attach.c: Likewise.
+ * misc.c: Split file into function segments.
+ * pthread_equal.c: Separated routine from nonportable.c.
+ * pthread_getconcurrency.c: Likewise.
+ * pthread_once.c: Likewise.
+ * pthread_self.c: Likewise.
+ * pthread_setconcurrency.c: Likewise.
+ * ptw32_calloc.c: Likewise.
+ * ptw32_new.c: Likewise.
+ * w32_CancelableWait.c: Likewise.
+
+2002-02-09 Ross Johnson <rpj@setup1.ise.canberra.edu.au
+
+ Reduce executable size.
+ -----------------------
+ When linking with the static library, only those
+ routines actually called, either directly or indirectly
+ should be included.
+
+ [Gcc has the -ffunction-segments option to do this but MSVC
+ doesn't have this feature as far as I can determine. Other
+ compilers are undetermined as well. - rpj]
+
+ * condvar.c: Split file into function segments.
+ * condvar_attr_destroy.c: Separated routine from condvar.c.
+ * condvar_attr_getpshared.c: Likewise.
+ * condvar_attr_init.c: Likewise.
+ * condvar_attr_setpshared.c: Likewise.
+ * condvar_check_need_init.c: Likewise.
+ * condvar_destroy.c: Likewise.
+ * condvar_init.c: Likewise.
+ * condvar_signal.c: Likewise.
+ * condvar_wait.c: Likewise.
+
+2002-02-07 Alexander Terekhov<TEREKHOV@de.ibm.com>
+
+ * nonportable.c (pthread_delay_np): Make a true
+ cancelation point. Deferred cancels will interrupt the
+ wait.
+
+2002-02-07 Ross Johnson <rpj@setup1.ise.canberra.edu.au
+
+ * misc.c (ptw32_new): Add creation of cancelEvent so that
+ implicit POSIX threads (Win32 threads with a POSIX face)
+ are cancelable; mainly so that pthread_delay_np doesn't fail
+ if called from the main thread.
+ * create.c (pthread_create): Remove creation of cancelEvent
+ from here; now in ptw32_new().
+
+ Reduce executable size.
+ -----------------------
+ When linking with the static library, only those
+ routines actually called, either directly or indirectly
+ should be included.
+
+ [Gcc has the -ffunction-segments option to do this but MSVC
+ doesn't have this feature as far as I can determine. Other
+ compilers are undetermined as well. - rpj]
+
+ * barrier.c: All routines are now in separate compilation units;
+ This file is used to congregate the separate modules for
+ potential inline optimisation and backward build compatibility.
+ * cancel.c: Likewise.
+ * barrier_attr_destroy.c: Separated routine from cancel.c.
+ * barrier_attr_getpshared.c: Likewise.
+ * barrier_attr_init.c: Likewise.
+ * barrier_attr_setpshared.c: Likewise.
+ * barrier_destroy.c: Likewise.
+ * barrier_init.c: Likewise.
+ * barrier_wait.c: Likewise.
+ * cancel_cancel.c: Likewise.
+ * cancel_setcancelstate.c: Likewise.
+ * cancel_setcanceltype.c: Likewise.
+ * cancel_testcancel.c: Likewise.
+
+2002-02-04 Max Woodbury <mtew@cds.duke.edu>
+
+ Reduced name space pollution.
+ -----------------------------
+ When the appropriate symbols are defined, the headers
+ will restrict the definitions of new names. In particular,
+ it must be possible to NOT include the <windows.h>
+ header and related definitions with some combination
+ of symbol definitions. Secondly, it should be possible
+ that additional definitions should be limited to POSIX
+ compliant symbols by the definition of appropriate symbols.
+
+ * pthread.h: POSIX conditionals.
+ * sched.h: POSIX conditionals.
+ * semaphore.h: POSIX conditionals.
+
+ * semaphore.c: Included <limits.h>.
+ (sem_init): Changed magic 0x7FFFFFFFL to INT_MAX.
+ (sem_getvalue): Trial version.
+
+ Reduce executable size.
+ -----------------------
+ When linking with the static library, only those
+ routines actually called, either directly or indirectly
+ should be included.
+
+ [Gcc has the -ffunction-segments option to do this but MSVC
+ doesn't have this feature as far as I can determine. Other
+ compilers are undetermined as well. - rpj]
+
+ * semaphore.c: All routines are now in separate compilation units;
+ This file is used to congregate the separate modules for
+ potential inline optimisation and backward build compatibility.
+ * semaphore_close.c: Separated routine from semaphore.c.
+ * semaphore_decrease.c: Likewise.
+ * semaphore_destroy.c: Likewise.
+ * semaphore_getvalue.c: Likewise.
+ * semaphore_increase.c: Likewise.
+ * semaphore_init.c: Likewise.
+ * semaphore_open.c: Likewise.
+ * semaphore_post.c: Likewise.
+ * semaphore_postmultiple.c: Likewise.
+ * semaphore_timedwait.c: Likewise.
+ * semaphore_trywait.c: Likewise.
+ * semaphore_unlink.c: Likewise.
+ * semaphore_wait.c: Likewise.
+
+2002-02-04 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ The following extends the idea above to the rest of pthreads-win32 - rpj
+
+ * attr.c: All routines are now in separate compilation units;
+ This file is used to congregate the separate modules for
+ potential inline optimisation and backward build compatibility.
+ * attr_destroy.c: Separated routine from attr.c.
+ * attr_getdetachstate.c: Likewise.
+ * attr_getscope.c: Likewise.
+ * attr_getstackaddr.c: Likewise.
+ * attr_getstacksize.c: Likewise.
+ * attr_init.c: Likewise.
+ * attr_is_attr.c: Likewise.
+ * attr_setdetachstate.c: Likewise.
+ * attr_setscope.c: Likewise.
+ * attr_setstackaddr.c: Likewise.
+ * attr_setstacksize.c: Likewise.
+
+ * pthread.c: Agregation of agregate modules for super-inlineability.
+
+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
+ for systems that define NEED_SEM (e.g. early WinCE).
+ * mutex.c (pthread_mutex_timedlock): Return ENOTSUP
+ for systems that define NEED_SEM since they don't
+ have sem_trywait().
+
+2002-01-27 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * mutex.c (pthread_mutex_timedlock): New function suggested by
+ Alexander Terekhov. The logic required to implement this
+ properly came from Alexander, with some collaboration
+ with Thomas Pfaff.
+ (pthread_mutex_unlock): Wrap the waiters check and sema
+ post in a critical section to prevent a race with
+ pthread_mutex_timedlock.
+ (ptw32_timed_semwait): New function;
+ returns a special result if the absolute timeout parameter
+ represents a time already passed when called; used by
+ pthread_mutex_timedwait(). Have deliberately not reused
+ the name "ptw32_sem_timedwait" because they are not the same
+ routine.
+ * condvar.c (ptw32_cond_timedwait): Use the new sem_timedwait()
+ instead of ptw32_sem_timedwait(), which now has a different
+ function. See previous.
+ * implement.h: Remove prototype for ptw32_sem_timedwait.
+ See next.
+ (pthread_mutex_t_): Add critical section element for access
+ to lock_idx during mutex post-timeout processing.
+ * semaphore.h (sem_timedwait): See next.
+ * semaphore.c (sem_timedwait): See next.
+ * private.c (ptw32_sem_timedwait): Move to semaphore.c
+ and rename as sem_timedwait().
+
+2002-01-18 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * sync.c (pthread_join): Was getting the exit code from the
+ calling thread rather than the joined thread if
+ defined(__MINGW32__) && !defined(__MSVCRT__).
+
+2002-01-15 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * pthread.h: Unless the build explicitly defines __CLEANUP_SEH,
+ __CLEANUP_CXX, or __CLEANUP_C, then the build defaults to
+ __CLEANUP_C style cleanup. This style uses setjmp/longjmp
+ in the cancelation and thread exit implementations and therefore
+ won't do stack unwinding if linked to applications that have it
+ (e.g. C++ apps). This is currently consistent with most/all
+ commercial Unix POSIX threads implementations.
+
+ * spin.c (pthread_spin_init): Edit renamed function call.
+ * nonportable.c (pthread_num_processors_np): New.
+ (pthread_getprocessors_np): Renamed to ptw32_getprocessors
+ and moved to private.c.
+ * private.c (pthread_getprocessors): Moved here from
+ nonportable.c.
+ * pthread.def (pthread_getprocessors_np): Removed
+ from export list.
+
+ * rwlock.c (pthread_rwlockattr_init): New.
+ (pthread_rwlockattr_destroy): New.
+ (pthread_rwlockattr_getpshared): New.
+ (pthread_rwlockattr_setpshared): New.
+
+2002-01-14 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * attr.c (pthread_attr_setscope): Fix struct pointer
+ indirection error introduced 2002-01-04.
+ (pthread_attr_getscope): Likewise.
+
+2002-01-12 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * pthread.dsp (SOURCE): Add missing source files.
+
+2002-01-08 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * mutex.c (pthread_mutex_trylock): use
+ ptw32_interlocked_compare_exchange function pointer
+ rather than ptw32_InterlockedCompareExchange() directly
+ to retain portability to non-iX86 processors,
+ e.g. WinCE etc. The pointer will point to the native
+ OS version of InterlockedCompareExchange() if the
+ OS supports it (see ChangeLog entry of 2001-10-17).
+
+2002-01-07 Thomas Pfaff <tpfaff@gmx.net>, Alexander Terekhov <TEREKHOV@de.ibm.com>
+
+ * mutex.c (pthread_mutex_init): Remove critical
+ section calls.
+ (pthread_mutex_destroy): Likewise.
+ (pthread_mutex_unlock): Likewise.
+ (pthread_mutex_trylock): Likewise; uses
+ ptw32_InterlockedCompareExchange() to avoid need for
+ critical section; library is no longer i386 compatible;
+ recursive mutexes now increment the lock count rather
+ than return EBUSY; errorcheck mutexes return EDEADLCK
+ rather than EBUSY. This behaviour is consistent with the
+ Solaris pthreads implementation.
+ * implement.h (pthread_mutex_t_): Remove critical
+ section element - no longer needed.
+
+
+2002-01-04 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * attr.c (pthread_attr_setscope): Add more error
+ checking and actually store the scope value even
+ though it's not really necessary.
+ (pthread_attr_getscope): Return stored value.
+ * implement.h (pthread_attr_t_): Add new scope element.
+ * ANNOUNCE: Fix out of date comment next to
+ pthread_attr_setscope in conformance section.
+
+2001-12-21 Alexander Terekhov <TEREKHOV@de.ibm.com>
+
+ * mutex.c (pthread_mutex_lock): Decrementing lock_idx was
+ not thread-safe.
+ (pthread_mutex_trylock): Likewise.
+
+2001-10-26 prionx@juno.com
+
+ * semaphore.c (sem_init): Fix typo and missing bracket
+ in conditionally compiled code. Only older versions of
+ WinCE require this code, hence it doesn't normally get
+ tested; somehow when sem_t reverted to an opaque struct
+ the calloc NULL check was left in the conditionally included
+ section.
+ (sem_destroy): Likewise, the calloced sem_t wasn't being freed.
+
+2001-10-25 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * GNUmakefile (libwsock32): Add to linker flags for
+ WSAGetLastError() and WSASetLastError().
+ * Makefile (wsock32.lib): Likewise.
+ * create.c: Minor mostly inert changes.
+ * implement.h (PTW32_MAX): Move into here and renamed
+ from sched.h.
+ (PTW32_MIN): Likewise.
+ * GNUmakefile (TEST_ICE): Define if testing internal
+ implementation of InterlockedCompareExchange.
+ * Makefile (TEST_ICE): Likewise.
+ * private.c (TEST_ICE): Likewise.
+
+2001-10-24 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * attr.c (pthread_attr_setstacksize): Quell warning
+ from LCC by conditionally compiling the stacksize
+ validity check. LCC correctly warns that the condition
+ (stacksize < PTHREAD_STACK_MIN) is suspicious
+ because STACK_MIN is 0 and stacksize is of type
+ size_t (or unsigned int).
+
+2001-10-17 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * barrier.c: Move _LONG and _LPLONG defines into
+ implement.h; rename to PTW32_INTERLOCKED_LONG and
+ PTW32_INTERLOCKED_LPLONG respectively.
+ * spin.c: Likewise; ptw32_interlocked_compare_exchange used
+ in place of InterlockedCompareExchange directly.
+ * global.c (ptw32_interlocked_compare_exchange): Add
+ prototype for this new routine pointer to be used when
+ InterlockedCompareExchange isn't supported by Windows.
+ * nonportable.c (pthread_win32_process_attach_np): Check for
+ support of InterlockedCompareExchange in kernel32 and assign its
+ address to ptw32_interlocked_compare_exchange if it exists, or
+ our own ix86 specific implementation ptw32_InterlockedCompareExchange.
+ *private.c (ptw32_InterlockedCompareExchange): An
+ implementation of InterlockedCompareExchange() which is
+ specific to ix86; written directly in assembler for either
+ MSVC or GNU C; needed because Windows 95 doesn't support
+ InterlockedCompareExchange().
+
+ * sched.c (sched_get_priority_min): Extend to return
+ THREAD_PRIORITY_IDLE.
+ (sched_get_priority_max): Extend to return
+ THREAD_PRIORITY_CRITICAL.
+
+2001-10-15 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * spin.c (pthread_spin_lock): PTHREAD_SPINLOCK_INITIALIZER
+ was causing a program fault.
+ (pthread_spin_init): Could have alloced memory
+ without freeing under some error conditions.
+
+ * mutex.c (pthread_mutex_init): Move memory
+ allocation of mutex struct after checking for
+ PROCESS_SHARED.
+
+2001-10-12 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * spin.c (pthread_spin_unlock): Was not returning
+ EPERM if the spinlock was not locked, for multi CPU
+ machines.
+
+2001-10-08 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * spin.c (pthread_spin_trylock): Was not returning
+ EBUSY for multi CPU machines.
+
+2001-08-24 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * condvar.c (pthread_cond_destroy): Remove cv element
+ that is no longer used.
+ * implement.h: Likewise.
+
+2001-08-23 Alexander Terekhov <TEREKHOV@de.ibm.com>
+
+ * condvar.c (pthread_cond_destroy): fix bug with
+ respect to deadlock in the case of concurrent
+ _destroy/_unblock; a condition variable can be destroyed
+ immediately after all the threads that are blocked on
+ it are awakened.
+
+2001-08-23 Phil Frisbie, Jr. <phil@hawksoft.com>
+
+ * tsd.c (pthread_getspecific): Preserve the last
+ winsock error [from WSAGetLastError()].
+
+2001-07-18 Scott McCaskill <scott@magruder.org>
+
+ * mutex.c (pthread_mutexattr_init): Return ENOMEM
+ immediately and don't dereference the NULL pointer
+ if calloc fails.
+ (pthread_mutexattr_getpshared): Don't dereference
+ a pointer that is possibly NULL.
+ * barrier.c (pthread_barrierattr_init): Likewise
+ (pthread_barrierattr_getpshared): Don't dereference
+ a pointer that is possibly NULL.
+ * condvar.c (pthread_condattr_getpshared): Don't dereference
+ a pointer that is possibly NULL.
+
+2001-07-15 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * rwlock.c (pthread_rwlock_wrlock): Is allowed to be
+ a cancelation point; re-enable deferred cancelability
+ around the CV call.
+
+2001-07-10 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * barrier.c: Still more revamping. The exclusive access
+ mutex isn't really needed so it has been removed and replaced
+ by an InterlockedDecrement(). nSerial has been removed.
+ iStep is now dual-purpose. The process shared attribute
+ is now stored in the barrier struct.
+ * implement.h (pthread_barrier_t_): Lost some/gained one
+ elements.
+ * private.c (ptw32_threadStart): Removed some comments.
+
+2001-07-10 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * barrier.c: Revamped to fix the race condition. Two alternating
+ semaphores are used instead of the PulseEvent. Also improved
+ overall throughput by returning PTHREAD_BARRIER_SERIAL_THREAD
+ to the first waking thread.
+ * implement.h (pthread_barrier_t_): Revamped.
+
+2001-07-09 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * barrier.c: Fix several bugs in all routines. Now passes
+ tests/barrier5.c which is fairly rigorous. There is still
+ a non-optimal work-around for a race condition between
+ the barrier breeched event signal and event wait. Basically
+ the last (signalling) thread to hit the barrier yields
+ to allow any other threads, which may have lost the race,
+ to complete.
+
+2001-07-07 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * barrier.c: Changed synchronisation mechanism to a
+ Win32 manual reset Event and use PulseEvent to signal
+ waiting threads. If the implementation continued to use
+ a semaphore it would require a second semaphore and
+ some management to use them alternately as barriers. A
+ single semaphore allows threads to cascade from one barrier
+ through the next, leaving some threads blocked at the first.
+ * implement.h (pthread_barrier_t_): As per above.
+ * general: Made a number of other routines inlinable.
+
+2001-07-07 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * spin.c: Revamped and working; included static initialiser.
+ Now beta level.
+ * barrier.c: Likewise.
+ * condvar.c: Macro constant change; inline auto init routine.
+ * mutex.c: Likewise.
+ * rwlock.c: Likewise.
+ * private.c: Add support for spinlock initialiser.
+ * global.c: Likewise.
+ * implement.h: Likewise.
+ * pthread.h (PTHREAD_SPINLOCK_INITIALIZER): Fix typo.
+
+2001-07-05 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * barrier.c: Remove static initialisation - irrelevent
+ for this object.
+ * pthread.h (PTHREAD_BARRIER_INITIALIZER): Removed.
+ * rwlock.c (pthread_rwlock_wrlock): This routine is
+ not a cancelation point - disable deferred
+ cancelation around call to pthread_cond_wait().
+
+2001-07-05 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * spin.c: New module implementing spin locks.
+ * barrier.c: New module implementing barriers.
+ * pthread.h (_POSIX_SPIN_LOCKS): defined.
+ (_POSIX_BARRIERS): Defined.
+ (pthread_spin_*): Defined.
+ (pthread_barrier*): Defined.
+ (PTHREAD_BARRIER_SERIAL_THREAD): Defined.
+ * implement.h (pthread_spinlock_t_): Defined.
+ (pthread_barrier_t_): Defined.
+ (pthread_barrierattr_t_): Defined.
+
+ * mutex.c (pthread_mutex_lock): Return with the error
+ if an auto-initialiser initialisation fails.
+
+ * nonportable.c (pthread_getprocessors_np): New; gets the
+ number of available processors for the current process.
+
+2001-07-03 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * pthread.h (_POSIX_READER_WRITER_LOCKS): Define it
+ if not already defined.
+
+2001-07-01 Alexander Terekhov <TEREKHOV@de.ibm.com>
+
+ * condvar.c: Fixed lost signal bug reported by Timur Aydin
+ (taydin@snet.net).
+ [RPJ (me) didn't translate the original algorithm
+ correctly.]
+ * semaphore.c: Added sem_post_multiple; this is a useful
+ routine, but it doesn't appear to be standard. For now it's
+ not an exported function.
+
+2001-06-25 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * create.c (pthread_create): Add priority inheritance
+ attributes.
+ * mutex.c (pthread_mutex_lock): Remove some overhead for
+ PTHREAD_MUTEX_NORMAL mutex types. Specifically, avoid
+ calling pthread_self() and pthread_equal() to check/set
+ the mutex owner. Introduce a new pseudo owner for this
+ type. Test results suggest increases in speed of up to
+ 90% for non-blocking locks.
+ This is the default type of mutex used internally by other
+ synchronising objects, ie. condition variables and
+ read-write locks. The test rwlock7.c shows about a
+ 30-35% speed increase over snapshot 2001-06-06. The
+ price of this is that the application developer
+ must ensure correct behaviour, or explicitly set the
+ mutex to a safer type such as PTHREAD_MUTEX_ERRORCHECK.
+ For example, PTHREAD_MUTEX_NORMAL (or PTHREAD_MUTEX_DEFAULT)
+ type mutexes will not return an error if a thread which is not
+ the owner calls pthread_mutex_unlock. The call will succeed
+ in unlocking the mutex if it is currently locked, but a
+ subsequent unlock by the true owner will then fail with EPERM.
+ This is however consistent with some other implementations.
+ (pthread_mutex_unlock): Likewise.
+ (pthread_mutex_trylock): Likewise.
+ (pthread_mutex_destroy): Likewise.
+ * attr.c (pthread_attr_init): PTHREAD_EXPLICIT_SCHED is the
+ default inheritance attribute; THREAD_PRIORITY_NORMAL is
+ the default priority for new threads.
+ * sched.c (pthread_attr_setschedpolicy): Added routine.
+ (pthread_attr_getschedpolicy): Added routine.
+ (pthread_attr_setinheritsched): Added routine.
+ (pthread_attr_getinheritsched): Added routine.
+ * pthread.h (sched_rr_set_interval): Added as a macro;
+ returns -1 with errno set to ENOSYS.
+
+2001-06-23 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ *sched.c (pthread_attr_setschedparam): Add priority range
+ check.
+ (sched_setscheduler): New function; checks for a valid
+ pid and policy; checks for permission to set information
+ in the target process; expects pid to be a Win32 process ID,
+ not a process handle; the only scheduler policy allowed is
+ SCHED_OTHER.
+ (sched_getscheduler): Likewise, but checks for permission
+ to query.
+ * pthread.h (SCHED_*): Moved to sched.h as defined in the
+ POSIX standard.
+ * sched.h (SCHED_*): Moved from pthread.h.
+ (pid_t): Defined if necessary.
+ (sched_setscheduler): Defined.
+ (sched_getscheduler): Defined.
+ * pthread.def (sched_setscheduler): Exported.
+ (sched_getscheduler): Likewise.
+
+2001-06-23 Ralf Brese <Ralf.Brese@pdb4.siemens.de>
+
+ * create.c (pthread_create): Set thread priority from
+ thread attributes.
+
+2001-06-18 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * Made organisational-only changes to UWIN additions.
+ * dll.c (dllMain): Moved UWIN process attach code
+ to pthread_win32_process_attach_np(); moved
+ instance of pthread_count to global.c.
+ * global.c (pthread_count): Moved from dll.c.
+ * nonportable.c (pthread_win32_process_attach_np):
+ Moved _UWIN code to here from dll.c.
+ * implement.h (pthread_count): Define extern int.
+ * create.c (pthread_count): Remove extern int.
+ * private.c (pthread_count): Likewise.
+ * exit.c (pthread_count): Likewise.
+
+2001-06-18 David Korn <dgk@research.att.com>
+
+ * dll.c: Added changes necessary to work with UWIN.
+ * create.c: Likewise.
+ * pthread.h: Likewise.
+ * misc.c: Likewise.
+ * exit.c: Likewise.
+ * private.c: Likewise.
+ * implement.h: Likewise.
+ There is some room at the start of struct pthread_t_
+ to implement the signal semantics in UWIN's posix.dll
+ although this is not yet complete.
+ * Nmakefile: Compatible with UWIN's Nmake utility.
+ * Nmakefile.tests: Likewise - for running the tests.
+
+2001-06-08 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * semaphore.h (sem_t): Fixed for compile and test.
+ * implement.h (sem_t_): Likewise.
+ * semaphore.c: Likewise.
+ * private.c (ptw32_sem_timedwait): Updated to use new
+ opaque sem_t.
+
+2001-06-06 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * semaphore.h (sem_t): Is now an opaque pointer;
+ moved actual definition to implement.h.
+ * implement.h (sem_t_): Move here from semaphore.h;
+ was the definition of sem_t.
+ * semaphore.c: Wherever necessary, changed use of sem
+ from that of a pointer to a pointer-pointer; added
+ extra checks for a valid sem_t; NULL sem_t when
+ it is destroyed; added extra checks when creating
+ and destroying sem_t elements in the NEED_SEM
+ code branches; changed from using a pthread_mutex_t
+ ((*sem)->mutex) to CRITICAL_SECTION ((*sem)->sem_lock_cs)
+ in NEED_SEM branches for access serialisation.
+
+2001-06-06 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * mutex.c (pthread_mutexattr_init): Remove
+ ptw32_mutex_default_kind.
+
+2001-06-05 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * nonportable.c (pthread_mutex_setdefaultkind_np):
+ Remove - should not have been included in the first place.
+ (pthread_mutex_getdefaultkind_np): Likewise.
+ * global.c (ptw32_mutex_default_kind): Likewise.
+ * mutex.c (pthread_mutex_init): Remove use of
+ ptw32_mutex_default_kind.
+ * pthread.h (pthread_mutex_setdefaultkind_np): Likewise.
+ (pthread_mutex_getdefaultkind_np): Likewise.
+ * pthread.def (pthread_mutexattr_setkind_np): Added.
+ (pthread_mutexattr_getkind_np): Likewise.
+
+ * README: Many changes that should have gone in before
+ the last snapshot.
+ * README.NONPORTABLE: New - referred to by ANNOUNCE
+ but never created; documents the non-portable routines
+ included in the library - moved from README with new
+ routines added.
+ * ANNOUNCE (pthread_mutexattr_setkind_np): Added to
+ compliance list.
+ (pthread_mutexattr_getkind_np): Likewise.
+
+2001-06-04 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * condvar.c: Add original description of the algorithm as
+ developed by Terekhov and Thomas, plus reference to
+ README.CV.
+
+2001-06-03 Alexander Terekhov <TEREKHOV@de.ibm.com>, Louis Thomas <lthomas@arbitrade.com>
+
+ * condvar.c (pthread_cond_init): Completely revamped.
+ (pthread_cond_destroy): Likewise.
+ (ptw32_cond_wait_cleanup): Likewise.
+ (ptw32_cond_timedwait): Likewise.
+ (ptw32_cond_unblock): New general signaling routine.
+ (pthread_cond_signal): Now calls ptw32_cond_unblock.
+ (pthread_cond_broadcast): Likewise.
+ * implement.h (pthread_cond_t_): Revamped.
+ * README.CV: New; explanation of the above changes.
+
+2001-05-30 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * pthread.h (rand_r): Fake using _seed argument to quell
+ compiler warning (compiler should optimise this away later).
+
+ * GNUmakefile (OPT): Leave symbolic information out of the library
+ and increase optimisation level - for smaller faster prebuilt
+ dlls.
+
+2001-05-29 Milan Gardian <Milan.Gardian@LEIBINGER.com>
+
+ * Makefile: fix typo.
+ * pthreads.h: Fix problems with stdcall/cdecl conventions, in particular
+ remove the need for PT_STDCALL everywhere; remove warning supression.
+ * (errno): Fix the longstanding "inconsistent dll linkage" problem
+ with errno; now also works with /MD debugging libs -
+ warnings emerged when compiling pthreads library with /MD (or /MDd)
+ compiler switch, instead of /MT (or /MTd) (i.e. when compiling pthreads
+ using Multithreaded DLL CRT instead of Multithreaded statically linked
+ CRT).
+ * create.c (pthread_create): Likewise; fix typo.
+ * private.c (ptw32_threadStart): Eliminate use of terminate() which doesn't
+ throw exceptions.
+ * Remove unnecessary #includes from a number of modules -
+ [I had to #include malloc.h in implement.h for gcc - rpj].
+
+2001-05-29 Thomas Pfaff <tpfaff@gmx.net>
+
+ * pthread.h (PTHREAD_MUTEX_DEFAULT): New; equivalent to
+ PTHREAD_MUTEX_DEFAULT_NP.
+ * (PTHREAD_MUTEX_NORMAL): Similarly.
+ * (PTHREAD_MUTEX_ERRORCHECK): Similarly.
+ * (PTHREAD_MUTEX_RECURSIVE): Similarly.
+ * (pthread_mutex_setdefaultkind_np): New; Linux compatibility stub
+ for pthread_mutexattr_settype.
+ * (pthread_mutexattr_getkind_np): New; Linux compatibility stub
+ for pthread_mutexattr_gettype.
+ * mutex.c (pthread_mutexattr_settype): New; allow
+ the following types of mutex:
+ PTHREAD_MUTEX_DEFAULT_NP
+ PTHREAD_MUTEX_NORMAL_NP
+ PTHREAD_MUTEX_ERRORCHECK_NP
+ PTHREAD_MUTEX_RECURSIVE_NP
+ * Note that PTHREAD_MUTEX_DEFAULT is equivalent to
+ PTHREAD_MUTEX_NORMAL - ie. mutexes should no longer
+ be recursive by default, and a thread will deadlock if it
+ tries to relock a mutex it already owns. This is inline with
+ other pthreads implementations.
+ * (pthread_mutex_lock): Process the lock request
+ according to the mutex type.
+ * (pthread_mutex_init): Eliminate use of Win32 mutexes as the
+ basis of POSIX mutexes - instead, a combination of one critical section
+ and one semaphore are used in conjunction with Win32 Interlocked* routines.
+ * (pthread_mutex_destroy): Likewise.
+ * (pthread_mutex_lock): Likewise.
+ * (pthread_mutex_trylock): Likewise.
+ * (pthread_mutex_unlock): Likewise.
+ * Use longjmp/setjmp to implement cancelation when building the library
+ using a C compiler which doesn't support exceptions, e.g. gcc -x c (note
+ that gcc -x c++ uses exceptions).
+ * Also fixed some of the same typos and eliminated PT_STDCALL as
+ Milan Gardian's patches above.
+
+2001-02-07 Alexander Terekhov <TEREKHOV@de.ibm.com>
+
+ * rwlock.c: Revamped.
+ * implement.h (pthread_rwlock_t_): Redefined.
+ This implementation does not have reader/writer starvation problem.
+ Rwlock attempts to behave more like a normal mutex with
+ races and scheduling policy determining who is more important;
+ It also supports recursive locking,
+ has less synchronization overhead (no broadcasts at all,
+ readers are not blocked on any condition variable) and seem to
+ be faster than the current implementation [W98 appears to be
+ approximately 15 percent faster at least - on top of speed increase
+ from Thomas Pfaff's changes to mutex.c - rpj].
+
+2000-12-29 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * Makefile: Back-out "for" loops which don't work.
+
+ * GNUmakefile: Remove the fake.a target; add the "realclean"
+ target; don't remove built libs under the "clean" target.
+
+ * config.h: Add a guard against multiple inclusion.
+
+ * semaphore.h: Add some defines from config.h to make
+ semaphore.h independent of config.h when building apps.
+
+ * pthread.h (_errno): Back-out previous fix until we know how to
+ fix it properly.
+
+ * implement.h (lockCount): Add missing element to pthread_mutex_t_.
+
+ * sync.c (pthread_join): Spelling fix in comment.
+
+ * private.c (ptw32_threadStart): Reset original termination
+ function (C++).
+ (ptw32_threadStart): Cleanup detached threads early in case
+ the library is statically linked.
+ (ptw32_callUserDestroyRoutines): Remove [SEH] __try block from
+ destructor call so that unhandled exceptions will be passed through
+ to the system; call terminate() from [C++] try block for the same
+ reason.
+
+ * tsd.c (pthread_getspecific): Add comment.
+
+ * mutex.c (pthread_mutex_init): Initialise new elements in
+ pthread_mutex_t.
+ (pthread_mutex_unlock): Invert "pthread_equal()" test.
+
+2000-12-28 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * semaphore.c (mode_t): Use ifndef HAVE_MODE_T to include definition.
+
+ * config.h.in (HAVE_MODE_T): Added.
+ (_UWIN): Start adding defines for the UWIN package.
+
+ * private.c (ptw32_threadStart): Unhandled exceptions are
+ now passed through to the system to deal with. This is consistent
+ with normal Windows behaviour. C++ applications may use
+ set_terminate() to override the default behaviour which is
+ to call ptw32_terminate(). Ptw32_terminate() cleans up some
+ POSIX thread stuff before calling the system default function
+ which calls abort(). The users termination function should conform
+ to standard C++ semantics which is to not return. It should
+ exit the thread (call pthread_exit()) or exit the application.
+ * private.c (ptw32_terminate): Added as the default set_terminate()
+ function. It calls the system default function after cleaning up
+ some POSIX thread stuff.
+
+ * implement.h (ptw32_try_enter_critical_section): Move
+ declaration.
+ * global.c (ptw32_try_enter_critical_section): Moved
+ from dll.c.
+ * dll.c: Move process and thread attach/detach code into
+ functions in nonportable.c.
+ * nonportable.c (pthread_win32_process_attach_np): Process
+ attach code from dll.c is now available to static linked
+ applications.
+ * nonportable.c (pthread_win32_process_detach_np): Likewise.
+ * nonportable.c (pthread_win32_thread_attach_np): Likewise.
+ * nonportable.c (pthread_win32_thread_detach_np): Likewise.
+
+ * pthread.h: Add new non-portable prototypes for static
+ linked applications.
+
+ * GNUmakefile (OPT): Increase optimisation flag and remove
+ debug info flag.
+
+ * pthread.def: Add new non-portable exports for static
+ linked applications.
+
+2000-12-11 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * FAQ: Update Answer 6 re getting a fully working
+ Mingw32 built library.
+
+2000-10-10 Steven Reddie <smr@essemer.com.au>
+
+ * misc.c (pthread_self): Restore Win32 "last error"
+ cleared by TlsGetValue() call in
+ pthread_getspecific()
+
+2000-09-20 Arthur Kantor <akantor@bexusa.com>
+
+ * mutex.c (pthread_mutex_lock): Record the owner
+ of the mutex. This requires also keeping count of
+ recursive locks ourselves rather than leaving it
+ to Win32 since we need to know when to NULL the
+ thread owner when the mutex is unlocked.
+ (pthread_mutex_trylock): Likewise.
+ (pthread_mutex_unlock): Check that the calling
+ thread owns the mutex, decrement the recursive
+ lock count, and NULL the owner if zero. Return
+ EPERM if the mutex is owned by another thread.
+ * implement.h (pthread_mutex_t_): Add ownerThread
+ and lockCount members.
+
+2000-09-13 Jef Gearhart <jgearhart@tpssys.com>
+
+ * mutex.c (pthread_mutex_init): Call
+ TryEnterCriticalSection through the pointer
+ rather than directly so that the dll can load
+ on Windows versions that can't resolve the
+ function, eg. Windows 95
+
+2000-09-09 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * pthread.h (ctime_r): Fix arg.
+
+2000-09-08 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * GNUmakefile(_WIN32_WINNT=0x400): Define in CFLAGS;
+ doesn't seem to be needed though.
+
+ * cancel.c (pthread_cancel): Must get "self" through
+ calling pthread_self() which will ensure a POSIX thread
+ struct is built for non-POSIX threads; return an error
+ if this fails
+ - Ollie Leahy <ollie@mpt.ie>
+ (pthread_setcancelstate): Likewise.
+ (pthread_setcanceltype): Likewise.
+ * misc.c (ptw32_cancelable_wait): Likewise.
+
+ * private.c (ptw32_tkAssocCreate): Remove unused #if 0
+ wrapped code.
+
+ * pthread.h (ptw32_get_exception_services_code):
+ Needed to be forward declared unconditionally.
+
+2000-09-06 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * cancel.c (pthread_cancel): If called from the main
+ thread "self" would be NULL; get "self" via pthread_self()
+ instead of directly from TLS so that an implicit
+ pthread object is created.
+
+ * misc.c (pthread_equal): Strengthen test for NULLs.
+
+2000-09-02 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * condvar.c (ptw32_cond_wait_cleanup): Ensure that all
+ waking threads check if they are the last, and notify
+ the broadcaster if so - even if an error occurs in the
+ waiter.
+
+ * semaphore.c (_decrease_semaphore): Should be
+ a call to ptw32_decrease_semaphore.
+ (_increase_semaphore): Should be a call to
+ ptw32_increase_semaphore.
+
+ * misc.c (ptw32_cancelable_wait): Renamed from
+ CancelableWait.
+ * rwlock.c (_rwlock_check*): Renamed to
+ ptw32_rwlock_check*.
+ * mutex.c (_mutex_check*): Renamed to ptw32_mutex_check*.
+ * condvar.c (cond_timed*): Renamed to ptw32_cond_timed*.
+ (_cond_check*): Renamed to ptw32_cond_check*.
+ (cond_wait_cleanup*): Rename to ptw32_cond_wait_cleanup*.
+ (ptw32_cond_timedwait): Add comments.
+
+2000-08-22 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * private.c (ptw32_throw): Fix exception test;
+ move exceptionInformation declaration.
+
+ * tsd.c (pthread_key_create): newkey wrongly declared.
+
+ * pthread.h: Fix comment block.
+
+2000-08-18 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * mutex.c (pthread_mutex_destroy): Check that the mutex isn't
+ held; invalidate the mutex as early as possible to avoid
+ contention; not perfect - FIXME!
+
+ * rwlock.c (pthread_rwlock_init): Remove redundant assignment
+ to "rw".
+ (pthread_rwlock_destroy): Invalidate the rwlock before
+ freeing up any of it's resources - to avoid contention.
+
+ * private.c (ptw32_tkAssocCreate): Change assoc->lock
+ to use a dynamically initialised mutex - only consumes
+ a W32 mutex or critical section when first used,
+ not before.
+
+ * mutex.c (pthread_mutex_init): Remove redundant assignment
+ to "mx".
+ (pthread_mutexattr_destroy): Set attribute to NULL
+ before freeing it's memory - to avoid contention.
+
+ * implement.h (PTW32_EPS_CANCEL/PTW32_EPS_EXIT):
+ Must be defined for all compilers - used as generic
+ exception selectors by ptw32_throw().
+
+ * Several: Fix typos from scripted edit session
+ yesterday.
+
+ * nonportable.c (pthread_mutexattr_setforcecs_np):
+ Moved this function from mutex.c.
+ (pthread_getw32threadhandle_np): New function to
+ return the win32 thread handle that the POSIX
+ thread is using.
+ * mutex.c (pthread_mutexattr_setforcecs_np):
+ Moved to new file "nonportable.c".
+
+ * pthread.h (PTW32_BUILD): Only redefine __except
+ and catch compiler keywords if we aren't building
+ the library (ie. PTW32_BUILD is not defined) -
+ this is safer than defining and then undefining
+ if not building the library.
+ * implement.h: Remove __except and catch undefines.
+ * Makefile (CFLAGS): Define PTW32_BUILD.
+ * GNUmakefile (CFLAGS): Define PTW32_BUILD.
+
+ * All appropriate: Change Pthread_exception* to
+ ptw32_exception* to be consistent with internal
+ identifier naming.
+
+ * private.c (ptw32_throw): New function to provide
+ a generic exception throw for all internal
+ exceptions and EH schemes.
+ (ptw32_threadStart): pthread_exit() value is now
+ returned via the thread structure exitStatus
+ element.
+ * exit.c (pthread_exit): pthread_exit() value is now
+ returned via the thread structure exitStatus
+ element.
+ * cancel.c (ptw32_cancel_self): Now uses ptw32_throw.
+ (pthread_setcancelstate): Ditto.
+ (pthread_setcanceltype): Ditto.
+ (pthread_testcancel): Ditto.
+ (pthread_cancel): Ditto.
+ * misc.c (CancelableWait): Ditto.
+ * exit.c (pthread_exit): Ditto.
+ * All applicable: Change PTW32_ prefix to
+ PTW32_ prefix to remove leading underscores
+ from private library identifiers.
+
+2000-08-17 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * All applicable: Change _pthread_ prefix to
+ ptw32_ prefix to remove leading underscores
+ from private library identifiers (single
+ and double leading underscores are reserved in the
+ ANSI C standard for compiler implementations).
+
+ * tsd.c (pthread_create_key): Initialise temporary
+ key before returning it's address to avoid race
+ conditions.
+
+2000-08-13 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * errno.c: Add _MD precompile condition; thus far
+ had no effect when using /MD compile option but I
+ thnk it should be there.
+
+ * exit.c: Add __cplusplus to various #if lines;
+ was compiling SEH code even when VC++ had
+ C++ compile options.
+
+ * private.c: ditto.
+
+ * create.c (pthread_create): Add PT_STDCALL macro to
+ function pointer arg in _beginthread().
+
+ * pthread.h: PT_STDCALL really does need to be defined
+ in both this and impliment.h; don't set it to __cdecl
+ - this macro is only used to extend function pointer
+ casting for functions that will be passed as parameters.
+ (~PThreadCleanup): add cast and group expression.
+ (_errno): Add _MD compile conditional.
+ (PtW32NoCatchWarn): Change pragma message.
+
+ * implement.h: Move and change PT_STDCALL define.
+
+ * need_errno.h: Add _MD to compilation conditional.
+
+ * GNUmakefile: Substantial rewrite for new naming
+ convention; set for nil optimisation (turn it up
+ when we have a working library build; add target
+ "fake.a" to build a libpthreadw32.a from the VC++
+ built DLL pthreadVCE.dll.
+
+ * pthread.def (LIBRARY): Don't specify in the .def
+ file - it is specified on the linker command line
+ since we now use the same .def file for variously
+ named .dlls.
+
+ * Makefile: Substantial rewrite for new naming
+ convention; default nmake target only issues a
+ help message; run nmake with specific target
+ corresponding to the EH scheme being used.
+
+ * README: Update information; add naming convention
+ explanation.
+
+ * ANNOUNCE: Update information.
+
+2000-08-12 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * pthread.h: Add compile-time message when using
+ MSC_VER compiler and C++ EH to warn application
+ programmers to use PtW32Catch instead of catch(...)
+ if they want cancelation and pthread_exit to work.
+
+ * implement.h: Remove #include <semaphore.h>; we
+ use our own local semaphore.h.
+
+2000-08-10 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * cleanup.c (pthread_pop_cleanup): Remove _pthread
+ prefix from __except and catch keywords; implement.h
+ now simply undefines ptw32__except and
+ ptw32_catch if defined; VC++ was not textually
+ substituting ptw32_catch etc back to catch as
+ it was redefined; the reason for using the prefixed
+ version was to make it clear that it was not using
+ the pthread.h redefined catch keyword.
+
+ * private.c (ptw32_threadStart): Ditto.
+ (ptw32_callUserDestroyRoutines): Ditto.
+
+ * implement.h (ptw32__except): Remove #define.
+ (ptw32_catch): Remove #define.
+
+ * GNUmakefile (pthread.a): New target to build
+ libpthread32.a from pthread.dll using dlltool.
+
+ * buildlib.bat: Duplicate cl commands with args to
+ build C++ EH version of pthread.dll; use of .bat
+ files is redundant now that nmake compatible
+ Makefile is included; used as a kludge only now.
+
+ * Makefile: Localise some macros and fix up the clean:
+ target to extend it and work properly.
+
+ * CONTRIBUTORS: Add contributors.
+
+ * ANNOUNCE: Updated.
+
+ * README: Updated.
+
+2000-08-06 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * pthread.h: Remove #warning - VC++ doesn't accept it.
+
+2000-08-05 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * pthread.h (PtW32CatchAll): Add macro. When compiling
+ applications using VC++ with C++ EH rather than SEH
+ 'PtW32CatchAll' must be used in place of any 'catch( ... )'
+ if the application wants pthread cancelation or
+ pthread_exit() to work.
+
+2000-08-03 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * pthread.h: Add a base class ptw32_exception for
+ library internal exceptions and change the "catch"
+ re-define macro to use it.
+
+2000-08-02 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * GNUmakefile (CFLAGS): Add -mthreads.
+ Add new targets to generate cpp and asm output.
+
+ * sync.c (pthread_join): Remove dead code.
+
+2000-07-25 Tristan Savatier <tristan@mpegtv.com>
+
+ * sched.c (sched_get_priority_max): Handle different WinCE and
+ Win32 priority values together.
+ (sched_get_priority_min): Ditto.
+
+2000-07-25 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * create.c (pthread_create): Force new threads to wait until
+ pthread_create has the new thread's handle; we also retain
+ a local copy of the handle for internal use until
+ pthread_create returns.
+
+ * private.c (ptw32_threadStart): Initialise ei[].
+ (ptw32_threadStart): When beginthread is used to start the
+ thread, force waiting until the creator thread had the
+ thread handle.
+
+ * cancel.c (ptw32_cancel_thread): Include context switch
+ code for defined(_X86_) environments in addition to _M_IX86.
+
+ * rwlock.c (pthread_rwlock_destroy): Assignment changed
+ to avoid compiler warning.
+
+ * private.c (ptw32_get_exception_services_code): Cast
+ NULL return value to avoid compiler warning.
+
+ * cleanup.c (pthread_pop_cleanup): Initialise "cleanup" variable
+ to avoid compiler warnings.
+
+ * misc.c (ptw32_new): Change "new" variable to "t" to avoid
+ confusion with the C++ keyword of the same name.
+
+ * condvar.c (cond_wait_cleanup): Initialise lastWaiter variable.
+ (cond_timedwait): Remove unused local variables. to avoid
+ compiler warnings.
+
+ * dll.c (dllMain): Remove 2000-07-21 change - problem
+ appears to be in pthread_create().
+
+2000-07-22 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * tsd.c (pthread_key_create): If a destructor was given
+ and the pthread_mutex_init failed, then would try to
+ reference a NULL pointer (*key); eliminate this section of
+ code by using a dynamically initialised mutex
+ (PTHREAD_MUTEX_INITIALIZER).
+
+ * tsd.c (pthread_setspecific): Return an error if
+ unable to set the value; simplify cryptic conditional.
+
+ * tsd.c (pthread_key_delete): Locking threadsLock relied
+ on mutex_lock returning an error if the key has no destructor.
+ ThreadsLock is only initialised if the key has a destructor.
+ Making this mutex a static could reduce the number of mutexes
+ used by an application since it is actually created only at
+ first use and it's often destroyed soon after.
+
+2000-07-22 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * FAQ: Added Q5 and Q6.
+
+2000-07-21 David Baggett <dmb@itasoftware.com>
+
+ * dll.c: Include resource leakage work-around. This is a
+ partial FIXME which doesn't stop all leakage. The real
+ problem needs to be found and fixed.
+
+2000-07-21 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * create.c (pthread_create): Set threadH to 0 (zero)
+ everywhere. Some assignments were using NULL. Maybe
+ it should be NULL everywhere - need to check. (I know
+ they are nearly always the same thing - but not by
+ definition.)
+
+ * misc.c (pthread_self): Try to catch NULL thread handles
+ at the point where they might be generated, even though
+ they should always be valid at this point.
+
+ * tsd.c (pthread_setspecific): return an error value if
+ pthread_self() returns NULL.
+
+ * sync.c (pthread_join): return an error value if
+ pthread_self() returns NULL.
+
+ * signal.c (pthread_sigmask): return an error value if
+ pthread_self() returns NULL.
+
+2000-03-02 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * attr.c (pthread_attr_init): Set default stacksize to zero (0)
+ rather than PTHREAD_STACK_MIN even though these are now the same.
+
+ * pthread.h (PTHREAD_STACK_MIN): Lowered to 0.
+
+2000-01-28 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * mutex.c (pthread_mutex_init): Free mutex if it has been alloced;
+ if critical sections can be used instead of Win32 mutexes, test
+ that the critical section works and return an error if not.
+
+2000-01-07 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * cleanup.c (pthread_pop_cleanup): Include SEH code only if MSC is not
+ compiling as C++.
+ (pthread_push_cleanup): Include SEH code only if MSC is not
+ compiling as C++.
+
+ * pthread.h: Include SEH code only if MSC is not
+ compiling as C++.
+
+ * implement.h: Include SEH code only if MSC is not
+ compiling as C++.
+
+ * cancel.c (ptw32_cancel_thread): Add _M_IX86 check.
+ (pthread_testcancel): Include SEH code only if MSC is not
+ compiling as C++.
+ (ptw32_cancel_self): Include SEH code only if MSC is not
+ compiling as C++.
+
+2000-01-06 Erik Hensema <erik.hensema@group2000.nl>
+
+ * Makefile: Remove inconsistencies in 'cl' args
+
+2000-01-04 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * private.c (ptw32_get_exception_services_code): New; returns
+ value of EXCEPTION_PTW32_SERVICES.
+ (ptw32_processInitialize): Remove initialisation of
+ ptw32_exception_services which is no longer needed.
+
+ * pthread.h (ptw32_exception_services): Remove extern.
+ (ptw32_get_exception_services_code): Add function prototype;
+ use this to return EXCEPTION_PTW32_SERVICES value instead of
+ using the ptw32_exception_services variable which I had
+ trouble exporting through pthread.def.
+
+ * global.c (ptw32_exception_services): Remove declaration.
+
+1999-11-22 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * implement.h: Forward declare ptw32_new();
+
+ * misc.c (ptw32_new): New; alloc and initialise a new pthread_t.
+ (pthread_self): New thread struct is generated by new routine
+ ptw32_new().
+
+ * create.c (pthread_create): New thread struct is generated
+ by new routine ptw32_new().
+
+1999-11-21 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * global.c (ptw32_exception_services): Declare new variable.
+
+ * private.c (ptw32_threadStart): Destroy thread's
+ cancelLock mutex; make 'catch' and '__except' usageimmune to
+ redfinitions in pthread.h.
+ (ptw32_processInitialize): Init new constant ptw32_exception_services.
+
+ * create.c (pthread_create): Initialise thread's cancelLock
+ mutex.
+
+ * cleanup.c (pthread_pop_cleanup): Make 'catch' and '__except'
+ usage immune to redfinition s in pthread.h.
+
+ * private.c: Ditto.
+
+ * pthread.h (catch): Redefine 'catch' so that C++ applications
+ won't catch our internal exceptions.
+ (__except): ditto for __except.
+
+ * implement.h (ptw32_catch): Define internal version
+ of 'catch' because 'catch' is redefined by pthread.h.
+ (__except): ditto for __except.
+ (struct pthread_t_): Add cancelLock mutex for async cancel
+ safety.
+
+1999-11-21 Jason Nye <jnye@nbnet.nb.ca>, Erik Hensema <erik.hensema@group2000.nl>
+
+ * cancel.c (ptw32_cancel_self): New; part of the async
+ cancellation implementation.
+ (ptw32_cancel_thread): Ditto; this function is X86
+ processor specific.
+ (pthread_setcancelstate): Add check for pending async
+ cancel request and cancel the calling thread if
+ required; add async-cancel safety lock.
+ (pthread_setcanceltype): Ditto.
+
+1999-11-13 Erik Hensema <erik.hensema@group2000.nl>
+
+ * configure.in (AC_OUTPUT): Put generated output into GNUmakefile
+ rather than Makefile. Makefile will become the MSC nmake compatible
+ version
+
+1999-11-13 John Bossom (John.Bossom@cognos.com>
+
+ * misc.c (pthread_self): Add a note about GetCurrentThread
+ returning a pseudo-handle
+
+1999-11-10 Todd Owen <towen@lucidcalm.dropbear.id.au>
+
+ * dll.c (dllMain): Free kernel32 ASAP.
+ If TryEnterCriticalSection is not being used, then free
+ the kernel32.dll handle now, rather than leaving it until
+ DLL_PROCESS_DETACH.
+
+ Note: this is not a pedantic exercise in freeing unused
+ resources! It is a work-around for a bug in Windows 95
+ (see microsoft knowledge base article, Q187684) which
+ does Bad Things when FreeLibrary is called within
+ the DLL_PROCESS_DETACH code, in certain situations.
+ Since w95 just happens to be a platform which does not
+ provide TryEnterCriticalSection, the bug will be
+ effortlessly avoided.
+
+1999-11-10 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * sync.c (pthread_join): Make it a deferred cancelation point.
+
+ * misc.c (pthread_self): Explicitly initialise implicitly
+ created thread state to default values.
+
+1999-11-05 Tristan Savatier <tristan@mpegtv.com>
+
+ * pthread.h (winsock.h): Include unconditionally.
+ (ETIMEDOUT): Change fallback value to that defined by winsock.h.
+
+ * general: Patched for portability to WinCE. The details are
+ described in the file WinCE-PORT. Follow the instructions
+ in README.WinCE to make the appropriate changes in config.h.
+
+1999-10-30 Erik Hensema <erik.hensema@group2000.nl>
+
+ * create.c (pthread_create): Explicitly initialise thread state to
+ default values.
+
+ * cancel.c (pthread_setcancelstate): Check for NULL 'oldstate'
+ for compatibility with Solaris pthreads;
+ (pthread_setcanceltype): ditto:
+
+1999-10-23 Erik Hensema <erik.hensema@group2000.nl>
+
+ * pthread.h (ctime_r): Fix incorrect argument "_tm"
+
+1999-10-21 Aurelio Medina <aureliom@crt.com>
+
+ * pthread.h (_POSIX_THREADS): Only define it if it isn't
+ already defined. Projects may need to define this on
+ the CC command line under Win32 as it doesn't have unistd.h
+
+1999-10-17 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * rwlock.c (pthread_rwlock_destroy): Add cast to remove compile
+ warning.
+
+ * condvar.c (pthread_cond_broadcast): Only release semaphores
+ if there are waiting threads.
+
+1999-10-15 Lorin Hochstein <lmh@xiphos.ca>, Peter Slacik <Peter.Slacik@tatramed.sk>
+
+ * condvar.c (cond_wait_cleanup): New static cleanup handler for
+ cond_timedwait;
+ (cond_timedwait): pthread_cleanup_push args changed;
+ canceling a thread while it's in pthread_cond_wait
+ will now decrement the waiters count and cleanup if it's the
+ last waiter.
+
+1999-10-15 Graham Dumpleton <Graham.Dumpleton@ra.pad.otc.telstra.com.au>
+
+ * condvar.c (cond_wait_cleanup): the last waiter will now reset the CV's
+ wasBroadcast flag
+
+Thu Sep 16 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * rwlock.c (pthread_rwlock_destroy): Add serialisation.
+ (_rwlock_check_need_init): Check for detroyed rwlock.
+ * rwlock.c: Check return codes from _rwlock_check_need_init();
+ modify comments; serialise access to rwlock objects during
+ operations; rename rw_mutex to rw_lock.
+ * implement.h: Rename rw_mutex to rw_lock.
+ * mutex.c (pthread_mutex_destroy): Add serialisation.
+ (_mutex_check_need_init): Check for detroyed mutex.
+ * condvar.c (pthread_cond_destroy): Add serialisation.
+ (_cond_check_need_init): Check for detroyed condvar.
+ * mutex.c: Modify comments.
+ * condvar.c: Modify comments.
+
+1999-08-10 Aurelio Medina <aureliom@crt.com>
+
+ * implement.h (pthread_rwlock_t_): Add.
+ * pthread.h (pthread_rwlock_t): Add.
+ (PTHREAD_RWLOCK_INITIALIZER): Add.
+ Add rwlock function prototypes.
+ * rwlock.c: New module.
+ * pthread.def: Add new rwlock functions.
+ * private.c (ptw32_processInitialize): initialise
+ ptw32_rwlock_test_init_lock critical section.
+ * global.c (ptw32_rwlock_test_init_lock): Add.
+
+ * mutex.c (pthread_mutex_destroy): Don't free mutex memory
+ if mutex is PTHREAD_MUTEX_INITIALIZER and has not been
+ initialised yet.
+
+1999-08-08 Milan Gardian <mg@tatramed.sk>
+
+ * mutex.c (pthread_mutex_destroy): Free mutex memory.
+
+1999-08-22 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * exit.c (pthread_exit): Fix reference to potentially
+ uninitialised pointer.
+
+1999-08-21 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c (ptw32_threadStart): Apply fix of 1999-08-19
+ this time to C++ and non-trapped C versions. Ommitted to
+ do this the first time through.
+
+1999-08-19 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c (ptw32_threadStart): Return exit status from
+ the application thread startup routine.
+ - Milan Gardian <mg@tatramed.sk>
+
+1999-08-18 John Bossom <john.Bossom@cognos.com>
+
+ * exit.c (pthread_exit): Put status into pthread_t->exitStatus
+ * private.c (ptw32_threadStart): Set pthread->exitStatus
+ on exit of try{} block.
+ * sync.c (pthread_join): use pthread_exitStatus value if the
+ thread exit doesn't return a value (for Mingw32 CRTDLL
+ which uses endthread instead of _endthreadex).
+
+Tue Aug 17 20:17:58 CDT 1999 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * create.c (pthread_create): Add CRTDLL suppport.
+ * exit.c (pthread_exit): Likewise.
+ * private.c (ptw32_threadStart): Likewise.
+ (ptw32_threadDestroy): Likewise.
+ * sync.c (pthread_join): Likewise.
+ * tests/join1.c (main): Warn about partial support for CRTDLL.
+
+Tue Aug 17 20:00:08 1999 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * Makefile.in (LD): Delete entry point.
+ * acconfig.h (STDCALL): Delete unused macro.
+ * configure.in: Remove test for STDCALL.
+ * config.h.in: Regenerate.
+ * errno.c (_errno): Fix self type.
+ * pthread.h (PT_STDCALL): Move from here to
+ * implement.h (PT_STDCALL): here.
+ (ptw32_threadStart): Fix prototype.
+ * private.c (ptw32_threadStart): Likewise.
+
+1999-08-14 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * exit.c (pthread_exit): Don't call pthread_self() but
+ get thread handle directly from TSD for efficiency.
+
+1999-08-12 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c (ptw32_threadStart): ei[] only declared if _MSC_VER.
+
+ * exit.c (pthread_exit): Check for implicitly created threads
+ to avoid raising an unhandled exception.
+
+1999-07-12 Peter Slacik <Peter.Slacik@tatramed.sk>
+
+ * condvar.c (pthread_cond_destroy): Add critical section.
+ (cond_timedwait): Add critical section; check for timeout
+ waiting on semaphore.
+ (pthread_cond_broadcast): Add critical section.
+
+1999-07-09 Lorin Hochstein <lmh@xiphos.ca>, John Bossom <John.Bossom@Cognos.COM>
+
+ The problem was that cleanup handlers were not executed when
+ pthread_exit() was called.
+
+ * implement.h (pthread_t_): Add exceptionInformation element for
+ C++ per-thread exception information.
+ (general): Define and rename exceptions.
+
+1999-07-09 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * misc.c (CancelableWait): PTW32_EPS_CANCEL (SEH) and
+ ptw32_exception_cancel (C++) used to identify the exception.
+
+ * cancel.c (pthread_testcancel): PTW32_EPS_CANCEL (SEH) and
+ ptw32_exception_cancel (C++) used to identify the exception.
+
+ * exit.c (pthread_exit): throw/raise an exception to return to
+ ptw32_threadStart() to exit the thread. PTW32_EPS_EXIT (SEH)
+ and ptw32_exception_exit (C++) used to identify the exception.
+
+ * private.c (ptw32_threadStart): Add pthread_exit exception trap;
+ clean up and exit the thread directly rather than via pthread_exit().
+
+Sun May 30 00:25:02 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * semaphore.h (mode_t): Conditionally typedef it.
+
+Fri May 28 13:33:05 1999 Mark E. Armstrong <avail@pacbell.net>
+
+ * condvar.c (pthread_cond_broadcast): Fix possible memory fault
+
+Thu May 27 13:08:46 1999 Peter Slacik <Peter.Slacik@tatramed.sk>
+
+ * condvar.c (pthread_cond_broadcast): Fix logic bug
+
+Thu May 27 13:08:46 1999 Bossom, John <John.Bossom@Cognos.COM>
+
+ * condvar.c (pthread_cond_broadcast): optimise sem_post loop
+
+Fri May 14 12:13:18 1999 Mike Russo <miker@eai.com>
+
+ * attr.c (pthread_attr_setdetachstate): Fix logic bug
+
+Sat May 8 09:42:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.def (sem_open): Add.
+ (sem_close): Add.
+ (sem_unlink): Add.
+ (sem_getvalue): Add.
+
+ * FAQ (Question 3): Add.
+
+Thu Apr 8 01:16:23 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * semaphore.c (sem_open): New function; returns an error (ENOSYS).
+ (sem_close): ditto.
+ (sem_unlink): ditto.
+ (sem_getvalue): ditto.
+
+ * semaphore.h (_POSIX_SEMAPHORES): define.
+
+Wed Apr 7 14:09:52 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * errno.c (_REENTRANT || _MT): Invert condition.
+
+ * pthread.h (_errno): Conditionally include prototype.
+
+Wed Apr 7 09:37:00 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * *.c (comments): Remove individual attributions - these are
+ documented sufficiently elsewhere.
+
+ * implement.h (pthread.h): Remove extraneous include.
+
+Sun Apr 4 11:05:57 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * sched.c (sched.h): Include.
+
+ * sched.h: New file for POSIX 1b scheduling.
+
+ * pthread.h: Move opaque structures to implement.h; move sched_*
+ prototypes out and into sched.h.
+
+ * implement.h: Add opaque structures from pthread.h.
+
+ * sched.c (sched_yield): New function.
+
+ * condvar.c (ptw32_sem_*): Rename to sem_*; except for
+ ptw32_sem_timedwait which is an private function.
+
+Sat Apr 3 23:28:00 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * Makefile.in (OBJS): Add errno.o.
+
+Fri Apr 2 11:08:50 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h (ptw32_sem_*): Remove prototypes now defined in
+ semaphore.h.
+
+ * pthread.h (sempahore.h): Include.
+
+ * semaphore.h: New file for POSIX 1b semaphores.
+
+ * semaphore.c (ptw32_sem_timedwait): Moved to private.c.
+
+ * pthread.h (ptw32_sem_t): Change to sem_t.
+
+ * private.c (ptw32_sem_timedwait): Moved from semaphore.c;
+ set errno on error.
+
+ * pthread.h (pthread_t_): Add per-thread errno element.
+
+Fri Apr 2 11:08:50 1999 John Bossom <jebossom@cognos.com>
+
+ * semaphore.c (ptw32_sem_*): Change to sem_*; these functions
+ will be exported from the library; set errno on error.
+
+ * errno.c (_errno): New file. New function.
+
+Fri Mar 26 14:11:45 1999 Tor Lillqvist <tml@iki.fi>
+
+ * semaphore.c (ptw32_sem_timedwait): Check for negative
+ milliseconds.
+
+Wed Mar 24 11:32:07 1999 John Bossom <jebossom@cognos.com>
+
+ * misc.c (CancelableWait): Initialise exceptionInformation[2].
+ (pthread_self): Get a real Win32 thread handle for implicit threads.
+
+ * cancel.c (pthread_testcancel): Initialise exceptionInformation[2].
+
+ * implement.h (SE_INFORMATION): Fix values.
+
+ * private.c (ptw32_threadDestroy): Close the thread handle.
+
+Fri Mar 19 12:57:27 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * cancel.c (comments): Update and cleanup.
+
+Fri Mar 19 09:12:59 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c (ptw32_threadStart): status returns PTHREAD_CANCELED.
+
+ * pthread.h (PTHREAD_CANCELED): defined.
+
+Tue Mar 16 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * all: Add GNU LGPL and Copyright and Warranty.
+
+Mon Mar 15 00:20:13 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * condvar.c (pthread_cond_init): fix possible uninitialised use
+ of cv.
+
+Sun Mar 14 21:01:59 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * condvar.c (pthread_cond_destroy): don't do full cleanup if
+ static initialised cv has never been used.
+ (cond_timedwait): check result of auto-initialisation.
+
+Thu Mar 11 09:01:48 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (pthread_mutex_t): revert to (pthread_mutex_t *);
+ define a value to serve as PTHREAD_MUTEX_INITIALIZER.
+ (pthread_mutex_t_): remove staticinit and valid elements.
+ (pthread_cond_t): revert to (pthread_cond_t_ *);
+ define a value to serve as PTHREAD_COND_INITIALIZER.
+ (pthread_cond_t_): remove staticinit and valid elements.
+
+ * mutex.c (pthread_mutex_t args): adjust indirection of references.
+ (all functions): check for PTHREAD_MUTEX_INITIALIZER value;
+ check for NULL (invalid).
+
+ * condvar.c (pthread_cond_t args): adjust indirection of references.
+ (all functions): check for PTHREAD_COND_INITIALIZER value;
+ check for NULL (invalid).
+
+Wed Mar 10 17:18:12 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * misc.c (CancelableWait): Undo changes from Mar 8 and 7.
+
+Mon Mar 8 11:18:59 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * misc.c (CancelableWait): Ensure cancelEvent handle is the lowest
+ indexed element in the handles array. Enhance test for abandoned
+ objects.
+
+ * pthread.h (PTHREAD_MUTEX_INITIALIZER): Trailing elements not
+ initialised are set to zero by the compiler. This avoids the
+ problem of initialising the opaque critical section element in it.
+ (PTHREAD_COND_INITIALIZER): Ditto.
+
+ * semaphore.c (ptw32_sem_timedwait): Check sem == NULL earlier.
+
+Sun Mar 7 12:31:14 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * condvar.c (pthread_cond_init): set semaphore initial value
+ to 0, not 1. cond_timedwait was returning signaled immediately.
+
+ * misc.c (CancelableWait): Place the cancel event handle first
+ in the handle table for WaitForMultipleObjects. This ensures that
+ the cancel event is recognised and acted apon if both objects
+ happen to be signaled together.
+
+ * private.c (ptw32_cond_test_init_lock): Initialise and destroy.
+
+ * implement.h (ptw32_cond_test_init_lock): Add extern.
+
+ * global.c (ptw32_cond_test_init_lock): Add declaration.
+
+ * condvar.c (pthread_cond_destroy): check for valid initialised CV;
+ flag destroyed CVs as invalid.
+ (pthread_cond_init): pthread_cond_t is no longer just a pointer.
+ This is because PTHREAD_COND_INITIALIZER needs state info to reside
+ in pthread_cond_t so that it can initialise on first use. Will work on
+ making pthread_cond_t (and other objects like it) opaque again, if
+ possible, later.
+ (cond_timedwait): add check for statically initialisation of
+ CV; initialise on first use.
+ (pthread_cond_signal): check for valid CV.
+ (pthread_cond_broadcast): check for valid CV.
+ (_cond_check_need_init): Add.
+
+ * pthread.h (PTHREAD_COND_INITIALIZER): Fix.
+ (pthread_cond_t): no longer a pointer to pthread_cond_t_.
+ (pthread_cond_t_): add 'staticinit' and 'valid' elements.
+
+Sat Mar 6 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h: Undate comments.
+
+Sun Feb 21 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (PTHREAD_MUTEX_INITIALIZER): missing braces around
+ cs element initialiser.
+
+1999-02-21 Ben Elliston <bje@cygnus.com>
+
+ * pthread.h (pthread_exit): The return type of this function is
+ void, not int.
+
+ * exit.c (pthread_exit): Do not return 0.
+
+Sat Feb 20 16:03:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * dll.c (DLLMain): Expand TryEnterCriticalSection support test.
+
+ * mutex.c (pthread_mutex_trylock): The check for
+ ptw32_try_enter_critical_section == NULL should have been
+ removed long ago.
+
+Fri Feb 19 16:03:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * sync.c (pthread_join): Fix pthread_equal() test.
+
+ * mutex.c (pthread_mutex_trylock): Check mutex != NULL before
+ using it.
+
+Thu Feb 18 16:17:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * misc.c (pthread_equal): Fix inverted result.
+
+ * Makefile.in: Use libpthread32.a as the name of the DLL export
+ library instead of pthread.lib.
+
+ * condvar.c (pthread_cond_init): cv could have been used unitialised;
+ initialise.
+
+ * create.c (pthread_create): parms could have been used unitialised;
+ initialise.
+
+ * pthread.h (struct pthread_once_t_): Remove redefinition.
+
+Sat Feb 13 03:03:30 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (struct pthread_once_t_): Replaced.
+
+ * misc.c (pthread_once): Replace with John Bossom's version;
+ has lighter weight serialisation; fixes problem of not holding
+ competing threads until after the init_routine completes.
+
+Thu Feb 11 13:34:14 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * misc.c (CancelableWait): Change C++ exception throw.
+
+ * sync.c (pthread_join): Change FIXME comment - issue resolved.
+
+Wed Feb 10 12:49:11 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * configure: Various temporary changes.
+ - Kevin Ruland <Kevin.Ruland@anheuser-busch.com>
+
+ * README: Update.
+
+ * pthread.def (pthread_attr_getstackaddr): uncomment
+ (pthread_attr_setstackaddr): uncomment
+
+Fri Feb 5 13:42:30 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * semaphore.c: Comment format changes.
+
+Thu Feb 4 10:07:28 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * global.c: Remove ptw32_exception instantiation.
+
+ * cancel.c (pthread_testcancel): Change C++ exception throw.
+
+ * implement.h: Remove extern declaration.
+
+Wed Feb 3 13:04:44 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * cleanup.c: Rename ptw32_*_cleanup() to pthread_*_cleanup().
+
+ * pthread.def: Ditto.
+
+ * pthread.h: Ditto.
+
+ * pthread.def (pthread_cleanup_push): Remove from export list;
+ the function is defined as a macro under all compilers.
+ (pthread_cleanup_pop): Ditto.
+
+ * pthread.h: Remove #if defined().
+
+Wed Feb 3 10:13:48 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * sync.c (pthread_join): Check for NULL value_ptr arg;
+ check for detached threads.
+
+Tue Feb 2 18:07:43 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * implement.h: Add #include <pthread.h>.
+ Change sem_t to ptw32_sem_t.
+
+ Various patches by Kevin Ruland <Kevin.Ruland@anheuser-busch.com>
+
+ * signal.c (pthread_sigmask): Add and modify casts.
+ Reverse LHS/RHS bitwise assignments.
+
+ * pthread.h: Remove #include <semaphore.h>.
+ (PTW32_ATTR_VALID): Add cast.
+ (struct pthread_t_): Add sigmask element.
+
+ * dll.c: Add "extern C" for DLLMain.
+ (DllMain): Add cast.
+
+ * create.c (pthread_create): Set sigmask in thread.
+
+ * condvar.c: Remove #include. Change sem_* to ptw32_sem_*.
+
+ * attr.c: Changed #include.
+
+ * Makefile.in: Additional targets and changes to build the library
+ as a DLL.
+
+Fri Jan 29 11:56:28 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * Makefile.in (OBJS): Add semaphore.o to list.
+
+ * semaphore.c (ptw32_sem_timedwait): Move from private.c.
+ Rename sem_* to ptw32_sem_*.
+
+ * pthread.h (pthread_cond_t): Change type of sem_t.
+ _POSIX_SEMAPHORES no longer defined.
+
+ * semaphore.h: Contents moved to implement.h.
+ Removed from source tree.
+
+ * implement.h: Add semaphore function prototypes and rename all
+ functions to prepend 'ptw32_'. They are
+ now private to the pthreads-win32 implementation.
+
+ * private.c: Change #warning.
+ Move ptw32_sem_timedwait() to semaphore.c.
+
+ * cleanup.c: Change #warning.
+
+ * misc.c: Remove #include <errno.h>
+
+ * pthread.def: Cleanup CVS merge conflicts.
+
+ * global.c: Ditto.
+
+ * ChangeLog: Ditto.
+
+ * cleanup.c: Ditto.
+
+Sun Jan 24 01:34:52 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * semaphore.c (sem_wait): Remove second arg to
+ pthreadCancelableWait() call.
+
+Sat Jan 23 17:36:40 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.def: Add new functions to export list.
+
+ * pthread.h (PTHREAD_MUTEX_AUTO_CS_NP): New.
+ (PTHREAD_MUTEX_FORCE_CS_NP): New.
+
+ * README: Updated.
+
+Fri Jan 22 14:31:59 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * Makefile.in (CFLAGS): Remove -fhandle-exceptions. Not needed
+ with egcs. Add -g for debugging.
+
+ * create.c (pthread_create): Replace __stdcall with PT_STDCALL
+ macro. This is a hack and must be fixed.
+
+ * misc.c (CancelableWait): Remove redundant statement.
+
+ * mutex.c (pthread_mutexattr_init): Cast calloc return value.
+
+ * misc.c (CancelableWait): Add cast.
+ (pthread_self): Add cast.
+
+ * exit.c (pthread_exit): Add cast.
+
+ * condvar.c (pthread_condattr_init): Cast calloc return value.
+
+ * cleanup.c: Reorganise conditional compilation.
+
+ * attr.c (pthread_attr_init): Remove unused 'result'.
+ Cast malloc return value.
+
+ * private.c (ptw32_callUserDestroyRoutines): Redo conditional
+ compilation.
+
+ * misc.c (CancelableWait): C++ version uses 'throw'.
+
+ * cancel.c (pthread_testcancel): Ditto.
+
+ * implement.h (class ptw32_exception): Define for C++.
+
+ * pthread.h: Fix C, C++, and Win32 SEH condition compilation
+ mayhem around pthread_cleanup_* defines. C++ version now uses John
+ Bossom's cleanup handlers.
+ (pthread_attr_t): Make 'valid' unsigned.
+ Define '_timeb' as 'timeb' for Ming32.
+ Define PT_STDCALL as nothing for Mingw32. May be temporary.
+
+ * cancel.c (pthread_testcancel): Cast return value.
+
+Wed Jan 20 09:31:28 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (pthread_mutexattr_t): Changed to a pointer.
+
+ * mutex.c (pthread_mutex_init): Conditionally create Win32 mutex
+ - from John Bossom's implementation.
+ (pthread_mutex_destroy): Conditionally close Win32 mutex
+ - from John Bossom's implementation.
+ (pthread_mutexattr_init): Replaced by John Bossom's version.
+ (pthread_mutexattr_destroy): Ditto.
+ (pthread_mutexattr_getpshared): New function from John Bossom's
+ implementation.
+ (pthread_mutexattr_setpshared): New function from John Bossom's
+ implementation.
+
+Tue Jan 19 18:27:42 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * pthread.h (pthreadCancelableTimedWait): New prototype.
+ (pthreadCancelableWait): Remove second argument.
+
+ * misc.c (CancelableWait): New static function is
+ pthreadCancelableWait() renamed.
+ (pthreadCancelableWait): Now just calls CancelableWait() with
+ INFINITE timeout.
+ (pthreadCancelableTimedWait): Just calls CancelableWait()
+ with passed in timeout.
+
+Tue Jan 19 18:27:42 1999 Scott Lightner <scott@curriculum.com>
+
+ * private.c (ptw32_sem_timedwait): 'abstime' arg really is
+ absolute time. Calculate relative time to wait from current
+ time before passing timeout to new routine
+ pthreadCancelableTimedWait().
+
+Tue Jan 19 10:27:39 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (pthread_mutexattr_setforcecs_np): New prototype.
+
+ * mutex.c (pthread_mutexattr_init): Init 'pshared' and 'forcecs'
+ attributes to 0.
+ (pthread_mutexattr_setforcecs_np): New function (not portable).
+
+ * pthread.h (pthread_mutex_t):
+ Add 'mutex' element. Set to NULL in PTHREAD_MUTEX_INITIALIZER.
+ The pthread_mutex_*() routines will try to optimise performance
+ by choosing either mutexes or critical sections as the basis
+ for pthread mutexes for each indevidual mutex.
+ (pthread_mutexattr_t_): Add 'forcecs' element.
+ Some applications may choose to force use of critical sections
+ if they know that:-
+ the mutex is PROCESS_PRIVATE and,
+ either the OS supports TryEnterCriticalSection() or
+ pthread_mutex_trylock() will never be called on the mutex.
+ This attribute will be setable via a non-portable routine.
+
+ Note: We don't yet support PROCESS_SHARED mutexes, so the
+ implementation as it stands will default to Win32 mutexes only if
+ the OS doesn't support TryEnterCriticalSection. On Win9x, and early
+ versions of NT 'forcecs' will need to be set in order to get
+ critical section based mutexes.
+
+Sun Jan 17 12:01:26 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (PTHREAD_MUTEX_INITIALIZER): Init new 'staticinit'
+ value to '1' and existing 'valid' value to '1'.
+
+ * global.c (ptw32_mutex_test_init_lock): Add.
+
+ * implement.h (ptw32_mutex_test_init_lock.): Add extern.
+
+ * private.c (ptw32_processInitialize): Init critical section for
+ global lock used by _mutex_check_need_init().
+ (ptw32_processTerminate): Ditto (:s/Init/Destroy/).
+
+ * dll.c (dllMain): Move call to FreeLibrary() so that it is only
+ called once when the process detaches.
+
+ * mutex.c (_mutex_check_need_init): New static function to test
+ and init PTHREAD_MUTEX_INITIALIZER mutexes. Provides serialised
+ access to the internal state of the uninitialised static mutex.
+ Called from pthread_mutex_trylock() and pthread_mutex_lock() which
+ do a quick unguarded test to check if _mutex_check_need_init()
+ needs to be called. This is safe as the test is conservative
+ and is repeated inside the guarded section of
+ _mutex_check_need_init(). Thus in all calls except the first
+ calls to lock static mutexes, the additional overhead to lock any
+ mutex is a single memory fetch and test for zero.
+
+ * pthread.h (pthread_mutex_t_): Add 'staticinit' member. Mutexes
+ initialised by PTHREAD_MUTEX_INITIALIZER aren't really initialised
+ until the first attempt to lock it. Using the 'valid'
+ flag (which flags the mutex as destroyed or not) to record this
+ information would be messy. It is possible for a statically
+ initialised mutex such as this to be destroyed before ever being
+ used.
+
+ * mutex.c (pthread_mutex_trylock): Call _mutex_check_need_init()
+ to test/init PTHREAD_MUTEX_INITIALIZER mutexes.
+ (pthread_mutex_lock): Ditto.
+ (pthread_mutex_unlock): Add check to ensure we don't try to unlock
+ an unitialised static mutex.
+ (pthread_mutex_destroy): Add check to ensure we don't try to delete
+ a critical section that we never created. Allows us to destroy
+ a static mutex that has never been locked (and hence initialised).
+ (pthread_mutex_init): Set 'staticinit' flag to 0 for the new mutex.
+
+Sun Jan 17 12:01:26 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c (ptw32_sem_timedwait): Move from semaphore.c.
+
+ * semaphore.c : Remove redundant #includes.
+ (ptw32_sem_timedwait): Move to private.c.
+ (sem_wait): Add missing abstime arg to pthreadCancelableWait() call.
+
+Fri Jan 15 23:38:05 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * condvar.c (cond_timedwait): Remove comment.
+
+Fri Jan 15 15:41:28 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * pthread.h: Add new 'abstime' arg to pthreadCancelableWait()
+ prototype.
+
+ * condvar.c (cond_timedwait): New generalised function called by
+ both pthread_cond_wait() and pthread_cond_timedwait(). This is
+ essentially pthread_cond_wait() renamed and modified to add the
+ 'abstime' arg and call the new ptw32_sem_timedwait() instead of
+ sem_wait().
+ (pthread_cond_wait): Now just calls the internal static
+ function cond_timedwait() with an INFINITE wait.
+ (pthread_cond_timedwait): Now implemented. Calls the internal
+ static function cond_timedwait().
+
+ * implement.h (ptw32_sem_timedwait): New internal function
+ prototype.
+
+ * misc.c (pthreadCancelableWait): Added new 'abstime' argument
+ to allow shorter than INFINITE wait.
+
+ * semaphore.c (ptw32_sem_timedwait): New function for internal
+ use. This is essentially sem_wait() modified to add the
+ 'abstime' arg and call the modified (see above)
+ pthreadCancelableWait().
+
+Thu Jan 14 14:27:13 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * cleanup.c: Correct _cplusplus to __cplusplus wherever used.
+
+ * Makefile.in: Add CC=g++ and add -fhandle-exceptions to CFLAGS.
+ The derived Makefile will compile all units of the package as C++
+ so that those which include try/catch exception handling should work
+ properly. The package should compile ok if CC=gcc, however, exception
+ handling will not be included and thus thread cancellation, for
+ example, will not work.
+
+ * cleanup.c (ptw32_pop_cleanup): Add #warning to compile this
+ file as C++ if using a cygwin32 environment. Perhaps the whole package
+ should be compiled using g++ under cygwin.
+
+ * private.c (ptw32_threadStart): Change #error directive
+ into #warning and bracket for __CYGWIN__ and derivative compilers.
+
+Wed Jan 13 09:34:52 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * build.bat: Delete old binaries before compiling/linking.
+
+Tue Jan 12 09:58:38 1999 Tor Lillqvist <tml@iki.fi>
+
+ * dll.c: The Microsoft compiler pragmas probably are more
+ appropriately protected by _MSC_VER than by _WIN32.
+
+ * pthread.h: Define ETIMEDOUT. This should be returned by
+ pthread_cond_timedwait which is not implemented yet as of
+ snapshot-1999-01-04-1305. It was implemented in the older version.
+ The Microsoft compiler pragmas probably are more appropriately
+ protected by _MSC_VER than by _WIN32.
+
+ * pthread.def: pthread_mutex_destroy was missing from the def file
+
+ * condvar.c (pthread_cond_broadcast): Ensure we only wait on threads
+ if there were any waiting on the condition.
+ I think pthread_cond_broadcast should do the WaitForSingleObject
+ only if cv->waiters > 0? Otherwise it seems to hang, at least in the
+ testg thread program from glib.
+
+Tue Jan 12 09:58:38 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * condvar.c (pthread_cond_timedwait): Fix function description
+ comments.
+
+ * semaphore.c (sem_post): Correct typo in comment.
+
+Mon Jan 11 20:33:19 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h: Re-arrange conditional compile of pthread_cleanup-*
+ macros.
+
+ * cleanup.c (ptw32_push_cleanup): Provide conditional
+ compile of cleanup->prev.
+
+1999-01-11 Tor Lillqvist <tml@iki.fi>
+
+ * condvar.c (pthread_cond_init): Invert logic when testing the
+ return value from calloc().
+
+Sat Jan 9 14:32:08 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h: Compile-time switch for CYGWIN derived environments
+ to use CreateThread instead of _beginthreadex. Ditto for ExitThread.
+ Patch provided by Anders Norlander <anorland@hem2.passagen.se>.
+
+Tue Jan 5 16:33:04 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * cleanup.c (ptw32_pop_cleanup): Add C++ version of __try/__except
+ block. Move trailing "}" out of #ifdef _WIN32 block left there by
+ (rpj's) mistake.
+
+ * private.c: Remove #include <errno.h> which is included by pthread.h.
+
+1998-12-11 Ben Elliston <bje@toilet.to.cygnus.com>
+
+ * README: Update info about subscribing to the mailing list.
+
+Mon Jan 4 11:23:40 1999 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * all: No code changes, just cleanup.
+ - remove #if 0 /* Pre Bossom */ enclosed code.
+ - Remove some redundant #includes.
+ * pthread.h: Update implemented/unimplemented routines list.
+ * Tag the bossom merge branch getting ready to merge back to main
+ trunk.
+
+Tue Dec 29 13:11:16 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h: Move the following struct definitions to pthread.h:
+ pthread_t_, pthread_attr_t_, pthread_mutex_t_, pthread_mutex_t_,
+ pthread_mutexattr_t_, pthread_key_t_, pthread_cond_t_,
+ pthread_condattr_t_, pthread_once_t_.
+
+ * pthread.h: Add "_" prefix to pthread_push_cleanup and
+ pthread_pop_cleanup internal routines, and associated struct and
+ typedefs.
+
+ * buildlib.bat: Add compile command for semaphore.c
+
+ * pthread.def: Comment out pthread_atfork routine name.
+ Now unimplemented.
+
+ * tsd.c (pthread_setspecific): Rename tkAssocCreate to
+ ptw32_tkAssocCreate.
+ (pthread_key_delete): Rename tkAssocDestroy to
+ ptw32_tkAssocDestroy.
+
+ * sync.c (pthread_join): Rename threadDestroy to ptw32_threadDestroy
+
+ * sched.c (is_attr): attr is now **attr (was *attr), so add extra
+ NULL pointer test.
+ (pthread_attr_setschedparam): Increase redirection for attr which is
+ now a **.
+ (pthread_attr_getschedparam): Ditto.
+ (pthread_setschedparam): Change thread validation and rename "thread"
+ Win32 thread Handle element name to match John Bossom's version.
+ (pthread_getschedparam): Ditto.
+
+ * private.c (ptw32_threadDestroy): Rename call to
+ callUserDestroyRoutines() as ptw32_callUserDestroyRoutines()
+
+ * misc.c: Add #include "implement.h".
+
+ * dll.c: Remove defined(KLUDGE) wrapped code.
+
+ * fork.c: Remove redefinition of ENOMEM.
+ Remove pthread_atfork() and fork() with #if 0/#endif.
+
+ * create.c (pthread_create): Rename threadStart and threadDestroy calls
+ to ptw32_threadStart and ptw32_threadDestroy.
+
+ * implement.h: Rename "detachedstate" to "detachstate".
+
+ * attr.c: Rename "detachedstate" to "detachstate".
+
+Mon Dec 28 09:54:39 1998 John Bossom
+
+ * semaphore.c: Initial version.
+ * semaphore.h: Initial version.
+
+Mon Dec 28 09:54:39 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (pthread_attr_t_): Change to *pthread_attr_t.
+
+Mon Dec 28 09:54:39 1998 John Bossom, Ben Elliston
+
+ * attr.c (pthread_attr_setstacksize): Merge with John's version.
+ (pthread_attr_getstacksize): Merge with John's version.
+ (pthread_attr_setstackaddr): Merge with John's version.
+ (pthread_attr_getstackaddr): Merge with John's version.
+ (pthread_attr_init): Merge with John's version.
+ (pthread_attr_destroy): Merge with John's version.
+ (pthread_attr_getdetachstate): Merge with John's version.
+ (pthread_attr_setdetachstate): Merge with John's version.
+ (is_attr): attr is now **attr (was *attr), so add extra NULL pointer
+ test.
+
+Mon Dec 28 09:54:39 1998 Ross Johnson
+
+ * implement.h (pthread_attr_t_): Add and rename elements in JEB's
+ version to correspond to original, so that it can be used with
+ original attr routines.
+
+ * pthread.h: Add #endif at end which was truncated in merging.
+
+Sun Dec 20 14:51:58 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * misc.c (pthreadCancelableWait): New function by John Bossom. Non-standard
+ but provides a hook that can be used to implement cancellation points in
+ applications that use this library.
+
+ * pthread.h (pthread_cleanup_pop): C++ (non-WIN32) version uses
+ try/catch to emulate John Bossom's WIN32 __try/__finally behaviour.
+ In the WIN32 version __finally block, add a test for AbnormalTermination otherwise
+ cleanup is only run if the cleanup_pop execute arg is non-zero. Cancellation
+ should cause the cleanup to run irrespective of the execute arg.
+
+ * condvar.c (pthread_condattr_init): Replaced by John Bossom's version.
+ (pthread_condattr_destroy): Replaced by John Bossom's version.
+ (pthread_condattr_getpshared): Replaced by John Bossom's version.
+ (pthread_condattr_setpshared): Replaced by John Bossom's version.
+ (pthread_cond_init): Replaced by John Bossom's version.
+ Fix comment (refered to mutex rather than condition variable).
+ (pthread_cond_destroy): Replaced by John Bossom's version.
+ (pthread_cond_wait): Replaced by John Bossom's version.
+ (pthread_cond_timedwait): Replaced by John Bossom's version.
+ (pthread_cond_signal): Replaced by John Bossom's version.
+ (pthread_cond_broadcast): Replaced by John Bossom's version.
+
+Thu Dec 17 19:10:46 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * tsd.c (pthread_key_create): Replaced by John Bossom's version.
+ (pthread_key_delete): Replaced by John Bossom's version.
+ (pthread_setspecific): Replaced by John Bossom's version.
+ (pthread_getspecific): Replaced by John Bossom's version.
+
+Mon Dec 7 09:44:40 1998 John Bossom
+
+ * cancel.c (pthread_setcancelstate): Replaced.
+ (pthread_setcanceltype): Replaced.
+ (pthread_testcancel): Replaced.
+ (pthread_cancel): Replaced.
+
+ * exit.c (pthread_exit): Replaced.
+
+ * misc.c (pthread_self): Replaced.
+ (pthread_equal): Replaced.
+
+ * sync.c (pthread_detach): Replaced.
+ (pthread_join): Replaced.
+
+ * create.c (pthread_create): Replaced.
+
+ * private.c (ptw32_processInitialize): New.
+ (ptw32_processTerminate): New.
+ (ptw32_threadStart): New.
+ (ptw32_threadDestroy): New.
+ (ptw32_cleanupStack): New.
+ (ptw32_tkAssocCreate): New.
+ (ptw32_tkAssocDestroy): New.
+ (ptw32_callUserDestroyRoutines): New.
+
+ * implement.h: Added non-API structures and declarations.
+
+ * dll.c (PthreadsEntryPoint): Cast return value of GetProcAddress
+ to resolve compile warning from MSVC.
+
+ * dll.c (DLLmain): Replaced.
+ * dll.c (PthreadsEntryPoint):
+ Re-applied Anders Norlander's patch:-
+ Initialize ptw32_try_enter_critical_section at startup
+ and release kernel32 handle when DLL is being unloaded.
+
+Sun Dec 6 21:54:35 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * buildlib.bat: Fix args to CL when building the .DLL
+
+ * cleanup.c (ptw32_destructor_run_all): Fix TSD key management.
+ This is a tidy-up before TSD and Thread management is completely
+ replaced by John Bossom's code.
+
+ * tsd.c (pthread_key_create): Fix TSD key management.
+
+ * global.c (ptw32_key_virgin_next): Initialise.
+
+ * build.bat: New DOS script to compile and link a pthreads app
+ using Microsoft's CL compiler linker.
+ * buildlib.bat: New DOS script to compile all the object files
+ and create pthread.lib and pthread.dll using Microsoft's CL
+ compiler linker.
+
+1998-12-05 Anders Norlander <anorland@hem2.passagen.se>
+
+ * implement.h (ptw32_try_enter_critical_section): New extern
+ * dll.c (ptw32_try_enter_critical_section): New pointer to
+ TryEnterCriticalSection if it exists; otherwise NULL.
+ * dll.c (PthreadsEntryPoint):
+ Initialize ptw32_try_enter_critical_section at startup
+ and release kernel32 handle when DLL is being unloaded.
+ * mutex.c (pthread_mutex_trylock): Replaced check for NT with
+ a check if ptw32_try_enter_critical_section is valid
+ pointer to a function. Call ptw32_try_enter_critical_section
+ instead of TryEnterCriticalSection to avoid errors on Win95.
+
+Thu Dec 3 13:32:00 1998 Ross Johnson <rpj@ise.canberra.edu.au>
+
+ * README: Correct cygwin32 compatibility statement.
+
+Sun Nov 15 21:24:06 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * cleanup.c (ptw32_destructor_run_all): Declare missing void * arg.
+ Fixup CVS merge conflicts.
+
+1998-10-30 Ben Elliston <bje@cygnus.com>
+
+ * condvar.c (cond_wait): Fix semantic error. Test for equality
+ instead of making an assignment.
+
+Fri Oct 30 15:15:50 1998 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * cleanup.c (ptw32_handler_push): Fixed bug appending new
+ handler to list reported by Peter Slacik
+ <Peter.Slacik@leibinger.freinet.de>.
+ (new_thread): Rename poorly named local variable to
+ "new_handler".
+
+Sat Oct 24 18:34:59 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * global.c: Add TSD key management array and index declarations.
+
+ * implement.h: Ditto for externs.
+
+Fri Oct 23 00:08:09 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h (PTW32_TSD_KEY_REUSE): Add enum.
+
+ * private.c (ptw32_delete_thread): Add call to
+ ptw32_destructor_run_all() to clean up the threads keys.
+
+ * cleanup.c (ptw32_destructor_run_all): Check for no more dirty
+ keys to run destructors on. Assume that the destructor call always
+ succeeds and set the key value to NULL.
+
+Thu Oct 22 21:44:44 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * tsd.c (pthread_setspecific): Add key management code.
+ (pthread_key_create): Ditto.
+ (pthread_key_delete): Ditto.
+
+ * implement.h (struct ptw32_tsd_key): Add status member.
+
+ * tsd.c: Add description of pthread_key_delete() from the
+ standard as a comment.
+
+Fri Oct 16 17:38:47 1998 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * cleanup.c (ptw32_destructor_run_all): Fix and improve
+ stepping through the key table.
+
+Thu Oct 15 14:05:01 1998 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * private.c (ptw32_new_thread): Remove init of destructorstack.
+ No longer an element of pthread_t.
+
+ * tsd.c (pthread_setspecific): Fix type declaration and cast.
+ (pthread_getspecific): Ditto.
+ (pthread_getspecific): Change error return value to NULL if key
+ is not in use.
+
+Thu Oct 15 11:53:21 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * global.c (ptw32_tsd_key_table): Fix declaration.
+
+ * implement.h(ptw32_TSD_keys_TlsIndex): Add missing extern.
+ (ptw32_tsd_mutex): Ditto.
+
+ * create.c (ptw32_start_call): Fix "keys" array declaration.
+ Add comment.
+
+ * tsd.c (pthread_setspecific): Fix type declaration and cast.
+ (pthread_getspecific): Ditto.
+
+ * cleanup.c (ptw32_destructor_run_all): Declare missing loop
+ counter.
+
+Wed Oct 14 21:09:24 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c (ptw32_new_thread): Increment ptw32_threads_count.
+ (ptw32_delete_thread): Decrement ptw32_threads_count.
+ Remove some comments.
+
+ * exit.c (ptw32_exit): : Fix two pthread_mutex_lock() calls that
+ should have been pthread_mutex_unlock() calls.
+ (ptw32_vacuum): Remove call to ptw32_destructor_pop_all().
+
+ * create.c (pthread_create): Fix two pthread_mutex_lock() calls that
+ should have been pthread_mutex_unlock() calls.
+
+ * global.c (ptw32_tsd_mutex): Add mutex for TSD operations.
+
+ * tsd.c (pthread_key_create): Add critical section.
+ (pthread_setspecific): Ditto.
+ (pthread_getspecific): Ditto.
+ (pthread_key_delete): Ditto.
+
+ * sync.c (pthread_join): Fix two pthread_mutex_lock() calls that
+ should have been pthread_mutex_unlock() calls.
+
+Mon Oct 12 00:00:44 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h (ptw32_tsd_key_table): New.
+
+ * create.c (ptw32_start_call): Initialise per-thread TSD keys
+ to NULL.
+
+ * misc.c (pthread_once): Correct typo in comment.
+
+ * implement.h (ptw32_destructor_push): Remove.
+ (ptw32_destructor_pop): Remove.
+ (ptw32_destructor_run_all): Rename from ptw32_destructor_pop_all.
+ (PTW32_TSD_KEY_DELETED): Add enum.
+ (PTW32_TSD_KEY_INUSE): Add enum.
+
+ * cleanup.c (ptw32_destructor_push): Remove.
+ (ptw32_destructor_pop): Remove.
+ (ptw32_destructor_run_all): Totally revamped TSD.
+
+ * dll.c (ptw32_TSD_keys_TlsIndex): Initialise.
+
+ * tsd.c (pthread_setspecific): Totally revamped TSD.
+ (pthread_getspecific): Ditto.
+ (pthread_create): Ditto.
+ (pthread_delete): Ditto.
+
+Sun Oct 11 22:44:55 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * global.c (ptw32_tsd_key_table): Add new global.
+
+ * implement.h (ptw32_tsd_key_t and struct ptw32_tsd_key):
+ Add.
+ (struct _pthread): Remove destructorstack.
+
+ * cleanup.c (ptw32_destructor_run_all): Rename from
+ ptw32_destructor_pop_all. The key destructor stack was made
+ global rather than per-thread. No longer removes destructor nodes
+ from the stack. Comments updated.
+
+1998-10-06 Ben Elliston <bje@cygnus.com>
+
+ * condvar.c (cond_wait): Use POSIX, not Win32 mutex calls.
+ (pthread_cond_broadcast): Likewise.
+ (pthread_cond_signal): Likewise.
+
+1998-10-05 Ben Elliston <bje@cygnus.com>
+
+ * pthread.def: Update. Some functions aren't available yet, others
+ are macros in <pthread.h>.
+
+ * tests/join.c: Remove; useless.
+
+Mon Oct 5 14:25:08 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.def: New file for building the DLL.
+
+1998-10-05 Ben Elliston <bje@cygnus.com>
+
+ * misc.c (pthread_equal): Correct inverted logic bug.
+ (pthread_once): Use the POSIX mutex primitives, not Win32. Remove
+ irrelevant FIXME comment.
+
+ * global.c (PTHREAD_MUTEX_INITIALIZER): Move to pthread.h.
+
+ * pthread.h (PTHREAD_MUTEX_INITIALIZER): Define.
+ (pthread_mutex_t): Reimplement as a struct containing a valid
+ flag. If the flag is ever down upon entry to a mutex operation,
+ we call pthread_mutex_create() to initialise the object. This
+ fixes the problem of how to handle statically initialised objects
+ that can't call InitializeCriticalSection() due to their context.
+ (PTHREAD_ONCE_INIT): Define.
+
+ * mutex.c (pthread_mutex_init): Set valid flag.
+ (pthread_mutex_destroy): Clear valid flag.
+ (pthread_mutex_lock): Check and handle the valid flag.
+ (pthread_mutex_unlock): Likewise.
+ (pthread_mutex_trylock): Likewise.
+
+ * tests/mutex3.c: New file; test for the static initialisation
+ macro. Passes.
+
+ * tests/create1.c: New file; test pthread_create(). Passes.
+
+ * tests/equal.c: Poor test; remove.
+
+ * tests/equal1.c New file; test pthread_equal(). Passes.
+
+ * tests/once1.c: New file; test for pthread_once(). Passes.
+
+ * tests/self.c: Remove; rename to self1.c.
+
+ * tests/self1.c: This is the old self.c.
+
+ * tests/self2.c: New file. Test pthread_self() with a single
+ thread. Passes.
+
+ * tests/self3.c: New file. Test pthread_self() with a couple of
+ threads to ensure their thread IDs differ. Passes.
+
+1998-10-04 Ben Elliston <bje@cygnus.com>
+
+ * tests/mutex2.c: Test pthread_mutex_trylock(). Passes.
+
+ * tests/mutex1.c: New basic test for mutex functions (it passes).
+ (main): Eliminate warning.
+
+ * configure.in: Test for __stdcall, not _stdcall. Typo.
+
+ * configure: Regenerate.
+
+ * attr.c (pthread_attr_setstackaddr): Remove FIXME comment. Win32
+ does know about ENOSYS after all.
+ (pthread_attr_setstackaddr): Likewise.
+
+1998-10-03 Ben Elliston <bje@cygnus.com>
+
+ * configure.in: Test for the `_stdcall' keyword. Define `STDCALL'
+ to `_stdcall' if we have it, null otherwise.
+
+ * configure: Regenerate.
+
+ * acconfig.h (STDCALL): New define.
+
+ * config.h.in: Regenerate.
+
+ * create.c (ptw32_start_call): Add STDCALL prefix.
+
+ * mutex.c (pthread_mutex_init): Correct function signature.
+
+ * attr.c (pthread_attr_init): Only zero out the `sigmask' member
+ if we have the sigset_t type.
+
+ * pthread.h: No need to include <unistd.h>. It doesn't even exist
+ on Win32! Again, an artifact of cross-compilation.
+ (pthread_sigmask): Only provide if we have the sigset_t type.
+
+ * process.h: Remove. This was a stand-in before we started doing
+ native compilation under Win32.
+
+ * pthread.h (pthread_mutex_init): Make `attr' argument const.
+
+1998-10-02 Ben Elliston <bje@cygnus.com>
+
+ * COPYING: Remove.
+
+ * COPYING.LIB: Add. This library is under the LGPL.
+
+1998-09-13 Ben Elliston <bje@cygnus.com>
+
+ * configure.in: Test for required system features.
+
+ * configure: Generate.
+
+ * acconfig.h: New file.
+
+ * config.h.in: Generate.
+
+ * Makefile.in: Renamed from Makefile.
+
+ * COPYING: Import from a recent GNU package.
+
+ * config.guess: Likewise.
+
+ * config.sub: Likewise.
+
+ * install-sh: Likewise.
+
+ * config.h: Remove.
+
+ * Makefile: Likewise.
+
+1998-09-12 Ben Elliston <bje@cygnus.com>
+
+ * windows.h: No longer needed; remove.
+
+ * windows.c: Likewise.
+
+Sat Sep 12 20:09:24 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * windows.h: Remove error number definitions. These are in <errno.h>
+
+ * tsd.c: Add comment explaining rationale for not building
+ POSIX TSD on top of Win32 TLS.
+
+1998-09-12 Ben Elliston <bje@cygnus.com>
+
+ * {most}.c: Include <errno.h> to get POSIX error values.
+
+ * signal.c (pthread_sigmask): Only provide if HAVE_SIGSET_T is
+ defined.
+
+ * config.h: #undef features, don't #define them. This will be
+ generated by autoconf very soon.
+
+1998-08-11 Ben Elliston <bje@cygnus.com>
+
+ * Makefile (LIB): Define.
+ (clean): Define target.
+ (all): Build a library not just the object files.
+
+ * pthread.h: Provide a definition for struct timespec if we don't
+ already have one.
+
+ * windows.c (TlsGetValue): Bug fix.
+
+Thu Aug 6 15:19:22 1998 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * misc.c (pthread_once): Fix arg 1 of EnterCriticalSection()
+ and LeaveCriticalSection() calls to pass address-of lock.
+
+ * fork.c (pthread_atfork): Typecast (void (*)(void *)) funcptr
+ in each ptw32_handler_push() call.
+
+ * exit.c (ptw32_exit): Fix attr arg in
+ pthread_attr_getdetachstate() call.
+
+ * private.c (ptw32_new_thread): Typecast (HANDLE) NULL.
+ (ptw32_delete_thread): Ditto.
+
+ * implement.h: (PTW32_MAX_THREADS): Add define. This keeps
+ changing in an attempt to make thread administration data types
+ opaque and cleanup DLL startup.
+
+ * dll.c (PthreadsEntryPoint):
+ (ptw32_virgins): Remove malloc() and free() calls.
+ (ptw32_reuse): Ditto.
+ (ptw32_win32handle_map): Ditto.
+ (ptw32_threads_mutex_table): Ditto.
+
+ * global.c (_POSIX_THREAD_THREADS_MAX): Initialise with
+ PTW32_MAX_THREADS.
+ (ptw32_virgins): Ditto.
+ (ptw32_reuse): Ditto.
+ (ptw32_win32handle_map): Ditto.
+ (ptw32_threads_mutex_table): Ditto.
+
+ * create.c (pthread_create): Typecast (HANDLE) NULL.
+ Typecast (unsigned (*)(void *)) start_routine.
+
+ * condvar.c (pthread_cond_init): Add address-of operator & to
+ arg 1 of pthread_mutex_init() call.
+ (pthread_cond_destroy): Add address-of operator & to
+ arg 1 of pthread_mutex_destroy() call.
+
+ * cleanup.c (ptw32_destructor_pop_all): Add (int) cast to
+ pthread_getspecific() arg.
+ (ptw32_destructor_pop): Add (void *) cast to "if" conditional.
+ (ptw32_destructor_push): Add (void *) cast to
+ ptw32_handler_push() "key" arg.
+ (malloc.h): Add include.
+
+ * implement.h (ptw32_destructor_pop): Add prototype.
+
+ * tsd.c (implement.h): Add include.
+
+ * sync.c (pthread_join): Remove target_thread_mutex and it's
+ initialisation. Rename getdetachedstate to getdetachstate.
+ Remove unused variable "exitcode".
+ (pthread_detach): Remove target_thread_mutex and it's
+ initialisation. Rename getdetachedstate to getdetachstate.
+ Rename setdetachedstate to setdetachstate.
+
+ * signal.c (pthread_sigmask): Rename SIG_SET to SIG_SETMASK.
+ Cast "set" to (long *) in assignment to passify compiler warning.
+ Add address-of operator & to thread->attr.sigmask in memcpy() call
+ and assignment.
+ (pthread_sigmask): Add address-of operator & to thread->attr.sigmask
+ in memcpy() call and assignment.
+
+ * windows.h (THREAD_PRIORITY_ERROR_RETURN): Add.
+ (THREAD_PRIORITY_LOWEST): Add.
+ (THREAD_PRIORITY_HIGHEST): Add.
+
+ * sched.c (is_attr): Add function.
+ (implement.h): Add include.
+ (pthread_setschedparam): Rename all instances of "sched_policy"
+ to "sched_priority".
+ (pthread_getschedparam): Ditto.
+
+Tue Aug 4 16:57:58 1998 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * private.c (ptw32_delete_thread): Fix typo. Add missing ';'.
+
+ * global.c (ptw32_virgins): Change types from pointer to
+ array pointer.
+ (ptw32_reuse): Ditto.
+ (ptw32_win32handle_map): Ditto.
+ (ptw32_threads_mutex_table): Ditto.
+
+ * implement.h(ptw32_virgins): Change types from pointer to
+ array pointer.
+ (ptw32_reuse): Ditto.
+ (ptw32_win32handle_map): Ditto.
+ (ptw32_threads_mutex_table): Ditto.
+
+ * private.c (ptw32_delete_thread): Fix "entry" should be "thread".
+
+ * misc.c (pthread_self): Add extern for ptw32_threadID_TlsIndex.
+
+ * global.c: Add comment.
+
+ * misc.c (pthread_once): Fix member -> dereferences.
+ Change ptw32_once_flag to once_control->flag in "if" test.
+
+Tue Aug 4 00:09:30 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h(ptw32_virgins): Add extern.
+ (ptw32_virgin_next): Ditto.
+ (ptw32_reuse): Ditto.
+ (ptw32_reuse_top): Ditto.
+ (ptw32_win32handle_map): Ditto.
+ (ptw32_threads_mutex_table): Ditto.
+
+ * global.c (ptw32_virgins): Changed from array to pointer.
+ Storage allocation for the array moved into dll.c.
+ (ptw32_reuse): Ditto.
+ (ptw32_win32handle_map): Ditto.
+ (ptw32_threads_mutex_table): Ditto.
+
+ * dll.c (PthreadsEntryPoint): Set up thread admin storage when
+ DLL is loaded.
+
+ * fork.c (pthread_atfork): Fix function pointer arg to all
+ ptw32_handler_push() calls. Change "arg" arg to NULL in child push.
+
+ * exit.c: Add windows.h and process.h includes.
+ (ptw32_exit): Add local detachstate declaration.
+ (ptw32_exit): Fix incorrect name for pthread_attr_getdetachstate().
+
+ * pthread.h (_POSIX_THREAD_ATTR_STACKSIZE): Move from global.c
+ (_POSIX_THREAD_ATTR_STACKADDR): Ditto.
+
+ * create.c (pthread_create): Fix #if should be #ifdef.
+ (ptw32_start_call): Remove usused variables.
+
+ * process.h: Create.
+
+ * windows.h: Move _beginthreadex and _endthreadex into
+ process.h
+
+Mon Aug 3 21:19:57 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * condvar.c (pthread_cond_init): Add NULL attr to
+ pthread_mutex_init() call - default attributes will be used.
+ (cond_wait): Fix typo.
+ (cond_wait): Fix typo - cv was ev.
+ (pthread_cond_broadcast): Fix two identical typos.
+
+ * cleanup.c (ptw32_destructor_pop_all): Remove _ prefix from
+ PTHREAD_DESTRUCTOR_ITERATIONS.
+
+ * pthread.h: Move _POSIX_* values into posix.h
+
+ * pthread.h: Fix typo in pthread_mutex_init() prototype.
+
+ * attr.c (pthread_attr_init): Fix error in priority member init.
+
+ * windows.h (THREAD_PRIORITY_NORMAL): Add.
+
+ * pthread.h (sched_param): Add missing ';' to struct definition.
+
+ * attr.c (pthread_attr_init): Remove obsolete pthread_attr_t
+ member initialisation - cancelstate, canceltype, cancel_pending.
+ (is_attr): Make arg "attr" a const.
+
+ * implement.h (PTW32_HANDLER_POP_LIFO): Remove definition.
+ (PTW32_HANDLER_POP_FIFO): Ditto.
+ (PTW32_VALID): Add missing newline escape (\).
+ (ptw32_handler_node): Make element "next" a pointer.
+
+1998-08-02 Ben Elliston <bje@cygnus.com>
+
+ * windows.h: Remove duplicate TlsSetValue() prototype. Add
+ TlsGetValue() prototype.
+ (FALSE): Define.
+ (TRUE): Likewise.
+ Add forgotten errno values. Guard against multiple #includes.
+
+ * windows.c: New file. Implement stubs for Win32 functions.
+
+ * Makefile (SRCS): Remove. Not explicitly needed.
+ (CFLAGS): Add -Wall for all warnings with GCC.
+
+Sun Aug 2 19:03:42 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * config.h: Create. This is a temporary stand-in for autoconf yet
+ to be done.
+ (HAVE_SIGNAL_H): Add.
+
+ * pthread.h: Minor rearrangement for temporary config.h.
+
+Fri Jul 31 14:00:29 1998 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * cleanup.c (ptw32_destructor_pop): Implement. Removes
+ destructors associated with a key without executing them.
+ (ptw32_destructor_pop_all): Add FIXME comment.
+
+ * tsd.c (pthread_key_delete): Add call to ptw32_destructor_pop().
+
+Fri Jul 31 00:05:45 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * tsd.c (pthread_key_create): Update to properly associate
+ the destructor routine with the key.
+ (pthread_key_delete): Add FIXME comment.
+
+ * exit.c (ptw32_vacuum): Add call to
+ ptw32_destructor_pop_all().
+
+ * implement.h (ptw32_handler_pop_all): Add prototype.
+ (ptw32_destructor_pop_all): Ditto.
+
+ * cleanup.c (ptw32_destructor_push): Implement. This is just a
+ call to ptw32_handler_push().
+ (ptw32_destructor_pop_all): Implement. This is significantly
+ different to ptw32_handler_pop_all().
+
+ * Makefile (SRCS): Create. Preliminary.
+
+ * windows.h: Create. Contains Win32 definitions for compile
+ testing. This is just a standin for the real one.
+
+ * pthread.h (SIG_UNBLOCK): Fix typo. Was SIG_BLOCK.
+ (windows.h): Add include. Required for CRITICAL_SECTION.
+ (pthread_cond_t): Move enum declaration outside of struct
+ definition.
+ (unistd.h): Add include - may be temporary.
+
+ * condvar.c (windows.h): Add include.
+
+ * implement.h (PTW32_THIS): Remove - no longer required.
+ (PTW32_STACK): Use pthread_self() instead of PTW32_THIS.
+
+Thu Jul 30 23:12:45 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h: Remove ptw32_find_entry() prototype.
+
+ * private.c: Extend comments.
+ Remove ptw32_find_entry() - no longer needed.
+
+ * create.c (ptw32_start_call): Add call to TlsSetValue() to
+ store the thread ID.
+
+ * dll.c (PthreadsEntryPoint): Implement. This is called
+ whenever a process loads the DLL. Used to initialise thread
+ local storage.
+
+ * implement.h: Add ptw32_threadID_TlsIndex.
+ Add ()s around PTW32_VALID expression.
+
+ * misc.c (pthread_self): Re-implement using Win32 TLS to store
+ the threads own ID.
+
+Wed Jul 29 11:39:03 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c: Corrections in comments.
+ (ptw32_new_thread): Alter "if" flow to be more natural.
+
+ * cleanup.c (ptw32_handler_push): Same as below.
+
+ * create.c (pthread_create): Same as below.
+
+ * private.c (ptw32_new_thread): Rename "new" to "new_thread".
+ Since when has a C programmer been required to know C++?
+
+Tue Jul 28 14:04:29 1998 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * implement.h: Add PTW32_VALID macro.
+
+ * sync.c (pthread_join): Modify to use the new thread
+ type and ptw32_delete_thread(). Rename "target" to "thread".
+ Remove extra local variable "target".
+ (pthread_detach): Ditto.
+
+ * signal.c (pthread_sigmask): Move init of "us" out of inner block.
+ Fix instance of "this" should have been "us". Rename "us" to "thread".
+
+ * sched.c (pthread_setschedparam): Modify to use the new thread
+ type.
+ (pthread_getschedparam): Ditto.
+
+ * private.c (ptw32_find_thread): Fix return type and arg.
+
+ * implement.h: Remove PTW32_YES and PTW32_NO.
+ (ptw32_new_thread): Add prototype.
+ (ptw32_find_thread): Ditto.
+ (ptw32_delete_thread): Ditto.
+ (ptw32_new_thread_entry): Remove prototype.
+ (ptw32_find_thread_entry): Ditto.
+ (ptw32_delete_thread_entry): Ditto.
+ ( PTW32_NEW, PTW32_INUSE, PTW32_EXITED, PTW32_REUSE):
+ Add.
+
+
+ * create.c (pthread_create): Minor rename "us" to "new" (I need
+ these cues but it doesn't stop me coming out with some major bugs
+ at times).
+ Load start_routine and arg into the thread so the wrapper can
+ call it.
+
+ * exit.c (pthread_exit): Fix pthread_this should be pthread_self.
+
+ * cancel.c (pthread_setcancelstate): Change
+ ptw32_threads_thread_t * to pthread_t and init with
+ pthread_this().
+ (pthread_setcanceltype): Ditto.
+
+ * exit.c (ptw32_exit): Add new pthread_t arg.
+ Rename ptw32_delete_thread_entry to ptw32_delete_thread.
+ Rename "us" to "thread".
+ (pthread_exit): Call ptw32_exit with added thread arg.
+
+ * create.c (ptw32_start_call): Insert missing ")".
+ Add "us" arg to ptw32_exit() call.
+ (pthread_create): Modify to use new thread allocation scheme.
+
+ * private.c: Added detailed explanation of the new thread
+ allocation scheme.
+ (ptw32_new_thread): Totally rewritten to use
+ new thread allocation scheme.
+ (ptw32_delete_thread): Ditto.
+ (ptw32_find_thread): Obsolete.
+
+Mon Jul 27 17:46:37 1998 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * create.c (pthread_create): Start of rewrite. Not completed yet.
+
+ * private.c (ptw32_new_thread_entry): Start of rewrite. Not
+ complete.
+
+ * implement.h (ptw32_threads_thread): Rename, remove thread
+ member, add win32handle and ptstatus members.
+ (ptw32_t): Add.
+
+ * pthread.h: pthread_t is no longer mapped directly to a Win32
+ HANDLE type. This is so we can let the Win32 thread terminate and
+ reuse the HANDLE while pthreads holds it's own thread ID until
+ the last waiting join exits.
+
+Mon Jul 27 00:20:37 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c (ptw32_delete_thread_entry): Destroy the thread
+ entry attribute object before deleting the thread entry itself.
+
+ * attr.c (pthread_attr_init): Initialise cancel_pending = FALSE.
+ (pthread_attr_setdetachstate): Rename "detached" to "detachedstate".
+ (pthread_attr_getdetachstate): Ditto.
+
+ * exit.c (ptw32_exit): Fix incorrect check for detachedstate.
+
+ * implement.h (ptw32_call_t): Remove env member.
+
+Sun Jul 26 13:06:12 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h (ptw32_new_thread_entry): Fix prototype.
+ (ptw32_find_thread_entry): Ditto.
+ (ptw32_delete_thread_entry): Ditto.
+ (ptw32_exit): Add prototype.
+
+ * exit.c (ptw32_exit): New function. Called from pthread_exit()
+ and ptw32_start_call() to exit the thread. It allows an extra
+ argument which is the return code passed to _endthreadex().
+ (ptw32_exit): Move thread entry delete call from ptw32_vacuum()
+ into here. Add more explanation of thread entry deletion.
+ (ptw32_exit): Clarify comment.
+
+ * create.c (ptw32_start_call): Change pthread_exit() call to
+ ptw32_exit() call.
+
+ * exit.c (ptw32_vacuum): Add thread entry deletion code
+ moved from ptw32_start_call(). See next item.
+ (pthread_exit): Remove longjmp(). Add mutex lock around thread table
+ manipulation code. This routine now calls _enthreadex().
+
+ * create.c (ptw32_start_call): Remove setjmp() call and move
+ cleanup code out. Call pthread_exit(NULL) to terminate the thread.
+
+1998-07-26 Ben Elliston <bje@cygnus.com>
+
+ * tsd.c (pthread_getspecific): Update comments.
+
+ * mutex.c (pthread_mutexattr_setpshared): Not supported; remove.
+ (pthread_mutexattr_getpshared): Likewise.
+
+ * pthread.h (pthread_mutexattr_setpshared): Remove prototype.
+ (pthread_mutexattr_getpshared): Likewise.
+
+Sun Jul 26 00:09:59 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * sync.c: Rename all instances of ptw32_count_mutex to
+ ptw32_table_mutex.
+
+ * implement.h: Rename ptw32_count_mutex to
+ ptw32_table_mutex.
+
+ * global.c: Rename ptw32_count_mutex to
+ ptw32_table_mutex.
+
+ * create.c (pthread_create): Add critical sections.
+ (ptw32_start_call): Rename ptw32_count_mutex to
+ ptw32_table_mutex.
+
+ * cancel.c (pthread_setcancelstate): Fix indirection bug and rename
+ "this" to "us".
+
+ * signal.c (pthread_sigmask): Rename "this" to "us" and fix some
+ minor syntax errors. Declare "us" and initialise it.
+
+ * sync.c (pthread_detach): Rename "this" to "target".
+
+ * pthread.h: Converting PTHREAD_* defines to alias the (const int)
+ values in global.c.
+
+ * global.c: Started converting PTHREAD_* defines to (const int) as
+ a part of making the eventual pthreads DLL binary compatible
+ through version changes.
+
+ * condvar.c (cond_wait): Add cancelation point. This applies the
+ point to both pthread_cond_wait() and pthread_cond_timedwait().
+
+ * exit.c (pthread_exit): Rename "this" to "us".
+
+ * implement.h: Add comment.
+
+ * sync.c (pthread_join): I've satisfied myself that pthread_detach()
+ does set the detached attribute in the thread entry attributes
+ to PTHREAD_CREATE_DETACHED. "if" conditions were changed to test
+ that attribute instead of a separate flag.
+
+ * create.c (pthread_create): Rename "this" to "us".
+ (pthread_create): cancelstate and canceltype are not attributes
+ so the copy to thread entry attribute storage was removed.
+ Only the thread itself can change it's cancelstate or canceltype,
+ ie. the thread must exist already.
+
+ * private.c (ptw32_delete_thread_entry): Mutex locks removed.
+ Mutexes must be applied at the caller level.
+ (ptw32_new_thread_entry): Ditto.
+ (ptw32_new_thread_entry): Init cancelstate, canceltype, and
+ cancel_pending to default values.
+ (ptw32_new_thread_entry): Rename "this" to "new".
+ (ptw32_find_thread_entry): Rename "this" to "entry".
+ (ptw32_delete_thread_entry): Rename "thread_entry" to "entry".
+
+ * create.c (ptw32_start_call): Mutexes changed to
+ ptw32_count_mutex. All access to the threads table entries is
+ under the one mutex. Otherwise chaos reigns.
+
+Sat Jul 25 23:16:51 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h (ptw32_threads_thread): Move cancelstate and
+ canceltype members out of pthread_attr_t into here.
+
+ * fork.c (fork): Add comment.
+
+1998-07-25 Ben Elliston <bje@cygnus.com>
+
+ * fork.c (fork): Autoconfiscate.
+
+Sat Jul 25 00:00:13 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * create.c (ptw32_start_call): Set thread priority. Ensure our
+ thread entry is removed from the thread table but only if
+ pthread_detach() was called and there are no waiting joins.
+ (pthread_create): Set detach flag in thread entry if the
+ thread is created PTHREAD_CREATE_DETACHED.
+
+ * pthread.h (pthread_attr_t): Rename member "detachedstate".
+
+ * attr.c (pthread_attr_init): Rename attr members.
+
+ * exit.c (pthread_exit): Fix indirection mistake.
+
+ * implement.h (PTW32_THREADS_TABLE_INDEX): Add.
+
+ * exit.c (ptw32_vacuum): Fix incorrect args to
+ ptw32_handler_pop_all() calls.
+ Make thread entry removal conditional.
+
+ * sync.c (pthread_join): Add multiple join and async detach handling.
+
+ * implement.h (PTW32_THREADS_TABLE_INDEX): Add.
+
+ * global.c (ptw32_threads_mutex_table): Add.
+
+ * implement.h (ptw32_once_flag): Remove.
+ (ptw32_once_lock): Ditto.
+ (ptw32_threads_mutex_table): Add.
+
+ * global.c (ptw32_once_flag): Remove.
+ (ptw32_once_lock): Ditto.
+
+ * sync.c (pthread_join): Fix tests involving new return value
+ from ptw32_find_thread_entry().
+ (pthread_detach): Ditto.
+
+ * private.c (ptw32_find_thread_entry): Failure return code
+ changed from -1 to NULL.
+
+Fri Jul 24 23:09:33 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * create.c (pthread_create): Change . to -> in sigmask memcpy() args.
+
+ * pthread.h: (pthread_cancel): Add function prototype.
+ (pthread_testcancel): Ditto.
+
+1998-07-24 Ben Elliston <bje@cygnus.com>
+
+ * pthread.h (pthread_condattr_t): Rename dummy structure member.
+ (pthread_mutexattr_t): Likewise.
+
+Fri Jul 24 21:13:55 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * cancel.c (pthread_cancel): Implement.
+ (pthread_testcancel): Implement.
+
+ * exit.c (pthread_exit): Add comment explaining the longjmp().
+
+ * implement.h (ptw32_threads_thread_t): New member cancelthread.
+ (PTW32_YES): Define.
+ (PTW32_NO): Define.
+ (RND_SIZEOF): Remove.
+
+ * create.c (pthread_create): Rename cancelability to cancelstate.
+
+ * pthread.h (pthread_attr_t): Rename cancelability to cancelstate.
+ (PTHREAD_CANCELED): Define.
+
+1998-07-24 Ben Elliston <bje@cygnus.com>
+
+ * pthread.h (SIG_BLOCK): Define if not already defined.
+ (SIG_UNBLOCK): Likewise.
+ (SIG_SETMASK): Likewise.
+ (pthread_attr_t): Add signal mask member.
+ (pthread_sigmask): Add function prototype.
+
+ * signal.c (pthread_sigmask): Implement.
+
+ * create.c: #include <string.h> to get a prototype for memcpy().
+ (pthread_create): New threads inherit their creator's signal
+ mask. Copy the signal mask to the new thread structure if we know
+ about signals.
+
+Fri Jul 24 16:33:17 1998 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * fork.c (pthread_atfork): Add all the necessary push calls.
+ Local implementation semantics:
+ If we get an ENOMEM at any time then ALL handlers
+ (including those from previous pthread_atfork() calls) will be
+ popped off each of the three atfork stacks before we return.
+ (fork): Add all the necessary pop calls. Add the thread cancellation
+ and join calls to the child fork.
+ Add #includes.
+
+ * implement.h: (ptw32_handler_push): Fix return type and stack arg
+ type in prototype.
+ (ptw32_handler_pop): Fix stack arg type in prototype.
+ (ptw32_handler_pop_all): Fix stack arg type in prototype.
+
+ * cleanup.c (ptw32_handler_push): Change return type to int and
+ return ENOMEM if malloc() fails.
+
+ * sync.c (pthread_detach): Use equality test, not assignment.
+
+ * create.c (ptw32_start_call): Add call to Win32 CloseHandle()
+ if thread is detached.
+
+1998-07-24 Ben Elliston <bje@cygnus.com>
+
+ * sync.c (pthread_detach): Close the Win32 thread handle to
+ emulate detached (or daemon) threads.
+
+Fri Jul 24 03:00:25 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * sync.c (pthread_join): Save valueptr arg in joinvalueptr for
+ pthread_exit() to use.
+
+ * private.c (ptw32_new_thread_entry): Initialise joinvalueptr to
+ NULL.
+
+ * create.c (ptw32_start_call): Rewrite to facilitate joins.
+ pthread_exit() will do a longjmp() back to here. Does appropriate
+ cleanup and exit/return from the thread.
+ (pthread_create): _beginthreadex() now passes a pointer to our
+ thread table entry instead of just the call member of that entry.
+
+ * implement.h (ptw32_threads_thread): New member
+ void ** joinvalueptr.
+ (ptw32_call_t): New member jmpbuf env.
+
+ * exit.c (pthread_exit): Major rewrite to handle joins and handing
+ value pointer to joining thread. Uses longjmp() back to
+ ptw32_start_call().
+
+ * create.c (pthread_create): Ensure values of new attribute members
+ are copied to the thread attribute object.
+
+ * attr.c (pthread_attr_destroy): Fix merge conflicts.
+ (pthread_attr_getdetachstate): Fix merge conflicts.
+ (pthread_attr_setdetachstate): Fix merge conflicts.
+
+ * pthread.h: Fix merge conflicts.
+
+ * sync.c (pthread_join): Fix merge conflicts.
+
+Fri Jul 24 00:21:21 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * sync.c (pthread_join): Add check for valid and joinable
+ thread.
+ (pthread_detach): Implement. After checking for a valid and joinable
+ thread, it's still a no-op.
+
+ * private.c (ptw32_find_thread_entry): Bug prevented returning
+ an error value in some cases.
+
+ * attr.c (pthread_attr_setdetachedstate): Implement.
+ (pthread_attr_getdetachedstate): Implement.
+
+ * implement.h: Move more hidden definitions into here from
+ pthread.h.
+
+1998-07-24 Ben Elliston <bje@cygnus.com>
+
+ * pthread.h (PTHREAD_CREATE_JOINABLE): Define.
+ (PTHREAD_CREATE_DETACHED): Likewise.
+ (pthread_attr_t): Add new structure member `detached'.
+ (pthread_attr_getdetachstate): Add function prototype.
+ (pthread_attr_setdetachstate): Likewise.
+
+ * sync.c (pthread_join): Return if the target thread is detached.
+
+ * attr.c (pthread_attr_init): Initialise cancelability and
+ canceltype structure members.
+ (pthread_attr_getdetachstate): Implement.
+ (pthread_attr_setdetachstate): Likewise.
+
+ * implement.h (PTW32_CANCEL_DEFAULTS): Remove. Bit fields
+ proved to be too cumbersome. Set the defaults in attr.c using the
+ public PTHREAD_CANCEL_* constants.
+
+ * cancel.c: New file.
+
+ * pthread.h (sched_param): Define this type.
+ (pthread_attr_getschedparam): Add function prototype.
+ (pthread_attr_setschedparam): Likewise.
+ (pthread_setcancelstate): Likewise.
+ (pthread_setcanceltype): Likewise.
+ (sched_get_priority_min): Likewise.
+ (sched_get_priority_max): Likewise.
+ (pthread_mutexattr_setprotocol): Remove; not supported.
+ (pthread_mutexattr_getprotocol): Likewise.
+ (pthread_mutexattr_setprioceiling): Likewise.
+ (pthread_mutexattr_getprioceiling): Likewise.
+ (pthread_attr_t): Add canceltype member. Update comments.
+ (SCHED_OTHER): Define this scheduling policy constant.
+ (SCHED_FIFO): Likewise.
+ (SCHED_RR): Likewise.
+ (SCHED_MIN): Define the lowest possible value for this constant.
+ (SCHED_MAX): Likewise, the maximum possible value.
+ (PTHREAD_CANCEL_ASYNCHRONOUS): Redefine.
+ (PTHREAD_CANCEL_DEFERRED): Likewise.
+
+ * sched.c: New file.
+ (pthread_setschedparam): Implement.
+ (pthread_getschedparam): Implement.
+ (sched_get_priority_max): Validate policy argument.
+ (sched_get_priority_min): Likewise.
+
+ * mutex.c (pthread_mutexattr_setprotocol): Remove; not supported.
+ (pthread_mutexattr_getprotocol): Likewise.
+ (pthread_mutexattr_setprioceiling): Likewise.
+ (pthread_mutexattr_getprioceiling): Likewise.
+
+Fri Jul 24 00:21:21 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * create.c (pthread_create): Arg to ptw32_new_thread_entry()
+ changed. See next entry. Move mutex locks out. Changes made yesterday
+ and today allow us to start the new thread running rather than
+ temporarily suspended.
+
+ * private.c (ptw32_new_thread_entry): ptw32_thread_table
+ was changed back to a table of thread structures rather than pointers.
+ As such we're trading storage for increaded speed. This routine
+ was modified to work with the new table. Mutex lock put in around
+ global data accesses.
+ (ptw32_find_thread_entry): Ditto
+ (ptw32_delete_thread_entry): Ditto
+
+Thu Jul 23 23:25:30 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * global.c: New. Global data objects declared here. These moved from
+ pthread.h.
+
+ * pthread.h: Move implementation hidden definitions into
+ implement.h.
+
+ * implement.h: Move implementation hidden definitions from
+ pthread.h. Add constants to index into the different handler stacks.
+
+ * cleanup.c (ptw32_handler_push): Simplify args. Restructure.
+ (ptw32_handler_pop): Simplify args. Restructure.
+ (ptw32_handler_pop_all): Simplify args. Restructure.
+
+Wed Jul 22 00:16:22 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * attr.c, implement.h, pthread.h, ChangeLog: Resolve CVS merge
+ conflicts.
+
+ * private.c (ptw32_find_thread_entry): Changes to return type
+ to support leaner ptw32_threads_table[] which now only stores
+ ptw32_thread_thread_t *.
+ (ptw32_new_thread_entry): Internal changes.
+ (ptw32_delete_thread_entry): Internal changes to avoid contention.
+ Calling routines changed accordingly.
+
+ * pthread.h: Modified cleanup macros to use new generic push and pop.
+ Added destructor and atfork stacks to ptw32_threads_thread_t.
+
+ * cleanup.c (ptw32_handler_push, ptw32_handler_pop,
+ ptw32_handler_pop_all): Renamed cleanup push and pop routines
+ and made generic to handle destructors and atfork handlers as
+ well.
+
+ * create.c (ptw32_start_call): New function is a wrapper for
+ all new threads. It allows us to do some cleanup when the thread
+ returns, ie. that is otherwise only done if the thread is cancelled.
+
+ * exit.c (ptw32_vacuum): New function contains code from
+ pthread_exit() that we need in the new ptw32_start_call()
+ as well.
+
+ * implement.h: Various additions and minor changes.
+
+ * pthread.h: Various additions and minor changes.
+ Change cleanup handler macros to use generic handler push and pop
+ functions.
+
+ * attr.c: Minor mods to all functions.
+ (is_attr): Implemented missing function.
+
+ * create.c (pthread_create): More clean up.
+
+ * private.c (ptw32_find_thread_entry): Implement.
+ (ptw32_delete_thread_entry): Implement.
+ (ptw32_new_thread_entry): Implement.
+ These functions manipulate the implementations internal thread
+ table and are part of general code cleanup and modularisation.
+ They replace ptw32_getthreadindex() which was removed.
+
+ * exit.c (pthread_exit): Changed to use the new code above.
+
+ * pthread.h: Add cancelability constants. Update comments.
+
+1998-07-22 Ben Elliston <bje@cygnus.com>
+
+ * attr.c (pthread_setstacksize): Update test of attr argument.
+ (pthread_getstacksize): Likewise.
+ (pthread_setstackaddr): Likewise.
+ (pthread_getstackaddr): Likewise.
+ (pthread_attr_init): No need to allocate any storage.
+ (pthread_attr_destroy): No need to free any storage.
+
+ * mutex.c (is_attr): Not likely to be needed; remove.
+ (remove_attr): Likewise.
+ (insert_attr): Likewise.
+
+ * implement.h (ptw32_mutexattr_t): Moved to a public definition
+ in pthread.h. There was little gain in hiding these details.
+ (ptw32_condattr_t): Likewise.
+ (ptw32_attr_t): Likewise.
+
+ * pthread.h (pthread_atfork): Add function prototype.
+ (pthread_attr_t): Moved here from implement.h.
+
+ * fork.c (pthread_atfork): Preliminary implementation.
+ (ptw32_fork): Likewise.
+
+Wed Jul 22 00:16:22 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * cleanup.c (ptw32_cleanup_push): Implement.
+ (ptw32_cleanup_pop): Implement.
+ (ptw32_do_cancellation): Implement.
+ These are private to the implementation. The real cleanup functions
+ are macros. See below.
+
+ * pthread.h (pthread_cleanup_push): Implement as a macro.
+ (pthread_cleanup_pop): Implement as a macro.
+ Because these are macros which start and end a block, the POSIX scoping
+ requirement is observed. See the comment in the file.
+
+ * exit.c (pthread_exit): Refine the code.
+
+ * create.c (pthread_create): Code cleanup.
+
+ * implement.h (RND_SIZEOF): Add RND_SIZEOF(T) to round sizeof(T)
+ up to multiple of DWORD.
+ Add function prototypes.
+
+ * private.c (ptw32_getthreadindex): "*thread" should have been
+ "thread". Detect empty slot fail condition.
+
+1998-07-20 Ben Elliston <bje@cygnus.com>
+
+ * misc.c (pthread_once): Implement. Don't use a per-application
+ flag and mutex--make `pthread_once_t' contain these elements in
+ their structure. The earlier version had incorrect semantics.
+
+ * pthread.h (ptw32_once_flag): Add new variable. Remove.
+ (ptw32_once_lock): Add new mutex lock to ensure integrity of
+ access to ptw32_once_flag. Remove.
+ (pthread_once): Add function prototype.
+ (pthread_once_t): Define this type.
+
+Mon Jul 20 02:31:05 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * private.c (ptw32_getthreadindex): Implement.
+
+ * pthread.h: Add application static data dependent on
+ _PTHREADS_BUILD_DLL define. This is needed to avoid allocating
+ non-sharable static data within the pthread DLL.
+
+ * implement.h: Add ptw32_cleanup_stack_t, ptw32_cleanup_node_t
+ and PTW32_HASH_INDEX.
+
+ * exit.c (pthread_exit): Begin work on cleanup and de-allocate
+ thread-private storage.
+
+ * create.c (pthread_create): Add thread to thread table.
+ Keep a thread-private copy of the attributes with default values
+ filled in when necessary. Same for the cleanup stack. Make
+ pthread_create C run-time library friendly by using _beginthreadex()
+ instead of CreateThread(). Fix error returns.
+
+Sun Jul 19 16:26:23 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h: Rename pthreads_thread_count to ptw32_threads_count.
+ Create ptw32_threads_thread_t struct to keep thread specific data.
+
+ * create.c: Rename pthreads_thread_count to ptw32_threads_count.
+ (pthread_create): Handle errors from CreateThread().
+
+1998-07-19 Ben Elliston <bje@cygnus.com>
+
+ * condvar.c (pthread_cond_wait): Generalise. Moved from here ..
+ (cond_wait): To here.
+ (pthread_cond_timedwait): Implement; use generalised cond_wait().
+
+ * pthread.h (pthread_key_t): Define this type.
+ (pthread_key_create): Add function prototype.
+ (pthread_setspecific): Likewise.
+ (pthread_getspecific): Likwise.
+ (pthread_key_delete): Likewise.
+
+ * tsd.c (pthread_key_create): Implement.
+ (pthread_setspecific): Likewise.
+ (pthread_getspecific): Likewise.
+ (pthread_key_delete): Likewise.
+
+ * mutex.c (pthread_mutex_trylock): Return ENOSYS if this function
+ is called on a Win32 platform which is not Windows NT.
+
+1998-07-18 Ben Elliston <bje@cygnus.com>
+
+ * condvar.c (pthread_condattr_init): Do not attempt to malloc any
+ storage; none is needed now that condattr_t is an empty struct.
+ (pthread_condattr_destory): Likewise; do not free storage.
+ (pthread_condattr_setpshared): No longer supported; return ENOSYS.
+ (pthread_condattr_getpshared): Likewise.
+ (pthread_cond_init): Implement with help from Douglas Schmidt.
+ Remember to initialise the cv's internal mutex.
+ (pthread_cond_wait): Likewise.
+ (pthread_cond_signal): Likewise.
+ (pthread_cond_broadcast): Likewise.
+ (pthread_cond_timedwait): Preliminary implementation, but I need
+ to see some API documentation for `WaitForMultipleObject'.
+ (pthread_destory): Implement.
+
+ * pthread.h (pthread_cond_init): Add function protoype.
+ (pthread_cond_broadcast): Likewise.
+ (pthread_cond_signal): Likewise.
+ (pthread_cond_timedwait): Likewise.
+ (pthread_cond_wait): Likewise.
+ (pthread_cond_destroy): Likewise.
+ (pthread_cond_t): Define this type. Fix for u_int. Do not assume
+ that the mutex contained withing the pthread_cond_t structure will
+ be a critical section. Use our new POSIX type!
+
+ * implement.h (ptw32_condattr_t): Remove shared attribute.
+
+1998-07-17 Ben Elliston <bje@cygnus.com>
+
+ * pthread.h (PTHREADS_PROCESS_PRIVATE): Remove.
+ (PTHREAD_PROCESS_SHARED): Likewise. No support for mutexes shared
+ across processes for now.
+ (pthread_mutex_t): Use a Win32 CRITICAL_SECTION type for better
+ performance.
+
+ * implement.h (ptw32_mutexattr_t): Remove shared attribute.
+
+ * mutex.c (pthread_mutexattr_setpshared): This optional function
+ is no longer supported, since we want to implement POSIX mutex
+ variables using the much more efficient Win32 critical section
+ primitives. Critical section objects in Win32 cannot be shared
+ between processes.
+ (pthread_mutexattr_getpshared): Likewise.
+ (pthread_mutexattr_init): No need to malloc any storage; the
+ attributes structure is now empty.
+ (pthread_mutexattr_destroy): This is now a nop.
+ (pthread_mutex_init): Use InitializeCriticalSection().
+ (pthread_mutex_destroy): Use DeleteCriticalSection().
+ (pthread_mutex_lock): Use EnterCriticalSection().
+ (pthread_mutex_trylock): Use TryEnterCriticalSection(). This is
+ not supported by Windows 9x, but trylock is a hack anyway, IMHO.
+ (pthread_mutex_unlock): Use LeaveCriticalSection().
+
+1998-07-14 Ben Elliston <bje@cygnus.com>
+
+ * attr.c (pthread_attr_setstacksize): Implement.
+ (pthread_attr_getstacksize): Likewise.
+ (pthread_attr_setstackaddr): Likewise.
+ (pthread_attr_getstackaddr): Likewise.
+ (pthread_attr_init): Likewise.
+ (pthread_attr_destroy): Likewise.
+
+ * condvar.c (pthread_condattr_init): Add `_cond' to function name.
+
+ * mutex.c (pthread_mutex_lock): Add `_mutex' to function name.
+ (pthread_mutex_trylock): Likewise.
+ (pthread_mutex_unlock): Likewise.
+
+ * pthread.h (pthread_condattr_setpshared): Fix typo.
+ (pthread_attr_init): Add function prototype.
+ (pthread_attr_destroy): Likewise.
+ (pthread_attr_setstacksize): Likewise.
+ (pthread_attr_getstacksize): Likewise.
+ (pthread_attr_setstackaddr): Likewise.
+ (pthread_attr_getstackaddr): Likewise.
+
+Mon Jul 13 01:09:55 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h: Wrap in #ifndef _IMPLEMENT_H
+
+ * create.c (pthread_create): Map stacksize attr to Win32.
+
+ * mutex.c: Include implement.h
+
+1998-07-13 Ben Elliston <bje@cygnus.com>
+
+ * condvar.c (pthread_condattr_init): Implement.
+ (pthread_condattr_destroy): Likewise.
+ (pthread_condattr_setpshared): Likewise.
+ (pthread_condattr_getpshared): Likewise.
+
+ * implement.h (PTHREAD_THREADS_MAX): Remove trailing semicolon.
+ (PTHREAD_STACK_MIN): Specify; needs confirming.
+ (ptw32_attr_t): Define this type.
+ (ptw32_condattr_t): Likewise.
+
+ * pthread.h (pthread_mutex_t): Define this type.
+ (pthread_condattr_t): Likewise.
+ (pthread_mutex_destroy): Add function prototype.
+ (pthread_lock): Likewise.
+ (pthread_trylock): Likewise.
+ (pthread_unlock): Likewise.
+ (pthread_condattr_init): Likewise.
+ (pthread_condattr_destroy): Likewise.
+ (pthread_condattr_setpshared): Likewise.
+ (pthread_condattr_getpshared): Likewise.
+
+ * mutex.c (pthread_mutex_init): Implement.
+ (pthread_mutex_destroy): Likewise.
+ (pthread_lock): Likewise.
+ (pthread_trylock): Likewise.
+ (pthread_unlock): Likewise.
+
+1998-07-12 Ben Elliston <bje@cygnus.com>
+
+ * implement.h (ptw32_mutexattr_t): Define this implementation
+ internal type. Application programmers only see a mutex attribute
+ object as a void pointer.
+
+ * pthread.h (pthread_mutexattr_t): Define this type.
+ (pthread_mutexattr_init): Add function prototype.
+ (pthread_mutexattr_destroy): Likewise.
+ (pthread_mutexattr_setpshared): Likewise.
+ (pthread_mutexattr_getpshared): Likewise.
+ (pthread_mutexattr_setprotocol): Likewise.
+ (pthread_mutexattr_getprotocol): Likewise.
+ (pthread_mutexattr_setprioceiling): Likewise.
+ (pthread_mutexattr_getprioceiling): Likewise.
+ (PTHREAD_PROCESS_PRIVATE): Define.
+ (PTHREAD_PROCESS_SHARED): Define.
+
+ * mutex.c (pthread_mutexattr_init): Implement.
+ (pthread_mutexattr_destroy): Implement.
+ (pthread_mutexattr_setprotocol): Implement.
+ (pthread_mutexattr_getprotocol): Likewise.
+ (pthread_mutexattr_setprioceiling): Likewise.
+ (pthread_mutexattr_getprioceiling): Likewise.
+ (pthread_mutexattr_setpshared): Likewise.
+ (pthread_mutexattr_getpshared): Likewise.
+ (insert_attr): New function; very preliminary implementation!
+ (is_attr): Likewise.
+ (remove_attr): Likewise.
+
+Sat Jul 11 14:48:54 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * implement.h: Preliminary implementation specific defines.
+
+ * create.c (pthread_create): Preliminary implementation.
+
+1998-07-11 Ben Elliston <bje@cygnus.com>
+
+ * sync.c (pthread_join): Implement.
+
+ * misc.c (pthread_equal): Likewise.
+
+ * pthread.h (pthread_join): Add function prototype.
+ (pthread_equal): Likewise.
+
+1998-07-10 Ben Elliston <bje@cygnus.com>
+
+ * misc.c (pthread_self): Implement.
+
+ * exit.c (pthread_exit): Implement.
+
+ * pthread.h (pthread_exit): Add function prototype.
+ (pthread_self): Likewise.
+ (pthread_t): Define this type.
+
+1998-07-09 Ben Elliston <bje@cygnus.com>
+
+ * create.c (pthread_create): A dummy stub right now.
+
+ * pthread.h (pthread_create): Add function prototype.
diff --git a/FAQ b/FAQ
index a4fa889..2efc820 100644
--- a/FAQ
+++ b/FAQ
@@ -1,393 +1,393 @@
- =========================================
- PTHREADS-WIN32 Frequently Asked Questions
- =========================================
-
-INDEX
------
-
-Q 1 What is it?
-
-Q 2 Which of the several dll versions do I use?
- or,
- What are all these pthread*.dll and pthread*.lib files?
-
-Q 3 What is the library naming convention?
-
-Q 4 Cleanup code default style or: it used to work when I built
- the library myself, but now it doesn't - why?
-
-Q 5 Why is the default library version now less exception-friendly?
-
-Q 6 Should I use Cygwin or Mingw32 as a development environment?
-
-Q 7 Now that pthreads-win32 builds under Mingw32, why do I get
- memory access violations (segfaults)?
-
-Q 8 How do I use pthread.dll for Win32 (Visual C++ 5.0)
-
-Q 9 Cancelation doesn't work for me, why?
-
-Q 10 Thread won't block after two calls to mutex_lock
-
-Q 11 How do I generate pthreadGCE.dll and libpthreadw32.a for use with Mingw32?
-
-=============================================================================
-
-Q 1 What is it?
----
-
-Pthreads-win32 is an Open Source Software implementation of the
-Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's
-Win32 environment. Some functions from POSIX 1003.1b are also
-supported including semaphores. Other related functions include
-the set of read-write lock functions. The library also supports
-some of the functionality of the Open Group's Single Unix
-specification, version 2, namely mutex types.
-
-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?
-
-Simply, you only use one of them, but you need to choose carefully.
-
-The most important choice you need to make is whether to use a
-version that uses exceptions internally, or not (there are versions
-of the library that use exceptions as part of the thread
-cancelation and exit implementation, and one that uses
-setjmp/longjmp instead).
-
-There is some contension amongst POSIX threads experts as
-to how POSIX threads cancelation and exit should work
-with languages that include exceptions and handlers, e.g.
-C++ and even C (Microsoft's Structured Exceptions).
-
-The issue is: should cancelation of a thread in, say,
-a C++ application cause object destructors and C++ exception
-handlers to be invoked as the stack unwinds during thread
-exit, or not?
-
-There seems to be more opinion in favour of using the
-standard C version of the library (no EH) with C++ applications
-since this appears to be the assumption commercial pthreads
-implementations make. Therefore, if you use an EH version
-of pthreads-win32 then you may be under the illusion that
-your application will be portable, when in fact it is likely to
-behave very differently linked with other pthreads libraries.
-
-Now you may be asking: why have you kept the EH versions of
-the library?
-
-There are a couple of reasons:
-- there is division amongst the experts and so the code may
- be needed in the future. (Yes, it's in the repository and we
- can get it out anytime in the future, but ...)
-- pthreads-win32 is one of the few implementations, and possibly
- the only freely available one, that has EH versions. It may be
- useful to people who want to play with or study application
- behaviour under these conditions.
-
-
-------------------------------------------------------------------------------
-
-Q 3 What is the library naming convention?
----
-
-Because the library is being built using various exception
-handling schemes and compilers - and because the library
-may not work reliably if these are mixed in an application,
-each different version of the library has it's own name.
-
-Note 1: the incompatibility is really between EH implementations
-of the different compilers. It should be possible to use the
-standard C version from either compiler with C++ applications
-built with a different compiler. If you use an EH version of
-the library, then you must use the same compiler for the
-application. This is another complication and dependency that
-can be avoided by using only the standard C library version.
-
-Note 2: if you use a standard C pthread*.dll with a C++
-application, then any functions that you define that are
-intended to be called via pthread_cleanup_push() must be
-__cdecl.
-
-Note 3: the intention is to also name either the VC or GC
-version (it should be arbitrary) as pthread.dll, including
-pthread.lib and libpthread.a as appropriate.
-
-In general:
- pthread[VG]{SE,CE,C}.dll
- pthread[VG]{SE,CE,C}.lib
-
-where:
- [VG] indicates the compiler
- V - MS VC
- G - GNU C
-
- {SE,CE,C} indicates the exception handling scheme
- SE - Structured EH
- CE - C++ EH
- C - no exceptions - uses setjmp/longjmp
-
-For example:
- pthreadVSE.dll (MSVC/SEH)
- pthreadGCE.dll (GNUC/C++ EH)
- pthreadGC.dll (GNUC/not dependent on exceptions)
-
-The GNU library archive file names have changed to:
-
- libpthreadGCE.a
- 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?
-
-Up to and including snapshot 2001-07-12, if not defined, the cleanup
-style was determined automatically from the compiler used, and one
-of the following was defined accordingly:
-
- __CLEANUP_SEH MSVC only
- __CLEANUP_CXX C++, including MSVC++, GNU G++
- __CLEANUP_C C, including GNU GCC, not MSVC
-
-These defines determine the style of cleanup (see pthread.h) and,
-most importantly, the way that cancelation and thread exit (via
-pthread_exit) is performed (see the routine ptw32_throw() in private.c).
-
-In short, the exceptions versions of the library throw an exception
-when a thread is canceled or exits (via pthread_exit()), which is
-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().
-
-After snapshot 2001-07-12, unless your 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.
-
-Although it was not clearly documented before, it is still necessary to
-build your application using the same __CLEANUP_* define as was
-used for the version of the library that you link with, so that the
-correct parts of pthread.h are included. That is, the possible
-defines require the following library versions:
-
- __CLEANUP_SEH pthreadVSE.dll
- __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll
- __CLEANUP_C pthreadVC.dll or pthreadGC.dll
-
-THE POINT OF ALL THIS IS: if you have not been defining one of these
-explicitly, then the defaults have been set according to the compiler
-and language you are using, as described at the top of this
-section.
-
-THIS NOW CHANGES, as has been explained above. For 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.
-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 is canceled, nor when the thread calls pthread_exit().
-
-Your application will now most likely behave differently to previous
-versions, and in non-obvious ways. Most likely is that local
-objects may not be destroyed or cleaned up after a thread
-is canceled.
-
-If you want the same behaviour as before, then you must now define
-__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 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:
-- because there are well respected POSIX threads people who believe
- that POSIX threads implementations should be exceptions-aware and
- do the expected thing in that context. (There are equally respected
- people who believe it should not be easily accessible, if it's there
- at all.)
-- because pthreads-win32 is one of the few implementations that has
- the choice, perhaps the only freely available one, and so offers
- a laboratory to people who may want to explore the effects;
-- although the code will always be around somewhere for anyone who
- wants it, once it's removed from the current version it will not be
- 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.
-
-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)?
-
-The latest Mingw32 package has thread-safe exception handling (see Q10).
-Also, see Q6 above.
-
-------------------------------------------------------------------------------
-
-Q 8 How do I use pthread.dll for Win32 (Visual C++ 5.0)
----
-
->
-> I'm a "rookie" when it comes to your pthread implementation. I'm currently
-> desperately trying to install the prebuilt .dll file into my MSVC compiler.
-> Could you please provide me with explicit instructions on how to do this (or
-> direct me to a resource(s) where I can acquire such information)?
->
-> Thank you,
->
-
-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.
-
-The .lib file can go in any directory listed in your LIB environment
-variable.
-
-The .h files can go in any directory listed in your INCLUDE
-environment variable.
-
-Or you might prefer to put the .lib and .h files into a new directory
-and add its path to LIB and INCLUDE. You can probably do this easiest
-by editing the file:-
-
-C:\Program Files\DevStudio\vc\bin\vcvars32.bat
-
-The .def file isn't used by anything in the pre-compiled version but
-is included for information.
-
-Cheers.
-Ross
-
-------------------------------------------------------------------------------
-
-Q 9 Cancelation doesn't work for me, why?
----
-
-> I'm investigating a problem regarding thread cancelation. The thread I want
-> to cancel has PTHREAD_CANCEL_ASYNCHRONOUS, however, this piece of code
-> blocks on the join():
->
-> if ((retv = Pthread_cancel( recvThread )) == 0)
-> {
-> retv = Pthread_join( recvThread, 0 );
-> }
->
-> Pthread_* are just macro's; they call pthread_*.
->
-> The thread recvThread seems to block on a select() call. It doesn't get
-> cancelled.
->
-> Two questions:
->
-> 1) is this normal behaviour?
->
-> 2) if not, how does the cancel mechanism work? I'm not very familliar to
-> win32 programming, so I don't really understand how the *Event() family of
-> calls work.
-
-Async cancelation should be in versions post snapshot-1999-11-02
-of pthreads-win32 (currently only for x86 architectures).
-
-The answer to your first question is, normal POSIX behaviour would
-be to asynchronously cancel the thread. However, even that doesn't
-guarantee cancelation as the standard only says it should be
-cancelled as soon as possible.
-
-However ...
-
-Snapshot 99-11-02 or earlier only partially supports asynchronous cancellation.
-Snapshots since then simulate async cancelation by poking the address of
-a cancelation routine into the PC of the threads context. This requires
-the thread to be resumed in some way for the cancelation to actually
-proceed. This is not true async cancelation, but it is as close as we've
-been able to get to it.
-
-If the thread you're trying to cancel is blocked (for instance, it could be
-waiting for data from the network), it will only get cancelled when it unblocks
-(when the data arrives). Unfortunately, there is no way to do so from
-outside the thread.
-
-Using deferred cancelation would normally be the way to go, however,
-even though the POSIX threads standard lists a number of C library
-functions that are defined as deferred cancelation points, there is
-no hookup between those which are provided by Windows and the
-pthreads-win32 library.
-
-Incidently, it's worth noting for code portability that the POSIX
-threads standard list doesn't include "select" because (as I read in
-Butenhof) it isn't part of POSIX.
-
-Effectively, the only cancelation points that pthreads-win32 can
-recognise are those the library implements itself, ie.
-
- pthread_testcancel
- pthread_cond_wait
- pthread_cond_timedwait
- pthread_join
- sem_wait
- pthread_delay_np
-
-Pthreads-win32 also provides two functions that allow you to create
-cancelation points within your application, but only for cases where
-a thread is going to block on a Win32 handle. These are:
-
- pthreadCancelableWait(HANDLE waitHandle) /* Infinite wait */
-
- pthreadCancelableTimedWait(HANDLE waitHandle, DWORD timeout)
-
-Regards.
-Ross
-
-------------------------------------------------------------------------------
-
-
-Q 10 How do I create thread-safe applications using
----- pthreadGCE.dll, libpthreadw32.a and Mingw32?
-
-See Thomas Pfaff's email at:
-http://sources.redhat.com/ml/pthreads-win32/2002/msg00000.html
-
-------------------------------------------------------------------------------
-
+ =========================================
+ PTHREADS-WIN32 Frequently Asked Questions
+ =========================================
+
+INDEX
+-----
+
+Q 1 What is it?
+
+Q 2 Which of the several dll versions do I use?
+ or,
+ What are all these pthread*.dll and pthread*.lib files?
+
+Q 3 What is the library naming convention?
+
+Q 4 Cleanup code default style or: it used to work when I built
+ the library myself, but now it doesn't - why?
+
+Q 5 Why is the default library version now less exception-friendly?
+
+Q 6 Should I use Cygwin or Mingw32 as a development environment?
+
+Q 7 Now that pthreads-win32 builds under Mingw32, why do I get
+ memory access violations (segfaults)?
+
+Q 8 How do I use pthread.dll for Win32 (Visual C++ 5.0)
+
+Q 9 Cancelation doesn't work for me, why?
+
+Q 10 Thread won't block after two calls to mutex_lock
+
+Q 11 How do I generate pthreadGCE.dll and libpthreadw32.a for use with Mingw32?
+
+=============================================================================
+
+Q 1 What is it?
+---
+
+Pthreads-win32 is an Open Source Software implementation of the
+Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's
+Win32 environment. Some functions from POSIX 1003.1b are also
+supported including semaphores. Other related functions include
+the set of read-write lock functions. The library also supports
+some of the functionality of the Open Group's Single Unix
+specification, version 2, namely mutex types.
+
+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?
+
+Simply, you only use one of them, but you need to choose carefully.
+
+The most important choice you need to make is whether to use a
+version that uses exceptions internally, or not (there are versions
+of the library that use exceptions as part of the thread
+cancelation and exit implementation, and one that uses
+setjmp/longjmp instead).
+
+There is some contension amongst POSIX threads experts as
+to how POSIX threads cancelation and exit should work
+with languages that include exceptions and handlers, e.g.
+C++ and even C (Microsoft's Structured Exceptions).
+
+The issue is: should cancelation of a thread in, say,
+a C++ application cause object destructors and C++ exception
+handlers to be invoked as the stack unwinds during thread
+exit, or not?
+
+There seems to be more opinion in favour of using the
+standard C version of the library (no EH) with C++ applications
+since this appears to be the assumption commercial pthreads
+implementations make. Therefore, if you use an EH version
+of pthreads-win32 then you may be under the illusion that
+your application will be portable, when in fact it is likely to
+behave very differently linked with other pthreads libraries.
+
+Now you may be asking: why have you kept the EH versions of
+the library?
+
+There are a couple of reasons:
+- there is division amongst the experts and so the code may
+ be needed in the future. (Yes, it's in the repository and we
+ can get it out anytime in the future, but ...)
+- pthreads-win32 is one of the few implementations, and possibly
+ the only freely available one, that has EH versions. It may be
+ useful to people who want to play with or study application
+ behaviour under these conditions.
+
+
+------------------------------------------------------------------------------
+
+Q 3 What is the library naming convention?
+---
+
+Because the library is being built using various exception
+handling schemes and compilers - and because the library
+may not work reliably if these are mixed in an application,
+each different version of the library has it's own name.
+
+Note 1: the incompatibility is really between EH implementations
+of the different compilers. It should be possible to use the
+standard C version from either compiler with C++ applications
+built with a different compiler. If you use an EH version of
+the library, then you must use the same compiler for the
+application. This is another complication and dependency that
+can be avoided by using only the standard C library version.
+
+Note 2: if you use a standard C pthread*.dll with a C++
+application, then any functions that you define that are
+intended to be called via pthread_cleanup_push() must be
+__cdecl.
+
+Note 3: the intention is to also name either the VC or GC
+version (it should be arbitrary) as pthread.dll, including
+pthread.lib and libpthread.a as appropriate.
+
+In general:
+ pthread[VG]{SE,CE,C}.dll
+ pthread[VG]{SE,CE,C}.lib
+
+where:
+ [VG] indicates the compiler
+ V - MS VC
+ G - GNU C
+
+ {SE,CE,C} indicates the exception handling scheme
+ SE - Structured EH
+ CE - C++ EH
+ C - no exceptions - uses setjmp/longjmp
+
+For example:
+ pthreadVSE.dll (MSVC/SEH)
+ pthreadGCE.dll (GNUC/C++ EH)
+ pthreadGC.dll (GNUC/not dependent on exceptions)
+
+The GNU library archive file names have changed to:
+
+ libpthreadGCE.a
+ 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?
+
+Up to and including snapshot 2001-07-12, if not defined, the cleanup
+style was determined automatically from the compiler used, and one
+of the following was defined accordingly:
+
+ __CLEANUP_SEH MSVC only
+ __CLEANUP_CXX C++, including MSVC++, GNU G++
+ __CLEANUP_C C, including GNU GCC, not MSVC
+
+These defines determine the style of cleanup (see pthread.h) and,
+most importantly, the way that cancelation and thread exit (via
+pthread_exit) is performed (see the routine ptw32_throw() in private.c).
+
+In short, the exceptions versions of the library throw an exception
+when a thread is canceled or exits (via pthread_exit()), which is
+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().
+
+After snapshot 2001-07-12, unless your 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.
+
+Although it was not clearly documented before, it is still necessary to
+build your application using the same __CLEANUP_* define as was
+used for the version of the library that you link with, so that the
+correct parts of pthread.h are included. That is, the possible
+defines require the following library versions:
+
+ __CLEANUP_SEH pthreadVSE.dll
+ __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll
+ __CLEANUP_C pthreadVC.dll or pthreadGC.dll
+
+THE POINT OF ALL THIS IS: if you have not been defining one of these
+explicitly, then the defaults have been set according to the compiler
+and language you are using, as described at the top of this
+section.
+
+THIS NOW CHANGES, as has been explained above. For 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.
+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 is canceled, nor when the thread calls pthread_exit().
+
+Your application will now most likely behave differently to previous
+versions, and in non-obvious ways. Most likely is that local
+objects may not be destroyed or cleaned up after a thread
+is canceled.
+
+If you want the same behaviour as before, then you must now define
+__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 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:
+- because there are well respected POSIX threads people who believe
+ that POSIX threads implementations should be exceptions-aware and
+ do the expected thing in that context. (There are equally respected
+ people who believe it should not be easily accessible, if it's there
+ at all.)
+- because pthreads-win32 is one of the few implementations that has
+ the choice, perhaps the only freely available one, and so offers
+ a laboratory to people who may want to explore the effects;
+- although the code will always be around somewhere for anyone who
+ wants it, once it's removed from the current version it will not be
+ 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.
+
+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)?
+
+The latest Mingw32 package has thread-safe exception handling (see Q10).
+Also, see Q6 above.
+
+------------------------------------------------------------------------------
+
+Q 8 How do I use pthread.dll for Win32 (Visual C++ 5.0)
+---
+
+>
+> I'm a "rookie" when it comes to your pthread implementation. I'm currently
+> desperately trying to install the prebuilt .dll file into my MSVC compiler.
+> Could you please provide me with explicit instructions on how to do this (or
+> direct me to a resource(s) where I can acquire such information)?
+>
+> Thank you,
+>
+
+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.
+
+The .lib file can go in any directory listed in your LIB environment
+variable.
+
+The .h files can go in any directory listed in your INCLUDE
+environment variable.
+
+Or you might prefer to put the .lib and .h files into a new directory
+and add its path to LIB and INCLUDE. You can probably do this easiest
+by editing the file:-
+
+C:\Program Files\DevStudio\vc\bin\vcvars32.bat
+
+The .def file isn't used by anything in the pre-compiled version but
+is included for information.
+
+Cheers.
+Ross
+
+------------------------------------------------------------------------------
+
+Q 9 Cancelation doesn't work for me, why?
+---
+
+> I'm investigating a problem regarding thread cancelation. The thread I want
+> to cancel has PTHREAD_CANCEL_ASYNCHRONOUS, however, this piece of code
+> blocks on the join():
+>
+> if ((retv = Pthread_cancel( recvThread )) == 0)
+> {
+> retv = Pthread_join( recvThread, 0 );
+> }
+>
+> Pthread_* are just macro's; they call pthread_*.
+>
+> The thread recvThread seems to block on a select() call. It doesn't get
+> cancelled.
+>
+> Two questions:
+>
+> 1) is this normal behaviour?
+>
+> 2) if not, how does the cancel mechanism work? I'm not very familliar to
+> win32 programming, so I don't really understand how the *Event() family of
+> calls work.
+
+Async cancelation should be in versions post snapshot-1999-11-02
+of pthreads-win32 (currently only for x86 architectures).
+
+The answer to your first question is, normal POSIX behaviour would
+be to asynchronously cancel the thread. However, even that doesn't
+guarantee cancelation as the standard only says it should be
+cancelled as soon as possible.
+
+However ...
+
+Snapshot 99-11-02 or earlier only partially supports asynchronous cancellation.
+Snapshots since then simulate async cancelation by poking the address of
+a cancelation routine into the PC of the threads context. This requires
+the thread to be resumed in some way for the cancelation to actually
+proceed. This is not true async cancelation, but it is as close as we've
+been able to get to it.
+
+If the thread you're trying to cancel is blocked (for instance, it could be
+waiting for data from the network), it will only get cancelled when it unblocks
+(when the data arrives). Unfortunately, there is no way to do so from
+outside the thread.
+
+Using deferred cancelation would normally be the way to go, however,
+even though the POSIX threads standard lists a number of C library
+functions that are defined as deferred cancelation points, there is
+no hookup between those which are provided by Windows and the
+pthreads-win32 library.
+
+Incidently, it's worth noting for code portability that the POSIX
+threads standard list doesn't include "select" because (as I read in
+Butenhof) it isn't part of POSIX.
+
+Effectively, the only cancelation points that pthreads-win32 can
+recognise are those the library implements itself, ie.
+
+ pthread_testcancel
+ pthread_cond_wait
+ pthread_cond_timedwait
+ pthread_join
+ sem_wait
+ pthread_delay_np
+
+Pthreads-win32 also provides two functions that allow you to create
+cancelation points within your application, but only for cases where
+a thread is going to block on a Win32 handle. These are:
+
+ pthreadCancelableWait(HANDLE waitHandle) /* Infinite wait */
+
+ pthreadCancelableTimedWait(HANDLE waitHandle, DWORD timeout)
+
+Regards.
+Ross
+
+------------------------------------------------------------------------------
+
+
+Q 10 How do I create thread-safe applications using
+---- pthreadGCE.dll, libpthreadw32.a and Mingw32?
+
+See Thomas Pfaff's email at:
+http://sources.redhat.com/ml/pthreads-win32/2002/msg00000.html
+
+------------------------------------------------------------------------------
+
diff --git a/GNUmakefile b/GNUmakefile
index 5887ea2..ddaa96c 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -113,17 +113,36 @@ SMALL_STATIC_OBJS = \
cancel_testcancel.o \
cancel_cancel.o \
cleanup.o \
- condvar.o \
+ condvar_attr_destroy.o \
+ condvar_attr_getpshared.o \
+ condvar_attr_init.o \
+ condvar_attr_setpshared.o \
+ condvar_check_need_init.o \
+ condvar_destroy.o \
+ condvar_init.o \
+ condvar_signal.o \
+ condvar_wait.o \
create.o \
dll.o \
errno.o \
exit.o \
fork.o \
global.o \
- misc.o \
mutex.o \
- nonportable.o \
+ np_mutexattr_setkind.o \
+ np_mutexattr_getkind.o \
+ np_getw32threadhandle.o \
+ np_delay.o \
+ np_num_processors.o \
+ np_win32_attach.o \
private.o \
+ pthread_equal.o \
+ pthread_getconcurrency.o \
+ pthread_once.o \
+ pthread_self.o \
+ pthread_setconcurrency.o \
+ ptw32_calloc.o \
+ ptw32_new.o \
rwlock.o \
sched.o \
semaphore_init.o \
@@ -142,7 +161,8 @@ SMALL_STATIC_OBJS = \
signal.o \
spin.o \
sync.o \
- tsd.o
+ tsd.o \
+ w32_CancelableWait.o
INCL = \
config.h \
@@ -179,6 +199,35 @@ CANCEL_SRCS = \
cancel_testcancel.c \
cancel_cancel.c
+CONDVAR_SRCS = \
+ condvar_attr_destroy.c \
+ condvar_attr_getpshared.c \
+ condvar_attr_init.c \
+ condvar_attr_setpshared.c \
+ condvar_check_need_init.c \
+ condvar_destroy.c \
+ condvar_init.c \
+ condvar_signal.c \
+ condvar_wait.c
+
+MISC_SRCS = \
+ pthread_equal.c \
+ pthread_getconcurrency.c \
+ pthread_once.c \
+ pthread_self.c \
+ pthread_setconcurrency.c \
+ ptw32_calloc.c \
+ ptw32_new.c \
+ w32_CancelableWait.c
+
+NONPORTABLE_SRCS = \
+ np_mutexattr_setkind.c \
+ np_mutexattr_getkind.c \
+ np_getw32threadhandle.c \
+ np_delay.c \
+ np_num_processors.c \
+ np_win32_attach.c
+
SEMAPHORE_SRCS = \
semaphore_init.c \
semaphore_destroy.c \
@@ -252,6 +301,9 @@ realclean: clean
-$(RM) $(GCE_DLL)
attr.o: attr.c $(ATTR_SRCS) $(INCL)
-barrier.o: barrier.c $(BARRIER_SRCS) $(INCL)
-cancel.o: cancel.c $(CANCEL_SRCS) $(INCL)
+barrier.o: barrier.c $(BARRIER_SRCS) $(INCL)
+cancel.o: cancel.c $(CANCEL_SRCS) $(INCL)
+condvar.o: condvar.c $(CONDVAR_SRCS) $(INCL)
+misc.o: misc.c $(MISC_SRCS) $(INCL)
+nonportable.o: nonportable.c $(NONPORTABLE_SRCS) $(INCL)
semaphore.o: semaphore.c $(SEMAPHORE_SRCS) $(INCL)
diff --git a/Makefile b/Makefile
index 7940235..4bb23c7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,201 +1,253 @@
-# This makefile is compatible with MS nmake and can be used as a
-# replacement for buildlib.bat. I've changed the target from an ordinary dll
-# (/LD) to a debugging dll (/LDd).
-#
-# The variables $DLLDEST and $LIBDEST hold the destination directories for the
-# dll and the lib, respectively. Probably all that needs to change is $DEVROOT.
-
-DEVROOT=c:\pthreads
-
-DLLDEST=$(DEVROOT)\DLL
-LIBDEST=$(DEVROOT)\DLL
-
-DLLS = pthreadVCE.dll pthreadVSE.dll pthreadVC.dll
-
-OPTIM = /O2
-
-# C++ Exceptions
-VCEFLAGS = /GX /TP /D__CLEANUP_CXX
-#Structured Exceptions
-VSEFLAGS = /D__CLEANUP_SEH
-#C cleanup code
-VCFLAGS = /D__CLEANUP_C
-
-#CFLAGS = $(OPTIM) /W3 /MT /nologo /Yd /Zi /I. /D_WIN32_WINNT=0x400 /DHAVE_CONFIG_H /DTEST_ICE
-CFLAGS = $(OPTIM) /W3 /MT /nologo /Yd /Zi /I. /D_WIN32_WINNT=0x400 /DHAVE_CONFIG_H
-
-# Agregate modules for inlinability
-DLL_OBJS = \
- attr.obj \
- barrier.obj \
- cancel.obj \
- cleanup.obj \
- condvar.obj \
- create.obj \
- dll.obj \
- errno.obj \
- exit.obj \
- fork.obj \
- global.obj \
- misc.obj \
- mutex.obj \
- nonportable.obj \
- private.obj \
- rwlock.obj \
- sched.obj \
- semaphore.obj \
- signal.obj \
- spin.obj \
- sync.obj \
- tsd.obj
-
-# Separate modules for minimising the size of statically linked images
-SMALL_STATIC_OBJS = \
- attr_is_attr.obj \
- attr_init.obj \
- attr_destroy.obj \
- attr_getdetachstate.obj \
- attr_setdetachstate.obj \
- attr_getstackaddr.obj \
- attr_setstackaddr.obj \
- attr_getstacksize.obj \
- attr_setstacksize.obj \
- attr_getscope.obj \
- attr_setscope.obj \
- barrier_init.obj \
- barrier_destroy.obj \
- barrier_wait.obj \
- barrier_attr_init.obj \
- barrier_attr_destroy.obj \
- barrier_attr_setpshared.obj \
- barrier_attr_getpshared.obj \
- cancel_setcancelstate.obj \
- cancel_setcanceltype.obj \
- cancel_testcancel.obj \
- cancel_cancel.obj \
- cleanup.obj \
- condvar.obj \
- create.obj \
- dll.obj \
- errno.obj \
- exit.obj \
- fork.obj \
- global.obj \
- misc.obj \
- mutex.obj \
- nonportable.obj \
- private.obj \
- rwlock.obj \
- sched.obj \
- semaphore_init.obj \
- semaphore_destroy.obj \
- semaphore_trywait.obj \
- semaphore_timedwait.obj \
- semaphore_wait.obj \
- semaphore_post.obj \
- semaphore_postmultiple.obj \
- semaphore_getvalue.obj \
- semaphore_increase.obj \
- semaphore_decrease.obj \
- semaphore_open.obj \
- semaphore_close.obj \
- semaphore_unlink.obj \
- signal.obj \
- spin.obj \
- sync.obj \
- tsd.obj
-
-INCL = config.h implement.h semaphore.h pthread.h need_errno.h
-
-ATTR_SRCS = \
- attr_is_attr.c \
- attr_init.c \
- attr_destroy.c \
- attr_getdetachstate.c \
- attr_setdetachstate.c \
- attr_getstackaddr.c \
- attr_setstackaddr.c \
- attr_getstacksize.c \
- attr_setstacksize.c \
- attr_getscope.c \
- attr_setscope.c
-
-BARRIER_SRCS = \
- barrier_init.c \
- barrier_destroy.c \
- barrier_wait.c \
- barrier_attr_init.c \
- barrier_attr_destroy.c \
- barrier_attr_setpshared.c \
- barrier_attr_getpshared.c
-
-CANCEL_SRCS = \
- cancel_setcancelstate.c \
- cancel_setcanceltype.c \
- cancel_testcancel.c \
- cancel_cancel.c
-
-SEMAPHORE_SRCS = \
- semaphore_init.c \
- semaphore_destroy.c \
- semaphore_trywait.c \
- semaphore_timedwait.c \
- semaphore_wait.c \
- semaphore_post.c \
- semaphore_postmultiple.c \
- semaphore_getvalue.c \
- semaphore_increase.c \
- semaphore_decrease.c \
- semaphore_open.c \
- semaphore_close.c \
- semaphore_unlink.c
-
-all:
- @ echo Run one of the following command lines:
- @ echo nmake clean VCE (to build the MSVC dll with C++ exception handling)
- @ echo nmake clean VSE (to build the MSVC dll with structured exception handling)
- @ echo nmake clean VC (to build the MSVC dll with C cleanup code)
-
-auto:
- @ nmake clean VCE
- @ nmake clean VSE
- @ nmake clean VC
-
-VCE:
- @ nmake /nologo EHFLAGS="$(VCEFLAGS)" pthreadVCE.dll
-
-VSE:
- @ nmake /nologo EHFLAGS="$(VSEFLAGS)" pthreadVSE.dll
-
-VC:
- @ nmake /nologo EHFLAGS="$(VCFLAGS)" pthreadVC.dll
-
-realclean: clean
- if exist *.dll del *.dll
- if exist *.lib del *.lib
-
-clean:
- if exist *.obj del *.obj
- if exist *.ilk del *.ilk
- if exist *.pdb del *.pdb
- if exist *.exp del *.exp
- if exist *.o del *.o
-
-
-install: $(DLLS)
- copy pthread*.dll $(DLLDEST)
- copy pthread*.lib $(LIBDEST)
-
-$(DLLS): $(DLL_OBJS) pthread.def
- cl /LD /Zi /nologo $(DLL_OBJS) \
- /link /nodefaultlib:libcmt /implib:$*.lib \
- msvcrt.lib wsock32.lib /def:pthread.def /out:$@
-
-.c.obj:
- cl $(EHFLAGS) $(CFLAGS) -c $<
-
-attr.obj: attr.c $(ATTR_SRCS) $(INCL)
-barrier.obj: barrier.c $(BARRIER_SRCS) $(INCL)
-cancel.obj: cancel.c $(CANCEL_SRCS) $(INCL)
-semaphore.obj: semaphore.c $(SEMAPHORE_SRCS) $(INCL)
-
+# This makefile is compatible with MS nmake and can be used as a
+# replacement for buildlib.bat. I've changed the target from an ordinary dll
+# (/LD) to a debugging dll (/LDd).
+#
+# The variables $DLLDEST and $LIBDEST hold the destination directories for the
+# dll and the lib, respectively. Probably all that needs to change is $DEVROOT.
+
+DEVROOT=c:\pthreads
+
+DLLDEST=$(DEVROOT)\DLL
+LIBDEST=$(DEVROOT)\DLL
+
+DLLS = pthreadVCE.dll pthreadVSE.dll pthreadVC.dll
+
+OPTIM = /O2
+
+# C++ Exceptions
+VCEFLAGS = /GX /TP /D__CLEANUP_CXX
+#Structured Exceptions
+VSEFLAGS = /D__CLEANUP_SEH
+#C cleanup code
+VCFLAGS = /D__CLEANUP_C
+
+#CFLAGS = $(OPTIM) /W3 /MT /nologo /Yd /Zi /I. /D_WIN32_WINNT=0x400 /DHAVE_CONFIG_H /DTEST_ICE
+CFLAGS = $(OPTIM) /W3 /MT /nologo /Yd /Zi /I. /D_WIN32_WINNT=0x400 /DHAVE_CONFIG_H
+
+# Agregate modules for inlinability
+DLL_OBJS = \
+ attr.obj \
+ barrier.obj \
+ cancel.obj \
+ cleanup.obj \
+ condvar.obj \
+ create.obj \
+ dll.obj \
+ errno.obj \
+ exit.obj \
+ fork.obj \
+ global.obj \
+ misc.obj \
+ mutex.obj \
+ nonportable.obj \
+ private.obj \
+ rwlock.obj \
+ sched.obj \
+ semaphore.obj \
+ signal.obj \
+ spin.obj \
+ sync.obj \
+ tsd.obj
+
+# Separate modules for minimising the size of statically linked images
+SMALL_STATIC_OBJS = \
+ attr_is_attr.obj \
+ attr_init.obj \
+ attr_destroy.obj \
+ attr_getdetachstate.obj \
+ attr_setdetachstate.obj \
+ attr_getstackaddr.obj \
+ attr_setstackaddr.obj \
+ attr_getstacksize.obj \
+ attr_setstacksize.obj \
+ attr_getscope.obj \
+ attr_setscope.obj \
+ barrier_init.obj \
+ barrier_destroy.obj \
+ barrier_wait.obj \
+ barrier_attr_init.obj \
+ barrier_attr_destroy.obj \
+ barrier_attr_setpshared.obj \
+ barrier_attr_getpshared.obj \
+ cancel_setcancelstate.obj \
+ cancel_setcanceltype.obj \
+ cancel_testcancel.obj \
+ cancel_cancel.obj \
+ cleanup.obj \
+ condvar_attr_destroy.obj \
+ condvar_attr_getpshared.obj \
+ condvar_attr_init.obj \
+ condvar_attr_setpshared.obj \
+ condvar_check_need_init.obj \
+ condvar_destroy.obj \
+ condvar_init.obj \
+ condvar_signal.obj \
+ condvar_wait.obj \
+ create.obj \
+ dll.obj \
+ errno.obj \
+ exit.obj \
+ fork.obj \
+ global.obj \
+ mutex.obj \
+ np_mutexattr_setkind.obj \
+ np_mutexattr_getkind.obj \
+ np_getw32threadhandle.obj \
+ np_delay.obj \
+ np_num_processors.obj \
+ np_win32_attach.obj \
+ private.obj \
+ pthread_equal.obj \
+ pthread_getconcurrency.obj \
+ pthread_once.obj \
+ pthread_self.obj \
+ pthread_setconcurrency.obj \
+ ptw32_calloc.obj \
+ ptw32_new.obj \
+ rwlock.obj \
+ sched.obj \
+ semaphore_init.obj \
+ semaphore_destroy.obj \
+ semaphore_trywait.obj \
+ semaphore_timedwait.obj \
+ semaphore_wait.obj \
+ semaphore_post.obj \
+ semaphore_postmultiple.obj \
+ semaphore_getvalue.obj \
+ semaphore_increase.obj \
+ semaphore_decrease.obj \
+ semaphore_open.obj \
+ semaphore_close.obj \
+ semaphore_unlink.obj \
+ signal.obj \
+ spin.obj \
+ sync.obj \
+ tsd.obj \
+ w32_CancelableWait.obj
+
+INCL = config.h implement.h semaphore.h pthread.h need_errno.h
+
+ATTR_SRCS = \
+ attr_is_attr.c \
+ attr_init.c \
+ attr_destroy.c \
+ attr_getdetachstate.c \
+ attr_setdetachstate.c \
+ attr_getstackaddr.c \
+ attr_setstackaddr.c \
+ attr_getstacksize.c \
+ attr_setstacksize.c \
+ attr_getscope.c \
+ attr_setscope.c
+
+BARRIER_SRCS = \
+ barrier_init.c \
+ barrier_destroy.c \
+ barrier_wait.c \
+ barrier_attr_init.c \
+ barrier_attr_destroy.c \
+ barrier_attr_setpshared.c \
+ barrier_attr_getpshared.c
+
+CANCEL_SRCS = \
+ cancel_setcancelstate.c \
+ cancel_setcanceltype.c \
+ cancel_testcancel.c \
+ cancel_cancel.c
+
+CONDVAR_SRCS = \
+ condvar_attr_destroy.c \
+ condvar_attr_getpshared.c \
+ condvar_attr_init.c \
+ condvar_attr_setpshared.c \
+ condvar_check_need_init.c \
+ condvar_destroy.c \
+ condvar_init.c \
+ condvar_signal.c \
+ condvar_wait.c
+
+MISC_SRCS = \
+ pthread_equal.c \
+ pthread_getconcurrency.c \
+ pthread_once.c \
+ pthread_self.c \
+ pthread_setconcurrency.c \
+ ptw32_calloc.c \
+ ptw32_new.c \
+ w32_CancelableWait.c
+
+NONPORTABLE_SRCS = \
+ np_mutexattr_setkind.c \
+ np_mutexattr_getkind.c \
+ np_getw32threadhandle.c \
+ np_delay.c \
+ np_num_processors.c \
+ np_win32_attach.c
+
+SEMAPHORE_SRCS = \
+ semaphore_init.c \
+ semaphore_destroy.c \
+ semaphore_trywait.c \
+ semaphore_timedwait.c \
+ semaphore_wait.c \
+ semaphore_post.c \
+ semaphore_postmultiple.c \
+ semaphore_getvalue.c \
+ semaphore_increase.c \
+ semaphore_decrease.c \
+ semaphore_open.c \
+ semaphore_close.c \
+ semaphore_unlink.c
+
+all:
+ @ echo Run one of the following command lines:
+ @ echo nmake clean VCE (to build the MSVC dll with C++ exception handling)
+ @ echo nmake clean VSE (to build the MSVC dll with structured exception handling)
+ @ echo nmake clean VC (to build the MSVC dll with C cleanup code)
+
+auto:
+ @ nmake clean VCE
+ @ nmake clean VSE
+ @ nmake clean VC
+
+VCE:
+ @ nmake /nologo EHFLAGS="$(VCEFLAGS)" pthreadVCE.dll
+
+VSE:
+ @ nmake /nologo EHFLAGS="$(VSEFLAGS)" pthreadVSE.dll
+
+VC:
+ @ nmake /nologo EHFLAGS="$(VCFLAGS)" pthreadVC.dll
+
+realclean: clean
+ if exist *.dll del *.dll
+ if exist *.lib del *.lib
+
+clean:
+ if exist *.obj del *.obj
+ if exist *.ilk del *.ilk
+ if exist *.pdb del *.pdb
+ if exist *.exp del *.exp
+ if exist *.o del *.o
+
+
+install: $(DLLS)
+ copy pthread*.dll $(DLLDEST)
+ copy pthread*.lib $(LIBDEST)
+
+$(DLLS): $(DLL_OBJS) pthread.def
+ cl /LD /Zi /nologo $(DLL_OBJS) \
+ /link /nodefaultlib:libcmt /implib:$*.lib \
+ msvcrt.lib wsock32.lib /def:pthread.def /out:$@
+
+.c.obj:
+ cl $(EHFLAGS) $(CFLAGS) -c $<
+
+attr.obj: attr.c $(ATTR_SRCS) $(INCL)
+barrier.obj: barrier.c $(BARRIER_SRCS) $(INCL)
+cancel.obj: cancel.c $(CANCEL_SRCS) $(INCL)
+condvar.obj: condvar.c $(CONDVAR_SRCS) $(INCL)
+misc.obj: misc.c $(MISC_SRCS) $(INCL)
+nonportable.obj: nonportable.c $(NONPORTABLE_SRCS) $(INCL)
+semaphore.obj: semaphore.c $(SEMAPHORE_SRCS) $(INCL)
+
diff --git a/Nmakefile b/Nmakefile
index 30df290..6028919 100644
--- a/Nmakefile
+++ b/Nmakefile
@@ -1,24 +1,24 @@
-/*
- * nmake file for uwin pthread library
- */
-
-VERSION = -
-CCFLAGS = -V -g $(CC.DLL)
-HAVE_CONFIG_H == 1
-_MT == 1
-_timeb == timeb
-_ftime == ftime
-_errno == _ast_errno
-
-$(INCLUDEDIR) :INSTALLDIR: pthread.h sched.h
-
-pthread $(VERSION) :LIBRARY: pthread.def attr.c barrier.c cancel.c cleanup.c condvar.c \
- create.c dll.c exit.c fork.c global.c misc.c mutex.c private.c \
- rwlock.c sched.c semaphore.c spin.c sync.c tsd.c nonportable.c
-
-:: ANNOUNCE CONTRIBUTORS COPYING.LIB ChangeLog FAQ GNUmakefile MAINTAINERS \
- Makefile Makefile.in Makefile.vc NEWS PROGRESS README README.WinCE \
- TODO WinCE-PORT install-sh errno.c tests tests.mk acconfig.h \
- config.guess config.h.in config.sub configure configure.in signal.c \
- README.CV README.NONPORTABLE pthread.dsp pthread.dsw
-
+/*
+ * nmake file for uwin pthread library
+ */
+
+VERSION = -
+CCFLAGS = -V -g $(CC.DLL)
+HAVE_CONFIG_H == 1
+_MT == 1
+_timeb == timeb
+_ftime == ftime
+_errno == _ast_errno
+
+$(INCLUDEDIR) :INSTALLDIR: pthread.h sched.h
+
+pthread $(VERSION) :LIBRARY: pthread.def attr.c barrier.c cancel.c cleanup.c condvar.c \
+ create.c dll.c exit.c fork.c global.c misc.c mutex.c private.c \
+ rwlock.c sched.c semaphore.c spin.c sync.c tsd.c nonportable.c
+
+:: ANNOUNCE CONTRIBUTORS COPYING.LIB ChangeLog FAQ GNUmakefile MAINTAINERS \
+ Makefile Makefile.in Makefile.vc NEWS PROGRESS README README.WinCE \
+ TODO WinCE-PORT install-sh errno.c tests tests.mk acconfig.h \
+ config.guess config.h.in config.sub configure configure.in signal.c \
+ README.CV README.NONPORTABLE pthread.dsp pthread.dsw
+
diff --git a/Nmakefile.tests b/Nmakefile.tests
index ca0cc6f..b604551 100644
--- a/Nmakefile.tests
+++ b/Nmakefile.tests
@@ -1,196 +1,196 @@
-/* for running tests */
-CCFLAGS = -g
-_MT == 1
-_timeb == timeb
-_ftime == ftime
-
-.SOURCE: tests
-/*
-:PACKAGE: pthread
-*/
-
-set keepgoing
-
-":test:" : .MAKE .OPERATOR
- local I
- $(<:D:B:S=.pass) : .IMPLICIT $(>:D:B:S=.pass)
- for I $(<) $(>)
- $(I:D:B:S=.pass) : .VIRTUAL .FORCE $(I)
- $(>)
- end
-loadfree:: loadfree.c
-mutex1:: mutex1.c
-mutex1e:: mutex1e.c
-mutex1n:: mutex1n.c
-mutex1r:: mutex1r.c
-mutex2:: mutex1.2
-exit1:: exit1.c
-condvar1:: condvar1.c
-self1:: self1.c
-condvar2:: condvar2.c
-condvar2_1:: condvar2_1.c
-condvar3_1:: condvar3_1.c
-condvar3_2:: condvar3_2.c
-condvar3_3:: condvar3_3.c
-create1.:: create1.c
-cancel1:: cancel1.c
-cancel2:: cancel2.c
-mutex3:: mutex3.c
-mutex4:: mutex4.c
-mutex5:: mutex5.c
-mutex6:: mutex6.c
-mutex6e:: mutex6e.c
-mutex6n:: mutex6n.c
-mutex6r:: mutex6r.c
-mutex7:: mutex7.c
-mutex7e:: mutex7e.c
-mutex7n:: mutex7n.c
-mutex7r:: mutex7r.c
-mutex8:: mutex8.c
-mutex8e:: mutex8e.c
-mutex8n:: mutex8n.c
-mutex8r:: mutex8r.c
-equal1:: equal1.c
-exit2:: exit2.c
-exit3:: exit3.c
-exit4:: exit4.c
-join0:: join0.c
-join1:: join1.c
-join2:: join2.c
-count1:: count1.c
-once1:: once1.c
-tsd1:: tsd1.c
-self2:: self2.c
-eyal1:: eyal1.c
-condvar3:: condvar3.c
-condvar4:: condvar4.c
-condvar5:: condvar5.c
-condvar6:: condvar6.c
-condvar7:: condvar7.c
-condvar8:: condvar8.c
-condvar9:: condvar9.c
-errno1:: errno1.c
-rwlock1:: rwlock1.c
-rwlock2:: rwlock2.c
-rwlock3:: rwlock3.c
-rwlock4:: rwlock4.c
-rwlock5:: rwlock5.c
-rwlock6:: rwlock6.c
-rwlock7:: rwlock7.c
-context1:: context1.c
-cancel3:: cancel3.c
-cancel4:: cancel4.c
-cancel5:: cancel5.c
-cancel6a:: cancel6a.c
-cancel6d:: cancel6d.c
-cleanup0:: cleanup0.c
-cleanup1:: cleanup1.c
-cleanup2:: cleanup2.c
-cleanup3:: cleanup3.c
-priority1:: priority1.c
-priority2:: priority2.c
-inherit1:: inherit1.c
-spin1:: spin1.c
-spin2:: spin2.c
-spin3:: spin3.c
-spin4:: spin4.c
-barrier1:: barrier1.c
-barrier2:: barrier2.c
-barrier3:: barrier3.c
-barrier4:: barrier4.c
-barrier5:: barrier5.c
-exception1:: exception1.c
-exception2:: exception2.c
-exception3:: exception3.c
-benchtest1:: benchtest1.c
-benchtest2:: benchtest2.c
-benchtest3:: benchtest3.c
-benchtest4:: benchtest4.c
-benchtest5:: benchtest5.c
-
-loadfree: :test:
-mutex5 :test: loadfree
-mutex1 :test: loadfree
-mutex2 :test: loadfree
-exit1 :test: loadfree
-condvar1 :test: loadfree
-self1 :test: loadfree
-condvar2 :test: condvar1
-condvar2_1 :test: condvar2
-create1 :test: mutex2
-cancel1 :test: create1
-cancel2 :test: cancel1
-mutex3 :test: create1
-mutex4 :test: mutex3
-mutex6 :test: mutex4
-mutex6n :test: mutex4
-mutex6e :test: mutex4
-mutex6r :test: mutex4
-mutex7 :test: mutex6
-mutex7n :test: mutex6n
-mutex7e :test: mutex6e
-mutex7r :test: mutex6r
-mutex8 :test: mutex7
-mutex8n :test: mutex7n
-mutex8e :test: mutex7e
-mutex8r :test: mutex7r
-equal1 :test: create1
-exit2 :test: create1
-exit3 :test: create1
-join0 :test: create1
-join1 :test: create1
-join2 :test: create1
-count1 :test: join1
-once1 :test: create1
-tsd1 :test: join1
-self2 :test: create1
-eyal1 :test: tsd1
-condvar3 :test: create1
-condvar3_1 :test: condvar3
-condvar3_2 :test: condvar3_1
-condvar3_3 :test: condvar3_2
-condvar4 :test: create1
-condvar5 :test: condvar4
-condvar6 :test: condvar5
-condvar7 :test: condvar6 cleanup1
-condvar8 :test: condvar7
-condvar9 :test: condvar8
-errno1 :test: mutex3
-rwlock1 :test: condvar6
-rwlock2 :test: rwlock1
-rwlock3 :test: rwlock2
-rwlock4 :test: rwlock3
-rwlock5 :test: rwlock4
-rwlock6 :test: rwlock5
-context1 :test: cancel2
-cancel3 :test: context1
-cancel4 :test: cancel3
-cancel5 :test: cancel3
-cancel6a :test: cancel3
-cancel6d :test: cancel3
-cleanup0 :test: cancel5
-cleanup1 :test: cleanup0
-cleanup2 :test: cleanup1
-cleanup3 :test: cleanup2
-priority1 :test: join1
-priority2 :test: priority1
-inherit1 :test: join1
-spin1 :test:
-spin2 :test: spin1.c
-spin3 :test: spin2.c
-spin4 :test: spin3.c
-barrier1 :test:
-barrier2 :test: barrier1.c
-barrier3 :test: barrier2.c
-barrier4 :test: barrier3.c
-barrier5 :test: barrier4.c
-benchtest1 :test: mutex3
-benchtest2 :test: benchtest1
-benchtest3 :test: benchtest2
-benchtest4 :test: benchtest3
-benchtest5 :test: benchtest4
-exception1 :test: cancel4
-exception2 :test: exception1
-exception3 :test: exception2
-exit4 :test: exit3
-
+/* for running tests */
+CCFLAGS = -g
+_MT == 1
+_timeb == timeb
+_ftime == ftime
+
+.SOURCE: tests
+/*
+:PACKAGE: pthread
+*/
+
+set keepgoing
+
+":test:" : .MAKE .OPERATOR
+ local I
+ $(<:D:B:S=.pass) : .IMPLICIT $(>:D:B:S=.pass)
+ for I $(<) $(>)
+ $(I:D:B:S=.pass) : .VIRTUAL .FORCE $(I)
+ $(>)
+ end
+loadfree:: loadfree.c
+mutex1:: mutex1.c
+mutex1e:: mutex1e.c
+mutex1n:: mutex1n.c
+mutex1r:: mutex1r.c
+mutex2:: mutex1.2
+exit1:: exit1.c
+condvar1:: condvar1.c
+self1:: self1.c
+condvar2:: condvar2.c
+condvar2_1:: condvar2_1.c
+condvar3_1:: condvar3_1.c
+condvar3_2:: condvar3_2.c
+condvar3_3:: condvar3_3.c
+create1.:: create1.c
+cancel1:: cancel1.c
+cancel2:: cancel2.c
+mutex3:: mutex3.c
+mutex4:: mutex4.c
+mutex5:: mutex5.c
+mutex6:: mutex6.c
+mutex6e:: mutex6e.c
+mutex6n:: mutex6n.c
+mutex6r:: mutex6r.c
+mutex7:: mutex7.c
+mutex7e:: mutex7e.c
+mutex7n:: mutex7n.c
+mutex7r:: mutex7r.c
+mutex8:: mutex8.c
+mutex8e:: mutex8e.c
+mutex8n:: mutex8n.c
+mutex8r:: mutex8r.c
+equal1:: equal1.c
+exit2:: exit2.c
+exit3:: exit3.c
+exit4:: exit4.c
+join0:: join0.c
+join1:: join1.c
+join2:: join2.c
+count1:: count1.c
+once1:: once1.c
+tsd1:: tsd1.c
+self2:: self2.c
+eyal1:: eyal1.c
+condvar3:: condvar3.c
+condvar4:: condvar4.c
+condvar5:: condvar5.c
+condvar6:: condvar6.c
+condvar7:: condvar7.c
+condvar8:: condvar8.c
+condvar9:: condvar9.c
+errno1:: errno1.c
+rwlock1:: rwlock1.c
+rwlock2:: rwlock2.c
+rwlock3:: rwlock3.c
+rwlock4:: rwlock4.c
+rwlock5:: rwlock5.c
+rwlock6:: rwlock6.c
+rwlock7:: rwlock7.c
+context1:: context1.c
+cancel3:: cancel3.c
+cancel4:: cancel4.c
+cancel5:: cancel5.c
+cancel6a:: cancel6a.c
+cancel6d:: cancel6d.c
+cleanup0:: cleanup0.c
+cleanup1:: cleanup1.c
+cleanup2:: cleanup2.c
+cleanup3:: cleanup3.c
+priority1:: priority1.c
+priority2:: priority2.c
+inherit1:: inherit1.c
+spin1:: spin1.c
+spin2:: spin2.c
+spin3:: spin3.c
+spin4:: spin4.c
+barrier1:: barrier1.c
+barrier2:: barrier2.c
+barrier3:: barrier3.c
+barrier4:: barrier4.c
+barrier5:: barrier5.c
+exception1:: exception1.c
+exception2:: exception2.c
+exception3:: exception3.c
+benchtest1:: benchtest1.c
+benchtest2:: benchtest2.c
+benchtest3:: benchtest3.c
+benchtest4:: benchtest4.c
+benchtest5:: benchtest5.c
+
+loadfree: :test:
+mutex5 :test: loadfree
+mutex1 :test: loadfree
+mutex2 :test: loadfree
+exit1 :test: loadfree
+condvar1 :test: loadfree
+self1 :test: loadfree
+condvar2 :test: condvar1
+condvar2_1 :test: condvar2
+create1 :test: mutex2
+cancel1 :test: create1
+cancel2 :test: cancel1
+mutex3 :test: create1
+mutex4 :test: mutex3
+mutex6 :test: mutex4
+mutex6n :test: mutex4
+mutex6e :test: mutex4
+mutex6r :test: mutex4
+mutex7 :test: mutex6
+mutex7n :test: mutex6n
+mutex7e :test: mutex6e
+mutex7r :test: mutex6r
+mutex8 :test: mutex7
+mutex8n :test: mutex7n
+mutex8e :test: mutex7e
+mutex8r :test: mutex7r
+equal1 :test: create1
+exit2 :test: create1
+exit3 :test: create1
+join0 :test: create1
+join1 :test: create1
+join2 :test: create1
+count1 :test: join1
+once1 :test: create1
+tsd1 :test: join1
+self2 :test: create1
+eyal1 :test: tsd1
+condvar3 :test: create1
+condvar3_1 :test: condvar3
+condvar3_2 :test: condvar3_1
+condvar3_3 :test: condvar3_2
+condvar4 :test: create1
+condvar5 :test: condvar4
+condvar6 :test: condvar5
+condvar7 :test: condvar6 cleanup1
+condvar8 :test: condvar7
+condvar9 :test: condvar8
+errno1 :test: mutex3
+rwlock1 :test: condvar6
+rwlock2 :test: rwlock1
+rwlock3 :test: rwlock2
+rwlock4 :test: rwlock3
+rwlock5 :test: rwlock4
+rwlock6 :test: rwlock5
+context1 :test: cancel2
+cancel3 :test: context1
+cancel4 :test: cancel3
+cancel5 :test: cancel3
+cancel6a :test: cancel3
+cancel6d :test: cancel3
+cleanup0 :test: cancel5
+cleanup1 :test: cleanup0
+cleanup2 :test: cleanup1
+cleanup3 :test: cleanup2
+priority1 :test: join1
+priority2 :test: priority1
+inherit1 :test: join1
+spin1 :test:
+spin2 :test: spin1.c
+spin3 :test: spin2.c
+spin4 :test: spin3.c
+barrier1 :test:
+barrier2 :test: barrier1.c
+barrier3 :test: barrier2.c
+barrier4 :test: barrier3.c
+barrier5 :test: barrier4.c
+benchtest1 :test: mutex3
+benchtest2 :test: benchtest1
+benchtest3 :test: benchtest2
+benchtest4 :test: benchtest3
+benchtest5 :test: benchtest4
+exception1 :test: cancel4
+exception2 :test: exception1
+exception3 :test: exception2
+exit4 :test: exit3
+
diff --git a/README b/README
index e3a5312..b4e0288 100644
--- a/README
+++ b/README
@@ -1,419 +1,419 @@
-PTHREADS-WIN32
-==============
-
-Pthreads-win32 is free software, distributed under the GNU Lesser
-General Public License (LGPL). See the file 'COPYING.LIB' for terms
-and conditions. Also see the file 'COPYING' for information
-specific to pthreads-win32, copyrights and the LGPL.
-
-
-What is it?
------------
-
-Pthreads-win32 is an Open Source Software implementation of the
-Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's
-Win32 environment. Some functions from POSIX 1003.1b are also
-supported including semaphores. Other related functions include
-the set of read-write lock functions. The library also supports
-some of the functionality of the Open Group's Single Unix
-specification, version 2, namely mutex types.
-
-See the file "ANNOUNCE" for more information including standards
-conformance details and list of supported routines.
-
-
-Which of the several dll versions to use?
------------------------------------------
-or,
----
-What are all these pthread*.dll and pthread*.lib files?
--------------------------------------------------------
-
-Simply, you only use one of them, but you need to choose carefully.
-
-The most important choice you need to make is whether to use a
-version that uses exceptions internally, or not (there are versions
-of the library that use exceptions as part of the thread
-cancelation and exit implementation, and one that uses
-setjmp/longjmp instead).
-
-There is some contension amongst POSIX threads experts as
-to how POSIX threads cancelation and exit should work
-with languages that include exceptions and handlers, e.g.
-C++ and even C (Microsoft's Structured Exceptions).
-
-The issue is: should cancelation of a thread in, say,
-a C++ application cause object destructors and C++ exception
-handlers to be invoked as the stack unwinds during thread
-exit, or not?
-
-There seems to be more opinion in favour of using the
-standard C version of the library (no EH) with C++ applications
-since this appears to be the assumption commercial pthreads
-implementations make. Therefore, if you use an EH version
-of pthreads-win32 then you may be under the illusion that
-your application will be portable, when in fact it is likely to
-behave very differently linked with other pthreads libraries.
-
-Now you may be asking: why have you kept the EH versions of
-the library?
-
-There are a couple of reasons:
-- there is division amongst the experts and so the code may
- be needed in the future. (Yes, it's in the repository and we
- can get it out anytime in the future, but ...)
-- pthreads-win32 is one of the few implementations, and possibly
- the only freely available one, that has EH versions. It may be
- useful to people who want to play with or study application
- behaviour under these conditions.
-
-
-Library naming
---------------
-
-Because the library is being built using various exception
-handling schemes and compilers - and because the library
-may not work reliably if these are mixed in an application,
-each different version of the library has it's own name.
-
-Note 1: the incompatibility is really between EH implementations
-of the different compilers. It should be possible to use the
-standard C version from either compiler with C++ applications
-built with a different compiler. If you use an EH version of
-the library, then you must use the same compiler for the
-application. This is another complication and dependency that
-can be avoided by using only the standard C library version.
-
-Note 2: if you use a standard C pthread*.dll with a C++
-application, then any functions that you define that are
-intended to be called via pthread_cleanup_push() must be
-__cdecl.
-
-Note 3: the intention is to also name either the VC or GC
-version (it should be arbitrary) as pthread.dll, including
-pthread.lib and libpthread.a as appropriate.
-
-In general:
- pthread[VG]{SE,CE,C}.dll
- pthread[VG]{SE,CE,C}.lib
-
-where:
- [VG] indicates the compiler
- V - MS VC
- G - GNU C
-
- {SE,CE,C} indicates the exception handling scheme
- SE - Structured EH
- CE - C++ EH
- C - no exceptions - uses setjmp/longjmp
-
-For example:
- pthreadVSE.dll (MSVC/SEH)
- pthreadGCE.dll (GNUC/C++ EH)
- pthreadGC.dll (GNUC/not dependent on exceptions)
-
-The GNU library archive file names have changed to:
-
- libpthreadGCE.a
- libpthreadGC.a
-
-
-Other name changes
-------------------
-
-All snapshots prior to and including snapshot 2000-08-13
-used "_pthread_" as the prefix to library internal
-functions, and "_PTHREAD_" to many library internal
-macros. These have now been changed to "ptw32_" and "PTW32_"
-respectively so as to not conflict with the ANSI standard's
-reservation of identifiers beginning with "_" and "__" for
-use by compiler implementations only.
-
-If you have written any applications and you are linking
-statically with the pthreads-win32 library then you may have
-included a call to _pthread_processInitialize. You will
-now have to change that to ptw32_processInitialize.
-
-
-A note on Cleanup code default style
-------------------------------------
-
-Previously, if not defined, the cleanup style was determined automatically
-from the compiler used, and one of the following was defined accordingly:
-
- __CLEANUP_SEH MSVC only
- __CLEANUP_CXX C++, including MSVC++, GNU G++
- __CLEANUP_C C, including GNU GCC, not MSVC
-
-These defines determine the style of cleanup (see pthread.h) and,
-most importantly, the way that cancelation and thread exit (via
-pthread_exit) is performed (see the routine ptw32_throw() in private.c).
-
-In short, the exceptions versions of the library throw an exception
-when a thread is canceled or exits (via pthread_exit()), which is
-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
-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.
-
-Although it was not clearly documented before, it is still necessary to
-build your application using the same __CLEANUP_* define as was
-used for the version of the library that you link with, so that the
-correct parts of pthread.h are included. That is, the possible
-defines require the following library versions:
-
- __CLEANUP_SEH pthreadVSE.dll
- __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll
- __CLEANUP_C pthreadVC.dll or pthreadGC.dll
-
-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
-section were being used.
-
-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.
-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
-is canceled, or the thread calls pthread_exit().
-
-Your application will now most likely behave differently to previous
-versions, and in non-obvious ways. Most likely is that locally
-instantiated objects may not be destroyed or cleaned up after a thread
-is canceled.
-
-If you want the same behaviour as before, then you must now define
-__CLEANUP_C++ explicitly using a compiler option and link with
-pthreadVCE.dll as you did before.
-
-
-WHY ARE WE MAKING THE DEFAULT STYLE 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 unless
-you consciously choose to do otherwise, your pthreads applications will
-now run or crash in similar ways irrespective of the threads platform
-you use. Or at least this is the hope.
-
-
-
-Building under VC++ using C++ EH, Structured EH, or just C
-----------------------------------------------------------
-
-From the source directory run one of the following:
-
-nmake clean VCE (builds the VC++ C++ EH version pthreadVCE.dll)
-
-or:
-
-nmake clean VSE (builds the VC++ structured EH version pthreadVSE.dll)
-
-or:
-
-nmake clean VC (builds the VC setjmp/longjmp version of pthreadVC.dll)
-
-You can run the testsuite by changing to the "tests" directory and
-running the target corresponding to the DLL version you built:
-
-nmake clean VCE
-
-or:
-
-nmake clean VSE
-
-or:
-
-nmake clean VC
-
-or:
-
-nmake clean VCX (tests the VC version of the library with C++ (EH)
- applications)
-
-
-Building under Mingw32
-----------------------
-
-The dll can be built with Mingw32 gcc-2.95.2-1 after you've
-made the changes to Mingw32 desribed in Question 6 of the FAQ.
-
-From the source directory, run
-
-make clean GCE
-
-or:
-
-make clean GC
-
-You can run the testsuite by changing to the "tests" directory and
-running
-
-make clean GCE
-
-or:
-
-make clean GC
-
-or:
-
-make clean GCX (tests the GC version of the library with C++ (EH)
- applications)
-
-
-Building the library under Cygwin
----------------------------------
-
-Not tested by me although I think some people have done this.
-Not sure how successfully though.
-
-Cygwin is implementing it's own POSIX threads routines and these
-will be the ones to use if you develop using Cygwin.
-
-
-Ready to run binaries
----------------------
-
-For convenience, the following ready-to-run files can be downloaded
-from the FTP site (see under "Availability" below):
-
- pthread.h
- semaphore.h
- sched.h
- pthread.def
- pthreadVCE.dll - built with MSVC++ compiler using C++ EH
- pthreadVCE.lib
- pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp
- pthreadVC.lib
- pthreadVSE.dll - built with MSVC compiler using SEH
- pthreadVSE.lib
- pthreadGCE.dll - built with Mingw32 G++
- pthreadGCE.a - derived from pthreadGCE.dll
- pthreadGC.dll - built with Mingw32 GCC
- pthreadGC.a - derived from pthreadGC.dll
- gcc.dll - needed to build and run applications that use
- pthreadGCE.dll.
-
-
-Building applications with the library
---------------------------------------
-
-Use the appropriate DLL and LIB files to match the exception handing
-that you use in your application, or specifically, in your POSIX
-threads. Don't mix them or neither thread cancelation nor
-pthread_exit() will work reliably if at all.
-
-If in doubt use the C (no-exceptions) versions of the library.
-
-
-Building applications with GNU compilers
-----------------------------------------
-
-If you're using pthreadGCE.dll:
-
-Use gcc-2.95.2-1 or later modified as per pthreads-win32 FAQ question 11.
-
-With the three header files, pthreadGCE.dll, gcc.dll and libpthreadGCE.a
-in the same directory as your application myapp.c, you could compile,
-link and run myapp.c under Mingw32 as follows:
-
- gcc -x c++ -o myapp.exe myapp.c -I. -L. -lpthreadGCE
- myapp
-
-Or put pthreadGCE.dll and gcc.dll in an appropriate directory in
-your PATH, put libpthreadGCE.a in MINGW_ROOT\i386-mingw32\lib, and
-put the three header files in MINGW_ROOT\i386-mingw32\include,
-then use:
-
- gcc -x c++ -o myapp.exe myapp.c -lpthreadGCE
- myapp
-
-If you're using pthreadGC.dll:
-
-With the three header files, pthreadGC.dll and libpthreadGC.a in the
-same directory as your application myapp.c, you could compile, link
-and run myapp.c under Mingw32 as follows:
-
- gcc -o myapp.exe myapp.c -I. -L. -lpthreadGC
- myapp
-
-Or put pthreadGC.dll in an appropriate directory in your PATH,
-put libpthreadGC.a in MINGW_ROOT\i386-mingw32\lib, and
-put the three header files in MINGW_ROOT\i386-mingw32\include,
-then use:
-
- gcc -o myapp.exe myapp.c -lpthreadGC
- myapp
-
-
-Availability
-------------
-
-The complete source code in either unbundled, self-extracting
-Zip file, or tar/gzipped format can be found at:
-
- ftp://sources.redhat.com/pub/pthreads-win32
-
-The pre-built DLL, export libraries and matching pthread.h can
-be found at:
-
- ftp://sources.redhat.com/pub/pthreads-win32/dll-latest
-
-Home page:
-
- http://sources.redhat.com/pthreads-win32/
-
-
-Mailing list
-------------
-
-There is a mailing list for discussing pthreads on Win32.
-To join, send email to:
-
- pthreads-win32-subscribe@sources.redhat.com
-
-Unsubscribe by sending mail to:
-
- pthreads-win32-unsubscribe@sources.redhat.com
-
-
-Acknowledgements
-----------------
-
-Pthreads-win32 is based substantially on a Win32 Pthreads
-implementation contributed by John E. Bossom.
-Many others have contributed important new code,
-improvements and bug fixes. Thanks go to Alexander Terekhov
-and Louis Thomas for their improvements to the implementation
-of condition variables.
-
-See the 'CONTRIBUTORS' file for the list of contributors.
-
-As much as possible, the ChangeLog file also attributes
-contributions and patches that have been incorporated
-in the library.
-
-----
-Ross Johnson
-<rpj@ise.canberra.edu.au>
-
-
-
-
-
-
-
-
+PTHREADS-WIN32
+==============
+
+Pthreads-win32 is free software, distributed under the GNU Lesser
+General Public License (LGPL). See the file 'COPYING.LIB' for terms
+and conditions. Also see the file 'COPYING' for information
+specific to pthreads-win32, copyrights and the LGPL.
+
+
+What is it?
+-----------
+
+Pthreads-win32 is an Open Source Software implementation of the
+Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's
+Win32 environment. Some functions from POSIX 1003.1b are also
+supported including semaphores. Other related functions include
+the set of read-write lock functions. The library also supports
+some of the functionality of the Open Group's Single Unix
+specification, version 2, namely mutex types.
+
+See the file "ANNOUNCE" for more information including standards
+conformance details and list of supported routines.
+
+
+Which of the several dll versions to use?
+-----------------------------------------
+or,
+---
+What are all these pthread*.dll and pthread*.lib files?
+-------------------------------------------------------
+
+Simply, you only use one of them, but you need to choose carefully.
+
+The most important choice you need to make is whether to use a
+version that uses exceptions internally, or not (there are versions
+of the library that use exceptions as part of the thread
+cancelation and exit implementation, and one that uses
+setjmp/longjmp instead).
+
+There is some contension amongst POSIX threads experts as
+to how POSIX threads cancelation and exit should work
+with languages that include exceptions and handlers, e.g.
+C++ and even C (Microsoft's Structured Exceptions).
+
+The issue is: should cancelation of a thread in, say,
+a C++ application cause object destructors and C++ exception
+handlers to be invoked as the stack unwinds during thread
+exit, or not?
+
+There seems to be more opinion in favour of using the
+standard C version of the library (no EH) with C++ applications
+since this appears to be the assumption commercial pthreads
+implementations make. Therefore, if you use an EH version
+of pthreads-win32 then you may be under the illusion that
+your application will be portable, when in fact it is likely to
+behave very differently linked with other pthreads libraries.
+
+Now you may be asking: why have you kept the EH versions of
+the library?
+
+There are a couple of reasons:
+- there is division amongst the experts and so the code may
+ be needed in the future. (Yes, it's in the repository and we
+ can get it out anytime in the future, but ...)
+- pthreads-win32 is one of the few implementations, and possibly
+ the only freely available one, that has EH versions. It may be
+ useful to people who want to play with or study application
+ behaviour under these conditions.
+
+
+Library naming
+--------------
+
+Because the library is being built using various exception
+handling schemes and compilers - and because the library
+may not work reliably if these are mixed in an application,
+each different version of the library has it's own name.
+
+Note 1: the incompatibility is really between EH implementations
+of the different compilers. It should be possible to use the
+standard C version from either compiler with C++ applications
+built with a different compiler. If you use an EH version of
+the library, then you must use the same compiler for the
+application. This is another complication and dependency that
+can be avoided by using only the standard C library version.
+
+Note 2: if you use a standard C pthread*.dll with a C++
+application, then any functions that you define that are
+intended to be called via pthread_cleanup_push() must be
+__cdecl.
+
+Note 3: the intention is to also name either the VC or GC
+version (it should be arbitrary) as pthread.dll, including
+pthread.lib and libpthread.a as appropriate.
+
+In general:
+ pthread[VG]{SE,CE,C}.dll
+ pthread[VG]{SE,CE,C}.lib
+
+where:
+ [VG] indicates the compiler
+ V - MS VC
+ G - GNU C
+
+ {SE,CE,C} indicates the exception handling scheme
+ SE - Structured EH
+ CE - C++ EH
+ C - no exceptions - uses setjmp/longjmp
+
+For example:
+ pthreadVSE.dll (MSVC/SEH)
+ pthreadGCE.dll (GNUC/C++ EH)
+ pthreadGC.dll (GNUC/not dependent on exceptions)
+
+The GNU library archive file names have changed to:
+
+ libpthreadGCE.a
+ libpthreadGC.a
+
+
+Other name changes
+------------------
+
+All snapshots prior to and including snapshot 2000-08-13
+used "_pthread_" as the prefix to library internal
+functions, and "_PTHREAD_" to many library internal
+macros. These have now been changed to "ptw32_" and "PTW32_"
+respectively so as to not conflict with the ANSI standard's
+reservation of identifiers beginning with "_" and "__" for
+use by compiler implementations only.
+
+If you have written any applications and you are linking
+statically with the pthreads-win32 library then you may have
+included a call to _pthread_processInitialize. You will
+now have to change that to ptw32_processInitialize.
+
+
+A note on Cleanup code default style
+------------------------------------
+
+Previously, if not defined, the cleanup style was determined automatically
+from the compiler used, and one of the following was defined accordingly:
+
+ __CLEANUP_SEH MSVC only
+ __CLEANUP_CXX C++, including MSVC++, GNU G++
+ __CLEANUP_C C, including GNU GCC, not MSVC
+
+These defines determine the style of cleanup (see pthread.h) and,
+most importantly, the way that cancelation and thread exit (via
+pthread_exit) is performed (see the routine ptw32_throw() in private.c).
+
+In short, the exceptions versions of the library throw an exception
+when a thread is canceled or exits (via pthread_exit()), which is
+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
+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.
+
+Although it was not clearly documented before, it is still necessary to
+build your application using the same __CLEANUP_* define as was
+used for the version of the library that you link with, so that the
+correct parts of pthread.h are included. That is, the possible
+defines require the following library versions:
+
+ __CLEANUP_SEH pthreadVSE.dll
+ __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll
+ __CLEANUP_C pthreadVC.dll or pthreadGC.dll
+
+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
+section were being used.
+
+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.
+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
+is canceled, or the thread calls pthread_exit().
+
+Your application will now most likely behave differently to previous
+versions, and in non-obvious ways. Most likely is that locally
+instantiated objects may not be destroyed or cleaned up after a thread
+is canceled.
+
+If you want the same behaviour as before, then you must now define
+__CLEANUP_C++ explicitly using a compiler option and link with
+pthreadVCE.dll as you did before.
+
+
+WHY ARE WE MAKING THE DEFAULT STYLE 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 unless
+you consciously choose to do otherwise, your pthreads applications will
+now run or crash in similar ways irrespective of the threads platform
+you use. Or at least this is the hope.
+
+
+
+Building under VC++ using C++ EH, Structured EH, or just C
+----------------------------------------------------------
+
+From the source directory run one of the following:
+
+nmake clean VCE (builds the VC++ C++ EH version pthreadVCE.dll)
+
+or:
+
+nmake clean VSE (builds the VC++ structured EH version pthreadVSE.dll)
+
+or:
+
+nmake clean VC (builds the VC setjmp/longjmp version of pthreadVC.dll)
+
+You can run the testsuite by changing to the "tests" directory and
+running the target corresponding to the DLL version you built:
+
+nmake clean VCE
+
+or:
+
+nmake clean VSE
+
+or:
+
+nmake clean VC
+
+or:
+
+nmake clean VCX (tests the VC version of the library with C++ (EH)
+ applications)
+
+
+Building under Mingw32
+----------------------
+
+The dll can be built with Mingw32 gcc-2.95.2-1 after you've
+made the changes to Mingw32 desribed in Question 6 of the FAQ.
+
+From the source directory, run
+
+make clean GCE
+
+or:
+
+make clean GC
+
+You can run the testsuite by changing to the "tests" directory and
+running
+
+make clean GCE
+
+or:
+
+make clean GC
+
+or:
+
+make clean GCX (tests the GC version of the library with C++ (EH)
+ applications)
+
+
+Building the library under Cygwin
+---------------------------------
+
+Not tested by me although I think some people have done this.
+Not sure how successfully though.
+
+Cygwin is implementing it's own POSIX threads routines and these
+will be the ones to use if you develop using Cygwin.
+
+
+Ready to run binaries
+---------------------
+
+For convenience, the following ready-to-run files can be downloaded
+from the FTP site (see under "Availability" below):
+
+ pthread.h
+ semaphore.h
+ sched.h
+ pthread.def
+ pthreadVCE.dll - built with MSVC++ compiler using C++ EH
+ pthreadVCE.lib
+ pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp
+ pthreadVC.lib
+ pthreadVSE.dll - built with MSVC compiler using SEH
+ pthreadVSE.lib
+ pthreadGCE.dll - built with Mingw32 G++
+ pthreadGCE.a - derived from pthreadGCE.dll
+ pthreadGC.dll - built with Mingw32 GCC
+ pthreadGC.a - derived from pthreadGC.dll
+ gcc.dll - needed to build and run applications that use
+ pthreadGCE.dll.
+
+
+Building applications with the library
+--------------------------------------
+
+Use the appropriate DLL and LIB files to match the exception handing
+that you use in your application, or specifically, in your POSIX
+threads. Don't mix them or neither thread cancelation nor
+pthread_exit() will work reliably if at all.
+
+If in doubt use the C (no-exceptions) versions of the library.
+
+
+Building applications with GNU compilers
+----------------------------------------
+
+If you're using pthreadGCE.dll:
+
+Use gcc-2.95.2-1 or later modified as per pthreads-win32 FAQ question 11.
+
+With the three header files, pthreadGCE.dll, gcc.dll and libpthreadGCE.a
+in the same directory as your application myapp.c, you could compile,
+link and run myapp.c under Mingw32 as follows:
+
+ gcc -x c++ -o myapp.exe myapp.c -I. -L. -lpthreadGCE
+ myapp
+
+Or put pthreadGCE.dll and gcc.dll in an appropriate directory in
+your PATH, put libpthreadGCE.a in MINGW_ROOT\i386-mingw32\lib, and
+put the three header files in MINGW_ROOT\i386-mingw32\include,
+then use:
+
+ gcc -x c++ -o myapp.exe myapp.c -lpthreadGCE
+ myapp
+
+If you're using pthreadGC.dll:
+
+With the three header files, pthreadGC.dll and libpthreadGC.a in the
+same directory as your application myapp.c, you could compile, link
+and run myapp.c under Mingw32 as follows:
+
+ gcc -o myapp.exe myapp.c -I. -L. -lpthreadGC
+ myapp
+
+Or put pthreadGC.dll in an appropriate directory in your PATH,
+put libpthreadGC.a in MINGW_ROOT\i386-mingw32\lib, and
+put the three header files in MINGW_ROOT\i386-mingw32\include,
+then use:
+
+ gcc -o myapp.exe myapp.c -lpthreadGC
+ myapp
+
+
+Availability
+------------
+
+The complete source code in either unbundled, self-extracting
+Zip file, or tar/gzipped format can be found at:
+
+ ftp://sources.redhat.com/pub/pthreads-win32
+
+The pre-built DLL, export libraries and matching pthread.h can
+be found at:
+
+ ftp://sources.redhat.com/pub/pthreads-win32/dll-latest
+
+Home page:
+
+ http://sources.redhat.com/pthreads-win32/
+
+
+Mailing list
+------------
+
+There is a mailing list for discussing pthreads on Win32.
+To join, send email to:
+
+ pthreads-win32-subscribe@sources.redhat.com
+
+Unsubscribe by sending mail to:
+
+ pthreads-win32-unsubscribe@sources.redhat.com
+
+
+Acknowledgements
+----------------
+
+Pthreads-win32 is based substantially on a Win32 Pthreads
+implementation contributed by John E. Bossom.
+Many others have contributed important new code,
+improvements and bug fixes. Thanks go to Alexander Terekhov
+and Louis Thomas for their improvements to the implementation
+of condition variables.
+
+See the 'CONTRIBUTORS' file for the list of contributors.
+
+As much as possible, the ChangeLog file also attributes
+contributions and patches that have been incorporated
+in the library.
+
+----
+Ross Johnson
+<rpj@ise.canberra.edu.au>
+
+
+
+
+
+
+
+
diff --git a/README.CV b/README.CV
index 522fa60..698728b 100644
--- a/README.CV
+++ b/README.CV
@@ -1,3036 +1,3036 @@
-README.CV -- Condition Variables
---------------------------------
-
-The original implementation of condition variables in
-pthreads-win32 was based on a discussion paper:
-
-"Strategies for Implementing POSIX Condition Variables
-on Win32": http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
-
-The changes suggested below were made on Feb 6 2001. This
-file is included in the package for the benefit of anyone
-interested in understanding the pthreads-win32 implementation
-of condition variables and the (sometimes subtle) issues that
-it attempts to resolve.
-
-Thanks go to the individuals whose names appear throughout
-the following text.
-
-Ross Johnson
-
---------------------------------------------------------------------
-
-fyi.. (more detailed problem description/demos + possible fix/patch)
-
-regards,
-alexander.
-
-
-Alexander Terekhov
-31.01.2001 17:43
-
-To: ace-bugs@cs.wustl.edu
-cc:
-From: Alexander Terekhov/Germany/IBM@IBMDE
-Subject: Implementation of POSIX CVs: spur.wakeups/lost
- signals/deadlocks/unfairness
-
-
-
- ACE VERSION:
-
- 5.1.12 (pthread-win32 snapshot 2000-12-29)
-
- HOST MACHINE and OPERATING SYSTEM:
-
- IBM IntelliStation Z Pro, 2 x XEON 1GHz, Win2K
-
- TARGET MACHINE and OPERATING SYSTEM, if different from HOST:
- COMPILER NAME AND VERSION (AND PATCHLEVEL):
-
- Microsoft Visual C++ 6.0
-
- AREA/CLASS/EXAMPLE AFFECTED:
-
- Implementation of POSIX condition variables - OS.cpp/.h
-
- DOES THE PROBLEM AFFECT:
-
- EXECUTION? YES!
-
- SYNOPSIS:
-
- a) spurious wakeups (minor problem)
- b) lost signals
- c) broadcast deadlock
- d) unfairness (minor problem)
-
- DESCRIPTION:
-
- Please see attached copy of discussion thread
- from comp.programming.threads for more details on
- some reported problems. (i've also posted a "fyi"
- message to ace-users a week or two ago but
- unfortunately did not get any response so far).
-
- It seems that current implementation suffers from
- two essential problems:
-
- 1) cond.waiters_count does not accurately reflect
- number of waiters blocked on semaphore - w/o
- proper synchronisation that could result (in the
- time window when counter is not accurate)
- in spurious wakeups organised by subsequent
- _signals and _broadcasts.
-
- 2) Always having (with no e.g. copy_and_clear/..)
- the same queue in use (semaphore+counter)
- neither signal nor broadcast provide 'atomic'
- behaviour with respect to other threads/subsequent
- calls to signal/broadcast/wait.
-
- Each problem and combination of both could produce
- various nasty things:
-
- a) spurious wakeups (minor problem)
-
- it is possible that waiter(s) which was already
- unblocked even so is still counted as blocked
- waiter. signal and broadcast will release
- semaphore which will produce a spurious wakeup
- for a 'real' waiter coming later.
-
- b) lost signals
-
- signalling thread ends up consuming its own
- signal. please see demo/discussion below.
-
- c) broadcast deadlock
-
- last_waiter processing code does not correctly
- handle the case with multiple threads
- waiting for the end of broadcast.
- please see demo/discussion below.
-
- d) unfairness (minor problem)
-
- without SignalObjectAndWait some waiter(s)
- may end up consuming broadcasted signals
- multiple times (spurious wakeups) because waiter
- thread(s) can be preempted before they call
- semaphore wait (but after count++ and mtx.unlock).
-
- REPEAT BY:
-
- See below... run problem demos programs (tennis.cpp and
- tennisb.cpp) number of times concurrently (on multiprocessor)
- and in multiple sessions or just add a couple of "Sleep"s
- as described in the attached copy of discussion thread
- from comp.programming.threads
-
- SAMPLE FIX/WORKAROUND:
-
- See attached patch to pthread-win32.. well, I can not
- claim that it is completely bug free but at least my
- test and tests provided by pthreads-win32 seem to work.
- Perhaps that will help.
-
- regards,
- alexander.
-
-
->> Forum: comp.programming.threads
->> Thread: pthread_cond_* implementation questions
-.
-.
-.
-David Schwartz <davids@webmaster.com> wrote:
-
-> terekhov@my-deja.com wrote:
->
->> BTW, could you please also share your view on other perceived
->> "problems" such as nested broadcast deadlock, spurious wakeups
->> and (the latest one) lost signals??
->
->I'm not sure what you mean. The standard allows an implementation
->to do almost whatever it likes. In fact, you could implement
->pthread_cond_wait by releasing the mutex, sleeping a random
->amount of time, and then reacquiring the mutex. Of course,
->this would be a pretty poor implementation, but any code that
->didn't work under that implementation wouldn't be strictly
->compliant.
-
-The implementation you suggested is indeed correct
-one (yes, now I see it :). However it requires from
-signal/broadcast nothing more than to "{ return 0; }"
-That is not the case for pthread-win32 and ACE
-implementations. I do think that these implementations
-(basically the same implementation) have some serious
-problems with wait/signal/broadcast calls. I am looking
-for help to clarify whether these problems are real
-or not. I think that I can demonstrate what I mean
-using one or two small sample programs.
-.
-.
-.
-==========
-tennis.cpp
-==========
-
-#include "ace/Synch.h"
-#include "ace/Thread.h"
-
-enum GAME_STATE {
-
- START_GAME,
- PLAYER_A, // Player A playes the ball
- PLAYER_B, // Player B playes the ball
- GAME_OVER,
- ONE_PLAYER_GONE,
- BOTH_PLAYERS_GONE
-
-};
-
-enum GAME_STATE eGameState;
-ACE_Mutex* pmtxGameStateLock;
-ACE_Condition< ACE_Mutex >* pcndGameStateChange;
-
-void*
- playerA(
- void* pParm
- )
-{
-
- // For access to game state variable
- pmtxGameStateLock->acquire();
-
- // Play loop
- while ( eGameState < GAME_OVER ) {
-
- // Play the ball
- cout << endl << "PLAYER-A" << endl;
-
- // Now its PLAYER-B's turn
- eGameState = PLAYER_B;
-
- // Signal to PLAYER-B that now it is his turn
- pcndGameStateChange->signal();
-
- // Wait until PLAYER-B finishes playing the ball
- do {
-
- pcndGameStateChange->wait();
-
- if ( PLAYER_B == eGameState )
- cout << endl << "----PLAYER-A: SPURIOUS WAKEUP!!!" << endl;
-
- } while ( PLAYER_B == eGameState );
-
- }
-
- // PLAYER-A gone
- eGameState = (GAME_STATE)(eGameState+1);
- cout << endl << "PLAYER-A GONE" << endl;
-
- // No more access to state variable needed
- pmtxGameStateLock->release();
-
- // Signal PLAYER-A gone event
- pcndGameStateChange->broadcast();
-
- return 0;
-
-}
-
-void*
- playerB(
- void* pParm
- )
-{
-
- // For access to game state variable
- pmtxGameStateLock->acquire();
-
- // Play loop
- while ( eGameState < GAME_OVER ) {
-
- // Play the ball
- cout << endl << "PLAYER-B" << endl;
-
- // Now its PLAYER-A's turn
- eGameState = PLAYER_A;
-
- // Signal to PLAYER-A that now it is his turn
- pcndGameStateChange->signal();
-
- // Wait until PLAYER-A finishes playing the ball
- do {
-
- pcndGameStateChange->wait();
-
- if ( PLAYER_A == eGameState )
- cout << endl << "----PLAYER-B: SPURIOUS WAKEUP!!!" << endl;
-
- } while ( PLAYER_A == eGameState );
-
- }
-
- // PLAYER-B gone
- eGameState = (GAME_STATE)(eGameState+1);
- cout << endl << "PLAYER-B GONE" << endl;
-
- // No more access to state variable needed
- pmtxGameStateLock->release();
-
- // Signal PLAYER-B gone event
- pcndGameStateChange->broadcast();
-
- return 0;
-
-}
-
-
-int
-main (int, ACE_TCHAR *[])
-{
-
- pmtxGameStateLock = new ACE_Mutex();
- pcndGameStateChange = new ACE_Condition< ACE_Mutex >( *pmtxGameStateLock
-);
-
- // Set initial state
- eGameState = START_GAME;
-
- // Create players
- ACE_Thread::spawn( playerA );
- ACE_Thread::spawn( playerB );
-
- // Give them 5 sec. to play
- Sleep( 5000 );//sleep( 5 );
-
- // Set game over state
- pmtxGameStateLock->acquire();
- eGameState = GAME_OVER;
-
- // Let them know
- pcndGameStateChange->broadcast();
-
- // Wait for players to stop
- do {
-
- pcndGameStateChange->wait();
-
- } while ( eGameState < BOTH_PLAYERS_GONE );
-
- // Cleanup
- cout << endl << "GAME OVER" << endl;
- pmtxGameStateLock->release();
- delete pcndGameStateChange;
- delete pmtxGameStateLock;
-
- return 0;
-
-}
-
-===========
-tennisb.cpp
-===========
-#include "ace/Synch.h"
-#include "ace/Thread.h"
-
-enum GAME_STATE {
-
- START_GAME,
- PLAYER_A, // Player A playes the ball
- PLAYER_B, // Player B playes the ball
- GAME_OVER,
- ONE_PLAYER_GONE,
- BOTH_PLAYERS_GONE
-
-};
-
-enum GAME_STATE eGameState;
-ACE_Mutex* pmtxGameStateLock;
-ACE_Condition< ACE_Mutex >* pcndGameStateChange;
-
-void*
- playerA(
- void* pParm
- )
-{
-
- // For access to game state variable
- pmtxGameStateLock->acquire();
-
- // Play loop
- while ( eGameState < GAME_OVER ) {
-
- // Play the ball
- cout << endl << "PLAYER-A" << endl;
-
- // Now its PLAYER-B's turn
- eGameState = PLAYER_B;
-
- // Signal to PLAYER-B that now it is his turn
- pcndGameStateChange->broadcast();
-
- // Wait until PLAYER-B finishes playing the ball
- do {
-
- pcndGameStateChange->wait();
-
- if ( PLAYER_B == eGameState )
- cout << endl << "----PLAYER-A: SPURIOUS WAKEUP!!!" << endl;
-
- } while ( PLAYER_B == eGameState );
-
- }
-
- // PLAYER-A gone
- eGameState = (GAME_STATE)(eGameState+1);
- cout << endl << "PLAYER-A GONE" << endl;
-
- // No more access to state variable needed
- pmtxGameStateLock->release();
-
- // Signal PLAYER-A gone event
- pcndGameStateChange->broadcast();
-
- return 0;
-
-}
-
-void*
- playerB(
- void* pParm
- )
-{
-
- // For access to game state variable
- pmtxGameStateLock->acquire();
-
- // Play loop
- while ( eGameState < GAME_OVER ) {
-
- // Play the ball
- cout << endl << "PLAYER-B" << endl;
-
- // Now its PLAYER-A's turn
- eGameState = PLAYER_A;
-
- // Signal to PLAYER-A that now it is his turn
- pcndGameStateChange->broadcast();
-
- // Wait until PLAYER-A finishes playing the ball
- do {
-
- pcndGameStateChange->wait();
-
- if ( PLAYER_A == eGameState )
- cout << endl << "----PLAYER-B: SPURIOUS WAKEUP!!!" << endl;
-
- } while ( PLAYER_A == eGameState );
-
- }
-
- // PLAYER-B gone
- eGameState = (GAME_STATE)(eGameState+1);
- cout << endl << "PLAYER-B GONE" << endl;
-
- // No more access to state variable needed
- pmtxGameStateLock->release();
-
- // Signal PLAYER-B gone event
- pcndGameStateChange->broadcast();
-
- return 0;
-
-}
-
-
-int
-main (int, ACE_TCHAR *[])
-{
-
- pmtxGameStateLock = new ACE_Mutex();
- pcndGameStateChange = new ACE_Condition< ACE_Mutex >( *pmtxGameStateLock
-);
-
- // Set initial state
- eGameState = START_GAME;
-
- // Create players
- ACE_Thread::spawn( playerA );
- ACE_Thread::spawn( playerB );
-
- // Give them 5 sec. to play
- Sleep( 5000 );//sleep( 5 );
-
- // Make some noise
- pmtxGameStateLock->acquire();
- cout << endl << "---Noise ON..." << endl;
- pmtxGameStateLock->release();
- for ( int i = 0; i < 100000; i++ )
- pcndGameStateChange->broadcast();
- cout << endl << "---Noise OFF" << endl;
-
- // Set game over state
- pmtxGameStateLock->acquire();
- eGameState = GAME_OVER;
- cout << endl << "---Stopping the game..." << endl;
-
- // Let them know
- pcndGameStateChange->broadcast();
-
- // Wait for players to stop
- do {
-
- pcndGameStateChange->wait();
-
- } while ( eGameState < BOTH_PLAYERS_GONE );
-
- // Cleanup
- cout << endl << "GAME OVER" << endl;
- pmtxGameStateLock->release();
- delete pcndGameStateChange;
- delete pmtxGameStateLock;
-
- return 0;
-
-}
-.
-.
-.
-David Schwartz <davids@webmaster.com> wrote:
->> > It's compliant
->>
->> That is really good.
->
->> Tomorrow (I have to go urgently now) I will try to
->> demonstrate the lost-signal "problem" of current
->> pthread-win32 and ACE-(variant w/o SingleObjectAndWait)
->> implementations: players start suddenly drop their balls :-)
->> (with no change in source code).
->
->Signals aren't lost, they're going to the main thread,
->which isn't coded correctly to handle them. Try this:
->
-> // Wait for players to stop
-> do {
->
-> pthread_cond_wait( &cndGameStateChange,&mtxGameStateLock );
->printf("Main thread stole a signal\n");
->
-> } while ( eGameState < BOTH_PLAYERS_GONE );
->
->I bet everytime you thing a signal is lost, you'll see that printf.
->The signal isn't lost, it was stolen by another thread.
-
-well, you can probably loose your bet.. it was indeed stolen
-by "another" thread but not the one you seem to think of.
-
-I think that what actually happens is the following:
-
-H:\SA\UXX\pt\PTHREADS\TESTS>tennis3.exe
-
-PLAYER-A
-
-PLAYER-B
-
-----PLAYER-B: SPURIOUS WAKEUP!!!
-
-PLAYER-A GONE
-
-PLAYER-B GONE
-
-GAME OVER
-
-H:\SA\UXX\pt\PTHREADS\TESTS>
-
-here you can see that PLAYER-B after playing his first
-ball (which came via signal from PLAYER-A) just dropped
-it down. What happened is that his signal to player A
-was consumed as spurious wakeup by himself (player B).
-
-The implementation has a problem:
-
-================
-waiting threads:
-================
-
-{ /** Critical Section
-
- inc cond.waiters_count
-
-}
-
- /*
- /* Atomic only if using Win32 SignalObjectAndWait
- /*
- cond.mtx.release
-
- /*** ^^-- A THREAD WHICH DID SIGNAL MAY ACQUIRE THE MUTEX,
- /*** GO INTO WAIT ON THE SAME CONDITION AND OVERTAKE
- /*** ORIGINAL WAITER(S) CONSUMING ITS OWN SIGNAL!
-
- cond.sem.wait
-
-Player-A after playing game's initial ball went into
-wait (called _wait) but was pre-empted before reaching
-wait semaphore. He was counted as waiter but was not
-actually waiting/blocked yet.
-
-===============
-signal threads:
-===============
-
-{ /** Critical Section
-
- waiters_count = cond.waiters_count
-
-}
-
- if ( waiters_count != 0 )
-
- sem.post 1
-
- endif
-
-Player-B after he received signal/ball from Player A
-called _signal. The _signal did see that there was
-one waiter blocked on the condition (Player-A) and
-released the semaphore.. (but it did not unblock
-Player-A because he was not actually blocked).
-Player-B thread continued its execution, called _wait,
-was counted as second waiter BUT was allowed to slip
-through opened semaphore gate (which was opened for
-Player-B) and received his own signal. Player B remained
-blocked followed by Player A. Deadlock happened which
-lasted until main thread came in and said game over.
-
-It seems to me that the implementation fails to
-correctly implement the following statement
-from specification:
-
-http://www.opengroup.org/
-onlinepubs/007908799/xsh/pthread_cond_wait.html
-
-"These functions atomically release mutex and cause
-the calling thread to block on the condition variable
-cond; atomically here means "atomically with respect
-to access by another thread to the mutex and then the
-condition variable". That is, if another thread is
-able to acquire the mutex after the about-to-block
-thread has released it, then a subsequent call to
-pthread_cond_signal() or pthread_cond_broadcast()
-in that thread behaves as if it were issued after
-the about-to-block thread has blocked."
-
-Question: Am I right?
-
-(I produced the program output above by simply
-adding ?Sleep( 1 )?:
-
-================
-waiting threads:
-================
-
-{ /** Critical Section
-
- inc cond.waiters_count
-
-}
-
- /*
- /* Atomic only if using Win32 SignalObjectAndWait
- /*
- cond.mtx.release
-
-Sleep( 1 ); // Win32
-
- /*** ^^-- A THREAD WHICH DID SIGNAL MAY ACQUIRE THE MUTEX,
- /*** GO INTO WAIT ON THE SAME CONDITION AND OVERTAKE
- /*** ORIGINAL WAITER(S) CONSUMING ITS OWN SIGNAL!
-
- cond.sem.wait
-
-to the source code of pthread-win32 implementation:
-
-http://sources.redhat.com/cgi-bin/cvsweb.cgi/pthreads/
-condvar.c?rev=1.36&content-type=text/
-x-cvsweb-markup&cvsroot=pthreads-win32
-
-
- /*
- * We keep the lock held just long enough to increment the count of
- * waiters by one (above).
- * Note that we can't keep it held across the
- * call to sem_wait since that will deadlock other calls
- * to pthread_cond_signal
- */
- cleanup_args.mutexPtr = mutex;
- cleanup_args.cv = cv;
- cleanup_args.resultPtr = &result;
-
- pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *)
-&cleanup_args);
-
- if ((result = pthread_mutex_unlock (mutex)) == 0)
- {((result
-Sleep( 1 ); // @AT
-
- /*
- * Wait to be awakened by
- * pthread_cond_signal, or
- * pthread_cond_broadcast, or
- * a timeout
- *
- * Note:
- * ptw32_sem_timedwait is a cancelation point,
- * hence providing the
- * mechanism for making pthread_cond_wait a cancelation
- * point. We use the cleanup mechanism to ensure we
- * re-lock the mutex and decrement the waiters count
- * if we are canceled.
- */
- if (ptw32_sem_timedwait (&(cv->sema), abstime) == -1) {
- result = errno;
- }
- }
-
- pthread_cleanup_pop (1); /* Always cleanup */
-
-
-BTW, on my system (2 CPUs) I can manage to get
-signals lost even without any source code modification
-if I run the tennis program many times in different
-shell sessions.
-.
-.
-.
-David Schwartz <davids@webmaster.com> wrote:
->terekhov@my-deja.com wrote:
->
->> well, it might be that the program is in fact buggy.
->> but you did not show me any bug.
->
->You're right. I was close but not dead on. I was correct, however,
->that the code is buggy because it uses 'pthread_cond_signal' even
->though not any thread waiting on the condition variable can do the
->job. I was wrong in which thread could be waiting on the cv but
->unable to do the job.
-
-Okay, lets change 'pthread_cond_signal' to 'pthread_cond_broadcast'
-but also add some noise from main() right before declaring the game
-to be over (I need it in order to demonstrate another problem of
-pthread-win32/ACE implementations - broadcast deadlock)...
-.
-.
-.
-It is my understanding of POSIX conditions,
-that on correct implementation added noise
-in form of unnecessary broadcasts from main,
-should not break the tennis program. The
-only 'side effect' of added noise on correct
-implementation would be 'spurious wakeups' of
-players (in fact they are not spurious,
-players just see them as spurious) unblocked,
-not by another player but by main before
-another player had a chance to acquire the
-mutex and change the game state variable:
-.
-.
-.
-
-PLAYER-B
-
-PLAYER-A
-
----Noise ON...
-
-PLAYER-B
-
-PLAYER-A
-
-.
-.
-.
-
-PLAYER-B
-
-PLAYER-A
-
-----PLAYER-A: SPURIOUS WAKEUP!!!
-
-PLAYER-B
-
-PLAYER-A
-
----Noise OFF
-
-PLAYER-B
-
----Stopping the game...
-
-PLAYER-A GONE
-
-PLAYER-B GONE
-
-GAME OVER
-
-H:\SA\UXX\pt\PTHREADS\TESTS>
-
-On pthread-win32/ACE implementations the
-program could stall:
-
-.
-.
-.
-
-PLAYER-A
-
-PLAYER-B
-
-PLAYER-A
-
-PLAYER-B
-
-PLAYER-A
-
-PLAYER-B
-
-PLAYER-A
-
-PLAYER-B
-
----Noise ON...
-
-PLAYER-A
-
----Noise OFF
-^C
-H:\SA\UXX\pt\PTHREADS\TESTS>
-
-
-The implementation has problems:
-
-================
-waiting threads:
-================
-
-{ /** Critical Section
-
- inc cond.waiters_count
-
-}
-
- /*
- /* Atomic only if using Win32 SignalObjectAndWait
- /*
- cond.mtx.release
- cond.sem.wait
-
- /*** ^^-- WAITER CAN BE PREEMPTED AFTER BEING UNBLOCKED...
-
-{ /** Critical Section
-
- dec cond.waiters_count
-
- /*** ^^- ...AND BEFORE DECREMENTING THE COUNT (1)
-
- last_waiter = ( cond.was_broadcast &&
- cond.waiters_count == 0 )
-
- if ( last_waiter )
-
- cond.was_broadcast = FALSE
-
- endif
-
-}
-
- if ( last_waiter )
-
- /*
- /* Atomic only if using Win32 SignalObjectAndWait
- /*
- cond.auto_reset_event_or_sem.post /* Event for Win32
- cond.mtx.acquire
-
- /*** ^^-- ...AND BEFORE CALL TO mtx.acquire (2)
-
- /*** ^^-- NESTED BROADCASTS RESULT IN A DEADLOCK
-
-
- else
-
- cond.mtx.acquire
-
- /*** ^^-- ...AND BEFORE CALL TO mtx.acquire (3)
-
- endif
-
-
-==================
-broadcast threads:
-==================
-
-{ /** Critical Section
-
- waiters_count = cond.waiters_count
-
- if ( waiters_count != 0 )
-
- cond.was_broadcast = TRUE
-
- endif
-
-}
-
-if ( waiters_count != 0 )
-
- cond.sem.post waiters_count
-
- /*** ^^^^^--- SPURIOUS WAKEUPS DUE TO (1)
-
- cond.auto_reset_event_or_sem.wait /* Event for Win32
-
- /*** ^^^^^--- DEADLOCK FOR FURTHER BROADCASTS IF THEY
- HAPPEN TO GO INTO WAIT WHILE PREVIOUS
- BROADCAST IS STILL IN PROGRESS/WAITING
-
-endif
-
-a) cond.waiters_count does not accurately reflect
-number of waiters blocked on semaphore - that could
-result (in the time window when counter is not accurate)
-in spurios wakeups organised by subsequent _signals
-and _broadcasts. From standard compliance point of view
-that is OK but that could be a real problem from
-performance/efficiency point of view.
-
-b) If subsequent broadcast happen to go into wait on
-cond.auto_reset_event_or_sem before previous
-broadcast was unblocked from cond.auto_reset_event_or_sem
-by its last waiter, one of two blocked threads will
-remain blocked because last_waiter processing code
-fails to unblock both threads.
-
-In the situation with tennisb.c the Player-B was put
-in a deadlock by noise (broadcast) coming from main
-thread. And since Player-B holds the game state
-mutex when it calls broadcast, the whole program
-stalled: Player-A was deadlocked on mutex and
-main thread after finishing with producing the noise
-was deadlocked on mutex too (needed to declare the
-game over)
-
-(I produced the program output above by simply
-adding ?Sleep( 1 )?:
-
-==================
-broadcast threads:
-==================
-
-{ /** Critical Section
-
- waiters_count = cond.waiters_count
-
- if ( waiters_count != 0 )
-
- cond.was_broadcast = TRUE
-
- endif
-
-}
-
-if ( waiters_count != 0 )
-
-Sleep( 1 ); //Win32
-
- cond.sem.post waiters_count
-
- /*** ^^^^^--- SPURIOUS WAKEUPS DUE TO (1)
-
- cond.auto_reset_event_or_sem.wait /* Event for Win32
-
- /*** ^^^^^--- DEADLOCK FOR FURTHER BROADCASTS IF THEY
- HAPPEN TO GO INTO WAIT WHILE PREVIOUS
- BROADCAST IS STILL IN PROGRESS/WAITING
-
-endif
-
-to the source code of pthread-win32 implementation:
-
-http://sources.redhat.com/cgi-bin/cvsweb.cgi/pthreads/
-condvar.c?rev=1.36&content-type=text/
-x-cvsweb-markup&cvsroot=pthreads-win32
-
- if (wereWaiters)
- {(wereWaiters)sroot=pthreads-win32eb.cgi/pthreads/Yem...m
- /*
- * Wake up all waiters
- */
-
-Sleep( 1 ); //@AT
-
-#ifdef NEED_SEM
-
- result = (ptw32_increase_semaphore( &cv->sema, cv->waiters )
- ? 0
- : EINVAL);
-
-#else /* NEED_SEM */
-
- result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL )
- ? 0
- : EINVAL);
-
-#endif /* NEED_SEM */
-
- }
-
- (void) pthread_mutex_unlock(&(cv->waitersLock));
-
- if (wereWaiters && result == 0)
- {(wereWaiters
- /*
- * Wait for all the awakened threads to acquire their part of
- * the counting semaphore
- */
-
- if (WaitForSingleObject (cv->waitersDone, INFINITE)
- == WAIT_OBJECT_0)
- {
- result = 0;
- }
- else
- {
- result = EINVAL;
- }
-
- }
-
- return (result);
-
-}
-
-BTW, on my system (2 CPUs) I can manage to get
-the program stalled even without any source code
-modification if I run the tennisb program many
-times in different shell sessions.
-
-===================
-pthread-win32 patch
-===================
-struct pthread_cond_t_ {
- long nWaitersBlocked; /* Number of threads blocked
-*/
- long nWaitersUnblocked; /* Number of threads unblocked
-*/
- long nWaitersToUnblock; /* Number of threads to unblock
-*/
- sem_t semBlockQueue; /* Queue up threads waiting for the
-*/
- /* condition to become signalled
-*/
- sem_t semBlockLock; /* Semaphore that guards access to
-*/
- /* | waiters blocked count/block queue
-*/
- /* +-> Mandatory Sync.LEVEL-1
-*/
- pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to
-*/
- /* | waiters (to)unblock(ed) counts
-*/
- /* +-> Optional* Sync.LEVEL-2
-*/
-}; /* Opt*) for _timedwait and
-cancellation*/
-
-int
-pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
- int result = EAGAIN;
- pthread_cond_t cv = NULL;
-
- if (cond == NULL)
- {(cond
- return EINVAL;
- }
-
- if ((attr != NULL && *attr != NULL) &&
- ((*attr)->pshared == PTHREAD_PROCESS_SHARED))
- {
- /*
- * Creating condition variable that can be shared between
- * processes.
- */
- result = ENOSYS;
-
- goto FAIL0;
- }
-
- cv = (pthread_cond_t) calloc (1, sizeof (*cv));
-
- if (cv == NULL)
- {(cv
- result = ENOMEM;
- goto FAIL0;
- }
-
- cv->nWaitersBlocked = 0;
- cv->nWaitersUnblocked = 0;
- cv->nWaitersToUnblock = 0;
-
- if (sem_init (&(cv->semBlockLock), 0, 1) != 0)
- {(sem_init
- goto FAIL0;
- }
-
- if (sem_init (&(cv->semBlockQueue), 0, 0) != 0)
- {(sem_init
- goto FAIL1;
- }
-
- if (pthread_mutex_init (&(cv->mtxUnblockLock), 0) != 0)
- {(pthread_mutex_init
- goto FAIL2;
- }
-
-
- result = 0;
-
- goto DONE;
-
- /*
- * -------------
- * Failed...
- * -------------
- */
-FAIL2:
- (void) sem_destroy (&(cv->semBlockQueue));
-
-FAIL1:
- (void) sem_destroy (&(cv->semBlockLock));
-
-FAIL0:
-DONE:
- *cond = cv;
-
- return (result);
-
-} /* pthread_cond_init */
-
-int
-pthread_cond_destroy (pthread_cond_t * cond)
-{
- int result = 0;
- pthread_cond_t cv;
-
- /*
- * Assuming any race condition here is harmless.
- */
- if (cond == NULL
- || *cond == NULL)
- {
- return EINVAL;
- }
-
- if (*cond != (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
- {(*cond
- cv = *cond;
-
- /*
- * Synchronize access to waiters blocked count (LEVEL-1)
- */
- if (sem_wait(&(cv->semBlockLock)) != 0)
- {(sem_wait(&(cv->semBlockLock))
- return errno;
- }
-
- /*
- * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
- */
- if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
- {((result
- (void) sem_post(&(cv->semBlockLock));
- return result;
- }
-
- /*
- * Check whether cv is still busy (still has waiters blocked)
- */
- if (cv->nWaitersBlocked - cv->nWaitersUnblocked > 0)
- {(cv->nWaitersBlocked
- (void) sem_post(&(cv->semBlockLock));
- (void) pthread_mutex_unlock(&(cv->mtxUnblockLock));
- return EBUSY;
- }
-
- /*
- * Now it is safe to destroy
- */
- (void) sem_destroy (&(cv->semBlockLock));
- (void) sem_destroy (&(cv->semBlockQueue));
- (void) pthread_mutex_unlock (&(cv->mtxUnblockLock));
- (void) pthread_mutex_destroy (&(cv->mtxUnblockLock));
-
- free(cv);
- *cond = NULL;
- }
- else
- {
- /*
- * See notes in ptw32_cond_check_need_init() above also.
- */
- EnterCriticalSection(&ptw32_cond_test_init_lock);
-
- /*
- * Check again.
- */
- if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
- {(*cond
- /*
- * This is all we need to do to destroy a statically
- * initialised cond that has not yet been used (initialised).
- * If we get to here, another thread
- * waiting to initialise this cond will get an EINVAL.
- */
- *cond = NULL;
- }
- else
- {
- /*
- * The cv has been initialised while we were waiting
- * so assume it's in use.
- */
- result = EBUSY;
- }
-
- LeaveCriticalSection(&ptw32_cond_test_init_lock);
- }
-
- return (result);
-}
-
-/*
- * Arguments for cond_wait_cleanup, since we can only pass a
- * single void * to it.
- */
-typedef struct {
- pthread_mutex_t * mutexPtr;
- pthread_cond_t cv;
- int * resultPtr;
-} ptw32_cond_wait_cleanup_args_t;
-
-static void
-ptw32_cond_wait_cleanup(void * args)
-{
- ptw32_cond_wait_cleanup_args_t * cleanup_args =
-(ptw32_cond_wait_cleanup_args_t *) args;
- pthread_cond_t cv = cleanup_args->cv;
- int * resultPtr = cleanup_args->resultPtr;
- int eLastSignal; /* enum: 1=yes 0=no -1=cancelled/timedout w/o signal(s)
-*/
- int result;
-
- /*
- * Whether we got here as a result of signal/broadcast or because of
- * timeout on wait or thread cancellation we indicate that we are no
- * longer waiting. The waiter is responsible for adjusting waiters
- * (to)unblock(ed) counts (protected by unblock lock).
- * Unblock lock/Sync.LEVEL-2 supports _timedwait and cancellation.
- */
- if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
- {((result
- *resultPtr = result;
- return;
- }
-
- cv->nWaitersUnblocked++;
-
- eLastSignal = (cv->nWaitersToUnblock == 0) ?
- -1 : (--cv->nWaitersToUnblock == 0);
-
- /*
- * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed
- */
- if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
- {((result
- *resultPtr = result;
- return;
- }
-
- /*
- * If last signal...
- */
- if (eLastSignal == 1)
- {(eLastSignal
- /*
- * ...it means that we have end of 'atomic' signal/broadcast
- */
- if (sem_post(&(cv->semBlockLock)) != 0)
- {(sem_post(&(cv->semBlockLock))
- *resultPtr = errno;
- return;
- }
- }
- /*
- * If not last signal and not timed out/cancelled wait w/o signal...
- */
- else if (eLastSignal == 0)
- {
- /*
- * ...it means that next waiter can go through semaphore
- */
- if (sem_post(&(cv->semBlockQueue)) != 0)
- {(sem_post(&(cv->semBlockQueue))
- *resultPtr = errno;
- return;
- }
- }
-
- /*
- * XSH: Upon successful return, the mutex has been locked and is owned
- * by the calling thread
- */
- if ((result = pthread_mutex_lock(cleanup_args->mutexPtr)) != 0)
- {((result
- *resultPtr = result;
- }
-
-} /* ptw32_cond_wait_cleanup */
-
-static int
-ptw32_cond_timedwait (pthread_cond_t * cond,
- pthread_mutex_t * mutex,
- const struct timespec *abstime)
-{
- int result = 0;
- pthread_cond_t cv;
- ptw32_cond_wait_cleanup_args_t cleanup_args;
-
- if (cond == NULL || *cond == NULL)
- {(cond
- return EINVAL;
- }
-
- /*
- * We do a quick check to see if we need to do more work
- * to initialise a static condition variable. We check
- * again inside the guarded section of ptw32_cond_check_need_init()
- * to avoid race conditions.
- */
- if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
- {(*cond
- result = ptw32_cond_check_need_init(cond);
- }
-
- if (result != 0 && result != EBUSY)
- {(result
- return result;
- }
-
- cv = *cond;
-
- /*
- * Synchronize access to waiters blocked count (LEVEL-1)
- */
- if (sem_wait(&(cv->semBlockLock)) != 0)
- {(sem_wait(&(cv->semBlockLock))
- return errno;
- }
-
- cv->nWaitersBlocked++;
-
- /*
- * Thats it. Counted means waiting, no more access needed
- */
- if (sem_post(&(cv->semBlockLock)) != 0)
- {(sem_post(&(cv->semBlockLock))
- return errno;
- }
-
- /*
- * Setup this waiter cleanup handler
- */
- cleanup_args.mutexPtr = mutex;
- cleanup_args.cv = cv;
- cleanup_args.resultPtr = &result;
-
- pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args);
-
- /*
- * Now we can release 'mutex' and...
- */
- if ((result = pthread_mutex_unlock (mutex)) == 0)
- {((result
-
- /*
- * ...wait to be awakened by
- * pthread_cond_signal, or
- * pthread_cond_broadcast, or
- * timeout, or
- * thread cancellation
- *
- * Note:
- *
- * ptw32_sem_timedwait is 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
- * counts if we are cancelled, timed out or signalled.
- */
- if (ptw32_sem_timedwait (&(cv->semBlockQueue), abstime) != 0)
- {(ptw32_sem_timedwait
- result = errno;
- }
- }
-
- /*
- * Always cleanup
- */
- pthread_cleanup_pop (1);
-
-
- /*
- * "result" can be modified by the cleanup handler.
- */
- return (result);
-
-} /* ptw32_cond_timedwait */
-
-
-static int
-ptw32_cond_unblock (pthread_cond_t * cond,
- int unblockAll)
-{
- int result;
- pthread_cond_t cv;
-
- if (cond == NULL || *cond == NULL)
- {(cond
- return EINVAL;
- }
-
- cv = *cond;
-
- /*
- * No-op if the CV is static and hasn't been initialised yet.
- * Assuming that any race condition is harmless.
- */
- if (cv == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
- {(cv
- return 0;
- }
-
- /*
- * Synchronize access to waiters blocked count (LEVEL-1)
- */
- if (sem_wait(&(cv->semBlockLock)) != 0)
- {(sem_wait(&(cv->semBlockLock))
- return errno;
- }
-
- /*
- * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
- * This sync.level supports _timedwait and cancellation
- */
- if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
- {((result
- return result;
- }
-
- /*
- * Adjust waiters blocked and unblocked counts (collect garbage)
- */
- if (cv->nWaitersUnblocked != 0)
- {(cv->nWaitersUnblocked
- cv->nWaitersBlocked -= cv->nWaitersUnblocked;
- cv->nWaitersUnblocked = 0;
- }
-
- /*
- * If (after adjustment) there are still some waiters blocked counted...
- */
- if ( cv->nWaitersBlocked > 0)
- {(
- /*
- * We will unblock first waiter and leave semBlockLock/LEVEL-1 locked
- * LEVEL-1 access is left disabled until last signal/unblock
-completes
- */
- cv->nWaitersToUnblock = (unblockAll) ? cv->nWaitersBlocked : 1;
-
- /*
- * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed
- * This sync.level supports _timedwait and cancellation
- */
- if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
- {((result
- return result;
- }
-
-
- /*
- * Now, with LEVEL-2 lock released let first waiter go through
-semaphore
- */
- if (sem_post(&(cv->semBlockQueue)) != 0)
- {(sem_post(&(cv->semBlockQueue))
- return errno;
- }
- }
- /*
- * No waiter blocked - no more LEVEL-1 access to blocked count needed...
- */
- else if (sem_post(&(cv->semBlockLock)) != 0)
- {
- return errno;
- }
- /*
- * ...and no more LEVEL-2 access to waiters (to)unblock(ed) counts needed
-too
- * This sync.level supports _timedwait and cancellation
- */
- else
- {
- result = pthread_mutex_unlock(&(cv->mtxUnblockLock));
- }
-
- return(result);
-
-} /* ptw32_cond_unblock */
-
-int
-pthread_cond_wait (pthread_cond_t * cond,
- pthread_mutex_t * mutex)
-{
- /* The NULL abstime arg means INFINITE waiting. */
- return(ptw32_cond_timedwait(cond, mutex, NULL));
-} /* pthread_cond_wait */
-
-
-int
-pthread_cond_timedwait (pthread_cond_t * cond,
- pthread_mutex_t * mutex,
- const struct timespec *abstime)
-{
- if (abstime == NULL)
- {(abstime
- return EINVAL;
- }
-
- return(ptw32_cond_timedwait(cond, mutex, abstime));
-} /* pthread_cond_timedwait */
-
-
-int
-pthread_cond_signal (pthread_cond_t * cond)
-{
- /* The '0'(FALSE) unblockAll arg means unblock ONE waiter. */
- return(ptw32_cond_unblock(cond, 0));
-} /* pthread_cond_signal */
-
-int
-pthread_cond_broadcast (pthread_cond_t * cond)
-{
- /* The '1'(TRUE) unblockAll arg means unblock ALL waiters. */
- return(ptw32_cond_unblock(cond, 1));
-} /* pthread_cond_broadcast */
-
-
-
-
-TEREKHOV@de.ibm.com on 17.01.2001 01:00:57
-
-Please respond to TEREKHOV@de.ibm.com
-
-To: pthreads-win32@sourceware.cygnus.com
-cc: schmidt@uci.edu
-Subject: win32 conditions: sem+counter+event = broadcast_deadlock +
- spur.wakeup/unfairness/incorrectness ??
-
-
-
-
-
-
-
-Hi,
-
-Problem 1: broadcast_deadlock
-
-It seems that current implementation does not provide "atomic"
-broadcasts. That may lead to "nested" broadcasts... and it seems
-that nested case is not handled correctly -> producing a broadcast
-DEADLOCK as a result.
-
-Scenario:
-
-N (>1) waiting threads W1..N are blocked (in _wait) on condition's
-semaphore.
-
-Thread B1 calls pthread_cond_broadcast, which results in "releasing" N
-W threads via incrementing semaphore counter by N (stored in
-cv->waiters) BUT cv->waiters counter does not change!! The caller
-thread B1 remains blocked on cv->waitersDone event (auto-reset!!) BUT
-condition is not protected from starting another broadcast (when called
-on another thread) while still waiting for the "old" broadcast to
-complete on thread B1.
-
-M (>=0, <N) W threads are fast enough to go thru their _wait call and
-decrement cv->waiters counter.
-
-L (N-M) "late" waiter W threads are a) still blocked/not returned from
-their semaphore wait call or b) were preempted after sem_wait but before
-lock( &cv->waitersLock ) or c) are blocked on cv->waitersLock.
-
-cv->waiters is still > 0 (= L).
-
-Another thread B2 (or some W thread from M group) calls
-pthread_cond_broadcast and gains access to counter... neither a) nor b)
-prevent thread B2 in pthread_cond_broadcast from gaining access to
-counter and starting another broadcast ( for c) - it depends on
-cv->waitersLock scheduling rules: FIFO=OK, PRTY=PROBLEM,... )
-
-That call to pthread_cond_broadcast (on thread B2) will result in
-incrementing semaphore by cv->waiters (=L) which is INCORRECT (all
-W1..N were in fact already released by thread B1) and waiting on
-_auto-reset_ event cv->waitersDone which is DEADLY WRONG (produces a
-deadlock)...
-
-All late W1..L threads now have a chance to complete their _wait call.
-Last W_L thread sets an auto-reselt event cv->waitersDone which will
-release either B1 or B2 leaving one of B threads in a deadlock.
-
-Problem 2: spur.wakeup/unfairness/incorrectness
-
-It seems that:
-
-a) because of the same problem with counter which does not reflect the
-actual number of NOT RELEASED waiters, the signal call may increment
-a semaphore counter w/o having a waiter blocked on it. That will result
-in (best case) spurious wake ups - performance degradation due to
-unnecessary context switches and predicate re-checks and (in worth case)
-unfairness/incorrectness problem - see b)
-
-b) neither signal nor broadcast prevent other threads - "new waiters"
-(and in the case of signal, the caller thread as well) from going into
-_wait and overtaking "old" waiters (already released but still not returned
-from sem_wait on condition's semaphore). Win semaphore just [API DOC]:
-"Maintains a count between zero and some maximum value, limiting the number
-of threads that are simultaneously accessing a shared resource." Calling
-ReleaseSemaphore does not imply (at least not documented) that on return
-from ReleaseSemaphore all waiters will in fact become released (returned
-from their Wait... call) and/or that new waiters calling Wait... afterwards
-will become less importance. It is NOT documented to be an atomic release
-of
-waiters... And even if it would be there is still a problem with a thread
-being preempted after Wait on semaphore and before Wait on cv->waitersLock
-and scheduling rules for cv->waitersLock itself
-(??WaitForMultipleObjects??)
-That may result in unfairness/incorrectness problem as described
-for SetEvent impl. in "Strategies for Implementing POSIX Condition
-Variables
-on Win32": http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
-
-Unfairness -- The semantics of the POSIX pthread_cond_broadcast function is
-to wake up all threads currently blocked in wait calls on the condition
-variable. The awakened threads then compete for the external_mutex. To
-ensure
-fairness, all of these threads should be released from their
-pthread_cond_wait calls and allowed to recheck their condition expressions
-before other threads can successfully complete a wait on the condition
-variable.
-
-Unfortunately, the SetEvent implementation above does not guarantee that
-all
-threads sleeping on the condition variable when cond_broadcast is called
-will
-acquire the external_mutex and check their condition expressions. Although
-the Pthreads specification does not mandate this degree of fairness, the
-lack of fairness can cause starvation.
-
-To illustrate the unfairness problem, imagine there are 2 threads, C1 and
-C2,
-that are blocked in pthread_cond_wait on condition variable not_empty_ that
-is guarding a thread-safe message queue. Another thread, P1 then places two
-messages onto the queue and calls pthread_cond_broadcast. If C1 returns
-from
-pthread_cond_wait, dequeues and processes the message, and immediately
-waits
-again then it and only it may end up acquiring both messages. Thus, C2 will
-never get a chance to dequeue a message and run.
-
-The following illustrates the sequence of events:
-
-1. Thread C1 attempts to dequeue and waits on CV non_empty_
-2. Thread C2 attempts to dequeue and waits on CV non_empty_
-3. Thread P1 enqueues 2 messages and broadcasts to CV not_empty_
-4. Thread P1 exits
-5. Thread C1 wakes up from CV not_empty_, dequeues a message and runs
-6. Thread C1 waits again on CV not_empty_, immediately dequeues the 2nd
- message and runs
-7. Thread C1 exits
-8. Thread C2 is the only thread left and blocks forever since
- not_empty_ will never be signaled
-
-Depending on the algorithm being implemented, this lack of fairness may
-yield
-concurrent programs that have subtle bugs. Of course, application
-developers
-should not rely on the fairness semantics of pthread_cond_broadcast.
-However,
-there are many cases where fair implementations of condition variables can
-simplify application code.
-
-Incorrectness -- A variation on the unfairness problem described above
-occurs
-when a third consumer thread, C3, is allowed to slip through even though it
-was not waiting on condition variable not_empty_ when a broadcast occurred.
-
-To illustrate this, we will use the same scenario as above: 2 threads, C1
-and
-C2, are blocked dequeuing messages from the message queue. Another thread,
-P1
-then places two messages onto the queue and calls pthread_cond_broadcast.
-C1
-returns from pthread_cond_wait, dequeues and processes the message. At this
-time, C3 acquires the external_mutex, calls pthread_cond_wait and waits on
-the events in WaitForMultipleObjects. Since C2 has not had a chance to run
-yet, the BROADCAST event is still signaled. C3 then returns from
-WaitForMultipleObjects, and dequeues and processes the message in the
-queue.
-Thus, C2 will never get a chance to dequeue a message and run.
-
-The following illustrates the sequence of events:
-
-1. Thread C1 attempts to dequeue and waits on CV non_empty_
-2. Thread C2 attempts to dequeue and waits on CV non_empty_
-3. Thread P1 enqueues 2 messages and broadcasts to CV not_empty_
-4. Thread P1 exits
-5. Thread C1 wakes up from CV not_empty_, dequeues a message and runs
-6. Thread C1 exits
-7. Thread C3 waits on CV not_empty_, immediately dequeues the 2nd
- message and runs
-8. Thread C3 exits
-9. Thread C2 is the only thread left and blocks forever since
- not_empty_ will never be signaled
-
-In the above case, a thread that was not waiting on the condition variable
-when a broadcast occurred was allowed to proceed. This leads to incorrect
-semantics for a condition variable.
-
-
-COMMENTS???
-
-regards,
-alexander.
-
------------------------------------------------------------------------------
-
-Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_*
- implementation questions
-Date: Wed, 21 Feb 2001 11:54:47 +0100
-From: TEREKHOV@de.ibm.com
-To: lthomas@arbitrade.com
-CC: rpj@ise.canberra.edu.au, Thomas Pfaff <tpfaff@gmx.net>,
- Nanbor Wang <nanbor@cs.wustl.edu>
-
-Hi Louis,
-
-generation number 8..
-
-had some time to revisit timeouts/spurious wakeup problem..
-found some bugs (in 7.b/c/d) and something to improve
-(7a - using IPC semaphores but it should speedup Win32
-version as well).
-
-regards,
-alexander.
-
----------- Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL ------
-given:
-semBlockLock - bin.semaphore
-semBlockQueue - semaphore
-mtxExternal - mutex or CS
-mtxUnblockLock - mutex or CS
-nWaitersGone - int
-nWaitersBlocked - int
-nWaitersToUnblock - int
-
-wait( timeout ) {
-
- [auto: register int result ] // error checking omitted
- [auto: register int nSignalsWasLeft ]
- [auto: register int nWaitersWasGone ]
-
- sem_wait( semBlockLock );
- nWaitersBlocked++;
- sem_post( semBlockLock );
-
- unlock( mtxExternal );
- bTimedOut = sem_wait( semBlockQueue,timeout );
-
- lock( mtxUnblockLock );
- if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
- if ( bTimeout ) { // timeout (or canceled)
- if ( 0 != nWaitersBlocked ) {
- nWaitersBlocked--;
- }
- else {
- nWaitersGone++; // count spurious wakeups
- }
- }
- if ( 0 == --nWaitersToUnblock ) {
- if ( 0 != nWaitersBlocked ) {
- sem_post( semBlockLock ); // open the gate
- nSignalsWasLeft = 0; // do not open the gate below
-again
- }
- else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
- nWaitersGone = 0;
- }
- }
- }
- else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
-semaphore :-)
- sem_wait( semBlockLock );
- nWaitersBlocked -= nWaitersGone; // something is going on here -
-test of timeouts? :-)
- sem_post( semBlockLock );
- nWaitersGone = 0;
- }
- unlock( mtxUnblockLock );
-
- if ( 1 == nSignalsWasLeft ) {
- if ( 0 != nWaitersWasGone ) {
- // sem_adjust( -nWaitersWasGone );
- while ( nWaitersWasGone-- ) {
- sem_wait( semBlockLock ); // better now than spurious
-later
- }
- }
- sem_post( semBlockLock ); // open the gate
- }
-
- lock( mtxExternal );
-
- return ( bTimedOut ) ? ETIMEOUT : 0;
-}
-
-signal(bAll) {
-
- [auto: register int result ]
- [auto: register int nSignalsToIssue]
-
- lock( mtxUnblockLock );
-
- if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
- if ( 0 == nWaitersBlocked ) { // NO-OP
- return unlock( mtxUnblockLock );
- }
- if (bAll) {
- nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
- nWaitersBlocked = 0;
- }
- else {
- nSignalsToIssue = 1;
- nWaitersToUnblock++;
- nWaitersBlocked--;
- }
- }
- else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
- sem_wait( semBlockLock ); // close the gate
- if ( 0 != nWaitersGone ) {
- nWaitersBlocked -= nWaitersGone;
- nWaitersGone = 0;
- }
- if (bAll) {
- nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
- nWaitersBlocked = 0;
- }
- else {
- nSignalsToIssue = nWaitersToUnblock = 1;
- nWaitersBlocked--;
- }
- }
- else { // NO-OP
- return unlock( mtxUnblockLock );
- }
-
- unlock( mtxUnblockLock );
- sem_post( semBlockQueue,nSignalsToIssue );
- return result;
-}
-
----------- Algorithm 8b / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ONEBYONE
-------
-given:
-semBlockLock - bin.semaphore
-semBlockQueue - bin.semaphore
-mtxExternal - mutex or CS
-mtxUnblockLock - mutex or CS
-nWaitersGone - int
-nWaitersBlocked - int
-nWaitersToUnblock - int
-
-wait( timeout ) {
-
- [auto: register int result ] // error checking omitted
- [auto: register int nWaitersWasGone ]
- [auto: register int nSignalsWasLeft ]
-
- sem_wait( semBlockLock );
- nWaitersBlocked++;
- sem_post( semBlockLock );
-
- unlock( mtxExternal );
- bTimedOut = sem_wait( semBlockQueue,timeout );
-
- lock( mtxUnblockLock );
- if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
- if ( bTimeout ) { // timeout (or canceled)
- if ( 0 != nWaitersBlocked ) {
- nWaitersBlocked--;
- nSignalsWasLeft = 0; // do not unblock next waiter
-below (already unblocked)
- }
- else {
- nWaitersGone = 1; // spurious wakeup pending!!
- }
- }
- if ( 0 == --nWaitersToUnblock &&
- if ( 0 != nWaitersBlocked ) {
- sem_post( semBlockLock ); // open the gate
- nSignalsWasLeft = 0; // do not open the gate below
-again
- }
- else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
- nWaitersGone = 0;
- }
- }
- }
- else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
-semaphore :-)
- sem_wait( semBlockLock );
- nWaitersBlocked -= nWaitersGone; // something is going on here -
-test of timeouts? :-)
- sem_post( semBlockLock );
- nWaitersGone = 0;
- }
- unlock( mtxUnblockLock );
-
- if ( 1 == nSignalsWasLeft ) {
- if ( 0 != nWaitersWasGone ) {
- // sem_adjust( -1 );
- sem_wait( semBlockQueue ); // better now than spurious
-later
- }
- sem_post( semBlockLock ); // open the gate
- }
- else if ( 0 != nSignalsWasLeft ) {
- sem_post( semBlockQueue ); // unblock next waiter
- }
-
- lock( mtxExternal );
-
- return ( bTimedOut ) ? ETIMEOUT : 0;
-}
-
-signal(bAll) {
-
- [auto: register int result ]
-
- lock( mtxUnblockLock );
-
- if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
- if ( 0 == nWaitersBlocked ) { // NO-OP
- return unlock( mtxUnblockLock );
- }
- if (bAll) {
- nWaitersToUnblock += nWaitersBlocked;
- nWaitersBlocked = 0;
- }
- else {
- nWaitersToUnblock++;
- nWaitersBlocked--;
- }
- unlock( mtxUnblockLock );
- }
- else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
- sem_wait( semBlockLock ); // close the gate
- if ( 0 != nWaitersGone ) {
- nWaitersBlocked -= nWaitersGone;
- nWaitersGone = 0;
- }
- if (bAll) {
- nWaitersToUnblock = nWaitersBlocked;
- nWaitersBlocked = 0;
- }
- else {
- nWaitersToUnblock = 1;
- nWaitersBlocked--;
- }
- unlock( mtxUnblockLock );
- sem_post( semBlockQueue );
- }
- else { // NO-OP
- unlock( mtxUnblockLock );
- }
-
- return result;
-}
-
----------- Algorithm 8c / IMPL_EVENT,UNBLOCK_STRATEGY == UNBLOCK_ONEBYONE
----------
-given:
-hevBlockLock - auto-reset event
-hevBlockQueue - auto-reset event
-mtxExternal - mutex or CS
-mtxUnblockLock - mutex or CS
-nWaitersGone - int
-nWaitersBlocked - int
-nWaitersToUnblock - int
-
-wait( timeout ) {
-
- [auto: register int result ] // error checking omitted
- [auto: register int nSignalsWasLeft ]
- [auto: register int nWaitersWasGone ]
-
- wait( hevBlockLock,INFINITE );
- nWaitersBlocked++;
- set_event( hevBlockLock );
-
- unlock( mtxExternal );
- bTimedOut = wait( hevBlockQueue,timeout );
-
- lock( mtxUnblockLock );
- if ( 0 != (SignalsWasLeft = nWaitersToUnblock) ) {
- if ( bTimeout ) { // timeout (or canceled)
- if ( 0 != nWaitersBlocked ) {
- nWaitersBlocked--;
- nSignalsWasLeft = 0; // do not unblock next waiter
-below (already unblocked)
- }
- else {
- nWaitersGone = 1; // spurious wakeup pending!!
- }
- }
- if ( 0 == --nWaitersToUnblock )
- if ( 0 != nWaitersBlocked ) {
- set_event( hevBlockLock ); // open the gate
- nSignalsWasLeft = 0; // do not open the gate below
-again
- }
- else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
- nWaitersGone = 0;
- }
- }
- }
- else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
-event :-)
- wait( hevBlockLock,INFINITE );
- nWaitersBlocked -= nWaitersGone; // something is going on here -
-test of timeouts? :-)
- set_event( hevBlockLock );
- nWaitersGone = 0;
- }
- unlock( mtxUnblockLock );
-
- if ( 1 == nSignalsWasLeft ) {
- if ( 0 != nWaitersWasGone ) {
- reset_event( hevBlockQueue ); // better now than spurious
-later
- }
- set_event( hevBlockLock ); // open the gate
- }
- else if ( 0 != nSignalsWasLeft ) {
- set_event( hevBlockQueue ); // unblock next waiter
- }
-
- lock( mtxExternal );
-
- return ( bTimedOut ) ? ETIMEOUT : 0;
-}
-
-signal(bAll) {
-
- [auto: register int result ]
-
- lock( mtxUnblockLock );
-
- if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
- if ( 0 == nWaitersBlocked ) { // NO-OP
- return unlock( mtxUnblockLock );
- }
- if (bAll) {
- nWaitersToUnblock += nWaitersBlocked;
- nWaitersBlocked = 0;
- }
- else {
- nWaitersToUnblock++;
- nWaitersBlocked--;
- }
- unlock( mtxUnblockLock );
- }
- else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
- wait( hevBlockLock,INFINITE ); // close the gate
- if ( 0 != nWaitersGone ) {
- nWaitersBlocked -= nWaitersGone;
- nWaitersGone = 0;
- }
- if (bAll) {
- nWaitersToUnblock = nWaitersBlocked;
- nWaitersBlocked = 0;
- }
- else {
- nWaitersToUnblock = 1;
- nWaitersBlocked--;
- }
- unlock( mtxUnblockLock );
- set_event( hevBlockQueue );
- }
- else { // NO-OP
- unlock( mtxUnblockLock );
- }
-
- return result;
-}
-
----------- Algorithm 8d / IMPL_EVENT,UNBLOCK_STRATEGY == UNBLOCK_ALL ------
-given:
-hevBlockLock - auto-reset event
-hevBlockQueueS - auto-reset event // for signals
-hevBlockQueueB - manual-reset even // for broadcasts
-mtxExternal - mutex or CS
-mtxUnblockLock - mutex or CS
-eBroadcast - int // 0: no broadcast, 1: broadcast, 2:
-broadcast after signal(s)
-nWaitersGone - int
-nWaitersBlocked - int
-nWaitersToUnblock - int
-
-wait( timeout ) {
-
- [auto: register int result ] // error checking omitted
- [auto: register int eWasBroadcast ]
- [auto: register int nSignalsWasLeft ]
- [auto: register int nWaitersWasGone ]
-
- wait( hevBlockLock,INFINITE );
- nWaitersBlocked++;
- set_event( hevBlockLock );
-
- unlock( mtxExternal );
- bTimedOut = waitformultiple( hevBlockQueueS,hevBlockQueueB,timeout,ONE );
-
- lock( mtxUnblockLock );
- if ( 0 != (SignalsWasLeft = nWaitersToUnblock) ) {
- if ( bTimeout ) { // timeout (or canceled)
- if ( 0 != nWaitersBlocked ) {
- nWaitersBlocked--;
- nSignalsWasLeft = 0; // do not unblock next waiter
-below (already unblocked)
- }
- else if ( 1 != eBroadcast ) {
- nWaitersGone = 1;
- }
- }
- if ( 0 == --nWaitersToUnblock ) {
- if ( 0 != nWaitersBlocked ) {
- set_event( hevBlockLock ); // open the gate
- nSignalsWasLeft = 0; // do not open the gate below
-again
- }
- else {
- if ( 0 != (eWasBroadcast = eBroadcast) ) {
- eBroadcast = 0;
- }
- if ( 0 != (nWaitersWasGone = nWaitersGone ) {
- nWaitersGone = 0;
- }
- }
- }
- else if ( 0 != eBroadcast ) {
- nSignalsWasLeft = 0; // do not unblock next waiter
-below (already unblocked)
- }
- }
- else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
-event :-)
- wait( hevBlockLock,INFINITE );
- nWaitersBlocked -= nWaitersGone; // something is going on here -
-test of timeouts? :-)
- set_event( hevBlockLock );
- nWaitersGone = 0;
- }
- unlock( mtxUnblockLock );
-
- if ( 1 == nSignalsWasLeft ) {
- if ( 0 != eWasBroadcast ) {
- reset_event( hevBlockQueueB );
- }
- if ( 0 != nWaitersWasGone ) {
- reset_event( hevBlockQueueS ); // better now than spurious
-later
- }
- set_event( hevBlockLock ); // open the gate
- }
- else if ( 0 != nSignalsWasLeft ) {
- set_event( hevBlockQueueS ); // unblock next waiter
- }
-
- lock( mtxExternal );
-
- return ( bTimedOut ) ? ETIMEOUT : 0;
-}
-
-signal(bAll) {
-
- [auto: register int result ]
- [auto: register HANDLE hevBlockQueue ]
-
- lock( mtxUnblockLock );
-
- if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
- if ( 0 == nWaitersBlocked ) { // NO-OP
- return unlock( mtxUnblockLock );
- }
- if (bAll) {
- nWaitersToUnblock += nWaitersBlocked;
- nWaitersBlocked = 0;
- eBroadcast = 2;
- hevBlockQueue = hevBlockQueueB;
- }
- else {
- nWaitersToUnblock++;
- nWaitersBlocked--;
- return unlock( mtxUnblockLock );
- }
- }
- else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
- wait( hevBlockLock,INFINITE ); // close the gate
- if ( 0 != nWaitersGone ) {
- nWaitersBlocked -= nWaitersGone;
- nWaitersGone = 0;
- }
- if (bAll) {
- nWaitersToUnblock = nWaitersBlocked;
- nWaitersBlocked = 0;
- eBroadcast = 1;
- hevBlockQueue = hevBlockQueueB;
- }
- else {
- nWaitersToUnblock = 1;
- nWaitersBlocked--;
- hevBlockQueue = hevBlockQueueS;
- }
- }
- else { // NO-OP
- return unlock( mtxUnblockLock );
- }
-
- unlock( mtxUnblockLock );
- set_event( hevBlockQueue );
- return result;
-}
----------------------- Forwarded by Alexander Terekhov/Germany/IBM on
-02/21/2001 09:13 AM ---------------------------
-
-Alexander Terekhov
-02/20/2001 04:33 PM
-
-To: Louis Thomas <lthomas@arbitrade.com>
-cc:
-
-From: Alexander Terekhov/Germany/IBM@IBMDE
-Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio
- n questions
-Importance: Normal
-
->Sorry, gotta take a break and work on something else for a while.
->Real work
->calls, unfortunately. I'll get back to you in two or three days.
-
-ok. no problem. here is some more stuff for pauses you might have
-in between :)
-
----------- Algorithm 7d / IMPL_EVENT,UNBLOCK_STRATEGY == UNBLOCK_ALL ------
-given:
-hevBlockLock - auto-reset event
-hevBlockQueueS - auto-reset event // for signals
-hevBlockQueueB - manual-reset even // for broadcasts
-mtxExternal - mutex or CS
-mtxUnblockLock - mutex or CS
-bBroadcast - int
-nWaitersGone - int
-nWaitersBlocked - int
-nWaitersToUnblock - int
-
-wait( timeout ) {
-
- [auto: register int result ] // error checking omitted
- [auto: register int bWasBroadcast ]
- [auto: register int nSignalsWasLeft ]
-
- wait( hevBlockLock,INFINITE );
- nWaitersBlocked++;
- set_event( hevBlockLock );
-
- unlock( mtxExternal );
- bTimedOut = waitformultiple( hevBlockQueueS,hevBlockQueueB,timeout,ONE );
-
- lock( mtxUnblockLock );
- if ( 0 != (SignalsWasLeft = nWaitersToUnblock) ) {
- if ( bTimeout ) { // timeout (or canceled)
- if ( 0 != nWaitersBlocked ) {
- nWaitersBlocked--;
- nSignalsWasLeft = 0; // do not unblock next waiter
-below (already unblocked)
- }
- else if ( !bBroadcast ) {
- wait( hevBlockQueueS,INFINITE ); // better now than spurious
-later
- }
- }
- if ( 0 == --nWaitersToUnblock ) {
- if ( 0 != nWaitersBlocked ) {
- if ( bBroadcast ) {
- reset_event( hevBlockQueueB );
- bBroadcast = false;
- }
- set_event( hevBlockLock ); // open the gate
- nSignalsWasLeft = 0; // do not open the gate below
-again
- }
- else if ( false != (bWasBroadcast = bBroadcast) ) {
- bBroadcast = false;
- }
- }
- else {
- bWasBroadcast = bBroadcast;
- }
- }
- else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
-event :-)
- wait( hevBlockLock,INFINITE );
- nWaitersBlocked -= nWaitersGone; // something is going on here -
-test of timeouts? :-)
- set_event( hevBlockLock );
- nWaitersGone = 0;
- }
- unlock( mtxUnblockLock );
-
- if ( 1 == nSignalsWasLeft ) {
- if ( bWasBroadcast ) {
- reset_event( hevBlockQueueB );
- }
- set_event( hevBlockLock ); // open the gate
- }
- else if ( 0 != nSignalsWasLeft && !bWasBroadcast ) {
- set_event( hevBlockQueueS ); // unblock next waiter
- }
-
- lock( mtxExternal );
-
- return ( bTimedOut ) ? ETIMEOUT : 0;
-}
-
-signal(bAll) {
-
- [auto: register int result ]
- [auto: register HANDLE hevBlockQueue ]
-
- lock( mtxUnblockLock );
-
- if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
- if ( 0 == nWaitersBlocked ) { // NO-OP
- return unlock( mtxUnblockLock );
- }
- if (bAll) {
- nWaitersToUnblock += nWaitersBlocked;
- nWaitersBlocked = 0;
- bBroadcast = true;
- hevBlockQueue = hevBlockQueueB;
- }
- else {
- nWaitersToUnblock++;
- nWaitersBlocked--;
- return unlock( mtxUnblockLock );
- }
- }
- else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
- wait( hevBlockLock,INFINITE ); // close the gate
- if ( 0 != nWaitersGone ) {
- nWaitersBlocked -= nWaitersGone;
- nWaitersGone = 0;
- }
- if (bAll) {
- nWaitersToUnblock = nWaitersBlocked;
- nWaitersBlocked = 0;
- bBroadcast = true;
- hevBlockQueue = hevBlockQueueB;
- }
- else {
- nWaitersToUnblock = 1;
- nWaitersBlocked--;
- hevBlockQueue = hevBlockQueueS;
- }
- }
- else { // NO-OP
- return unlock( mtxUnblockLock );
- }
-
- unlock( mtxUnblockLock );
- set_event( hevBlockQueue );
- return result;
-}
-
-
-----------------------------------------------------------------------------
-
-Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio
- n questions
-Date: Mon, 26 Feb 2001 22:20:12 -0600
-From: Louis Thomas <lthomas@arbitrade.com>
-To: "'TEREKHOV@de.ibm.com'" <TEREKHOV@de.ibm.com>
-CC: rpj@ise.canberra.edu.au, Thomas Pfaff <tpfaff@gmx.net>,
- Nanbor Wang
- <nanbor@cs.wustl.edu>
-
-Sorry all. Busy week.
-
-> this insures the fairness
-> which POSIX does not (e.g. two subsequent broadcasts - the gate does
-insure
-> that first wave waiters will start the race for the mutex before waiters
-> from the second wave - Linux pthreads process/unblock both waves
-> concurrently...)
-
-I'm not sure how we are any more fair about this than Linux. We certainly
-don't guarantee that the threads released by the first broadcast will get
-the external mutex before the threads of the second wave. In fact, it is
-possible that those threads will never get the external mutex if there is
-enough contention for it.
-
-> e.g. i was thinking about implementation with a pool of
-> N semaphores/counters [...]
-
-I considered that too. The problem is as you mentioned in a). You really
-need to assign threads to semaphores once you know how you want to wake them
-up, not when they first begin waiting which is the only time you can assign
-them.
-
-> well, i am not quite sure that i've fully understood your scenario,
-
-Hmm. Well, it think it's an important example, so I'll try again. First, we
-have thread A which we KNOW is waiting on a condition. As soon as it becomes
-unblocked for any reason, we will know because it will set a flag. Since the
-flag is not set, we are 100% confident that thread A is waiting on the
-condition. We have another thread, thread B, which has acquired the mutex
-and is about to wait on the condition. Thus it is pretty clear that at any
-point, either just A is waiting, or A and B are waiting. Now thread C comes
-along. C is about to do a broadcast on the condition. A broadcast is
-guaranteed to unblock all threads currently waiting on a condition, right?
-Again, we said that either just A is waiting, or A and B are both waiting.
-So, when C does its broadcast, depending upon whether B has started waiting
-or not, thread C will unblock A or unblock A and B. Either way, C must
-unblock A, right?
-
-Now, you said anything that happens is correct so long as a) "a signal is
-not lost between unlocking the mutex and waiting on the condition" and b) "a
-thread must not steal a signal it sent", correct? Requirement b) is easy to
-satisfy: in this scenario, thread C will never wait on the condition, so it
-won't steal any signals. Requirement a) is not hard either. The only way we
-could fail to meet requirement a) in this scenario is if thread B was
-started waiting but didn't wake up because a signal was lost. This will not
-happen.
-
-Now, here is what happens. Assume thread C beats thread B. Thread C looks to
-see how many threads are waiting on the condition. Thread C sees just one
-thread, thread A, waiting. It does a broadcast waking up just one thread
-because just one thread is waiting. Next, before A can become unblocked,
-thread B begins waiting. Now there are two threads waiting, but only one
-will be unblocked. Suppose B wins. B will become unblocked. A will not
-become unblocked, because C only unblocked one thread (sema_post cond, 1).
-So at the end, B finishes and A remains blocked.
-
-We have met both of your requirements, so by your rules, this is an
-acceptable outcome. However, I think that the spec says this is an
-unacceptable outcome! We know for certain that A was waiting and that C did
-a broadcast, but A did not become unblocked! Yet, the spec says that a
-broadcast wakes up all waiting threads. This did not happen. Do you agree
-that this shows your rules are not strict enough?
-
-> and what about N2? :) this one does allow almost everything.
-
-Don't get me started about rule #2. I'll NEVER advocate an algorithm that
-uses rule 2 as an excuse to suck!
-
-> but it is done (decrement)under mutex protection - this is not a subject
-> of a race condition.
-
-You are correct. My mistake.
-
-> i would remove "_bTimedOut=false".. after all, it was a real timeout..
-
-I disagree. A thread that can't successfully retract its waiter status can't
-really have timed out. If a thread can't return without executing extra code
-to deal with the fact that someone tried to unblock it, I think it is a poor
-idea to pretend we
-didn't realize someone was trying to signal us. After all, a signal is more
-important than a time out.
-
-> when nSignaled != 0, it is possible to update nWaiters (--) and do not
-> touch nGone
-
-I realize this, but I was thinking that writing it the other ways saves
-another if statement.
-
-> adjust only if nGone != 0 and save one cache memory write - probably much
-slower than 'if'
-
-Hmm. You are probably right.
-
-> well, in a strange (e.g. timeout test) program you may (theoretically)
-> have an overflow of nWaiters/nGone counters (with waiters repeatedly
-timing
-> out and no signals at all).
-
-Also true. Not only that, but you also have the possibility that one could
-overflow the number of waiters as well! However, considering the limit you
-have chosen for nWaitersGone, I suppose it is unlikely that anyone would be
-able to get INT_MAX/2 threads waiting on a single condition. :)
-
-Analysis of 8a:
-
-It looks correct to me.
-
-What are IPC semaphores?
-
-In the line where you state, "else if ( nWaitersBlocked > nWaitersGone ) {
-// HARMLESS RACE CONDITION!" there is no race condition for nWaitersGone
-because nWaitersGone is never modified without holding mtxUnblockLock. You
-are correct that there is a harmless race on nWaitersBlocked, which can
-increase and make the condition become true just after we check it. If this
-happens, we interpret it as the wait starting after the signal.
-
-I like your optimization of this. You could improve Alg. 6 as follows:
----------- Algorithm 6b ----------
-signal(bAll) {
- _nSig=0
- lock counters
- // this is safe because nWaiting can only be decremented by a thread that
- // owns counters and nGone can only be changed by a thread that owns
-counters.
- if (nWaiting>nGone) {
- if (0==nSignaled) {
- sema_wait gate // close gate if not already closed
- }
- if (nGone>0) {
- nWaiting-=nGone
- nGone=0
- }
- _nSig=bAll?nWaiting:1
- nSignaled+=_nSig
- nWaiting-=_nSig
- }
- unlock counters
- if (0!=_nSig) {
- sema_post queue, _nSig
- }
-}
----------- ---------- ----------
-I guess this wouldn't apply to Alg 8a because nWaitersGone changes meanings
-depending upon whether the gate is open or closed.
-
-In the loop "while ( nWaitersWasGone-- ) {" you do a sema_wait on
-semBlockLock. Perhaps waiting on semBlockQueue would be a better idea.
-
-What have you gained by making the last thread to be signaled do the waits
-for all the timed out threads, besides added complexity? It took me a long
-time to figure out what your objective was with this, to realize you were
-using nWaitersGone to mean two different things, and to verify that you
-hadn't introduced any bug by doing this. Even now I'm not 100% sure.
-
-What has all this playing about with nWaitersGone really gained us besides a
-lot of complexity (it is much harder to verify that this solution is
-correct), execution overhead (we now have a lot more if statements to
-evaluate), and space overhead (more space for the extra code, and another
-integer in our data)? We did manage to save a lock/unlock pair in an
-uncommon case (when a time out occurs) at the above mentioned expenses in
-the common cases.
-
-As for 8b, c, and d, they look ok though I haven't studied them thoroughly.
-What would you use them for?
-
- Later,
- -Louis! :)
-
------------------------------------------------------------------------------
-
-Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio
- n questions
-Date: Tue, 27 Feb 2001 15:51:28 +0100
-From: TEREKHOV@de.ibm.com
-To: Louis Thomas <lthomas@arbitrade.com>
-CC: rpj@ise.canberra.edu.au, Thomas Pfaff <tpfaff@gmx.net>,
- Nanbor Wang <nanbor@cs.wustl.edu>
-
-Hi Louis,
-
->> that first wave waiters will start the race for the mutex before waiters
->> from the second wave - Linux pthreads process/unblock both waves
->> concurrently...)
->
->I'm not sure how we are any more fair about this than Linux. We certainly
->don't guarantee that the threads released by the first broadcast will get
->the external mutex before the threads of the second wave. In fact, it is
->possible that those threads will never get the external mutex if there is
->enough contention for it.
-
-correct. but gate is nevertheless more fair than Linux because of the
-barrier it establishes between two races (1st and 2nd wave waiters) for
-the mutex which under 'normal' circumstances (e.g. all threads of equal
-priorities,..) will 'probably' result in fair behaviour with respect to
-mutex ownership.
-
->> well, i am not quite sure that i've fully understood your scenario,
->
->Hmm. Well, it think it's an important example, so I'll try again. ...
-
-ok. now i seem to understand this example. well, now it seems to me
-that the only meaningful rule is just:
-
-a) "a signal is not lost between unlocking the mutex and waiting on the
-condition"
-
-and that the rule
-
-b) "a thread must not steal a signal it sent"
-
-is not needed at all because a thread which violates b) also violates a).
-
-i'll try to explain..
-
-i think that the most important thing is how POSIX defines waiter's
-visibility:
-
-"if another thread is able to acquire the mutex after the about-to-block
-thread
-has released it, then a subsequent call to pthread_cond_signal() or
-pthread_cond_broadcast() in that thread behaves as if it were issued after
-the about-to-block thread has blocked. "
-
-my understanding is the following:
-
-1) there is no guarantees whatsoever with respect to whether
-signal/broadcast
-will actually unblock any 'waiter' if it is done w/o acquiring the mutex
-first
-(note that a thread may release it before signal/broadcast - it does not
-matter).
-
-2) it is guaranteed that waiters become 'visible' - eligible for unblock as
-soon
-as signalling thread acquires the mutex (but not before!!)
-
-so..
-
->So, when C does its broadcast, depending upon whether B has started
-waiting
->or not, thread C will unblock A or unblock A and B. Either way, C must
->unblock A, right?
-
-right. but only if C did acquire the mutex prior to broadcast (it may
-release it before broadcast as well).
-
-implementation will violate waiters visibility rule (signal will become
-lost)
-if C will not unblock A.
-
->Now, here is what happens. Assume thread C beats thread B. Thread C looks
-to
->see how many threads are waiting on the condition. Thread C sees just one
->thread, thread A, waiting. It does a broadcast waking up just one thread
->because just one thread is waiting. Next, before A can become unblocked,
->thread B begins waiting. Now there are two threads waiting, but only one
->will be unblocked. Suppose B wins. B will become unblocked. A will not
->become unblocked, because C only unblocked one thread (sema_post cond, 1).
->So at the end, B finishes and A remains blocked.
-
-thread C did acquire the mutex ("Thread C sees just one thread, thread A,
-waiting"). beginning from that moment it is guaranteed that subsequent
-broadcast will unblock A. Otherwise we will have a lost signal with respect
-to A. I do think that it does not matter whether the signal was physically
-(completely) lost or was just stolen by another thread (B) - in both cases
-it was simply lost with respect to A.
-
->..Do you agree that this shows your rules are not strict enough?
-
-probably the opposite.. :-) i think that it shows that the only meaningful
-rule is
-
-a) "a signal is not lost between unlocking the mutex and waiting on the
-condition"
-
-with clarification of waiters visibility as defined by POSIX above.
-
->> i would remove "_bTimedOut=false".. after all, it was a real timeout..
->
->I disagree. A thread that can't successfully retract its waiter status
-can't
->really have timed out. If a thread can't return without executing extra
-code
->to deal with the fact that someone tried to unblock it, I think it is a
-poor
->idea to pretend we
->didn't realize someone was trying to signal us. After all, a signal is
-more
->important than a time out.
-
-a) POSIX does allow timed out thread to consume a signal (cancelled is
-not).
-b) ETIMEDOUT status just says that: "The time specified by abstime to
-pthread_cond_timedwait() has passed."
-c) it seem to me that hiding timeouts would violate "The
-pthread_cond_timedwait()
-function is the same as pthread_cond_wait() except that an error is
-returned if
-the absolute time specified by abstime passes (that is, system time equals
-or
-exceeds abstime) before the condition cond is signaled or broadcasted"
-because
-the abs. time did really pass before cond was signaled (waiter was
-released via semaphore). however, if it really matters, i could imaging
-that we
-can save an abs. time of signal/broadcast and compare it with timeout after
-unblock to find out whether it was a 'real' timeout or not. absent this
-check
-i do think that hiding timeouts would result in technical violation of
-specification.. but i think that this check is not important and we can
-simply
-trust timeout error code provided by wait since we are not trying to make
-'hard' realtime implementation.
-
->What are IPC semaphores?
-
-<sys/sem.h>
-int semctl(int, int, int, ...);
-int semget(key_t, int, int);
-int semop(int, struct sembuf *, size_t);
-
-they support adjustment of semaphore counter (semvalue)
-in one single call - imaging Win32 ReleaseSemaphore( hsem,-N )
-
->In the line where you state, "else if ( nWaitersBlocked > nWaitersGone ) {
->// HARMLESS RACE CONDITION!" there is no race condition for nWaitersGone
->because nWaitersGone is never modified without holding mtxUnblockLock. You
->are correct that there is a harmless race on nWaitersBlocked, which can
->increase and make the condition become true just after we check it. If
-this
->happens, we interpret it as the wait starting after the signal.
-
-well, the reason why i've asked on comp.programming.threads whether this
-race
-condition is harmless or not is that in order to be harmless it should not
-violate the waiters visibility rule (see above). Fortunately, we increment
-the counter under protection of external mutex.. so that any (signalling)
-thread which will acquire the mutex next, should see the updated counter
-(in signal) according to POSIX memory visibility rules and mutexes
-(memory barriers). But i am not so sure how it actually works on
-Win32/INTEL
-which does not explicitly define any memory visibility rules :(
-
->I like your optimization of this. You could improve Alg. 6 as follows:
->---------- Algorithm 6b ----------
->signal(bAll) {
-> _nSig=0
-> lock counters
-> // this is safe because nWaiting can only be decremented by a thread
-that
-> // owns counters and nGone can only be changed by a thread that owns
->counters.
-> if (nWaiting>nGone) {
-> if (0==nSignaled) {
-> sema_wait gate // close gate if not already closed
-> }
-> if (nGone>0) {
-> nWaiting-=nGone
-> nGone=0
-> }
-> _nSig=bAll?nWaiting:1
-> nSignaled+=_nSig
-> nWaiting-=_nSig
-> }
-> unlock counters
-> if (0!=_nSig) {
-> sema_post queue, _nSig
-> }
->}
->---------- ---------- ----------
->I guess this wouldn't apply to Alg 8a because nWaitersGone changes
-meanings
->depending upon whether the gate is open or closed.
-
-agree.
-
->In the loop "while ( nWaitersWasGone-- ) {" you do a sema_wait on
->semBlockLock. Perhaps waiting on semBlockQueue would be a better idea.
-
-you are correct. my mistake.
-
->What have you gained by making the last thread to be signaled do the waits
->for all the timed out threads, besides added complexity? It took me a long
->time to figure out what your objective was with this, to realize you were
->using nWaitersGone to mean two different things, and to verify that you
->hadn't introduced any bug by doing this. Even now I'm not 100% sure.
->
->What has all this playing about with nWaitersGone really gained us besides
-a
->lot of complexity (it is much harder to verify that this solution is
->correct), execution overhead (we now have a lot more if statements to
->evaluate), and space overhead (more space for the extra code, and another
->integer in our data)? We did manage to save a lock/unlock pair in an
->uncommon case (when a time out occurs) at the above mentioned expenses in
->the common cases.
-
-well, please consider the following:
-
-1) with multiple waiters unblocked (but some timed out) the trick with
-counter
-seem to ensure potentially higher level of concurrency by not delaying
-most of unblocked waiters for semaphore cleanup - only the last one
-will be delayed but all others would already contend/acquire/release
-the external mutex - the critical section protected by mtxUnblockLock is
-made smaller (increment + couple of IFs is faster than system/kernel call)
-which i think is good in general. however, you are right, this is done
-at expense of 'normal' waiters..
-
-2) some semaphore APIs (e.g. POSIX IPC sems) do allow to adjust the
-semaphore counter in one call => less system/kernel calls.. imagine:
-
-if ( 1 == nSignalsWasLeft ) {
- if ( 0 != nWaitersWasGone ) {
- ReleaseSemaphore( semBlockQueue,-nWaitersWasGone ); // better now
-than spurious later
- }
- sem_post( semBlockLock ); // open the gate
- }
-
-3) even on win32 a single thread doing multiple cleanup calls (to wait)
-will probably result in faster execution (because of processor caching)
-than multiple threads each doing a single call to wait.
-
->As for 8b, c, and d, they look ok though I haven't studied them
-thoroughly.
->What would you use them for?
-
-8b) for semaphores which do not allow to unblock multiple waiters
-in a single call to post/release (e.g. POSIX realtime semaphores -
-<semaphore.h>)
-
-8c/8d) for WinCE prior to 3.0 (WinCE 3.0 does have semaphores)
-
-ok. so, which one is the 'final' algorithm(s) which we should use in
-pthreads-win32??
-
-regards,
-alexander.
-
-----------------------------------------------------------------------------
-
-Louis Thomas <lthomas@arbitrade.com> on 02/27/2001 05:20:12 AM
-
-Please respond to Louis Thomas <lthomas@arbitrade.com>
-
-To: Alexander Terekhov/Germany/IBM@IBMDE
-cc: rpj@ise.canberra.edu.au, Thomas Pfaff <tpfaff@gmx.net>, Nanbor Wang
- <nanbor@cs.wustl.edu>
-Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio
- n questions
-
-Sorry all. Busy week.
-
-> this insures the fairness
-> which POSIX does not (e.g. two subsequent broadcasts - the gate does
-insure
-> that first wave waiters will start the race for the mutex before waiters
-> from the second wave - Linux pthreads process/unblock both waves
-> concurrently...)
-
-I'm not sure how we are any more fair about this than Linux. We certainly
-don't guarantee that the threads released by the first broadcast will get
-the external mutex before the threads of the second wave. In fact, it is
-possible that those threads will never get the external mutex if there is
-enough contention for it.
-
-> e.g. i was thinking about implementation with a pool of
-> N semaphores/counters [...]
-
-I considered that too. The problem is as you mentioned in a). You really
-need to assign threads to semaphores once you know how you want to wake
-them
-up, not when they first begin waiting which is the only time you can assign
-them.
-
-> well, i am not quite sure that i've fully understood your scenario,
-
-Hmm. Well, it think it's an important example, so I'll try again. First, we
-have thread A which we KNOW is waiting on a condition. As soon as it
-becomes
-unblocked for any reason, we will know because it will set a flag. Since
-the
-flag is not set, we are 100% confident that thread A is waiting on the
-condition. We have another thread, thread B, which has acquired the mutex
-and is about to wait on the condition. Thus it is pretty clear that at any
-point, either just A is waiting, or A and B are waiting. Now thread C comes
-along. C is about to do a broadcast on the condition. A broadcast is
-guaranteed to unblock all threads currently waiting on a condition, right?
-Again, we said that either just A is waiting, or A and B are both waiting.
-So, when C does its broadcast, depending upon whether B has started waiting
-or not, thread C will unblock A or unblock A and B. Either way, C must
-unblock A, right?
-
-Now, you said anything that happens is correct so long as a) "a signal is
-not lost between unlocking the mutex and waiting on the condition" and b)
-"a
-thread must not steal a signal it sent", correct? Requirement b) is easy to
-satisfy: in this scenario, thread C will never wait on the condition, so it
-won't steal any signals. Requirement a) is not hard either. The only way
-we
-could fail to meet requirement a) in this scenario is if thread B was
-started waiting but didn't wake up because a signal was lost. This will not
-happen.
-
-Now, here is what happens. Assume thread C beats thread B. Thread C looks
-to
-see how many threads are waiting on the condition. Thread C sees just one
-thread, thread A, waiting. It does a broadcast waking up just one thread
-because just one thread is waiting. Next, before A can become unblocked,
-thread B begins waiting. Now there are two threads waiting, but only one
-will be unblocked. Suppose B wins. B will become unblocked. A will not
-become unblocked, because C only unblocked one thread (sema_post cond, 1).
-So at the end, B finishes and A remains blocked.
-
-We have met both of your requirements, so by your rules, this is an
-acceptable outcome. However, I think that the spec says this is an
-unacceptable outcome! We know for certain that A was waiting and that C did
-a broadcast, but A did not become unblocked! Yet, the spec says that a
-broadcast wakes up all waiting threads. This did not happen. Do you agree
-that this shows your rules are not strict enough?
-
-> and what about N2? :) this one does allow almost everything.
-
-Don't get me started about rule #2. I'll NEVER advocate an algorithm that
-uses rule 2 as an excuse to suck!
-
-> but it is done (decrement)under mutex protection - this is not a subject
-> of a race condition.
-
-You are correct. My mistake.
-
-> i would remove "_bTimedOut=false".. after all, it was a real timeout..
-
-I disagree. A thread that can't successfully retract its waiter status
-can't
-really have timed out. If a thread can't return without executing extra
-code
-to deal with the fact that someone tried to unblock it, I think it is a
-poor
-idea to pretend we
-didn't realize someone was trying to signal us. After all, a signal is more
-important than a time out.
-
-> when nSignaled != 0, it is possible to update nWaiters (--) and do not
-> touch nGone
-
-I realize this, but I was thinking that writing it the other ways saves
-another if statement.
-
-> adjust only if nGone != 0 and save one cache memory write - probably much
-slower than 'if'
-
-Hmm. You are probably right.
-
-> well, in a strange (e.g. timeout test) program you may (theoretically)
-> have an overflow of nWaiters/nGone counters (with waiters repeatedly
-timing
-> out and no signals at all).
-
-Also true. Not only that, but you also have the possibility that one could
-overflow the number of waiters as well! However, considering the limit you
-have chosen for nWaitersGone, I suppose it is unlikely that anyone would be
-able to get INT_MAX/2 threads waiting on a single condition. :)
-
-Analysis of 8a:
-
-It looks correct to me.
-
-What are IPC semaphores?
-
-In the line where you state, "else if ( nWaitersBlocked > nWaitersGone ) {
-// HARMLESS RACE CONDITION!" there is no race condition for nWaitersGone
-because nWaitersGone is never modified without holding mtxUnblockLock. You
-are correct that there is a harmless race on nWaitersBlocked, which can
-increase and make the condition become true just after we check it. If this
-happens, we interpret it as the wait starting after the signal.
-
-I like your optimization of this. You could improve Alg. 6 as follows:
----------- Algorithm 6b ----------
-signal(bAll) {
- _nSig=0
- lock counters
- // this is safe because nWaiting can only be decremented by a thread that
- // owns counters and nGone can only be changed by a thread that owns
-counters.
- if (nWaiting>nGone) {
- if (0==nSignaled) {
- sema_wait gate // close gate if not already closed
- }
- if (nGone>0) {
- nWaiting-=nGone
- nGone=0
- }
- _nSig=bAll?nWaiting:1
- nSignaled+=_nSig
- nWaiting-=_nSig
- }
- unlock counters
- if (0!=_nSig) {
- sema_post queue, _nSig
- }
-}
----------- ---------- ----------
-I guess this wouldn't apply to Alg 8a because nWaitersGone changes meanings
-depending upon whether the gate is open or closed.
-
-In the loop "while ( nWaitersWasGone-- ) {" you do a sema_wait on
-semBlockLock. Perhaps waiting on semBlockQueue would be a better idea.
-
-What have you gained by making the last thread to be signaled do the waits
-for all the timed out threads, besides added complexity? It took me a long
-time to figure out what your objective was with this, to realize you were
-using nWaitersGone to mean two different things, and to verify that you
-hadn't introduced any bug by doing this. Even now I'm not 100% sure.
-
-What has all this playing about with nWaitersGone really gained us besides
-a
-lot of complexity (it is much harder to verify that this solution is
-correct), execution overhead (we now have a lot more if statements to
-evaluate), and space overhead (more space for the extra code, and another
-integer in our data)? We did manage to save a lock/unlock pair in an
-uncommon case (when a time out occurs) at the above mentioned expenses in
-the common cases.
-
-As for 8b, c, and d, they look ok though I haven't studied them thoroughly.
-What would you use them for?
-
- Later,
- -Louis! :)
-
+README.CV -- Condition Variables
+--------------------------------
+
+The original implementation of condition variables in
+pthreads-win32 was based on a discussion paper:
+
+"Strategies for Implementing POSIX Condition Variables
+on Win32": http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+
+The changes suggested below were made on Feb 6 2001. This
+file is included in the package for the benefit of anyone
+interested in understanding the pthreads-win32 implementation
+of condition variables and the (sometimes subtle) issues that
+it attempts to resolve.
+
+Thanks go to the individuals whose names appear throughout
+the following text.
+
+Ross Johnson
+
+--------------------------------------------------------------------
+
+fyi.. (more detailed problem description/demos + possible fix/patch)
+
+regards,
+alexander.
+
+
+Alexander Terekhov
+31.01.2001 17:43
+
+To: ace-bugs@cs.wustl.edu
+cc:
+From: Alexander Terekhov/Germany/IBM@IBMDE
+Subject: Implementation of POSIX CVs: spur.wakeups/lost
+ signals/deadlocks/unfairness
+
+
+
+ ACE VERSION:
+
+ 5.1.12 (pthread-win32 snapshot 2000-12-29)
+
+ HOST MACHINE and OPERATING SYSTEM:
+
+ IBM IntelliStation Z Pro, 2 x XEON 1GHz, Win2K
+
+ TARGET MACHINE and OPERATING SYSTEM, if different from HOST:
+ COMPILER NAME AND VERSION (AND PATCHLEVEL):
+
+ Microsoft Visual C++ 6.0
+
+ AREA/CLASS/EXAMPLE AFFECTED:
+
+ Implementation of POSIX condition variables - OS.cpp/.h
+
+ DOES THE PROBLEM AFFECT:
+
+ EXECUTION? YES!
+
+ SYNOPSIS:
+
+ a) spurious wakeups (minor problem)
+ b) lost signals
+ c) broadcast deadlock
+ d) unfairness (minor problem)
+
+ DESCRIPTION:
+
+ Please see attached copy of discussion thread
+ from comp.programming.threads for more details on
+ some reported problems. (i've also posted a "fyi"
+ message to ace-users a week or two ago but
+ unfortunately did not get any response so far).
+
+ It seems that current implementation suffers from
+ two essential problems:
+
+ 1) cond.waiters_count does not accurately reflect
+ number of waiters blocked on semaphore - w/o
+ proper synchronisation that could result (in the
+ time window when counter is not accurate)
+ in spurious wakeups organised by subsequent
+ _signals and _broadcasts.
+
+ 2) Always having (with no e.g. copy_and_clear/..)
+ the same queue in use (semaphore+counter)
+ neither signal nor broadcast provide 'atomic'
+ behaviour with respect to other threads/subsequent
+ calls to signal/broadcast/wait.
+
+ Each problem and combination of both could produce
+ various nasty things:
+
+ a) spurious wakeups (minor problem)
+
+ it is possible that waiter(s) which was already
+ unblocked even so is still counted as blocked
+ waiter. signal and broadcast will release
+ semaphore which will produce a spurious wakeup
+ for a 'real' waiter coming later.
+
+ b) lost signals
+
+ signalling thread ends up consuming its own
+ signal. please see demo/discussion below.
+
+ c) broadcast deadlock
+
+ last_waiter processing code does not correctly
+ handle the case with multiple threads
+ waiting for the end of broadcast.
+ please see demo/discussion below.
+
+ d) unfairness (minor problem)
+
+ without SignalObjectAndWait some waiter(s)
+ may end up consuming broadcasted signals
+ multiple times (spurious wakeups) because waiter
+ thread(s) can be preempted before they call
+ semaphore wait (but after count++ and mtx.unlock).
+
+ REPEAT BY:
+
+ See below... run problem demos programs (tennis.cpp and
+ tennisb.cpp) number of times concurrently (on multiprocessor)
+ and in multiple sessions or just add a couple of "Sleep"s
+ as described in the attached copy of discussion thread
+ from comp.programming.threads
+
+ SAMPLE FIX/WORKAROUND:
+
+ See attached patch to pthread-win32.. well, I can not
+ claim that it is completely bug free but at least my
+ test and tests provided by pthreads-win32 seem to work.
+ Perhaps that will help.
+
+ regards,
+ alexander.
+
+
+>> Forum: comp.programming.threads
+>> Thread: pthread_cond_* implementation questions
+.
+.
+.
+David Schwartz <davids@webmaster.com> wrote:
+
+> terekhov@my-deja.com wrote:
+>
+>> BTW, could you please also share your view on other perceived
+>> "problems" such as nested broadcast deadlock, spurious wakeups
+>> and (the latest one) lost signals??
+>
+>I'm not sure what you mean. The standard allows an implementation
+>to do almost whatever it likes. In fact, you could implement
+>pthread_cond_wait by releasing the mutex, sleeping a random
+>amount of time, and then reacquiring the mutex. Of course,
+>this would be a pretty poor implementation, but any code that
+>didn't work under that implementation wouldn't be strictly
+>compliant.
+
+The implementation you suggested is indeed correct
+one (yes, now I see it :). However it requires from
+signal/broadcast nothing more than to "{ return 0; }"
+That is not the case for pthread-win32 and ACE
+implementations. I do think that these implementations
+(basically the same implementation) have some serious
+problems with wait/signal/broadcast calls. I am looking
+for help to clarify whether these problems are real
+or not. I think that I can demonstrate what I mean
+using one or two small sample programs.
+.
+.
+.
+==========
+tennis.cpp
+==========
+
+#include "ace/Synch.h"
+#include "ace/Thread.h"
+
+enum GAME_STATE {
+
+ START_GAME,
+ PLAYER_A, // Player A playes the ball
+ PLAYER_B, // Player B playes the ball
+ GAME_OVER,
+ ONE_PLAYER_GONE,
+ BOTH_PLAYERS_GONE
+
+};
+
+enum GAME_STATE eGameState;
+ACE_Mutex* pmtxGameStateLock;
+ACE_Condition< ACE_Mutex >* pcndGameStateChange;
+
+void*
+ playerA(
+ void* pParm
+ )
+{
+
+ // For access to game state variable
+ pmtxGameStateLock->acquire();
+
+ // Play loop
+ while ( eGameState < GAME_OVER ) {
+
+ // Play the ball
+ cout << endl << "PLAYER-A" << endl;
+
+ // Now its PLAYER-B's turn
+ eGameState = PLAYER_B;
+
+ // Signal to PLAYER-B that now it is his turn
+ pcndGameStateChange->signal();
+
+ // Wait until PLAYER-B finishes playing the ball
+ do {
+
+ pcndGameStateChange->wait();
+
+ if ( PLAYER_B == eGameState )
+ cout << endl << "----PLAYER-A: SPURIOUS WAKEUP!!!" << endl;
+
+ } while ( PLAYER_B == eGameState );
+
+ }
+
+ // PLAYER-A gone
+ eGameState = (GAME_STATE)(eGameState+1);
+ cout << endl << "PLAYER-A GONE" << endl;
+
+ // No more access to state variable needed
+ pmtxGameStateLock->release();
+
+ // Signal PLAYER-A gone event
+ pcndGameStateChange->broadcast();
+
+ return 0;
+
+}
+
+void*
+ playerB(
+ void* pParm
+ )
+{
+
+ // For access to game state variable
+ pmtxGameStateLock->acquire();
+
+ // Play loop
+ while ( eGameState < GAME_OVER ) {
+
+ // Play the ball
+ cout << endl << "PLAYER-B" << endl;
+
+ // Now its PLAYER-A's turn
+ eGameState = PLAYER_A;
+
+ // Signal to PLAYER-A that now it is his turn
+ pcndGameStateChange->signal();
+
+ // Wait until PLAYER-A finishes playing the ball
+ do {
+
+ pcndGameStateChange->wait();
+
+ if ( PLAYER_A == eGameState )
+ cout << endl << "----PLAYER-B: SPURIOUS WAKEUP!!!" << endl;
+
+ } while ( PLAYER_A == eGameState );
+
+ }
+
+ // PLAYER-B gone
+ eGameState = (GAME_STATE)(eGameState+1);
+ cout << endl << "PLAYER-B GONE" << endl;
+
+ // No more access to state variable needed
+ pmtxGameStateLock->release();
+
+ // Signal PLAYER-B gone event
+ pcndGameStateChange->broadcast();
+
+ return 0;
+
+}
+
+
+int
+main (int, ACE_TCHAR *[])
+{
+
+ pmtxGameStateLock = new ACE_Mutex();
+ pcndGameStateChange = new ACE_Condition< ACE_Mutex >( *pmtxGameStateLock
+);
+
+ // Set initial state
+ eGameState = START_GAME;
+
+ // Create players
+ ACE_Thread::spawn( playerA );
+ ACE_Thread::spawn( playerB );
+
+ // Give them 5 sec. to play
+ Sleep( 5000 );//sleep( 5 );
+
+ // Set game over state
+ pmtxGameStateLock->acquire();
+ eGameState = GAME_OVER;
+
+ // Let them know
+ pcndGameStateChange->broadcast();
+
+ // Wait for players to stop
+ do {
+
+ pcndGameStateChange->wait();
+
+ } while ( eGameState < BOTH_PLAYERS_GONE );
+
+ // Cleanup
+ cout << endl << "GAME OVER" << endl;
+ pmtxGameStateLock->release();
+ delete pcndGameStateChange;
+ delete pmtxGameStateLock;
+
+ return 0;
+
+}
+
+===========
+tennisb.cpp
+===========
+#include "ace/Synch.h"
+#include "ace/Thread.h"
+
+enum GAME_STATE {
+
+ START_GAME,
+ PLAYER_A, // Player A playes the ball
+ PLAYER_B, // Player B playes the ball
+ GAME_OVER,
+ ONE_PLAYER_GONE,
+ BOTH_PLAYERS_GONE
+
+};
+
+enum GAME_STATE eGameState;
+ACE_Mutex* pmtxGameStateLock;
+ACE_Condition< ACE_Mutex >* pcndGameStateChange;
+
+void*
+ playerA(
+ void* pParm
+ )
+{
+
+ // For access to game state variable
+ pmtxGameStateLock->acquire();
+
+ // Play loop
+ while ( eGameState < GAME_OVER ) {
+
+ // Play the ball
+ cout << endl << "PLAYER-A" << endl;
+
+ // Now its PLAYER-B's turn
+ eGameState = PLAYER_B;
+
+ // Signal to PLAYER-B that now it is his turn
+ pcndGameStateChange->broadcast();
+
+ // Wait until PLAYER-B finishes playing the ball
+ do {
+
+ pcndGameStateChange->wait();
+
+ if ( PLAYER_B == eGameState )
+ cout << endl << "----PLAYER-A: SPURIOUS WAKEUP!!!" << endl;
+
+ } while ( PLAYER_B == eGameState );
+
+ }
+
+ // PLAYER-A gone
+ eGameState = (GAME_STATE)(eGameState+1);
+ cout << endl << "PLAYER-A GONE" << endl;
+
+ // No more access to state variable needed
+ pmtxGameStateLock->release();
+
+ // Signal PLAYER-A gone event
+ pcndGameStateChange->broadcast();
+
+ return 0;
+
+}
+
+void*
+ playerB(
+ void* pParm
+ )
+{
+
+ // For access to game state variable
+ pmtxGameStateLock->acquire();
+
+ // Play loop
+ while ( eGameState < GAME_OVER ) {
+
+ // Play the ball
+ cout << endl << "PLAYER-B" << endl;
+
+ // Now its PLAYER-A's turn
+ eGameState = PLAYER_A;
+
+ // Signal to PLAYER-A that now it is his turn
+ pcndGameStateChange->broadcast();
+
+ // Wait until PLAYER-A finishes playing the ball
+ do {
+
+ pcndGameStateChange->wait();
+
+ if ( PLAYER_A == eGameState )
+ cout << endl << "----PLAYER-B: SPURIOUS WAKEUP!!!" << endl;
+
+ } while ( PLAYER_A == eGameState );
+
+ }
+
+ // PLAYER-B gone
+ eGameState = (GAME_STATE)(eGameState+1);
+ cout << endl << "PLAYER-B GONE" << endl;
+
+ // No more access to state variable needed
+ pmtxGameStateLock->release();
+
+ // Signal PLAYER-B gone event
+ pcndGameStateChange->broadcast();
+
+ return 0;
+
+}
+
+
+int
+main (int, ACE_TCHAR *[])
+{
+
+ pmtxGameStateLock = new ACE_Mutex();
+ pcndGameStateChange = new ACE_Condition< ACE_Mutex >( *pmtxGameStateLock
+);
+
+ // Set initial state
+ eGameState = START_GAME;
+
+ // Create players
+ ACE_Thread::spawn( playerA );
+ ACE_Thread::spawn( playerB );
+
+ // Give them 5 sec. to play
+ Sleep( 5000 );//sleep( 5 );
+
+ // Make some noise
+ pmtxGameStateLock->acquire();
+ cout << endl << "---Noise ON..." << endl;
+ pmtxGameStateLock->release();
+ for ( int i = 0; i < 100000; i++ )
+ pcndGameStateChange->broadcast();
+ cout << endl << "---Noise OFF" << endl;
+
+ // Set game over state
+ pmtxGameStateLock->acquire();
+ eGameState = GAME_OVER;
+ cout << endl << "---Stopping the game..." << endl;
+
+ // Let them know
+ pcndGameStateChange->broadcast();
+
+ // Wait for players to stop
+ do {
+
+ pcndGameStateChange->wait();
+
+ } while ( eGameState < BOTH_PLAYERS_GONE );
+
+ // Cleanup
+ cout << endl << "GAME OVER" << endl;
+ pmtxGameStateLock->release();
+ delete pcndGameStateChange;
+ delete pmtxGameStateLock;
+
+ return 0;
+
+}
+.
+.
+.
+David Schwartz <davids@webmaster.com> wrote:
+>> > It's compliant
+>>
+>> That is really good.
+>
+>> Tomorrow (I have to go urgently now) I will try to
+>> demonstrate the lost-signal "problem" of current
+>> pthread-win32 and ACE-(variant w/o SingleObjectAndWait)
+>> implementations: players start suddenly drop their balls :-)
+>> (with no change in source code).
+>
+>Signals aren't lost, they're going to the main thread,
+>which isn't coded correctly to handle them. Try this:
+>
+> // Wait for players to stop
+> do {
+>
+> pthread_cond_wait( &cndGameStateChange,&mtxGameStateLock );
+>printf("Main thread stole a signal\n");
+>
+> } while ( eGameState < BOTH_PLAYERS_GONE );
+>
+>I bet everytime you thing a signal is lost, you'll see that printf.
+>The signal isn't lost, it was stolen by another thread.
+
+well, you can probably loose your bet.. it was indeed stolen
+by "another" thread but not the one you seem to think of.
+
+I think that what actually happens is the following:
+
+H:\SA\UXX\pt\PTHREADS\TESTS>tennis3.exe
+
+PLAYER-A
+
+PLAYER-B
+
+----PLAYER-B: SPURIOUS WAKEUP!!!
+
+PLAYER-A GONE
+
+PLAYER-B GONE
+
+GAME OVER
+
+H:\SA\UXX\pt\PTHREADS\TESTS>
+
+here you can see that PLAYER-B after playing his first
+ball (which came via signal from PLAYER-A) just dropped
+it down. What happened is that his signal to player A
+was consumed as spurious wakeup by himself (player B).
+
+The implementation has a problem:
+
+================
+waiting threads:
+================
+
+{ /** Critical Section
+
+ inc cond.waiters_count
+
+}
+
+ /*
+ /* Atomic only if using Win32 SignalObjectAndWait
+ /*
+ cond.mtx.release
+
+ /*** ^^-- A THREAD WHICH DID SIGNAL MAY ACQUIRE THE MUTEX,
+ /*** GO INTO WAIT ON THE SAME CONDITION AND OVERTAKE
+ /*** ORIGINAL WAITER(S) CONSUMING ITS OWN SIGNAL!
+
+ cond.sem.wait
+
+Player-A after playing game's initial ball went into
+wait (called _wait) but was pre-empted before reaching
+wait semaphore. He was counted as waiter but was not
+actually waiting/blocked yet.
+
+===============
+signal threads:
+===============
+
+{ /** Critical Section
+
+ waiters_count = cond.waiters_count
+
+}
+
+ if ( waiters_count != 0 )
+
+ sem.post 1
+
+ endif
+
+Player-B after he received signal/ball from Player A
+called _signal. The _signal did see that there was
+one waiter blocked on the condition (Player-A) and
+released the semaphore.. (but it did not unblock
+Player-A because he was not actually blocked).
+Player-B thread continued its execution, called _wait,
+was counted as second waiter BUT was allowed to slip
+through opened semaphore gate (which was opened for
+Player-B) and received his own signal. Player B remained
+blocked followed by Player A. Deadlock happened which
+lasted until main thread came in and said game over.
+
+It seems to me that the implementation fails to
+correctly implement the following statement
+from specification:
+
+http://www.opengroup.org/
+onlinepubs/007908799/xsh/pthread_cond_wait.html
+
+"These functions atomically release mutex and cause
+the calling thread to block on the condition variable
+cond; atomically here means "atomically with respect
+to access by another thread to the mutex and then the
+condition variable". That is, if another thread is
+able to acquire the mutex after the about-to-block
+thread has released it, then a subsequent call to
+pthread_cond_signal() or pthread_cond_broadcast()
+in that thread behaves as if it were issued after
+the about-to-block thread has blocked."
+
+Question: Am I right?
+
+(I produced the program output above by simply
+adding ?Sleep( 1 )?:
+
+================
+waiting threads:
+================
+
+{ /** Critical Section
+
+ inc cond.waiters_count
+
+}
+
+ /*
+ /* Atomic only if using Win32 SignalObjectAndWait
+ /*
+ cond.mtx.release
+
+Sleep( 1 ); // Win32
+
+ /*** ^^-- A THREAD WHICH DID SIGNAL MAY ACQUIRE THE MUTEX,
+ /*** GO INTO WAIT ON THE SAME CONDITION AND OVERTAKE
+ /*** ORIGINAL WAITER(S) CONSUMING ITS OWN SIGNAL!
+
+ cond.sem.wait
+
+to the source code of pthread-win32 implementation:
+
+http://sources.redhat.com/cgi-bin/cvsweb.cgi/pthreads/
+condvar.c?rev=1.36&content-type=text/
+x-cvsweb-markup&cvsroot=pthreads-win32
+
+
+ /*
+ * We keep the lock held just long enough to increment the count of
+ * waiters by one (above).
+ * Note that we can't keep it held across the
+ * call to sem_wait since that will deadlock other calls
+ * to pthread_cond_signal
+ */
+ cleanup_args.mutexPtr = mutex;
+ cleanup_args.cv = cv;
+ cleanup_args.resultPtr = &result;
+
+ pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *)
+&cleanup_args);
+
+ if ((result = pthread_mutex_unlock (mutex)) == 0)
+ {((result
+Sleep( 1 ); // @AT
+
+ /*
+ * Wait to be awakened by
+ * pthread_cond_signal, or
+ * pthread_cond_broadcast, or
+ * a timeout
+ *
+ * Note:
+ * ptw32_sem_timedwait is a cancelation point,
+ * hence providing the
+ * mechanism for making pthread_cond_wait a cancelation
+ * point. We use the cleanup mechanism to ensure we
+ * re-lock the mutex and decrement the waiters count
+ * if we are canceled.
+ */
+ if (ptw32_sem_timedwait (&(cv->sema), abstime) == -1) {
+ result = errno;
+ }
+ }
+
+ pthread_cleanup_pop (1); /* Always cleanup */
+
+
+BTW, on my system (2 CPUs) I can manage to get
+signals lost even without any source code modification
+if I run the tennis program many times in different
+shell sessions.
+.
+.
+.
+David Schwartz <davids@webmaster.com> wrote:
+>terekhov@my-deja.com wrote:
+>
+>> well, it might be that the program is in fact buggy.
+>> but you did not show me any bug.
+>
+>You're right. I was close but not dead on. I was correct, however,
+>that the code is buggy because it uses 'pthread_cond_signal' even
+>though not any thread waiting on the condition variable can do the
+>job. I was wrong in which thread could be waiting on the cv but
+>unable to do the job.
+
+Okay, lets change 'pthread_cond_signal' to 'pthread_cond_broadcast'
+but also add some noise from main() right before declaring the game
+to be over (I need it in order to demonstrate another problem of
+pthread-win32/ACE implementations - broadcast deadlock)...
+.
+.
+.
+It is my understanding of POSIX conditions,
+that on correct implementation added noise
+in form of unnecessary broadcasts from main,
+should not break the tennis program. The
+only 'side effect' of added noise on correct
+implementation would be 'spurious wakeups' of
+players (in fact they are not spurious,
+players just see them as spurious) unblocked,
+not by another player but by main before
+another player had a chance to acquire the
+mutex and change the game state variable:
+.
+.
+.
+
+PLAYER-B
+
+PLAYER-A
+
+---Noise ON...
+
+PLAYER-B
+
+PLAYER-A
+
+.
+.
+.
+
+PLAYER-B
+
+PLAYER-A
+
+----PLAYER-A: SPURIOUS WAKEUP!!!
+
+PLAYER-B
+
+PLAYER-A
+
+---Noise OFF
+
+PLAYER-B
+
+---Stopping the game...
+
+PLAYER-A GONE
+
+PLAYER-B GONE
+
+GAME OVER
+
+H:\SA\UXX\pt\PTHREADS\TESTS>
+
+On pthread-win32/ACE implementations the
+program could stall:
+
+.
+.
+.
+
+PLAYER-A
+
+PLAYER-B
+
+PLAYER-A
+
+PLAYER-B
+
+PLAYER-A
+
+PLAYER-B
+
+PLAYER-A
+
+PLAYER-B
+
+---Noise ON...
+
+PLAYER-A
+
+---Noise OFF
+^C
+H:\SA\UXX\pt\PTHREADS\TESTS>
+
+
+The implementation has problems:
+
+================
+waiting threads:
+================
+
+{ /** Critical Section
+
+ inc cond.waiters_count
+
+}
+
+ /*
+ /* Atomic only if using Win32 SignalObjectAndWait
+ /*
+ cond.mtx.release
+ cond.sem.wait
+
+ /*** ^^-- WAITER CAN BE PREEMPTED AFTER BEING UNBLOCKED...
+
+{ /** Critical Section
+
+ dec cond.waiters_count
+
+ /*** ^^- ...AND BEFORE DECREMENTING THE COUNT (1)
+
+ last_waiter = ( cond.was_broadcast &&
+ cond.waiters_count == 0 )
+
+ if ( last_waiter )
+
+ cond.was_broadcast = FALSE
+
+ endif
+
+}
+
+ if ( last_waiter )
+
+ /*
+ /* Atomic only if using Win32 SignalObjectAndWait
+ /*
+ cond.auto_reset_event_or_sem.post /* Event for Win32
+ cond.mtx.acquire
+
+ /*** ^^-- ...AND BEFORE CALL TO mtx.acquire (2)
+
+ /*** ^^-- NESTED BROADCASTS RESULT IN A DEADLOCK
+
+
+ else
+
+ cond.mtx.acquire
+
+ /*** ^^-- ...AND BEFORE CALL TO mtx.acquire (3)
+
+ endif
+
+
+==================
+broadcast threads:
+==================
+
+{ /** Critical Section
+
+ waiters_count = cond.waiters_count
+
+ if ( waiters_count != 0 )
+
+ cond.was_broadcast = TRUE
+
+ endif
+
+}
+
+if ( waiters_count != 0 )
+
+ cond.sem.post waiters_count
+
+ /*** ^^^^^--- SPURIOUS WAKEUPS DUE TO (1)
+
+ cond.auto_reset_event_or_sem.wait /* Event for Win32
+
+ /*** ^^^^^--- DEADLOCK FOR FURTHER BROADCASTS IF THEY
+ HAPPEN TO GO INTO WAIT WHILE PREVIOUS
+ BROADCAST IS STILL IN PROGRESS/WAITING
+
+endif
+
+a) cond.waiters_count does not accurately reflect
+number of waiters blocked on semaphore - that could
+result (in the time window when counter is not accurate)
+in spurios wakeups organised by subsequent _signals
+and _broadcasts. From standard compliance point of view
+that is OK but that could be a real problem from
+performance/efficiency point of view.
+
+b) If subsequent broadcast happen to go into wait on
+cond.auto_reset_event_or_sem before previous
+broadcast was unblocked from cond.auto_reset_event_or_sem
+by its last waiter, one of two blocked threads will
+remain blocked because last_waiter processing code
+fails to unblock both threads.
+
+In the situation with tennisb.c the Player-B was put
+in a deadlock by noise (broadcast) coming from main
+thread. And since Player-B holds the game state
+mutex when it calls broadcast, the whole program
+stalled: Player-A was deadlocked on mutex and
+main thread after finishing with producing the noise
+was deadlocked on mutex too (needed to declare the
+game over)
+
+(I produced the program output above by simply
+adding ?Sleep( 1 )?:
+
+==================
+broadcast threads:
+==================
+
+{ /** Critical Section
+
+ waiters_count = cond.waiters_count
+
+ if ( waiters_count != 0 )
+
+ cond.was_broadcast = TRUE
+
+ endif
+
+}
+
+if ( waiters_count != 0 )
+
+Sleep( 1 ); //Win32
+
+ cond.sem.post waiters_count
+
+ /*** ^^^^^--- SPURIOUS WAKEUPS DUE TO (1)
+
+ cond.auto_reset_event_or_sem.wait /* Event for Win32
+
+ /*** ^^^^^--- DEADLOCK FOR FURTHER BROADCASTS IF THEY
+ HAPPEN TO GO INTO WAIT WHILE PREVIOUS
+ BROADCAST IS STILL IN PROGRESS/WAITING
+
+endif
+
+to the source code of pthread-win32 implementation:
+
+http://sources.redhat.com/cgi-bin/cvsweb.cgi/pthreads/
+condvar.c?rev=1.36&content-type=text/
+x-cvsweb-markup&cvsroot=pthreads-win32
+
+ if (wereWaiters)
+ {(wereWaiters)sroot=pthreads-win32eb.cgi/pthreads/Yem...m
+ /*
+ * Wake up all waiters
+ */
+
+Sleep( 1 ); //@AT
+
+#ifdef NEED_SEM
+
+ result = (ptw32_increase_semaphore( &cv->sema, cv->waiters )
+ ? 0
+ : EINVAL);
+
+#else /* NEED_SEM */
+
+ result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL )
+ ? 0
+ : EINVAL);
+
+#endif /* NEED_SEM */
+
+ }
+
+ (void) pthread_mutex_unlock(&(cv->waitersLock));
+
+ if (wereWaiters && result == 0)
+ {(wereWaiters
+ /*
+ * Wait for all the awakened threads to acquire their part of
+ * the counting semaphore
+ */
+
+ if (WaitForSingleObject (cv->waitersDone, INFINITE)
+ == WAIT_OBJECT_0)
+ {
+ result = 0;
+ }
+ else
+ {
+ result = EINVAL;
+ }
+
+ }
+
+ return (result);
+
+}
+
+BTW, on my system (2 CPUs) I can manage to get
+the program stalled even without any source code
+modification if I run the tennisb program many
+times in different shell sessions.
+
+===================
+pthread-win32 patch
+===================
+struct pthread_cond_t_ {
+ long nWaitersBlocked; /* Number of threads blocked
+*/
+ long nWaitersUnblocked; /* Number of threads unblocked
+*/
+ long nWaitersToUnblock; /* Number of threads to unblock
+*/
+ sem_t semBlockQueue; /* Queue up threads waiting for the
+*/
+ /* condition to become signalled
+*/
+ sem_t semBlockLock; /* Semaphore that guards access to
+*/
+ /* | waiters blocked count/block queue
+*/
+ /* +-> Mandatory Sync.LEVEL-1
+*/
+ pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to
+*/
+ /* | waiters (to)unblock(ed) counts
+*/
+ /* +-> Optional* Sync.LEVEL-2
+*/
+}; /* Opt*) for _timedwait and
+cancellation*/
+
+int
+pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
+ int result = EAGAIN;
+ pthread_cond_t cv = NULL;
+
+ if (cond == NULL)
+ {(cond
+ return EINVAL;
+ }
+
+ if ((attr != NULL && *attr != NULL) &&
+ ((*attr)->pshared == PTHREAD_PROCESS_SHARED))
+ {
+ /*
+ * Creating condition variable that can be shared between
+ * processes.
+ */
+ result = ENOSYS;
+
+ goto FAIL0;
+ }
+
+ cv = (pthread_cond_t) calloc (1, sizeof (*cv));
+
+ if (cv == NULL)
+ {(cv
+ result = ENOMEM;
+ goto FAIL0;
+ }
+
+ cv->nWaitersBlocked = 0;
+ cv->nWaitersUnblocked = 0;
+ cv->nWaitersToUnblock = 0;
+
+ if (sem_init (&(cv->semBlockLock), 0, 1) != 0)
+ {(sem_init
+ goto FAIL0;
+ }
+
+ if (sem_init (&(cv->semBlockQueue), 0, 0) != 0)
+ {(sem_init
+ goto FAIL1;
+ }
+
+ if (pthread_mutex_init (&(cv->mtxUnblockLock), 0) != 0)
+ {(pthread_mutex_init
+ goto FAIL2;
+ }
+
+
+ result = 0;
+
+ goto DONE;
+
+ /*
+ * -------------
+ * Failed...
+ * -------------
+ */
+FAIL2:
+ (void) sem_destroy (&(cv->semBlockQueue));
+
+FAIL1:
+ (void) sem_destroy (&(cv->semBlockLock));
+
+FAIL0:
+DONE:
+ *cond = cv;
+
+ return (result);
+
+} /* pthread_cond_init */
+
+int
+pthread_cond_destroy (pthread_cond_t * cond)
+{
+ int result = 0;
+ pthread_cond_t cv;
+
+ /*
+ * Assuming any race condition here is harmless.
+ */
+ if (cond == NULL
+ || *cond == NULL)
+ {
+ return EINVAL;
+ }
+
+ if (*cond != (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
+ {(*cond
+ cv = *cond;
+
+ /*
+ * Synchronize access to waiters blocked count (LEVEL-1)
+ */
+ if (sem_wait(&(cv->semBlockLock)) != 0)
+ {(sem_wait(&(cv->semBlockLock))
+ return errno;
+ }
+
+ /*
+ * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
+ */
+ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
+ {((result
+ (void) sem_post(&(cv->semBlockLock));
+ return result;
+ }
+
+ /*
+ * Check whether cv is still busy (still has waiters blocked)
+ */
+ if (cv->nWaitersBlocked - cv->nWaitersUnblocked > 0)
+ {(cv->nWaitersBlocked
+ (void) sem_post(&(cv->semBlockLock));
+ (void) pthread_mutex_unlock(&(cv->mtxUnblockLock));
+ return EBUSY;
+ }
+
+ /*
+ * Now it is safe to destroy
+ */
+ (void) sem_destroy (&(cv->semBlockLock));
+ (void) sem_destroy (&(cv->semBlockQueue));
+ (void) pthread_mutex_unlock (&(cv->mtxUnblockLock));
+ (void) pthread_mutex_destroy (&(cv->mtxUnblockLock));
+
+ free(cv);
+ *cond = NULL;
+ }
+ else
+ {
+ /*
+ * See notes in ptw32_cond_check_need_init() above also.
+ */
+ EnterCriticalSection(&ptw32_cond_test_init_lock);
+
+ /*
+ * Check again.
+ */
+ if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
+ {(*cond
+ /*
+ * This is all we need to do to destroy a statically
+ * initialised cond that has not yet been used (initialised).
+ * If we get to here, another thread
+ * waiting to initialise this cond will get an EINVAL.
+ */
+ *cond = NULL;
+ }
+ else
+ {
+ /*
+ * The cv has been initialised while we were waiting
+ * so assume it's in use.
+ */
+ result = EBUSY;
+ }
+
+ LeaveCriticalSection(&ptw32_cond_test_init_lock);
+ }
+
+ return (result);
+}
+
+/*
+ * Arguments for cond_wait_cleanup, since we can only pass a
+ * single void * to it.
+ */
+typedef struct {
+ pthread_mutex_t * mutexPtr;
+ pthread_cond_t cv;
+ int * resultPtr;
+} ptw32_cond_wait_cleanup_args_t;
+
+static void
+ptw32_cond_wait_cleanup(void * args)
+{
+ ptw32_cond_wait_cleanup_args_t * cleanup_args =
+(ptw32_cond_wait_cleanup_args_t *) args;
+ pthread_cond_t cv = cleanup_args->cv;
+ int * resultPtr = cleanup_args->resultPtr;
+ int eLastSignal; /* enum: 1=yes 0=no -1=cancelled/timedout w/o signal(s)
+*/
+ int result;
+
+ /*
+ * Whether we got here as a result of signal/broadcast or because of
+ * timeout on wait or thread cancellation we indicate that we are no
+ * longer waiting. The waiter is responsible for adjusting waiters
+ * (to)unblock(ed) counts (protected by unblock lock).
+ * Unblock lock/Sync.LEVEL-2 supports _timedwait and cancellation.
+ */
+ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
+ {((result
+ *resultPtr = result;
+ return;
+ }
+
+ cv->nWaitersUnblocked++;
+
+ eLastSignal = (cv->nWaitersToUnblock == 0) ?
+ -1 : (--cv->nWaitersToUnblock == 0);
+
+ /*
+ * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed
+ */
+ if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
+ {((result
+ *resultPtr = result;
+ return;
+ }
+
+ /*
+ * If last signal...
+ */
+ if (eLastSignal == 1)
+ {(eLastSignal
+ /*
+ * ...it means that we have end of 'atomic' signal/broadcast
+ */
+ if (sem_post(&(cv->semBlockLock)) != 0)
+ {(sem_post(&(cv->semBlockLock))
+ *resultPtr = errno;
+ return;
+ }
+ }
+ /*
+ * If not last signal and not timed out/cancelled wait w/o signal...
+ */
+ else if (eLastSignal == 0)
+ {
+ /*
+ * ...it means that next waiter can go through semaphore
+ */
+ if (sem_post(&(cv->semBlockQueue)) != 0)
+ {(sem_post(&(cv->semBlockQueue))
+ *resultPtr = errno;
+ return;
+ }
+ }
+
+ /*
+ * XSH: Upon successful return, the mutex has been locked and is owned
+ * by the calling thread
+ */
+ if ((result = pthread_mutex_lock(cleanup_args->mutexPtr)) != 0)
+ {((result
+ *resultPtr = result;
+ }
+
+} /* ptw32_cond_wait_cleanup */
+
+static int
+ptw32_cond_timedwait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec *abstime)
+{
+ int result = 0;
+ pthread_cond_t cv;
+ ptw32_cond_wait_cleanup_args_t cleanup_args;
+
+ if (cond == NULL || *cond == NULL)
+ {(cond
+ return EINVAL;
+ }
+
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static condition variable. We check
+ * again inside the guarded section of ptw32_cond_check_need_init()
+ * to avoid race conditions.
+ */
+ if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
+ {(*cond
+ result = ptw32_cond_check_need_init(cond);
+ }
+
+ if (result != 0 && result != EBUSY)
+ {(result
+ return result;
+ }
+
+ cv = *cond;
+
+ /*
+ * Synchronize access to waiters blocked count (LEVEL-1)
+ */
+ if (sem_wait(&(cv->semBlockLock)) != 0)
+ {(sem_wait(&(cv->semBlockLock))
+ return errno;
+ }
+
+ cv->nWaitersBlocked++;
+
+ /*
+ * Thats it. Counted means waiting, no more access needed
+ */
+ if (sem_post(&(cv->semBlockLock)) != 0)
+ {(sem_post(&(cv->semBlockLock))
+ return errno;
+ }
+
+ /*
+ * Setup this waiter cleanup handler
+ */
+ cleanup_args.mutexPtr = mutex;
+ cleanup_args.cv = cv;
+ cleanup_args.resultPtr = &result;
+
+ pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args);
+
+ /*
+ * Now we can release 'mutex' and...
+ */
+ if ((result = pthread_mutex_unlock (mutex)) == 0)
+ {((result
+
+ /*
+ * ...wait to be awakened by
+ * pthread_cond_signal, or
+ * pthread_cond_broadcast, or
+ * timeout, or
+ * thread cancellation
+ *
+ * Note:
+ *
+ * ptw32_sem_timedwait is 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
+ * counts if we are cancelled, timed out or signalled.
+ */
+ if (ptw32_sem_timedwait (&(cv->semBlockQueue), abstime) != 0)
+ {(ptw32_sem_timedwait
+ result = errno;
+ }
+ }
+
+ /*
+ * Always cleanup
+ */
+ pthread_cleanup_pop (1);
+
+
+ /*
+ * "result" can be modified by the cleanup handler.
+ */
+ return (result);
+
+} /* ptw32_cond_timedwait */
+
+
+static int
+ptw32_cond_unblock (pthread_cond_t * cond,
+ int unblockAll)
+{
+ int result;
+ pthread_cond_t cv;
+
+ if (cond == NULL || *cond == NULL)
+ {(cond
+ return EINVAL;
+ }
+
+ cv = *cond;
+
+ /*
+ * No-op if the CV is static and hasn't been initialised yet.
+ * Assuming that any race condition is harmless.
+ */
+ if (cv == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
+ {(cv
+ return 0;
+ }
+
+ /*
+ * Synchronize access to waiters blocked count (LEVEL-1)
+ */
+ if (sem_wait(&(cv->semBlockLock)) != 0)
+ {(sem_wait(&(cv->semBlockLock))
+ return errno;
+ }
+
+ /*
+ * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
+ * This sync.level supports _timedwait and cancellation
+ */
+ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
+ {((result
+ return result;
+ }
+
+ /*
+ * Adjust waiters blocked and unblocked counts (collect garbage)
+ */
+ if (cv->nWaitersUnblocked != 0)
+ {(cv->nWaitersUnblocked
+ cv->nWaitersBlocked -= cv->nWaitersUnblocked;
+ cv->nWaitersUnblocked = 0;
+ }
+
+ /*
+ * If (after adjustment) there are still some waiters blocked counted...
+ */
+ if ( cv->nWaitersBlocked > 0)
+ {(
+ /*
+ * We will unblock first waiter and leave semBlockLock/LEVEL-1 locked
+ * LEVEL-1 access is left disabled until last signal/unblock
+completes
+ */
+ cv->nWaitersToUnblock = (unblockAll) ? cv->nWaitersBlocked : 1;
+
+ /*
+ * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed
+ * This sync.level supports _timedwait and cancellation
+ */
+ if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
+ {((result
+ return result;
+ }
+
+
+ /*
+ * Now, with LEVEL-2 lock released let first waiter go through
+semaphore
+ */
+ if (sem_post(&(cv->semBlockQueue)) != 0)
+ {(sem_post(&(cv->semBlockQueue))
+ return errno;
+ }
+ }
+ /*
+ * No waiter blocked - no more LEVEL-1 access to blocked count needed...
+ */
+ else if (sem_post(&(cv->semBlockLock)) != 0)
+ {
+ return errno;
+ }
+ /*
+ * ...and no more LEVEL-2 access to waiters (to)unblock(ed) counts needed
+too
+ * This sync.level supports _timedwait and cancellation
+ */
+ else
+ {
+ result = pthread_mutex_unlock(&(cv->mtxUnblockLock));
+ }
+
+ return(result);
+
+} /* ptw32_cond_unblock */
+
+int
+pthread_cond_wait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex)
+{
+ /* The NULL abstime arg means INFINITE waiting. */
+ return(ptw32_cond_timedwait(cond, mutex, NULL));
+} /* pthread_cond_wait */
+
+
+int
+pthread_cond_timedwait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec *abstime)
+{
+ if (abstime == NULL)
+ {(abstime
+ return EINVAL;
+ }
+
+ return(ptw32_cond_timedwait(cond, mutex, abstime));
+} /* pthread_cond_timedwait */
+
+
+int
+pthread_cond_signal (pthread_cond_t * cond)
+{
+ /* The '0'(FALSE) unblockAll arg means unblock ONE waiter. */
+ return(ptw32_cond_unblock(cond, 0));
+} /* pthread_cond_signal */
+
+int
+pthread_cond_broadcast (pthread_cond_t * cond)
+{
+ /* The '1'(TRUE) unblockAll arg means unblock ALL waiters. */
+ return(ptw32_cond_unblock(cond, 1));
+} /* pthread_cond_broadcast */
+
+
+
+
+TEREKHOV@de.ibm.com on 17.01.2001 01:00:57
+
+Please respond to TEREKHOV@de.ibm.com
+
+To: pthreads-win32@sourceware.cygnus.com
+cc: schmidt@uci.edu
+Subject: win32 conditions: sem+counter+event = broadcast_deadlock +
+ spur.wakeup/unfairness/incorrectness ??
+
+
+
+
+
+
+
+Hi,
+
+Problem 1: broadcast_deadlock
+
+It seems that current implementation does not provide "atomic"
+broadcasts. That may lead to "nested" broadcasts... and it seems
+that nested case is not handled correctly -> producing a broadcast
+DEADLOCK as a result.
+
+Scenario:
+
+N (>1) waiting threads W1..N are blocked (in _wait) on condition's
+semaphore.
+
+Thread B1 calls pthread_cond_broadcast, which results in "releasing" N
+W threads via incrementing semaphore counter by N (stored in
+cv->waiters) BUT cv->waiters counter does not change!! The caller
+thread B1 remains blocked on cv->waitersDone event (auto-reset!!) BUT
+condition is not protected from starting another broadcast (when called
+on another thread) while still waiting for the "old" broadcast to
+complete on thread B1.
+
+M (>=0, <N) W threads are fast enough to go thru their _wait call and
+decrement cv->waiters counter.
+
+L (N-M) "late" waiter W threads are a) still blocked/not returned from
+their semaphore wait call or b) were preempted after sem_wait but before
+lock( &cv->waitersLock ) or c) are blocked on cv->waitersLock.
+
+cv->waiters is still > 0 (= L).
+
+Another thread B2 (or some W thread from M group) calls
+pthread_cond_broadcast and gains access to counter... neither a) nor b)
+prevent thread B2 in pthread_cond_broadcast from gaining access to
+counter and starting another broadcast ( for c) - it depends on
+cv->waitersLock scheduling rules: FIFO=OK, PRTY=PROBLEM,... )
+
+That call to pthread_cond_broadcast (on thread B2) will result in
+incrementing semaphore by cv->waiters (=L) which is INCORRECT (all
+W1..N were in fact already released by thread B1) and waiting on
+_auto-reset_ event cv->waitersDone which is DEADLY WRONG (produces a
+deadlock)...
+
+All late W1..L threads now have a chance to complete their _wait call.
+Last W_L thread sets an auto-reselt event cv->waitersDone which will
+release either B1 or B2 leaving one of B threads in a deadlock.
+
+Problem 2: spur.wakeup/unfairness/incorrectness
+
+It seems that:
+
+a) because of the same problem with counter which does not reflect the
+actual number of NOT RELEASED waiters, the signal call may increment
+a semaphore counter w/o having a waiter blocked on it. That will result
+in (best case) spurious wake ups - performance degradation due to
+unnecessary context switches and predicate re-checks and (in worth case)
+unfairness/incorrectness problem - see b)
+
+b) neither signal nor broadcast prevent other threads - "new waiters"
+(and in the case of signal, the caller thread as well) from going into
+_wait and overtaking "old" waiters (already released but still not returned
+from sem_wait on condition's semaphore). Win semaphore just [API DOC]:
+"Maintains a count between zero and some maximum value, limiting the number
+of threads that are simultaneously accessing a shared resource." Calling
+ReleaseSemaphore does not imply (at least not documented) that on return
+from ReleaseSemaphore all waiters will in fact become released (returned
+from their Wait... call) and/or that new waiters calling Wait... afterwards
+will become less importance. It is NOT documented to be an atomic release
+of
+waiters... And even if it would be there is still a problem with a thread
+being preempted after Wait on semaphore and before Wait on cv->waitersLock
+and scheduling rules for cv->waitersLock itself
+(??WaitForMultipleObjects??)
+That may result in unfairness/incorrectness problem as described
+for SetEvent impl. in "Strategies for Implementing POSIX Condition
+Variables
+on Win32": http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+
+Unfairness -- The semantics of the POSIX pthread_cond_broadcast function is
+to wake up all threads currently blocked in wait calls on the condition
+variable. The awakened threads then compete for the external_mutex. To
+ensure
+fairness, all of these threads should be released from their
+pthread_cond_wait calls and allowed to recheck their condition expressions
+before other threads can successfully complete a wait on the condition
+variable.
+
+Unfortunately, the SetEvent implementation above does not guarantee that
+all
+threads sleeping on the condition variable when cond_broadcast is called
+will
+acquire the external_mutex and check their condition expressions. Although
+the Pthreads specification does not mandate this degree of fairness, the
+lack of fairness can cause starvation.
+
+To illustrate the unfairness problem, imagine there are 2 threads, C1 and
+C2,
+that are blocked in pthread_cond_wait on condition variable not_empty_ that
+is guarding a thread-safe message queue. Another thread, P1 then places two
+messages onto the queue and calls pthread_cond_broadcast. If C1 returns
+from
+pthread_cond_wait, dequeues and processes the message, and immediately
+waits
+again then it and only it may end up acquiring both messages. Thus, C2 will
+never get a chance to dequeue a message and run.
+
+The following illustrates the sequence of events:
+
+1. Thread C1 attempts to dequeue and waits on CV non_empty_
+2. Thread C2 attempts to dequeue and waits on CV non_empty_
+3. Thread P1 enqueues 2 messages and broadcasts to CV not_empty_
+4. Thread P1 exits
+5. Thread C1 wakes up from CV not_empty_, dequeues a message and runs
+6. Thread C1 waits again on CV not_empty_, immediately dequeues the 2nd
+ message and runs
+7. Thread C1 exits
+8. Thread C2 is the only thread left and blocks forever since
+ not_empty_ will never be signaled
+
+Depending on the algorithm being implemented, this lack of fairness may
+yield
+concurrent programs that have subtle bugs. Of course, application
+developers
+should not rely on the fairness semantics of pthread_cond_broadcast.
+However,
+there are many cases where fair implementations of condition variables can
+simplify application code.
+
+Incorrectness -- A variation on the unfairness problem described above
+occurs
+when a third consumer thread, C3, is allowed to slip through even though it
+was not waiting on condition variable not_empty_ when a broadcast occurred.
+
+To illustrate this, we will use the same scenario as above: 2 threads, C1
+and
+C2, are blocked dequeuing messages from the message queue. Another thread,
+P1
+then places two messages onto the queue and calls pthread_cond_broadcast.
+C1
+returns from pthread_cond_wait, dequeues and processes the message. At this
+time, C3 acquires the external_mutex, calls pthread_cond_wait and waits on
+the events in WaitForMultipleObjects. Since C2 has not had a chance to run
+yet, the BROADCAST event is still signaled. C3 then returns from
+WaitForMultipleObjects, and dequeues and processes the message in the
+queue.
+Thus, C2 will never get a chance to dequeue a message and run.
+
+The following illustrates the sequence of events:
+
+1. Thread C1 attempts to dequeue and waits on CV non_empty_
+2. Thread C2 attempts to dequeue and waits on CV non_empty_
+3. Thread P1 enqueues 2 messages and broadcasts to CV not_empty_
+4. Thread P1 exits
+5. Thread C1 wakes up from CV not_empty_, dequeues a message and runs
+6. Thread C1 exits
+7. Thread C3 waits on CV not_empty_, immediately dequeues the 2nd
+ message and runs
+8. Thread C3 exits
+9. Thread C2 is the only thread left and blocks forever since
+ not_empty_ will never be signaled
+
+In the above case, a thread that was not waiting on the condition variable
+when a broadcast occurred was allowed to proceed. This leads to incorrect
+semantics for a condition variable.
+
+
+COMMENTS???
+
+regards,
+alexander.
+
+-----------------------------------------------------------------------------
+
+Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_*
+ implementation questions
+Date: Wed, 21 Feb 2001 11:54:47 +0100
+From: TEREKHOV@de.ibm.com
+To: lthomas@arbitrade.com
+CC: rpj@ise.canberra.edu.au, Thomas Pfaff <tpfaff@gmx.net>,
+ Nanbor Wang <nanbor@cs.wustl.edu>
+
+Hi Louis,
+
+generation number 8..
+
+had some time to revisit timeouts/spurious wakeup problem..
+found some bugs (in 7.b/c/d) and something to improve
+(7a - using IPC semaphores but it should speedup Win32
+version as well).
+
+regards,
+alexander.
+
+---------- Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL ------
+given:
+semBlockLock - bin.semaphore
+semBlockQueue - semaphore
+mtxExternal - mutex or CS
+mtxUnblockLock - mutex or CS
+nWaitersGone - int
+nWaitersBlocked - int
+nWaitersToUnblock - int
+
+wait( timeout ) {
+
+ [auto: register int result ] // error checking omitted
+ [auto: register int nSignalsWasLeft ]
+ [auto: register int nWaitersWasGone ]
+
+ sem_wait( semBlockLock );
+ nWaitersBlocked++;
+ sem_post( semBlockLock );
+
+ unlock( mtxExternal );
+ bTimedOut = sem_wait( semBlockQueue,timeout );
+
+ lock( mtxUnblockLock );
+ if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
+ if ( bTimeout ) { // timeout (or canceled)
+ if ( 0 != nWaitersBlocked ) {
+ nWaitersBlocked--;
+ }
+ else {
+ nWaitersGone++; // count spurious wakeups
+ }
+ }
+ if ( 0 == --nWaitersToUnblock ) {
+ if ( 0 != nWaitersBlocked ) {
+ sem_post( semBlockLock ); // open the gate
+ nSignalsWasLeft = 0; // do not open the gate below
+again
+ }
+ else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
+ nWaitersGone = 0;
+ }
+ }
+ }
+ else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
+semaphore :-)
+ sem_wait( semBlockLock );
+ nWaitersBlocked -= nWaitersGone; // something is going on here -
+test of timeouts? :-)
+ sem_post( semBlockLock );
+ nWaitersGone = 0;
+ }
+ unlock( mtxUnblockLock );
+
+ if ( 1 == nSignalsWasLeft ) {
+ if ( 0 != nWaitersWasGone ) {
+ // sem_adjust( -nWaitersWasGone );
+ while ( nWaitersWasGone-- ) {
+ sem_wait( semBlockLock ); // better now than spurious
+later
+ }
+ }
+ sem_post( semBlockLock ); // open the gate
+ }
+
+ lock( mtxExternal );
+
+ return ( bTimedOut ) ? ETIMEOUT : 0;
+}
+
+signal(bAll) {
+
+ [auto: register int result ]
+ [auto: register int nSignalsToIssue]
+
+ lock( mtxUnblockLock );
+
+ if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
+ if ( 0 == nWaitersBlocked ) { // NO-OP
+ return unlock( mtxUnblockLock );
+ }
+ if (bAll) {
+ nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
+ nWaitersBlocked = 0;
+ }
+ else {
+ nSignalsToIssue = 1;
+ nWaitersToUnblock++;
+ nWaitersBlocked--;
+ }
+ }
+ else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
+ sem_wait( semBlockLock ); // close the gate
+ if ( 0 != nWaitersGone ) {
+ nWaitersBlocked -= nWaitersGone;
+ nWaitersGone = 0;
+ }
+ if (bAll) {
+ nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
+ nWaitersBlocked = 0;
+ }
+ else {
+ nSignalsToIssue = nWaitersToUnblock = 1;
+ nWaitersBlocked--;
+ }
+ }
+ else { // NO-OP
+ return unlock( mtxUnblockLock );
+ }
+
+ unlock( mtxUnblockLock );
+ sem_post( semBlockQueue,nSignalsToIssue );
+ return result;
+}
+
+---------- Algorithm 8b / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ONEBYONE
+------
+given:
+semBlockLock - bin.semaphore
+semBlockQueue - bin.semaphore
+mtxExternal - mutex or CS
+mtxUnblockLock - mutex or CS
+nWaitersGone - int
+nWaitersBlocked - int
+nWaitersToUnblock - int
+
+wait( timeout ) {
+
+ [auto: register int result ] // error checking omitted
+ [auto: register int nWaitersWasGone ]
+ [auto: register int nSignalsWasLeft ]
+
+ sem_wait( semBlockLock );
+ nWaitersBlocked++;
+ sem_post( semBlockLock );
+
+ unlock( mtxExternal );
+ bTimedOut = sem_wait( semBlockQueue,timeout );
+
+ lock( mtxUnblockLock );
+ if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
+ if ( bTimeout ) { // timeout (or canceled)
+ if ( 0 != nWaitersBlocked ) {
+ nWaitersBlocked--;
+ nSignalsWasLeft = 0; // do not unblock next waiter
+below (already unblocked)
+ }
+ else {
+ nWaitersGone = 1; // spurious wakeup pending!!
+ }
+ }
+ if ( 0 == --nWaitersToUnblock &&
+ if ( 0 != nWaitersBlocked ) {
+ sem_post( semBlockLock ); // open the gate
+ nSignalsWasLeft = 0; // do not open the gate below
+again
+ }
+ else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
+ nWaitersGone = 0;
+ }
+ }
+ }
+ else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
+semaphore :-)
+ sem_wait( semBlockLock );
+ nWaitersBlocked -= nWaitersGone; // something is going on here -
+test of timeouts? :-)
+ sem_post( semBlockLock );
+ nWaitersGone = 0;
+ }
+ unlock( mtxUnblockLock );
+
+ if ( 1 == nSignalsWasLeft ) {
+ if ( 0 != nWaitersWasGone ) {
+ // sem_adjust( -1 );
+ sem_wait( semBlockQueue ); // better now than spurious
+later
+ }
+ sem_post( semBlockLock ); // open the gate
+ }
+ else if ( 0 != nSignalsWasLeft ) {
+ sem_post( semBlockQueue ); // unblock next waiter
+ }
+
+ lock( mtxExternal );
+
+ return ( bTimedOut ) ? ETIMEOUT : 0;
+}
+
+signal(bAll) {
+
+ [auto: register int result ]
+
+ lock( mtxUnblockLock );
+
+ if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
+ if ( 0 == nWaitersBlocked ) { // NO-OP
+ return unlock( mtxUnblockLock );
+ }
+ if (bAll) {
+ nWaitersToUnblock += nWaitersBlocked;
+ nWaitersBlocked = 0;
+ }
+ else {
+ nWaitersToUnblock++;
+ nWaitersBlocked--;
+ }
+ unlock( mtxUnblockLock );
+ }
+ else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
+ sem_wait( semBlockLock ); // close the gate
+ if ( 0 != nWaitersGone ) {
+ nWaitersBlocked -= nWaitersGone;
+ nWaitersGone = 0;
+ }
+ if (bAll) {
+ nWaitersToUnblock = nWaitersBlocked;
+ nWaitersBlocked = 0;
+ }
+ else {
+ nWaitersToUnblock = 1;
+ nWaitersBlocked--;
+ }
+ unlock( mtxUnblockLock );
+ sem_post( semBlockQueue );
+ }
+ else { // NO-OP
+ unlock( mtxUnblockLock );
+ }
+
+ return result;
+}
+
+---------- Algorithm 8c / IMPL_EVENT,UNBLOCK_STRATEGY == UNBLOCK_ONEBYONE
+---------
+given:
+hevBlockLock - auto-reset event
+hevBlockQueue - auto-reset event
+mtxExternal - mutex or CS
+mtxUnblockLock - mutex or CS
+nWaitersGone - int
+nWaitersBlocked - int
+nWaitersToUnblock - int
+
+wait( timeout ) {
+
+ [auto: register int result ] // error checking omitted
+ [auto: register int nSignalsWasLeft ]
+ [auto: register int nWaitersWasGone ]
+
+ wait( hevBlockLock,INFINITE );
+ nWaitersBlocked++;
+ set_event( hevBlockLock );
+
+ unlock( mtxExternal );
+ bTimedOut = wait( hevBlockQueue,timeout );
+
+ lock( mtxUnblockLock );
+ if ( 0 != (SignalsWasLeft = nWaitersToUnblock) ) {
+ if ( bTimeout ) { // timeout (or canceled)
+ if ( 0 != nWaitersBlocked ) {
+ nWaitersBlocked--;
+ nSignalsWasLeft = 0; // do not unblock next waiter
+below (already unblocked)
+ }
+ else {
+ nWaitersGone = 1; // spurious wakeup pending!!
+ }
+ }
+ if ( 0 == --nWaitersToUnblock )
+ if ( 0 != nWaitersBlocked ) {
+ set_event( hevBlockLock ); // open the gate
+ nSignalsWasLeft = 0; // do not open the gate below
+again
+ }
+ else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
+ nWaitersGone = 0;
+ }
+ }
+ }
+ else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
+event :-)
+ wait( hevBlockLock,INFINITE );
+ nWaitersBlocked -= nWaitersGone; // something is going on here -
+test of timeouts? :-)
+ set_event( hevBlockLock );
+ nWaitersGone = 0;
+ }
+ unlock( mtxUnblockLock );
+
+ if ( 1 == nSignalsWasLeft ) {
+ if ( 0 != nWaitersWasGone ) {
+ reset_event( hevBlockQueue ); // better now than spurious
+later
+ }
+ set_event( hevBlockLock ); // open the gate
+ }
+ else if ( 0 != nSignalsWasLeft ) {
+ set_event( hevBlockQueue ); // unblock next waiter
+ }
+
+ lock( mtxExternal );
+
+ return ( bTimedOut ) ? ETIMEOUT : 0;
+}
+
+signal(bAll) {
+
+ [auto: register int result ]
+
+ lock( mtxUnblockLock );
+
+ if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
+ if ( 0 == nWaitersBlocked ) { // NO-OP
+ return unlock( mtxUnblockLock );
+ }
+ if (bAll) {
+ nWaitersToUnblock += nWaitersBlocked;
+ nWaitersBlocked = 0;
+ }
+ else {
+ nWaitersToUnblock++;
+ nWaitersBlocked--;
+ }
+ unlock( mtxUnblockLock );
+ }
+ else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
+ wait( hevBlockLock,INFINITE ); // close the gate
+ if ( 0 != nWaitersGone ) {
+ nWaitersBlocked -= nWaitersGone;
+ nWaitersGone = 0;
+ }
+ if (bAll) {
+ nWaitersToUnblock = nWaitersBlocked;
+ nWaitersBlocked = 0;
+ }
+ else {
+ nWaitersToUnblock = 1;
+ nWaitersBlocked--;
+ }
+ unlock( mtxUnblockLock );
+ set_event( hevBlockQueue );
+ }
+ else { // NO-OP
+ unlock( mtxUnblockLock );
+ }
+
+ return result;
+}
+
+---------- Algorithm 8d / IMPL_EVENT,UNBLOCK_STRATEGY == UNBLOCK_ALL ------
+given:
+hevBlockLock - auto-reset event
+hevBlockQueueS - auto-reset event // for signals
+hevBlockQueueB - manual-reset even // for broadcasts
+mtxExternal - mutex or CS
+mtxUnblockLock - mutex or CS
+eBroadcast - int // 0: no broadcast, 1: broadcast, 2:
+broadcast after signal(s)
+nWaitersGone - int
+nWaitersBlocked - int
+nWaitersToUnblock - int
+
+wait( timeout ) {
+
+ [auto: register int result ] // error checking omitted
+ [auto: register int eWasBroadcast ]
+ [auto: register int nSignalsWasLeft ]
+ [auto: register int nWaitersWasGone ]
+
+ wait( hevBlockLock,INFINITE );
+ nWaitersBlocked++;
+ set_event( hevBlockLock );
+
+ unlock( mtxExternal );
+ bTimedOut = waitformultiple( hevBlockQueueS,hevBlockQueueB,timeout,ONE );
+
+ lock( mtxUnblockLock );
+ if ( 0 != (SignalsWasLeft = nWaitersToUnblock) ) {
+ if ( bTimeout ) { // timeout (or canceled)
+ if ( 0 != nWaitersBlocked ) {
+ nWaitersBlocked--;
+ nSignalsWasLeft = 0; // do not unblock next waiter
+below (already unblocked)
+ }
+ else if ( 1 != eBroadcast ) {
+ nWaitersGone = 1;
+ }
+ }
+ if ( 0 == --nWaitersToUnblock ) {
+ if ( 0 != nWaitersBlocked ) {
+ set_event( hevBlockLock ); // open the gate
+ nSignalsWasLeft = 0; // do not open the gate below
+again
+ }
+ else {
+ if ( 0 != (eWasBroadcast = eBroadcast) ) {
+ eBroadcast = 0;
+ }
+ if ( 0 != (nWaitersWasGone = nWaitersGone ) {
+ nWaitersGone = 0;
+ }
+ }
+ }
+ else if ( 0 != eBroadcast ) {
+ nSignalsWasLeft = 0; // do not unblock next waiter
+below (already unblocked)
+ }
+ }
+ else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
+event :-)
+ wait( hevBlockLock,INFINITE );
+ nWaitersBlocked -= nWaitersGone; // something is going on here -
+test of timeouts? :-)
+ set_event( hevBlockLock );
+ nWaitersGone = 0;
+ }
+ unlock( mtxUnblockLock );
+
+ if ( 1 == nSignalsWasLeft ) {
+ if ( 0 != eWasBroadcast ) {
+ reset_event( hevBlockQueueB );
+ }
+ if ( 0 != nWaitersWasGone ) {
+ reset_event( hevBlockQueueS ); // better now than spurious
+later
+ }
+ set_event( hevBlockLock ); // open the gate
+ }
+ else if ( 0 != nSignalsWasLeft ) {
+ set_event( hevBlockQueueS ); // unblock next waiter
+ }
+
+ lock( mtxExternal );
+
+ return ( bTimedOut ) ? ETIMEOUT : 0;
+}
+
+signal(bAll) {
+
+ [auto: register int result ]
+ [auto: register HANDLE hevBlockQueue ]
+
+ lock( mtxUnblockLock );
+
+ if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
+ if ( 0 == nWaitersBlocked ) { // NO-OP
+ return unlock( mtxUnblockLock );
+ }
+ if (bAll) {
+ nWaitersToUnblock += nWaitersBlocked;
+ nWaitersBlocked = 0;
+ eBroadcast = 2;
+ hevBlockQueue = hevBlockQueueB;
+ }
+ else {
+ nWaitersToUnblock++;
+ nWaitersBlocked--;
+ return unlock( mtxUnblockLock );
+ }
+ }
+ else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
+ wait( hevBlockLock,INFINITE ); // close the gate
+ if ( 0 != nWaitersGone ) {
+ nWaitersBlocked -= nWaitersGone;
+ nWaitersGone = 0;
+ }
+ if (bAll) {
+ nWaitersToUnblock = nWaitersBlocked;
+ nWaitersBlocked = 0;
+ eBroadcast = 1;
+ hevBlockQueue = hevBlockQueueB;
+ }
+ else {
+ nWaitersToUnblock = 1;
+ nWaitersBlocked--;
+ hevBlockQueue = hevBlockQueueS;
+ }
+ }
+ else { // NO-OP
+ return unlock( mtxUnblockLock );
+ }
+
+ unlock( mtxUnblockLock );
+ set_event( hevBlockQueue );
+ return result;
+}
+---------------------- Forwarded by Alexander Terekhov/Germany/IBM on
+02/21/2001 09:13 AM ---------------------------
+
+Alexander Terekhov
+02/20/2001 04:33 PM
+
+To: Louis Thomas <lthomas@arbitrade.com>
+cc:
+
+From: Alexander Terekhov/Germany/IBM@IBMDE
+Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio
+ n questions
+Importance: Normal
+
+>Sorry, gotta take a break and work on something else for a while.
+>Real work
+>calls, unfortunately. I'll get back to you in two or three days.
+
+ok. no problem. here is some more stuff for pauses you might have
+in between :)
+
+---------- Algorithm 7d / IMPL_EVENT,UNBLOCK_STRATEGY == UNBLOCK_ALL ------
+given:
+hevBlockLock - auto-reset event
+hevBlockQueueS - auto-reset event // for signals
+hevBlockQueueB - manual-reset even // for broadcasts
+mtxExternal - mutex or CS
+mtxUnblockLock - mutex or CS
+bBroadcast - int
+nWaitersGone - int
+nWaitersBlocked - int
+nWaitersToUnblock - int
+
+wait( timeout ) {
+
+ [auto: register int result ] // error checking omitted
+ [auto: register int bWasBroadcast ]
+ [auto: register int nSignalsWasLeft ]
+
+ wait( hevBlockLock,INFINITE );
+ nWaitersBlocked++;
+ set_event( hevBlockLock );
+
+ unlock( mtxExternal );
+ bTimedOut = waitformultiple( hevBlockQueueS,hevBlockQueueB,timeout,ONE );
+
+ lock( mtxUnblockLock );
+ if ( 0 != (SignalsWasLeft = nWaitersToUnblock) ) {
+ if ( bTimeout ) { // timeout (or canceled)
+ if ( 0 != nWaitersBlocked ) {
+ nWaitersBlocked--;
+ nSignalsWasLeft = 0; // do not unblock next waiter
+below (already unblocked)
+ }
+ else if ( !bBroadcast ) {
+ wait( hevBlockQueueS,INFINITE ); // better now than spurious
+later
+ }
+ }
+ if ( 0 == --nWaitersToUnblock ) {
+ if ( 0 != nWaitersBlocked ) {
+ if ( bBroadcast ) {
+ reset_event( hevBlockQueueB );
+ bBroadcast = false;
+ }
+ set_event( hevBlockLock ); // open the gate
+ nSignalsWasLeft = 0; // do not open the gate below
+again
+ }
+ else if ( false != (bWasBroadcast = bBroadcast) ) {
+ bBroadcast = false;
+ }
+ }
+ else {
+ bWasBroadcast = bBroadcast;
+ }
+ }
+ else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious
+event :-)
+ wait( hevBlockLock,INFINITE );
+ nWaitersBlocked -= nWaitersGone; // something is going on here -
+test of timeouts? :-)
+ set_event( hevBlockLock );
+ nWaitersGone = 0;
+ }
+ unlock( mtxUnblockLock );
+
+ if ( 1 == nSignalsWasLeft ) {
+ if ( bWasBroadcast ) {
+ reset_event( hevBlockQueueB );
+ }
+ set_event( hevBlockLock ); // open the gate
+ }
+ else if ( 0 != nSignalsWasLeft && !bWasBroadcast ) {
+ set_event( hevBlockQueueS ); // unblock next waiter
+ }
+
+ lock( mtxExternal );
+
+ return ( bTimedOut ) ? ETIMEOUT : 0;
+}
+
+signal(bAll) {
+
+ [auto: register int result ]
+ [auto: register HANDLE hevBlockQueue ]
+
+ lock( mtxUnblockLock );
+
+ if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
+ if ( 0 == nWaitersBlocked ) { // NO-OP
+ return unlock( mtxUnblockLock );
+ }
+ if (bAll) {
+ nWaitersToUnblock += nWaitersBlocked;
+ nWaitersBlocked = 0;
+ bBroadcast = true;
+ hevBlockQueue = hevBlockQueueB;
+ }
+ else {
+ nWaitersToUnblock++;
+ nWaitersBlocked--;
+ return unlock( mtxUnblockLock );
+ }
+ }
+ else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
+ wait( hevBlockLock,INFINITE ); // close the gate
+ if ( 0 != nWaitersGone ) {
+ nWaitersBlocked -= nWaitersGone;
+ nWaitersGone = 0;
+ }
+ if (bAll) {
+ nWaitersToUnblock = nWaitersBlocked;
+ nWaitersBlocked = 0;
+ bBroadcast = true;
+ hevBlockQueue = hevBlockQueueB;
+ }
+ else {
+ nWaitersToUnblock = 1;
+ nWaitersBlocked--;
+ hevBlockQueue = hevBlockQueueS;
+ }
+ }
+ else { // NO-OP
+ return unlock( mtxUnblockLock );
+ }
+
+ unlock( mtxUnblockLock );
+ set_event( hevBlockQueue );
+ return result;
+}
+
+
+----------------------------------------------------------------------------
+
+Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio
+ n questions
+Date: Mon, 26 Feb 2001 22:20:12 -0600
+From: Louis Thomas <lthomas@arbitrade.com>
+To: "'TEREKHOV@de.ibm.com'" <TEREKHOV@de.ibm.com>
+CC: rpj@ise.canberra.edu.au, Thomas Pfaff <tpfaff@gmx.net>,
+ Nanbor Wang
+ <nanbor@cs.wustl.edu>
+
+Sorry all. Busy week.
+
+> this insures the fairness
+> which POSIX does not (e.g. two subsequent broadcasts - the gate does
+insure
+> that first wave waiters will start the race for the mutex before waiters
+> from the second wave - Linux pthreads process/unblock both waves
+> concurrently...)
+
+I'm not sure how we are any more fair about this than Linux. We certainly
+don't guarantee that the threads released by the first broadcast will get
+the external mutex before the threads of the second wave. In fact, it is
+possible that those threads will never get the external mutex if there is
+enough contention for it.
+
+> e.g. i was thinking about implementation with a pool of
+> N semaphores/counters [...]
+
+I considered that too. The problem is as you mentioned in a). You really
+need to assign threads to semaphores once you know how you want to wake them
+up, not when they first begin waiting which is the only time you can assign
+them.
+
+> well, i am not quite sure that i've fully understood your scenario,
+
+Hmm. Well, it think it's an important example, so I'll try again. First, we
+have thread A which we KNOW is waiting on a condition. As soon as it becomes
+unblocked for any reason, we will know because it will set a flag. Since the
+flag is not set, we are 100% confident that thread A is waiting on the
+condition. We have another thread, thread B, which has acquired the mutex
+and is about to wait on the condition. Thus it is pretty clear that at any
+point, either just A is waiting, or A and B are waiting. Now thread C comes
+along. C is about to do a broadcast on the condition. A broadcast is
+guaranteed to unblock all threads currently waiting on a condition, right?
+Again, we said that either just A is waiting, or A and B are both waiting.
+So, when C does its broadcast, depending upon whether B has started waiting
+or not, thread C will unblock A or unblock A and B. Either way, C must
+unblock A, right?
+
+Now, you said anything that happens is correct so long as a) "a signal is
+not lost between unlocking the mutex and waiting on the condition" and b) "a
+thread must not steal a signal it sent", correct? Requirement b) is easy to
+satisfy: in this scenario, thread C will never wait on the condition, so it
+won't steal any signals. Requirement a) is not hard either. The only way we
+could fail to meet requirement a) in this scenario is if thread B was
+started waiting but didn't wake up because a signal was lost. This will not
+happen.
+
+Now, here is what happens. Assume thread C beats thread B. Thread C looks to
+see how many threads are waiting on the condition. Thread C sees just one
+thread, thread A, waiting. It does a broadcast waking up just one thread
+because just one thread is waiting. Next, before A can become unblocked,
+thread B begins waiting. Now there are two threads waiting, but only one
+will be unblocked. Suppose B wins. B will become unblocked. A will not
+become unblocked, because C only unblocked one thread (sema_post cond, 1).
+So at the end, B finishes and A remains blocked.
+
+We have met both of your requirements, so by your rules, this is an
+acceptable outcome. However, I think that the spec says this is an
+unacceptable outcome! We know for certain that A was waiting and that C did
+a broadcast, but A did not become unblocked! Yet, the spec says that a
+broadcast wakes up all waiting threads. This did not happen. Do you agree
+that this shows your rules are not strict enough?
+
+> and what about N2? :) this one does allow almost everything.
+
+Don't get me started about rule #2. I'll NEVER advocate an algorithm that
+uses rule 2 as an excuse to suck!
+
+> but it is done (decrement)under mutex protection - this is not a subject
+> of a race condition.
+
+You are correct. My mistake.
+
+> i would remove "_bTimedOut=false".. after all, it was a real timeout..
+
+I disagree. A thread that can't successfully retract its waiter status can't
+really have timed out. If a thread can't return without executing extra code
+to deal with the fact that someone tried to unblock it, I think it is a poor
+idea to pretend we
+didn't realize someone was trying to signal us. After all, a signal is more
+important than a time out.
+
+> when nSignaled != 0, it is possible to update nWaiters (--) and do not
+> touch nGone
+
+I realize this, but I was thinking that writing it the other ways saves
+another if statement.
+
+> adjust only if nGone != 0 and save one cache memory write - probably much
+slower than 'if'
+
+Hmm. You are probably right.
+
+> well, in a strange (e.g. timeout test) program you may (theoretically)
+> have an overflow of nWaiters/nGone counters (with waiters repeatedly
+timing
+> out and no signals at all).
+
+Also true. Not only that, but you also have the possibility that one could
+overflow the number of waiters as well! However, considering the limit you
+have chosen for nWaitersGone, I suppose it is unlikely that anyone would be
+able to get INT_MAX/2 threads waiting on a single condition. :)
+
+Analysis of 8a:
+
+It looks correct to me.
+
+What are IPC semaphores?
+
+In the line where you state, "else if ( nWaitersBlocked > nWaitersGone ) {
+// HARMLESS RACE CONDITION!" there is no race condition for nWaitersGone
+because nWaitersGone is never modified without holding mtxUnblockLock. You
+are correct that there is a harmless race on nWaitersBlocked, which can
+increase and make the condition become true just after we check it. If this
+happens, we interpret it as the wait starting after the signal.
+
+I like your optimization of this. You could improve Alg. 6 as follows:
+---------- Algorithm 6b ----------
+signal(bAll) {
+ _nSig=0
+ lock counters
+ // this is safe because nWaiting can only be decremented by a thread that
+ // owns counters and nGone can only be changed by a thread that owns
+counters.
+ if (nWaiting>nGone) {
+ if (0==nSignaled) {
+ sema_wait gate // close gate if not already closed
+ }
+ if (nGone>0) {
+ nWaiting-=nGone
+ nGone=0
+ }
+ _nSig=bAll?nWaiting:1
+ nSignaled+=_nSig
+ nWaiting-=_nSig
+ }
+ unlock counters
+ if (0!=_nSig) {
+ sema_post queue, _nSig
+ }
+}
+---------- ---------- ----------
+I guess this wouldn't apply to Alg 8a because nWaitersGone changes meanings
+depending upon whether the gate is open or closed.
+
+In the loop "while ( nWaitersWasGone-- ) {" you do a sema_wait on
+semBlockLock. Perhaps waiting on semBlockQueue would be a better idea.
+
+What have you gained by making the last thread to be signaled do the waits
+for all the timed out threads, besides added complexity? It took me a long
+time to figure out what your objective was with this, to realize you were
+using nWaitersGone to mean two different things, and to verify that you
+hadn't introduced any bug by doing this. Even now I'm not 100% sure.
+
+What has all this playing about with nWaitersGone really gained us besides a
+lot of complexity (it is much harder to verify that this solution is
+correct), execution overhead (we now have a lot more if statements to
+evaluate), and space overhead (more space for the extra code, and another
+integer in our data)? We did manage to save a lock/unlock pair in an
+uncommon case (when a time out occurs) at the above mentioned expenses in
+the common cases.
+
+As for 8b, c, and d, they look ok though I haven't studied them thoroughly.
+What would you use them for?
+
+ Later,
+ -Louis! :)
+
+-----------------------------------------------------------------------------
+
+Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio
+ n questions
+Date: Tue, 27 Feb 2001 15:51:28 +0100
+From: TEREKHOV@de.ibm.com
+To: Louis Thomas <lthomas@arbitrade.com>
+CC: rpj@ise.canberra.edu.au, Thomas Pfaff <tpfaff@gmx.net>,
+ Nanbor Wang <nanbor@cs.wustl.edu>
+
+Hi Louis,
+
+>> that first wave waiters will start the race for the mutex before waiters
+>> from the second wave - Linux pthreads process/unblock both waves
+>> concurrently...)
+>
+>I'm not sure how we are any more fair about this than Linux. We certainly
+>don't guarantee that the threads released by the first broadcast will get
+>the external mutex before the threads of the second wave. In fact, it is
+>possible that those threads will never get the external mutex if there is
+>enough contention for it.
+
+correct. but gate is nevertheless more fair than Linux because of the
+barrier it establishes between two races (1st and 2nd wave waiters) for
+the mutex which under 'normal' circumstances (e.g. all threads of equal
+priorities,..) will 'probably' result in fair behaviour with respect to
+mutex ownership.
+
+>> well, i am not quite sure that i've fully understood your scenario,
+>
+>Hmm. Well, it think it's an important example, so I'll try again. ...
+
+ok. now i seem to understand this example. well, now it seems to me
+that the only meaningful rule is just:
+
+a) "a signal is not lost between unlocking the mutex and waiting on the
+condition"
+
+and that the rule
+
+b) "a thread must not steal a signal it sent"
+
+is not needed at all because a thread which violates b) also violates a).
+
+i'll try to explain..
+
+i think that the most important thing is how POSIX defines waiter's
+visibility:
+
+"if another thread is able to acquire the mutex after the about-to-block
+thread
+has released it, then a subsequent call to pthread_cond_signal() or
+pthread_cond_broadcast() in that thread behaves as if it were issued after
+the about-to-block thread has blocked. "
+
+my understanding is the following:
+
+1) there is no guarantees whatsoever with respect to whether
+signal/broadcast
+will actually unblock any 'waiter' if it is done w/o acquiring the mutex
+first
+(note that a thread may release it before signal/broadcast - it does not
+matter).
+
+2) it is guaranteed that waiters become 'visible' - eligible for unblock as
+soon
+as signalling thread acquires the mutex (but not before!!)
+
+so..
+
+>So, when C does its broadcast, depending upon whether B has started
+waiting
+>or not, thread C will unblock A or unblock A and B. Either way, C must
+>unblock A, right?
+
+right. but only if C did acquire the mutex prior to broadcast (it may
+release it before broadcast as well).
+
+implementation will violate waiters visibility rule (signal will become
+lost)
+if C will not unblock A.
+
+>Now, here is what happens. Assume thread C beats thread B. Thread C looks
+to
+>see how many threads are waiting on the condition. Thread C sees just one
+>thread, thread A, waiting. It does a broadcast waking up just one thread
+>because just one thread is waiting. Next, before A can become unblocked,
+>thread B begins waiting. Now there are two threads waiting, but only one
+>will be unblocked. Suppose B wins. B will become unblocked. A will not
+>become unblocked, because C only unblocked one thread (sema_post cond, 1).
+>So at the end, B finishes and A remains blocked.
+
+thread C did acquire the mutex ("Thread C sees just one thread, thread A,
+waiting"). beginning from that moment it is guaranteed that subsequent
+broadcast will unblock A. Otherwise we will have a lost signal with respect
+to A. I do think that it does not matter whether the signal was physically
+(completely) lost or was just stolen by another thread (B) - in both cases
+it was simply lost with respect to A.
+
+>..Do you agree that this shows your rules are not strict enough?
+
+probably the opposite.. :-) i think that it shows that the only meaningful
+rule is
+
+a) "a signal is not lost between unlocking the mutex and waiting on the
+condition"
+
+with clarification of waiters visibility as defined by POSIX above.
+
+>> i would remove "_bTimedOut=false".. after all, it was a real timeout..
+>
+>I disagree. A thread that can't successfully retract its waiter status
+can't
+>really have timed out. If a thread can't return without executing extra
+code
+>to deal with the fact that someone tried to unblock it, I think it is a
+poor
+>idea to pretend we
+>didn't realize someone was trying to signal us. After all, a signal is
+more
+>important than a time out.
+
+a) POSIX does allow timed out thread to consume a signal (cancelled is
+not).
+b) ETIMEDOUT status just says that: "The time specified by abstime to
+pthread_cond_timedwait() has passed."
+c) it seem to me that hiding timeouts would violate "The
+pthread_cond_timedwait()
+function is the same as pthread_cond_wait() except that an error is
+returned if
+the absolute time specified by abstime passes (that is, system time equals
+or
+exceeds abstime) before the condition cond is signaled or broadcasted"
+because
+the abs. time did really pass before cond was signaled (waiter was
+released via semaphore). however, if it really matters, i could imaging
+that we
+can save an abs. time of signal/broadcast and compare it with timeout after
+unblock to find out whether it was a 'real' timeout or not. absent this
+check
+i do think that hiding timeouts would result in technical violation of
+specification.. but i think that this check is not important and we can
+simply
+trust timeout error code provided by wait since we are not trying to make
+'hard' realtime implementation.
+
+>What are IPC semaphores?
+
+<sys/sem.h>
+int semctl(int, int, int, ...);
+int semget(key_t, int, int);
+int semop(int, struct sembuf *, size_t);
+
+they support adjustment of semaphore counter (semvalue)
+in one single call - imaging Win32 ReleaseSemaphore( hsem,-N )
+
+>In the line where you state, "else if ( nWaitersBlocked > nWaitersGone ) {
+>// HARMLESS RACE CONDITION!" there is no race condition for nWaitersGone
+>because nWaitersGone is never modified without holding mtxUnblockLock. You
+>are correct that there is a harmless race on nWaitersBlocked, which can
+>increase and make the condition become true just after we check it. If
+this
+>happens, we interpret it as the wait starting after the signal.
+
+well, the reason why i've asked on comp.programming.threads whether this
+race
+condition is harmless or not is that in order to be harmless it should not
+violate the waiters visibility rule (see above). Fortunately, we increment
+the counter under protection of external mutex.. so that any (signalling)
+thread which will acquire the mutex next, should see the updated counter
+(in signal) according to POSIX memory visibility rules and mutexes
+(memory barriers). But i am not so sure how it actually works on
+Win32/INTEL
+which does not explicitly define any memory visibility rules :(
+
+>I like your optimization of this. You could improve Alg. 6 as follows:
+>---------- Algorithm 6b ----------
+>signal(bAll) {
+> _nSig=0
+> lock counters
+> // this is safe because nWaiting can only be decremented by a thread
+that
+> // owns counters and nGone can only be changed by a thread that owns
+>counters.
+> if (nWaiting>nGone) {
+> if (0==nSignaled) {
+> sema_wait gate // close gate if not already closed
+> }
+> if (nGone>0) {
+> nWaiting-=nGone
+> nGone=0
+> }
+> _nSig=bAll?nWaiting:1
+> nSignaled+=_nSig
+> nWaiting-=_nSig
+> }
+> unlock counters
+> if (0!=_nSig) {
+> sema_post queue, _nSig
+> }
+>}
+>---------- ---------- ----------
+>I guess this wouldn't apply to Alg 8a because nWaitersGone changes
+meanings
+>depending upon whether the gate is open or closed.
+
+agree.
+
+>In the loop "while ( nWaitersWasGone-- ) {" you do a sema_wait on
+>semBlockLock. Perhaps waiting on semBlockQueue would be a better idea.
+
+you are correct. my mistake.
+
+>What have you gained by making the last thread to be signaled do the waits
+>for all the timed out threads, besides added complexity? It took me a long
+>time to figure out what your objective was with this, to realize you were
+>using nWaitersGone to mean two different things, and to verify that you
+>hadn't introduced any bug by doing this. Even now I'm not 100% sure.
+>
+>What has all this playing about with nWaitersGone really gained us besides
+a
+>lot of complexity (it is much harder to verify that this solution is
+>correct), execution overhead (we now have a lot more if statements to
+>evaluate), and space overhead (more space for the extra code, and another
+>integer in our data)? We did manage to save a lock/unlock pair in an
+>uncommon case (when a time out occurs) at the above mentioned expenses in
+>the common cases.
+
+well, please consider the following:
+
+1) with multiple waiters unblocked (but some timed out) the trick with
+counter
+seem to ensure potentially higher level of concurrency by not delaying
+most of unblocked waiters for semaphore cleanup - only the last one
+will be delayed but all others would already contend/acquire/release
+the external mutex - the critical section protected by mtxUnblockLock is
+made smaller (increment + couple of IFs is faster than system/kernel call)
+which i think is good in general. however, you are right, this is done
+at expense of 'normal' waiters..
+
+2) some semaphore APIs (e.g. POSIX IPC sems) do allow to adjust the
+semaphore counter in one call => less system/kernel calls.. imagine:
+
+if ( 1 == nSignalsWasLeft ) {
+ if ( 0 != nWaitersWasGone ) {
+ ReleaseSemaphore( semBlockQueue,-nWaitersWasGone ); // better now
+than spurious later
+ }
+ sem_post( semBlockLock ); // open the gate
+ }
+
+3) even on win32 a single thread doing multiple cleanup calls (to wait)
+will probably result in faster execution (because of processor caching)
+than multiple threads each doing a single call to wait.
+
+>As for 8b, c, and d, they look ok though I haven't studied them
+thoroughly.
+>What would you use them for?
+
+8b) for semaphores which do not allow to unblock multiple waiters
+in a single call to post/release (e.g. POSIX realtime semaphores -
+<semaphore.h>)
+
+8c/8d) for WinCE prior to 3.0 (WinCE 3.0 does have semaphores)
+
+ok. so, which one is the 'final' algorithm(s) which we should use in
+pthreads-win32??
+
+regards,
+alexander.
+
+----------------------------------------------------------------------------
+
+Louis Thomas <lthomas@arbitrade.com> on 02/27/2001 05:20:12 AM
+
+Please respond to Louis Thomas <lthomas@arbitrade.com>
+
+To: Alexander Terekhov/Germany/IBM@IBMDE
+cc: rpj@ise.canberra.edu.au, Thomas Pfaff <tpfaff@gmx.net>, Nanbor Wang
+ <nanbor@cs.wustl.edu>
+Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio
+ n questions
+
+Sorry all. Busy week.
+
+> this insures the fairness
+> which POSIX does not (e.g. two subsequent broadcasts - the gate does
+insure
+> that first wave waiters will start the race for the mutex before waiters
+> from the second wave - Linux pthreads process/unblock both waves
+> concurrently...)
+
+I'm not sure how we are any more fair about this than Linux. We certainly
+don't guarantee that the threads released by the first broadcast will get
+the external mutex before the threads of the second wave. In fact, it is
+possible that those threads will never get the external mutex if there is
+enough contention for it.
+
+> e.g. i was thinking about implementation with a pool of
+> N semaphores/counters [...]
+
+I considered that too. The problem is as you mentioned in a). You really
+need to assign threads to semaphores once you know how you want to wake
+them
+up, not when they first begin waiting which is the only time you can assign
+them.
+
+> well, i am not quite sure that i've fully understood your scenario,
+
+Hmm. Well, it think it's an important example, so I'll try again. First, we
+have thread A which we KNOW is waiting on a condition. As soon as it
+becomes
+unblocked for any reason, we will know because it will set a flag. Since
+the
+flag is not set, we are 100% confident that thread A is waiting on the
+condition. We have another thread, thread B, which has acquired the mutex
+and is about to wait on the condition. Thus it is pretty clear that at any
+point, either just A is waiting, or A and B are waiting. Now thread C comes
+along. C is about to do a broadcast on the condition. A broadcast is
+guaranteed to unblock all threads currently waiting on a condition, right?
+Again, we said that either just A is waiting, or A and B are both waiting.
+So, when C does its broadcast, depending upon whether B has started waiting
+or not, thread C will unblock A or unblock A and B. Either way, C must
+unblock A, right?
+
+Now, you said anything that happens is correct so long as a) "a signal is
+not lost between unlocking the mutex and waiting on the condition" and b)
+"a
+thread must not steal a signal it sent", correct? Requirement b) is easy to
+satisfy: in this scenario, thread C will never wait on the condition, so it
+won't steal any signals. Requirement a) is not hard either. The only way
+we
+could fail to meet requirement a) in this scenario is if thread B was
+started waiting but didn't wake up because a signal was lost. This will not
+happen.
+
+Now, here is what happens. Assume thread C beats thread B. Thread C looks
+to
+see how many threads are waiting on the condition. Thread C sees just one
+thread, thread A, waiting. It does a broadcast waking up just one thread
+because just one thread is waiting. Next, before A can become unblocked,
+thread B begins waiting. Now there are two threads waiting, but only one
+will be unblocked. Suppose B wins. B will become unblocked. A will not
+become unblocked, because C only unblocked one thread (sema_post cond, 1).
+So at the end, B finishes and A remains blocked.
+
+We have met both of your requirements, so by your rules, this is an
+acceptable outcome. However, I think that the spec says this is an
+unacceptable outcome! We know for certain that A was waiting and that C did
+a broadcast, but A did not become unblocked! Yet, the spec says that a
+broadcast wakes up all waiting threads. This did not happen. Do you agree
+that this shows your rules are not strict enough?
+
+> and what about N2? :) this one does allow almost everything.
+
+Don't get me started about rule #2. I'll NEVER advocate an algorithm that
+uses rule 2 as an excuse to suck!
+
+> but it is done (decrement)under mutex protection - this is not a subject
+> of a race condition.
+
+You are correct. My mistake.
+
+> i would remove "_bTimedOut=false".. after all, it was a real timeout..
+
+I disagree. A thread that can't successfully retract its waiter status
+can't
+really have timed out. If a thread can't return without executing extra
+code
+to deal with the fact that someone tried to unblock it, I think it is a
+poor
+idea to pretend we
+didn't realize someone was trying to signal us. After all, a signal is more
+important than a time out.
+
+> when nSignaled != 0, it is possible to update nWaiters (--) and do not
+> touch nGone
+
+I realize this, but I was thinking that writing it the other ways saves
+another if statement.
+
+> adjust only if nGone != 0 and save one cache memory write - probably much
+slower than 'if'
+
+Hmm. You are probably right.
+
+> well, in a strange (e.g. timeout test) program you may (theoretically)
+> have an overflow of nWaiters/nGone counters (with waiters repeatedly
+timing
+> out and no signals at all).
+
+Also true. Not only that, but you also have the possibility that one could
+overflow the number of waiters as well! However, considering the limit you
+have chosen for nWaitersGone, I suppose it is unlikely that anyone would be
+able to get INT_MAX/2 threads waiting on a single condition. :)
+
+Analysis of 8a:
+
+It looks correct to me.
+
+What are IPC semaphores?
+
+In the line where you state, "else if ( nWaitersBlocked > nWaitersGone ) {
+// HARMLESS RACE CONDITION!" there is no race condition for nWaitersGone
+because nWaitersGone is never modified without holding mtxUnblockLock. You
+are correct that there is a harmless race on nWaitersBlocked, which can
+increase and make the condition become true just after we check it. If this
+happens, we interpret it as the wait starting after the signal.
+
+I like your optimization of this. You could improve Alg. 6 as follows:
+---------- Algorithm 6b ----------
+signal(bAll) {
+ _nSig=0
+ lock counters
+ // this is safe because nWaiting can only be decremented by a thread that
+ // owns counters and nGone can only be changed by a thread that owns
+counters.
+ if (nWaiting>nGone) {
+ if (0==nSignaled) {
+ sema_wait gate // close gate if not already closed
+ }
+ if (nGone>0) {
+ nWaiting-=nGone
+ nGone=0
+ }
+ _nSig=bAll?nWaiting:1
+ nSignaled+=_nSig
+ nWaiting-=_nSig
+ }
+ unlock counters
+ if (0!=_nSig) {
+ sema_post queue, _nSig
+ }
+}
+---------- ---------- ----------
+I guess this wouldn't apply to Alg 8a because nWaitersGone changes meanings
+depending upon whether the gate is open or closed.
+
+In the loop "while ( nWaitersWasGone-- ) {" you do a sema_wait on
+semBlockLock. Perhaps waiting on semBlockQueue would be a better idea.
+
+What have you gained by making the last thread to be signaled do the waits
+for all the timed out threads, besides added complexity? It took me a long
+time to figure out what your objective was with this, to realize you were
+using nWaitersGone to mean two different things, and to verify that you
+hadn't introduced any bug by doing this. Even now I'm not 100% sure.
+
+What has all this playing about with nWaitersGone really gained us besides
+a
+lot of complexity (it is much harder to verify that this solution is
+correct), execution overhead (we now have a lot more if statements to
+evaluate), and space overhead (more space for the extra code, and another
+integer in our data)? We did manage to save a lock/unlock pair in an
+uncommon case (when a time out occurs) at the above mentioned expenses in
+the common cases.
+
+As for 8b, c, and d, they look ok though I haven't studied them thoroughly.
+What would you use them for?
+
+ Later,
+ -Louis! :)
+
diff --git a/TODO b/TODO
index 48b416e..f0e11bf 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,7 @@
- Things that should be doable but aren't yet
- -------------------------------------------
-
-1. Implement PTHREAD_PROCESS_SHARED for semaphores, mutexes,
- condition variables, read/write locks, barriers.
-
-
+ Things that should be doable but aren't yet
+ -------------------------------------------
+
+1. Implement PTHREAD_PROCESS_SHARED for semaphores, mutexes,
+ condition variables, read/write locks, barriers.
+
+
diff --git a/condvar.c b/condvar.c
index 32fee38..59878b2 100644
--- a/condvar.c
+++ b/condvar.c
@@ -34,1256 +34,19 @@
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- *
- * -------------------------------------------------------------
- * Algorithm:
- * The algorithm used in this implementation is that developed by
- * Alexander Terekhov in colaboration with Louis Thomas. The bulk
- * of the discussion is recorded in the file README.CV, which contains
- * several generations of both colaborators original algorithms. The final
- * algorithm used here is the one referred to as
- *
- * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
- *
- * presented below in pseudo-code as it appeared:
- *
- *
- * given:
- * semBlockLock - bin.semaphore
- * semBlockQueue - semaphore
- * mtxExternal - mutex or CS
- * mtxUnblockLock - mutex or CS
- * nWaitersGone - int
- * nWaitersBlocked - int
- * nWaitersToUnblock - int
- *
- * wait( timeout ) {
- *
- * [auto: register int result ] // error checking omitted
- * [auto: register int nSignalsWasLeft ]
- * [auto: register int nWaitersWasGone ]
- *
- * sem_wait( semBlockLock );
- * nWaitersBlocked++;
- * sem_post( semBlockLock );
- *
- * unlock( mtxExternal );
- * bTimedOut = sem_wait( semBlockQueue,timeout );
- *
- * lock( mtxUnblockLock );
- * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
- * if ( bTimeout ) { // timeout (or canceled)
- * if ( 0 != nWaitersBlocked ) {
- * nWaitersBlocked--;
- * }
- * else {
- * nWaitersGone++; // count spurious wakeups.
- * }
- * }
- * if ( 0 == --nWaitersToUnblock ) {
- * if ( 0 != nWaitersBlocked ) {
- * sem_post( semBlockLock ); // open the gate.
- * nSignalsWasLeft = 0; // do not open the gate
- * // below again.
- * }
- * else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
- * nWaitersGone = 0;
- * }
- * }
- * }
- * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
- * // spurious semaphore :-)
- * sem_wait( semBlockLock );
- * nWaitersBlocked -= nWaitersGone; // something is going on here
- * // - test of timeouts? :-)
- * sem_post( semBlockLock );
- * nWaitersGone = 0;
- * }
- * unlock( mtxUnblockLock );
- *
- * if ( 1 == nSignalsWasLeft ) {
- * if ( 0 != nWaitersWasGone ) {
- * // sem_adjust( semBlockQueue,-nWaitersWasGone );
- * while ( nWaitersWasGone-- ) {
- * sem_wait( semBlockQueue ); // better now than spurious later
- * }
- * } sem_post( semBlockLock ); // open the gate
- * }
- *
- * lock( mtxExternal );
- *
- * return ( bTimedOut ) ? ETIMEOUT : 0;
- * }
- *
- * signal(bAll) {
- *
- * [auto: register int result ]
- * [auto: register int nSignalsToIssue]
- *
- * lock( mtxUnblockLock );
- *
- * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
- * if ( 0 == nWaitersBlocked ) { // NO-OP
- * return unlock( mtxUnblockLock );
- * }
- * if (bAll) {
- * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
- * nWaitersBlocked = 0;
- * }
- * else {
- * nSignalsToIssue = 1;
- * nWaitersToUnblock++;
- * nWaitersBlocked--;
- * }
- * }
- * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
- * sem_wait( semBlockLock ); // close the gate
- * if ( 0 != nWaitersGone ) {
- * nWaitersBlocked -= nWaitersGone;
- * nWaitersGone = 0;
- * }
- * if (bAll) {
- * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
- * nWaitersBlocked = 0;
- * }
- * else {
- * nSignalsToIssue = nWaitersToUnblock = 1;
- * nWaitersBlocked--;
- * }
- * }
- * else { // NO-OP
- * return unlock( mtxUnblockLock );
- * }
- *
- * unlock( mtxUnblockLock );
- * sem_post( semBlockQueue,nSignalsToIssue );
- * return result;
- * }
- * -------------------------------------------------------------
- *
*/
#include "pthread.h"
#include "implement.h"
-static INLINE int
-ptw32_cond_check_need_init (pthread_cond_t *cond)
-{
- int result = 0;
-
- /*
- * The following guarded test is specifically for statically
- * initialised condition variables (via PTHREAD_OBJECT_INITIALIZER).
- *
- * Note that by not providing this synchronisation we risk
- * introducing race conditions into applications which are
- * correctly written.
- *
- * Approach
- * --------
- * We know that static condition variables will not be PROCESS_SHARED
- * so we can serialise access to internal state using
- * Win32 Critical Sections rather than Win32 Mutexes.
- *
- * If using a single global lock slows applications down too much,
- * multiple global locks could be created and hashed on some random
- * value associated with each mutex, the pointer perhaps. At a guess,
- * a good value for the optimal number of global locks might be
- * the number of processors + 1.
- *
- */
- EnterCriticalSection(&ptw32_cond_test_init_lock);
-
- /*
- * We got here possibly under race
- * conditions. Check again inside the critical section.
- * If a static cv has been destroyed, the application can
- * re-initialise it only by calling pthread_cond_init()
- * explicitly.
- */
- if (*cond == PTHREAD_COND_INITIALIZER)
- {
- result = pthread_cond_init(cond, NULL);
- }
- else if (*cond == NULL)
- {
- /*
- * The cv has been destroyed while we were waiting to
- * initialise it, so the operation that caused the
- * auto-initialisation should fail.
- */
- result = EINVAL;
- }
-
- LeaveCriticalSection(&ptw32_cond_test_init_lock);
-
- return result;
-}
-
-
-int
-pthread_condattr_init (pthread_condattr_t * attr)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * Initializes a condition variable attributes object
- * with default attributes.
- *
- * PARAMETERS
- * attr
- * pointer to an instance of pthread_condattr_t
- *
- *
- * DESCRIPTION
- * Initializes a condition variable attributes object
- * with default attributes.
- *
- * NOTES:
- * 1) Use to define condition variable types
- * 2) It is up to the application to ensure
- * that it doesn't re-init an attribute
- * without destroying it first. Otherwise
- * a memory leak is created.
- *
- * RESULTS
- * 0 successfully initialized attr,
- * ENOMEM insufficient memory for attr.
- *
- * ------------------------------------------------------
- */
-{
- pthread_condattr_t attr_result;
- int result = 0;
-
- attr_result = (pthread_condattr_t) calloc (1, sizeof (*attr_result));
-
- if (attr_result == NULL)
- {
- result = ENOMEM;
- }
-
- *attr = attr_result;
-
- return result;
-
-} /* pthread_condattr_init */
-
-
-int
-pthread_condattr_destroy (pthread_condattr_t * attr)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * Destroys a condition variable attributes object.
- * The object can no longer be used.
- *
- * PARAMETERS
- * attr
- * pointer to an instance of pthread_condattr_t
- *
- *
- * DESCRIPTION
- * Destroys a condition variable attributes object.
- * The object can no longer be used.
- *
- * NOTES:
- * 1) Does not affect condition variables created
- * using 'attr'
- *
- * RESULTS
- * 0 successfully released attr,
- * EINVAL 'attr' is invalid.
- *
- * ------------------------------------------------------
- */
-{
- int result = 0;
-
- if (attr == NULL || *attr == NULL)
- {
- result = EINVAL;
- }
- else
- {
- (void) free (*attr);
-
- *attr = NULL;
- result = 0;
- }
-
- return result;
-
-} /* pthread_condattr_destroy */
-
-
-int
-pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * Determine whether condition variables created with 'attr'
- * can be shared between processes.
- *
- * PARAMETERS
- * attr
- * pointer to an instance of pthread_condattr_t
- *
- * pshared
- * will be set to one of:
- *
- * PTHREAD_PROCESS_SHARED
- * May be shared if in shared memory
- *
- * PTHREAD_PROCESS_PRIVATE
- * Cannot be shared.
- *
- *
- * DESCRIPTION
- * Condition Variables created with 'attr' can be shared
- * between processes if pthread_cond_t variable is allocated
- * in memory shared by these processes.
- * NOTES:
- * 1) pshared condition variables MUST be allocated in
- * shared memory.
- *
- * 2) The following macro is defined if shared mutexes
- * are supported:
- * _POSIX_THREAD_PROCESS_SHARED
- *
- * RESULTS
- * 0 successfully retrieved attribute,
- * EINVAL 'attr' or 'pshared' is invalid,
- *
- * ------------------------------------------------------
- */
-{
- int result;
-
- if ((attr != NULL && *attr != NULL) && (pshared != NULL))
- {
- *pshared = (*attr)->pshared;
- result = 0;
- }
- else
- {
- result = EINVAL;
- }
-
- return result;
-
-} /* pthread_condattr_getpshared */
-
-
-int
-pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * Mutexes created with 'attr' can be shared between
- * processes if pthread_mutex_t variable is allocated
- * in memory shared by these processes.
- *
- * PARAMETERS
- * attr
- * pointer to an instance of pthread_mutexattr_t
- *
- * pshared
- * must be one of:
- *
- * PTHREAD_PROCESS_SHARED
- * May be shared if in shared memory
- *
- * PTHREAD_PROCESS_PRIVATE
- * Cannot be shared.
- *
- * DESCRIPTION
- * Mutexes creatd with 'attr' can be shared between
- * processes if pthread_mutex_t variable is allocated
- * in memory shared by these processes.
- *
- * NOTES:
- * 1) pshared mutexes MUST be allocated in shared
- * memory.
- *
- * 2) The following macro is defined if shared mutexes
- * are supported:
- * _POSIX_THREAD_PROCESS_SHARED
- *
- * RESULTS
- * 0 successfully set attribute,
- * EINVAL 'attr' or pshared is invalid,
- * ENOSYS PTHREAD_PROCESS_SHARED not supported,
- *
- * ------------------------------------------------------
- */
-{
- int result;
-
- if ((attr != NULL && *attr != NULL)
- && ((pshared == PTHREAD_PROCESS_SHARED)
- || (pshared == PTHREAD_PROCESS_PRIVATE)))
- {
- if (pshared == PTHREAD_PROCESS_SHARED)
- {
-
-#if !defined( _POSIX_THREAD_PROCESS_SHARED )
- result = ENOSYS;
- pshared = PTHREAD_PROCESS_PRIVATE;
-#else
- result = 0;
-
-#endif /* _POSIX_THREAD_PROCESS_SHARED */
-
- }
- else
- {
- result = 0;
- }
-
- (*attr)->pshared = pshared;
- }
- else
- {
- result = EINVAL;
- }
-
- return result;
-
-} /* pthread_condattr_setpshared */
-
-
-int
-pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function initializes a condition variable.
- *
- * PARAMETERS
- * cond
- * pointer to an instance of pthread_cond_t
- *
- * attr
- * specifies optional creation attributes.
- *
- *
- * DESCRIPTION
- * This function initializes a condition variable.
- *
- * RESULTS
- * 0 successfully created condition variable,
- * EINVAL 'attr' is invalid,
- * EAGAIN insufficient resources (other than
- * memory,
- * ENOMEM insufficient memory,
- * EBUSY 'cond' is already initialized,
- *
- * ------------------------------------------------------
- */
-{
- int result;
- pthread_cond_t cv = NULL;
-
- if (cond == NULL)
- {
- return EINVAL;
- }
-
- if ((attr != NULL && *attr != NULL) &&
- ((*attr)->pshared == PTHREAD_PROCESS_SHARED))
- {
- /*
- * Creating condition variable that can be shared between
- * processes.
- */
- result = ENOSYS;
- goto DONE;
- }
-
- cv = (pthread_cond_t) calloc(1, sizeof (*cv));
-
- if (cv == NULL)
- {
- result = ENOMEM;
- goto DONE;
- }
-
- cv->nWaitersBlocked = 0;
- cv->nWaitersToUnblock = 0;
- cv->nWaitersGone = 0;
-
- if (sem_init(&(cv->semBlockLock), 0, 1) != 0)
- {
- result = errno;
- goto FAIL0;
- }
-
- if (sem_init(&(cv->semBlockQueue), 0, 0) != 0)
- {
- result = errno;
- goto FAIL1;
- }
-
- if ((result = pthread_mutex_init(&(cv->mtxUnblockLock), 0)) != 0)
- {
- goto FAIL2;
- }
-
- result = 0;
-
- goto DONE;
-
- /*
- * -------------
- * Failed...
- * -------------
- */
-FAIL2:
- (void) sem_destroy(&(cv->semBlockQueue));
-
-FAIL1:
- (void) sem_destroy(&(cv->semBlockLock));
-
-FAIL0:
- (void) free(cv);
- cv = NULL;
-
-DONE:
- *cond = cv;
-
- return result;
-
-} /* pthread_cond_init */
-
-
-int
-pthread_cond_destroy (pthread_cond_t * cond)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function destroys a condition variable
- *
- *
- * PARAMETERS
- * cond
- * pointer to an instance of pthread_cond_t
- *
- *
- * DESCRIPTION
- * This function destroys a condition variable.
- *
- * NOTES:
- * 1) A condition variable can be destroyed
- * immediately after all the threads that
- * are blocked on it are awakened. e.g.
- *
- * struct list {
- * pthread_mutex_t lm;
- * ...
- * }
- *
- * struct elt {
- * key k;
- * int busy;
- * pthread_cond_t notbusy;
- * ...
- * }
- *
- *
- * struct elt *
- * list_find(struct list *lp, key k)
- * {
- * struct elt *ep;
- *
- * pthread_mutex_lock(&lp->lm);
- * while ((ep = find_elt(l,k) != NULL) && ep->busy)
- * pthread_cond_wait(&ep->notbusy, &lp->lm);
- * if (ep != NULL)
- * ep->busy = 1;
- * pthread_mutex_unlock(&lp->lm);
- * return(ep);
- * }
- *
- * delete_elt(struct list *lp, struct elt *ep)
- * {
- * pthread_mutex_lock(&lp->lm);
- * assert(ep->busy);
- * ... remove ep from list ...
- * ep->busy = 0;
- * (A) pthread_cond_broadcast(&ep->notbusy);
- * pthread_mutex_unlock(&lp->lm);
- * (B) pthread_cond_destroy(&rp->notbusy);
- * free(ep);
- * }
- *
- * In this example, the condition variable
- * and its list element may be freed (line B)
- * immediately after all threads waiting for
- * it are awakened (line A), since the mutex
- * and the code ensure that no other thread
- * can touch the element to be deleted.
- *
- * RESULTS
- * 0 successfully released condition variable,
- * EINVAL 'cond' is invalid,
- * EBUSY 'cond' is in use,
- *
- * ------------------------------------------------------
- */
-{
- pthread_cond_t cv;
- int result = 0, result1 = 0, result2 = 0;
-
- /*
- * Assuming any race condition here is harmless.
- */
- if (cond == NULL
- || *cond == NULL)
- {
- return EINVAL;
- }
-
- if (*cond != PTHREAD_COND_INITIALIZER)
- {
- cv = *cond;
-
- /*
- * Close the gate; this will synchronize this thread with
- * all already signaled waiters to let them retract their
- * waiter status - SEE NOTE 1 ABOVE!!!
- */
- if (sem_wait(&(cv->semBlockLock)) != 0)
- {
- return errno;
- }
-
- /*
- * !TRY! lock mtxUnblockLock; try will detect busy condition
- * and will not course a deadlock with respect to concurrent
- * signal/broadcast.
- */
- if ((result = pthread_mutex_trylock(&(cv->mtxUnblockLock))) != 0)
- {
- (void) sem_post(&(cv->semBlockLock));
- return result;
- }
-
- /*
- * Check whether cv is still busy (still has waiters)
- */
- if (cv->nWaitersBlocked > cv->nWaitersGone)
- {
- if (sem_post(&(cv->semBlockLock)) != 0)
- {
- result = errno;
- }
- result1 = pthread_mutex_unlock(&(cv->mtxUnblockLock));
- result2 = EBUSY;
- }
- else
- {
- /*
- * Now it is safe to destroy
- */
- *cond = NULL;
- if (sem_destroy(&(cv->semBlockLock)) != 0)
- {
- result = errno;
- }
- if (sem_destroy(&(cv->semBlockQueue)) != 0)
- {
- result1 = errno;
- }
- if ((result2 = pthread_mutex_unlock(&(cv->mtxUnblockLock))) == 0)
- {
- result2 = pthread_mutex_destroy(&(cv->mtxUnblockLock));
- }
-
- (void) free(cv);
- }
- }
- else
- {
- /*
- * See notes in ptw32_cond_check_need_init() above also.
- */
- EnterCriticalSection(&ptw32_cond_test_init_lock);
-
- /*
- * Check again.
- */
- if (*cond == PTHREAD_COND_INITIALIZER)
- {
- /*
- * This is all we need to do to destroy a statically
- * initialised cond that has not yet been used (initialised).
- * If we get to here, another thread waiting to initialise
- * this cond will get an EINVAL. That's OK.
- */
- *cond = NULL;
- }
- else
- {
- /*
- * The cv has been initialised while we were waiting
- * so assume it's in use.
- */
- result = EBUSY;
- }
-
- LeaveCriticalSection(&ptw32_cond_test_init_lock);
- }
-
- return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
-
-}
-
-
-/*
- * Arguments for cond_wait_cleanup, since we can only pass a
- * single void * to it.
- */
-typedef struct {
- pthread_mutex_t * mutexPtr;
- pthread_cond_t cv;
- int * resultPtr;
- int signaled;
-} ptw32_cond_wait_cleanup_args_t;
-
-static void
-ptw32_cond_wait_cleanup(void * args)
-{
- ptw32_cond_wait_cleanup_args_t * cleanup_args = (ptw32_cond_wait_cleanup_args_t *) args;
- pthread_cond_t cv = cleanup_args->cv;
- int * resultPtr = cleanup_args->resultPtr;
- int nSignalsWasLeft;
- int nWaitersWasGone = 0; /* Initialised to quell warnings. */
- int result;
-
- /*
- * Whether we got here as a result of signal/broadcast or because of
- * timeout on wait or thread cancellation we indicate that we are no
- * longer waiting. The waiter is responsible for adjusting waiters
- * (to)unblock(ed) counts (protected by unblock lock).
- */
- if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
- {
- *resultPtr = result;
- return;
- }
-
- if ( 0 != (nSignalsWasLeft = cv->nWaitersToUnblock) )
- {
- if ( !cleanup_args->signaled )
- {
- if ( 0 != cv->nWaitersBlocked )
- {
- (cv->nWaitersBlocked)--;
- }
- else
- {
- (cv->nWaitersGone)++;
- }
- }
- if ( 0 == --(cv->nWaitersToUnblock) )
- {
- if ( 0 != cv->nWaitersBlocked )
- {
- if (sem_post( &(cv->semBlockLock) ) != 0)
- {
- *resultPtr = errno;
- /*
- * This is a fatal error for this CV,
- * so we deliberately don't unlock
- * cv->mtxUnblockLock before returning.
- */
- return;
- }
- nSignalsWasLeft = 0;
- }
- else if ( 0 != (nWaitersWasGone = cv->nWaitersGone) )
- {
- cv->nWaitersGone = 0;
- }
- }
- }
- else if ( INT_MAX/2 == ++(cv->nWaitersGone) )
- {
- if (sem_wait( &(cv->semBlockLock) ) != 0)
- {
- *resultPtr = errno;
- /*
- * This is a fatal error for this CV,
- * so we deliberately don't unlock
- * cv->mtxUnblockLock before returning.
- */
- return;
- }
- cv->nWaitersBlocked -= cv->nWaitersGone;
- if (sem_post( &(cv->semBlockLock) ) != 0)
- {
- *resultPtr = errno;
- /*
- * This is a fatal error for this CV,
- * so we deliberately don't unlock
- * cv->mtxUnblockLock before returning.
- */
- return;
- }
- cv->nWaitersGone = 0;
- }
-
- if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
- {
- *resultPtr = result;
- return;
- }
-
- if ( 1 == nSignalsWasLeft )
- {
- if ( 0 != nWaitersWasGone )
- {
- // sem_adjust( &(cv->semBlockQueue), -nWaitersWasGone );
- while ( nWaitersWasGone-- )
- {
- if (sem_wait( &(cv->semBlockQueue)) != 0 )
- {
- *resultPtr = errno;
- return;
- }
- }
- }
- if (sem_post(&(cv->semBlockLock)) != 0)
- {
- *resultPtr = errno;
- return;
- }
- }
-
- /*
- * XSH: Upon successful return, the mutex has been locked and is owned
- * by the calling thread
- */
- if ((result = pthread_mutex_lock(cleanup_args->mutexPtr)) != 0)
- {
- *resultPtr = result;
- }
-
-} /* ptw32_cond_wait_cleanup */
-
-static INLINE int
-ptw32_cond_timedwait (pthread_cond_t * cond,
- pthread_mutex_t * mutex,
- const struct timespec *abstime)
-{
- int result = 0;
- pthread_cond_t cv;
- ptw32_cond_wait_cleanup_args_t cleanup_args;
-
- if (cond == NULL || *cond == NULL)
- {
- return EINVAL;
- }
-
- /*
- * We do a quick check to see if we need to do more work
- * to initialise a static condition variable. We check
- * again inside the guarded section of ptw32_cond_check_need_init()
- * to avoid race conditions.
- */
- if (*cond == PTHREAD_COND_INITIALIZER)
- {
- result = ptw32_cond_check_need_init(cond);
- }
-
- if (result != 0 && result != EBUSY)
- {
- return result;
- }
-
- cv = *cond;
-
- if (sem_wait(&(cv->semBlockLock)) != 0)
- {
- return errno;
- }
-
- cv->nWaitersBlocked++;
-
- if (sem_post(&(cv->semBlockLock)) != 0)
- {
- return errno;
- }
-
- /*
- * Setup this waiter cleanup handler
- */
- cleanup_args.mutexPtr = mutex;
- cleanup_args.cv = cv;
- cleanup_args.resultPtr = &result;
- /*
- * If we're canceled, or the cancelable wait fails for any reason,
- * including a timeout, then tell the cleanup routine that we
- * have not been signaled.
- */
- cleanup_args.signaled = 0;
-
-#ifdef _MSC_VER
-#pragma inline_depth(0)
-#endif
- pthread_cleanup_push(ptw32_cond_wait_cleanup, (void *) &cleanup_args);
-
- /*
- * Now we can release 'mutex' and...
- */
- if ((result = pthread_mutex_unlock(mutex)) == 0)
- {
-
- /*
- * ...wait to be awakened by
- * pthread_cond_signal, or
- * pthread_cond_broadcast, or
- * timeout, or
- * thread cancellation
- *
- * Note:
- *
- * sem_timedwait is 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
- * counts if we are cancelled, timed out or signalled.
- */
- if (sem_timedwait(&(cv->semBlockQueue), abstime) != 0)
- {
- result = errno;
- }
- }
-
- /*
- * Not executed if we're canceled. Signaled is false if we timed out.
- */
- cleanup_args.signaled = (result == 0);
-
- /*
- * Always cleanup
- */
- pthread_cleanup_pop(1);
-#ifdef _MSC_VER
-#pragma inline_depth()
-#endif
-
- /*
- * "result" can be modified by the cleanup handler.
- */
- return result;
-
-} /* ptw32_cond_timedwait */
-
-
-static INLINE int
-ptw32_cond_unblock (pthread_cond_t * cond,
- int unblockAll)
- /*
- * Notes.
- *
- * Does not use the external mutex for synchronisation,
- * therefore semBlockLock is needed.
- * mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the
- * state where the external mutex is not necessarily locked by
- * any thread, ie. between cond_wait unlocking and re-acquiring
- * the lock after having been signaled or a timeout or
- * cancellation.
- *
- * Uses the following CV elements:
- * nWaitersBlocked
- * nWaitersToUnblock
- * nWaitersGone
- * mtxUnblockLock
- * semBlockLock
- * semBlockQueue
- */
-{
- int result;
- pthread_cond_t cv;
- int nSignalsToIssue;
-
- if (cond == NULL || *cond == NULL)
- {
- return EINVAL;
- }
-
- cv = *cond;
-
- /*
- * No-op if the CV is static and hasn't been initialised yet.
- * Assuming that any race condition is harmless.
- */
- if (cv == PTHREAD_COND_INITIALIZER)
- {
- return 0;
- }
-
- if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
- {
- return result;
- }
-
- if ( 0 != cv->nWaitersToUnblock )
- {
- if ( 0 == cv->nWaitersBlocked )
- {
- return pthread_mutex_unlock( &(cv->mtxUnblockLock) );
- }
- if (unblockAll)
- {
- cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked);
- cv->nWaitersBlocked = 0;
- }
- else
- {
- nSignalsToIssue = 1;
- cv->nWaitersToUnblock++;
- cv->nWaitersBlocked--;
- }
- }
- else if ( cv->nWaitersBlocked > cv->nWaitersGone )
- {
- if (sem_wait( &(cv->semBlockLock) ) != 0)
- {
- result = errno;
- (void) pthread_mutex_unlock( &(cv->mtxUnblockLock) );
- return result;
- }
- if ( 0 != cv->nWaitersGone )
- {
- cv->nWaitersBlocked -= cv->nWaitersGone;
- cv->nWaitersGone = 0;
- }
- if (unblockAll)
- {
- nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked;
- cv->nWaitersBlocked = 0;
- }
- else
- {
- nSignalsToIssue = cv->nWaitersToUnblock = 1;
- cv->nWaitersBlocked--;
- }
- }
- else
- {
- return pthread_mutex_unlock( &(cv->mtxUnblockLock) );
- }
-
- if ((result = pthread_mutex_unlock( &(cv->mtxUnblockLock) )) == 0)
- {
- if (sem_post_multiple( &(cv->semBlockQueue), nSignalsToIssue ) != 0)
- {
- result = errno;
- }
- }
-
- return result;
-
-} /* ptw32_cond_unblock */
-
-int
-pthread_cond_wait (pthread_cond_t * cond,
- pthread_mutex_t * mutex)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function waits on a condition variable until
- * awakened by a signal or broadcast.
- *
- * Caller MUST be holding the mutex lock; the
- * lock is released and the caller is blocked waiting
- * on 'cond'. When 'cond' is signaled, the mutex
- * is re-acquired before returning to the caller.
- *
- * PARAMETERS
- * cond
- * pointer to an instance of pthread_cond_t
- *
- * mutex
- * pointer to an instance of pthread_mutex_t
- *
- *
- * DESCRIPTION
- * This function waits on a condition variable until
- * awakened by a signal or broadcast.
- *
- * NOTES:
- *
- * 1) The function must be called with 'mutex' LOCKED
- * by the calling thread, or undefined behaviour
- * will result.
- *
- * 2) This routine atomically releases 'mutex' and causes
- * the calling thread to block on the condition variable.
- * The blocked thread may be awakened by
- * pthread_cond_signal or
- * pthread_cond_broadcast.
- *
- * Upon successful completion, the 'mutex' has been locked and
- * is owned by the calling thread.
- *
- *
- * RESULTS
- * 0 caught condition; mutex released,
- * EINVAL 'cond' or 'mutex' is invalid,
- * EINVAL different mutexes for concurrent waits,
- * EINVAL mutex is not held by the calling thread,
- *
- * ------------------------------------------------------
- */
-{
- /*
- * The NULL abstime arg means INFINITE waiting.
- */
- return (ptw32_cond_timedwait(cond, mutex, NULL));
-
-} /* pthread_cond_wait */
-
-
-int
-pthread_cond_timedwait (pthread_cond_t * cond,
- pthread_mutex_t * mutex,
- const struct timespec *abstime)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function waits on a condition variable either until
- * awakened by a signal or broadcast; or until the time
- * specified by abstime passes.
- *
- * PARAMETERS
- * cond
- * pointer to an instance of pthread_cond_t
- *
- * mutex
- * pointer to an instance of pthread_mutex_t
- *
- * abstime
- * pointer to an instance of (const struct timespec)
- *
- *
- * DESCRIPTION
- * This function waits on a condition variable either until
- * awakened by a signal or broadcast; or until the time
- * specified by abstime passes.
- *
- * NOTES:
- * 1) The function must be called with 'mutex' LOCKED
- * by the calling thread, or undefined behaviour
- * will result.
- *
- * 2) This routine atomically releases 'mutex' and causes
- * the calling thread to block on the condition variable.
- * The blocked thread may be awakened by
- * pthread_cond_signal or
- * pthread_cond_broadcast.
- *
- *
- * RESULTS
- * 0 caught condition; mutex released,
- * EINVAL 'cond', 'mutex', or abstime is invalid,
- * EINVAL different mutexes for concurrent waits,
- * EINVAL mutex is not held by the calling thread,
- * ETIMEDOUT abstime ellapsed before cond was signaled.
- *
- * ------------------------------------------------------
- */
-{
- if (abstime == NULL)
- {
- return EINVAL;
- }
-
- return (ptw32_cond_timedwait(cond, mutex, abstime));
-
-} /* pthread_cond_timedwait */
-
-
-int
-pthread_cond_signal (pthread_cond_t * cond)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function signals a condition variable, waking
- * one waiting thread.
- * If SCHED_FIFO or SCHED_RR policy threads are waiting
- * the highest priority waiter is awakened; otherwise,
- * an unspecified waiter is awakened.
- *
- * PARAMETERS
- * cond
- * pointer to an instance of pthread_cond_t
- *
- *
- * DESCRIPTION
- * This function signals a condition variable, waking
- * one waiting thread.
- * If SCHED_FIFO or SCHED_RR policy threads are waiting
- * the highest priority waiter is awakened; otherwise,
- * an unspecified waiter is awakened.
- *
- * NOTES:
- *
- * 1) Use when any waiter can respond and only one need
- * respond (all waiters being equal).
- *
- * RESULTS
- * 0 successfully signaled condition,
- * EINVAL 'cond' is invalid,
- *
- * ------------------------------------------------------
- */
-{
- /*
- * The '0'(FALSE) unblockAll arg means unblock ONE waiter.
- */
- return (ptw32_cond_unblock(cond, 0));
-
-} /* pthread_cond_signal */
-
-int
-pthread_cond_broadcast (pthread_cond_t * cond)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function broadcasts the condition variable,
- * waking all current waiters.
- *
- * PARAMETERS
- * cond
- * pointer to an instance of pthread_cond_t
- *
- *
- * DESCRIPTION
- * This function signals a condition variable, waking
- * all waiting threads.
- *
- * NOTES:
- *
- * 1) Use when more than one waiter may respond to
- * predicate change or if any waiting thread may
- * not be able to respond
- *
- * RESULTS
- * 0 successfully signalled condition to all
- * waiting threads,
- * EINVAL 'cond' is invalid
- * ENOSPC a required resource has been exhausted,
- *
- * ------------------------------------------------------
- */
-{
- /*
- * The '1'(TRUE) unblockAll arg means unblock ALL waiters.
- */
- return (ptw32_cond_unblock(cond, 1));
-
-} /* pthread_cond_broadcast */
+#include "condvar_check_need_init.c"
+#include "condvar_attr_init.c"
+#include "condvar_attr_destroy.c"
+#include "condvar_attr_getpshared.c"
+#include "condvar_attr_setpshared.c"
+#include "condvar_init.c"
+#include "condvar_destroy.c"
+#include "condvar_wait.c"
+#include "condvar_timedwait.c"
+#include "condvar_signal.c"
+#include "condvar_broadcast.c"
diff --git a/condvar_attr_destroy.c b/condvar_attr_destroy.c
new file mode 100644
index 0000000..1be0daf
--- /dev/null
+++ b/condvar_attr_destroy.c
@@ -0,0 +1,86 @@
+/*
+ * condvar_attr_destroy.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_condattr_destroy (pthread_condattr_t * attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Destroys a condition variable attributes object.
+ * The object can no longer be used.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_condattr_t
+ *
+ *
+ * DESCRIPTION
+ * Destroys a condition variable attributes object.
+ * The object can no longer be used.
+ *
+ * NOTES:
+ * 1) Does not affect condition variables created
+ * using 'attr'
+ *
+ * RESULTS
+ * 0 successfully released attr,
+ * EINVAL 'attr' is invalid.
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if (attr == NULL || *attr == NULL)
+ {
+ result = EINVAL;
+ }
+ else
+ {
+ (void) free (*attr);
+
+ *attr = NULL;
+ result = 0;
+ }
+
+ return result;
+
+} /* pthread_condattr_destroy */
diff --git a/condvar_attr_getpshared.c b/condvar_attr_getpshared.c
new file mode 100644
index 0000000..6a9890e
--- /dev/null
+++ b/condvar_attr_getpshared.c
@@ -0,0 +1,97 @@
+/*
+ * condvar_attr_getpshared.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Determine whether condition variables created with 'attr'
+ * can be shared between processes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_condattr_t
+ *
+ * pshared
+ * will be set to one of:
+ *
+ * PTHREAD_PROCESS_SHARED
+ * May be shared if in shared memory
+ *
+ * PTHREAD_PROCESS_PRIVATE
+ * Cannot be shared.
+ *
+ *
+ * DESCRIPTION
+ * Condition Variables created with 'attr' can be shared
+ * between processes if pthread_cond_t variable is allocated
+ * in memory shared by these processes.
+ * NOTES:
+ * 1) pshared condition variables MUST be allocated in
+ * shared memory.
+ *
+ * 2) The following macro is defined if shared mutexes
+ * are supported:
+ * _POSIX_THREAD_PROCESS_SHARED
+ *
+ * RESULTS
+ * 0 successfully retrieved attribute,
+ * EINVAL 'attr' or 'pshared' is invalid,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ if ((attr != NULL && *attr != NULL) && (pshared != NULL))
+ {
+ *pshared = (*attr)->pshared;
+ result = 0;
+ }
+ else
+ {
+ result = EINVAL;
+ }
+
+ return result;
+
+} /* pthread_condattr_getpshared */
diff --git a/condvar_attr_init.c b/condvar_attr_init.c
new file mode 100644
index 0000000..b04c757
--- /dev/null
+++ b/condvar_attr_init.c
@@ -0,0 +1,87 @@
+/*
+ * condvar_attr_init.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_condattr_init (pthread_condattr_t * attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Initializes a condition variable attributes object
+ * with default attributes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_condattr_t
+ *
+ *
+ * DESCRIPTION
+ * Initializes a condition variable attributes object
+ * with default attributes.
+ *
+ * NOTES:
+ * 1) Use to define condition variable types
+ * 2) It is up to the application to ensure
+ * that it doesn't re-init an attribute
+ * without destroying it first. Otherwise
+ * a memory leak is created.
+ *
+ * RESULTS
+ * 0 successfully initialized attr,
+ * ENOMEM insufficient memory for attr.
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_condattr_t attr_result;
+ int result = 0;
+
+ attr_result = (pthread_condattr_t) calloc (1, sizeof (*attr_result));
+
+ if (attr_result == NULL)
+ {
+ result = ENOMEM;
+ }
+
+ *attr = attr_result;
+
+ return result;
+
+} /* pthread_condattr_init */
diff --git a/condvar_attr_setpshared.c b/condvar_attr_setpshared.c
new file mode 100644
index 0000000..4e396c2
--- /dev/null
+++ b/condvar_attr_setpshared.c
@@ -0,0 +1,117 @@
+/*
+ * condvar_attr_setpshared.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Mutexes created with 'attr' can be shared between
+ * processes if pthread_mutex_t variable is allocated
+ * in memory shared by these processes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_mutexattr_t
+ *
+ * pshared
+ * must be one of:
+ *
+ * PTHREAD_PROCESS_SHARED
+ * May be shared if in shared memory
+ *
+ * PTHREAD_PROCESS_PRIVATE
+ * Cannot be shared.
+ *
+ * DESCRIPTION
+ * Mutexes creatd with 'attr' can be shared between
+ * processes if pthread_mutex_t variable is allocated
+ * in memory shared by these processes.
+ *
+ * NOTES:
+ * 1) pshared mutexes MUST be allocated in shared
+ * memory.
+ *
+ * 2) The following macro is defined if shared mutexes
+ * are supported:
+ * _POSIX_THREAD_PROCESS_SHARED
+ *
+ * RESULTS
+ * 0 successfully set attribute,
+ * EINVAL 'attr' or pshared is invalid,
+ * ENOSYS PTHREAD_PROCESS_SHARED not supported,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ if ((attr != NULL && *attr != NULL)
+ && ((pshared == PTHREAD_PROCESS_SHARED)
+ || (pshared == PTHREAD_PROCESS_PRIVATE)))
+ {
+ if (pshared == PTHREAD_PROCESS_SHARED)
+ {
+
+#if !defined( _POSIX_THREAD_PROCESS_SHARED )
+ result = ENOSYS;
+ pshared = PTHREAD_PROCESS_PRIVATE;
+#else
+ result = 0;
+
+#endif /* _POSIX_THREAD_PROCESS_SHARED */
+
+ }
+ else
+ {
+ result = 0;
+ }
+
+ (*attr)->pshared = pshared;
+ }
+ else
+ {
+ result = EINVAL;
+ }
+
+ return result;
+
+} /* pthread_condattr_setpshared */
diff --git a/condvar_check_need_init.c b/condvar_check_need_init.c
new file mode 100644
index 0000000..1f6bba7
--- /dev/null
+++ b/condvar_check_need_init.c
@@ -0,0 +1,94 @@
+/*
+ * condvar_check_need_init.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+static INLINE int
+ptw32_cond_check_need_init (pthread_cond_t *cond)
+{
+ int result = 0;
+
+ /*
+ * The following guarded test is specifically for statically
+ * initialised condition variables (via PTHREAD_OBJECT_INITIALIZER).
+ *
+ * Note that by not providing this synchronisation we risk
+ * introducing race conditions into applications which are
+ * correctly written.
+ *
+ * Approach
+ * --------
+ * We know that static condition variables will not be PROCESS_SHARED
+ * so we can serialise access to internal state using
+ * Win32 Critical Sections rather than Win32 Mutexes.
+ *
+ * If using a single global lock slows applications down too much,
+ * multiple global locks could be created and hashed on some random
+ * value associated with each mutex, the pointer perhaps. At a guess,
+ * a good value for the optimal number of global locks might be
+ * the number of processors + 1.
+ *
+ */
+ EnterCriticalSection(&ptw32_cond_test_init_lock);
+
+ /*
+ * We got here possibly under race
+ * conditions. Check again inside the critical section.
+ * If a static cv has been destroyed, the application can
+ * re-initialise it only by calling pthread_cond_init()
+ * explicitly.
+ */
+ if (*cond == PTHREAD_COND_INITIALIZER)
+ {
+ result = pthread_cond_init(cond, NULL);
+ }
+ else if (*cond == NULL)
+ {
+ /*
+ * The cv has been destroyed while we were waiting to
+ * initialise it, so the operation that caused the
+ * auto-initialisation should fail.
+ */
+ result = EINVAL;
+ }
+
+ LeaveCriticalSection(&ptw32_cond_test_init_lock);
+
+ return result;
+}
diff --git a/condvar_destroy.c b/condvar_destroy.c
new file mode 100644
index 0000000..d0af374
--- /dev/null
+++ b/condvar_destroy.c
@@ -0,0 +1,222 @@
+/*
+ * condvar_destroy.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_cond_destroy (pthread_cond_t * cond)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function destroys a condition variable
+ *
+ *
+ * PARAMETERS
+ * cond
+ * pointer to an instance of pthread_cond_t
+ *
+ *
+ * DESCRIPTION
+ * This function destroys a condition variable.
+ *
+ * NOTES:
+ * 1) A condition variable can be destroyed
+ * immediately after all the threads that
+ * are blocked on it are awakened. e.g.
+ *
+ * struct list {
+ * pthread_mutex_t lm;
+ * ...
+ * }
+ *
+ * struct elt {
+ * key k;
+ * int busy;
+ * pthread_cond_t notbusy;
+ * ...
+ * }
+ *
+ *
+ * struct elt *
+ * list_find(struct list *lp, key k)
+ * {
+ * struct elt *ep;
+ *
+ * pthread_mutex_lock(&lp->lm);
+ * while ((ep = find_elt(l,k) != NULL) && ep->busy)
+ * pthread_cond_wait(&ep->notbusy, &lp->lm);
+ * if (ep != NULL)
+ * ep->busy = 1;
+ * pthread_mutex_unlock(&lp->lm);
+ * return(ep);
+ * }
+ *
+ * delete_elt(struct list *lp, struct elt *ep)
+ * {
+ * pthread_mutex_lock(&lp->lm);
+ * assert(ep->busy);
+ * ... remove ep from list ...
+ * ep->busy = 0;
+ * (A) pthread_cond_broadcast(&ep->notbusy);
+ * pthread_mutex_unlock(&lp->lm);
+ * (B) pthread_cond_destroy(&rp->notbusy);
+ * free(ep);
+ * }
+ *
+ * In this example, the condition variable
+ * and its list element may be freed (line B)
+ * immediately after all threads waiting for
+ * it are awakened (line A), since the mutex
+ * and the code ensure that no other thread
+ * can touch the element to be deleted.
+ *
+ * RESULTS
+ * 0 successfully released condition variable,
+ * EINVAL 'cond' is invalid,
+ * EBUSY 'cond' is in use,
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_cond_t cv;
+ int result = 0, result1 = 0, result2 = 0;
+
+ /*
+ * Assuming any race condition here is harmless.
+ */
+ if (cond == NULL
+ || *cond == NULL)
+ {
+ return EINVAL;
+ }
+
+ if (*cond != PTHREAD_COND_INITIALIZER)
+ {
+ cv = *cond;
+
+ /*
+ * Close the gate; this will synchronize this thread with
+ * all already signaled waiters to let them retract their
+ * waiter status - SEE NOTE 1 ABOVE!!!
+ */
+ if (sem_wait(&(cv->semBlockLock)) != 0)
+ {
+ return errno;
+ }
+
+ /*
+ * !TRY! lock mtxUnblockLock; try will detect busy condition
+ * and will not course a deadlock with respect to concurrent
+ * signal/broadcast.
+ */
+ if ((result = pthread_mutex_trylock(&(cv->mtxUnblockLock))) != 0)
+ {
+ (void) sem_post(&(cv->semBlockLock));
+ return result;
+ }
+
+ /*
+ * Check whether cv is still busy (still has waiters)
+ */
+ if (cv->nWaitersBlocked > cv->nWaitersGone)
+ {
+ if (sem_post(&(cv->semBlockLock)) != 0)
+ {
+ result = errno;
+ }
+ result1 = pthread_mutex_unlock(&(cv->mtxUnblockLock));
+ result2 = EBUSY;
+ }
+ else
+ {
+ /*
+ * Now it is safe to destroy
+ */
+ *cond = NULL;
+ if (sem_destroy(&(cv->semBlockLock)) != 0)
+ {
+ result = errno;
+ }
+ if (sem_destroy(&(cv->semBlockQueue)) != 0)
+ {
+ result1 = errno;
+ }
+ if ((result2 = pthread_mutex_unlock(&(cv->mtxUnblockLock))) == 0)
+ {
+ result2 = pthread_mutex_destroy(&(cv->mtxUnblockLock));
+ }
+
+ (void) free(cv);
+ }
+ }
+ else
+ {
+ /*
+ * See notes in ptw32_cond_check_need_init() above also.
+ */
+ EnterCriticalSection(&ptw32_cond_test_init_lock);
+
+ /*
+ * Check again.
+ */
+ if (*cond == PTHREAD_COND_INITIALIZER)
+ {
+ /*
+ * This is all we need to do to destroy a statically
+ * initialised cond that has not yet been used (initialised).
+ * If we get to here, another thread waiting to initialise
+ * this cond will get an EINVAL. That's OK.
+ */
+ *cond = NULL;
+ }
+ else
+ {
+ /*
+ * The cv has been initialised while we were waiting
+ * so assume it's in use.
+ */
+ result = EBUSY;
+ }
+
+ LeaveCriticalSection(&ptw32_cond_test_init_lock);
+ }
+
+ return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
+
+}
diff --git a/condvar_init.c b/condvar_init.c
new file mode 100644
index 0000000..ecd4297
--- /dev/null
+++ b/condvar_init.c
@@ -0,0 +1,143 @@
+/*
+ * condvar_init.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function initializes a condition variable.
+ *
+ * PARAMETERS
+ * cond
+ * pointer to an instance of pthread_cond_t
+ *
+ * attr
+ * specifies optional creation attributes.
+ *
+ *
+ * DESCRIPTION
+ * This function initializes a condition variable.
+ *
+ * RESULTS
+ * 0 successfully created condition variable,
+ * EINVAL 'attr' is invalid,
+ * EAGAIN insufficient resources (other than
+ * memory,
+ * ENOMEM insufficient memory,
+ * EBUSY 'cond' is already initialized,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+ pthread_cond_t cv = NULL;
+
+ if (cond == NULL)
+ {
+ return EINVAL;
+ }
+
+ if ((attr != NULL && *attr != NULL) &&
+ ((*attr)->pshared == PTHREAD_PROCESS_SHARED))
+ {
+ /*
+ * Creating condition variable that can be shared between
+ * processes.
+ */
+ result = ENOSYS;
+ goto DONE;
+ }
+
+ cv = (pthread_cond_t) calloc(1, sizeof (*cv));
+
+ if (cv == NULL)
+ {
+ result = ENOMEM;
+ goto DONE;
+ }
+
+ cv->nWaitersBlocked = 0;
+ cv->nWaitersToUnblock = 0;
+ cv->nWaitersGone = 0;
+
+ if (sem_init(&(cv->semBlockLock), 0, 1) != 0)
+ {
+ result = errno;
+ goto FAIL0;
+ }
+
+ if (sem_init(&(cv->semBlockQueue), 0, 0) != 0)
+ {
+ result = errno;
+ goto FAIL1;
+ }
+
+ if ((result = pthread_mutex_init(&(cv->mtxUnblockLock), 0)) != 0)
+ {
+ goto FAIL2;
+ }
+
+ result = 0;
+
+ goto DONE;
+
+ /*
+ * -------------
+ * Failed...
+ * -------------
+ */
+FAIL2:
+ (void) sem_destroy(&(cv->semBlockQueue));
+
+FAIL1:
+ (void) sem_destroy(&(cv->semBlockLock));
+
+FAIL0:
+ (void) free(cv);
+ cv = NULL;
+
+DONE:
+ *cond = cv;
+
+ return result;
+
+} /* pthread_cond_init */
diff --git a/condvar_signal.c b/condvar_signal.c
new file mode 100644
index 0000000..604ef4d
--- /dev/null
+++ b/condvar_signal.c
@@ -0,0 +1,355 @@
+/*
+ * condvar_signal.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * -------------------------------------------------------------
+ * Algorithm:
+ * The algorithm used in this implementation is that developed by
+ * Alexander Terekhov in colaboration with Louis Thomas. The bulk
+ * of the discussion is recorded in the file README.CV, which contains
+ * several generations of both colaborators original algorithms. The final
+ * algorithm used here is the one referred to as
+ *
+ * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
+ *
+ * presented below in pseudo-code as it appeared:
+ *
+ *
+ * given:
+ * semBlockLock - bin.semaphore
+ * semBlockQueue - semaphore
+ * mtxExternal - mutex or CS
+ * mtxUnblockLock - mutex or CS
+ * nWaitersGone - int
+ * nWaitersBlocked - int
+ * nWaitersToUnblock - int
+ *
+ * wait( timeout ) {
+ *
+ * [auto: register int result ] // error checking omitted
+ * [auto: register int nSignalsWasLeft ]
+ * [auto: register int nWaitersWasGone ]
+ *
+ * sem_wait( semBlockLock );
+ * nWaitersBlocked++;
+ * sem_post( semBlockLock );
+ *
+ * unlock( mtxExternal );
+ * bTimedOut = sem_wait( semBlockQueue,timeout );
+ *
+ * lock( mtxUnblockLock );
+ * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
+ * if ( bTimeout ) { // timeout (or canceled)
+ * if ( 0 != nWaitersBlocked ) {
+ * nWaitersBlocked--;
+ * }
+ * else {
+ * nWaitersGone++; // count spurious wakeups.
+ * }
+ * }
+ * if ( 0 == --nWaitersToUnblock ) {
+ * if ( 0 != nWaitersBlocked ) {
+ * sem_post( semBlockLock ); // open the gate.
+ * nSignalsWasLeft = 0; // do not open the gate
+ * // below again.
+ * }
+ * else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
+ * nWaitersGone = 0;
+ * }
+ * }
+ * }
+ * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
+ * // spurious semaphore :-)
+ * sem_wait( semBlockLock );
+ * nWaitersBlocked -= nWaitersGone; // something is going on here
+ * // - test of timeouts? :-)
+ * sem_post( semBlockLock );
+ * nWaitersGone = 0;
+ * }
+ * unlock( mtxUnblockLock );
+ *
+ * if ( 1 == nSignalsWasLeft ) {
+ * if ( 0 != nWaitersWasGone ) {
+ * // sem_adjust( semBlockQueue,-nWaitersWasGone );
+ * while ( nWaitersWasGone-- ) {
+ * sem_wait( semBlockQueue ); // better now than spurious later
+ * }
+ * } sem_post( semBlockLock ); // open the gate
+ * }
+ *
+ * lock( mtxExternal );
+ *
+ * return ( bTimedOut ) ? ETIMEOUT : 0;
+ * }
+ *
+ * signal(bAll) {
+ *
+ * [auto: register int result ]
+ * [auto: register int nSignalsToIssue]
+ *
+ * lock( mtxUnblockLock );
+ *
+ * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
+ * if ( 0 == nWaitersBlocked ) { // NO-OP
+ * return unlock( mtxUnblockLock );
+ * }
+ * if (bAll) {
+ * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
+ * nWaitersBlocked = 0;
+ * }
+ * else {
+ * nSignalsToIssue = 1;
+ * nWaitersToUnblock++;
+ * nWaitersBlocked--;
+ * }
+ * }
+ * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
+ * sem_wait( semBlockLock ); // close the gate
+ * if ( 0 != nWaitersGone ) {
+ * nWaitersBlocked -= nWaitersGone;
+ * nWaitersGone = 0;
+ * }
+ * if (bAll) {
+ * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
+ * nWaitersBlocked = 0;
+ * }
+ * else {
+ * nSignalsToIssue = nWaitersToUnblock = 1;
+ * nWaitersBlocked--;
+ * }
+ * }
+ * else { // NO-OP
+ * return unlock( mtxUnblockLock );
+ * }
+ *
+ * unlock( mtxUnblockLock );
+ * sem_post( semBlockQueue,nSignalsToIssue );
+ * return result;
+ * }
+ * -------------------------------------------------------------
+ *
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+static INLINE int
+ptw32_cond_unblock (pthread_cond_t * cond,
+ int unblockAll)
+ /*
+ * Notes.
+ *
+ * Does not use the external mutex for synchronisation,
+ * therefore semBlockLock is needed.
+ * mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the
+ * state where the external mutex is not necessarily locked by
+ * any thread, ie. between cond_wait unlocking and re-acquiring
+ * the lock after having been signaled or a timeout or
+ * cancellation.
+ *
+ * Uses the following CV elements:
+ * nWaitersBlocked
+ * nWaitersToUnblock
+ * nWaitersGone
+ * mtxUnblockLock
+ * semBlockLock
+ * semBlockQueue
+ */
+{
+ int result;
+ pthread_cond_t cv;
+ int nSignalsToIssue;
+
+ if (cond == NULL || *cond == NULL)
+ {
+ return EINVAL;
+ }
+
+ cv = *cond;
+
+ /*
+ * No-op if the CV is static and hasn't been initialised yet.
+ * Assuming that any race condition is harmless.
+ */
+ if (cv == PTHREAD_COND_INITIALIZER)
+ {
+ return 0;
+ }
+
+ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
+ {
+ return result;
+ }
+
+ if ( 0 != cv->nWaitersToUnblock )
+ {
+ if ( 0 == cv->nWaitersBlocked )
+ {
+ return pthread_mutex_unlock( &(cv->mtxUnblockLock) );
+ }
+ if (unblockAll)
+ {
+ cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked);
+ cv->nWaitersBlocked = 0;
+ }
+ else
+ {
+ nSignalsToIssue = 1;
+ cv->nWaitersToUnblock++;
+ cv->nWaitersBlocked--;
+ }
+ }
+ else if ( cv->nWaitersBlocked > cv->nWaitersGone )
+ {
+ if (sem_wait( &(cv->semBlockLock) ) != 0)
+ {
+ result = errno;
+ (void) pthread_mutex_unlock( &(cv->mtxUnblockLock) );
+ return result;
+ }
+ if ( 0 != cv->nWaitersGone )
+ {
+ cv->nWaitersBlocked -= cv->nWaitersGone;
+ cv->nWaitersGone = 0;
+ }
+ if (unblockAll)
+ {
+ nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked;
+ cv->nWaitersBlocked = 0;
+ }
+ else
+ {
+ nSignalsToIssue = cv->nWaitersToUnblock = 1;
+ cv->nWaitersBlocked--;
+ }
+ }
+ else
+ {
+ return pthread_mutex_unlock( &(cv->mtxUnblockLock) );
+ }
+
+ if ((result = pthread_mutex_unlock( &(cv->mtxUnblockLock) )) == 0)
+ {
+ if (sem_post_multiple( &(cv->semBlockQueue), nSignalsToIssue ) != 0)
+ {
+ result = errno;
+ }
+ }
+
+ return result;
+
+} /* ptw32_cond_unblock */
+
+int
+pthread_cond_signal (pthread_cond_t * cond)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function signals a condition variable, waking
+ * one waiting thread.
+ * If SCHED_FIFO or SCHED_RR policy threads are waiting
+ * the highest priority waiter is awakened; otherwise,
+ * an unspecified waiter is awakened.
+ *
+ * PARAMETERS
+ * cond
+ * pointer to an instance of pthread_cond_t
+ *
+ *
+ * DESCRIPTION
+ * This function signals a condition variable, waking
+ * one waiting thread.
+ * If SCHED_FIFO or SCHED_RR policy threads are waiting
+ * the highest priority waiter is awakened; otherwise,
+ * an unspecified waiter is awakened.
+ *
+ * NOTES:
+ *
+ * 1) Use when any waiter can respond and only one need
+ * respond (all waiters being equal).
+ *
+ * RESULTS
+ * 0 successfully signaled condition,
+ * EINVAL 'cond' is invalid,
+ *
+ * ------------------------------------------------------
+ */
+{
+ /*
+ * The '0'(FALSE) unblockAll arg means unblock ONE waiter.
+ */
+ return (ptw32_cond_unblock(cond, 0));
+
+} /* pthread_cond_signal */
+
+int
+pthread_cond_broadcast (pthread_cond_t * cond)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function broadcasts the condition variable,
+ * waking all current waiters.
+ *
+ * PARAMETERS
+ * cond
+ * pointer to an instance of pthread_cond_t
+ *
+ *
+ * DESCRIPTION
+ * This function signals a condition variable, waking
+ * all waiting threads.
+ *
+ * NOTES:
+ *
+ * 1) Use when more than one waiter may respond to
+ * predicate change or if any waiting thread may
+ * not be able to respond
+ *
+ * RESULTS
+ * 0 successfully signalled condition to all
+ * waiting threads,
+ * EINVAL 'cond' is invalid
+ * ENOSPC a required resource has been exhausted,
+ *
+ * ------------------------------------------------------
+ */
+{
+ /*
+ * The '1'(TRUE) unblockAll arg means unblock ALL waiters.
+ */
+ return (ptw32_cond_unblock(cond, 1));
+
+} /* pthread_cond_broadcast */
diff --git a/condvar_wait.c b/condvar_wait.c
new file mode 100644
index 0000000..550b6c0
--- /dev/null
+++ b/condvar_wait.c
@@ -0,0 +1,527 @@
+/*
+ * condvar_wait.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * -------------------------------------------------------------
+ * Algorithm:
+ * The algorithm used in this implementation is that developed by
+ * Alexander Terekhov in colaboration with Louis Thomas. The bulk
+ * of the discussion is recorded in the file README.CV, which contains
+ * several generations of both colaborators original algorithms. The final
+ * algorithm used here is the one referred to as
+ *
+ * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
+ *
+ * presented below in pseudo-code as it appeared:
+ *
+ *
+ * given:
+ * semBlockLock - bin.semaphore
+ * semBlockQueue - semaphore
+ * mtxExternal - mutex or CS
+ * mtxUnblockLock - mutex or CS
+ * nWaitersGone - int
+ * nWaitersBlocked - int
+ * nWaitersToUnblock - int
+ *
+ * wait( timeout ) {
+ *
+ * [auto: register int result ] // error checking omitted
+ * [auto: register int nSignalsWasLeft ]
+ * [auto: register int nWaitersWasGone ]
+ *
+ * sem_wait( semBlockLock );
+ * nWaitersBlocked++;
+ * sem_post( semBlockLock );
+ *
+ * unlock( mtxExternal );
+ * bTimedOut = sem_wait( semBlockQueue,timeout );
+ *
+ * lock( mtxUnblockLock );
+ * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
+ * if ( bTimeout ) { // timeout (or canceled)
+ * if ( 0 != nWaitersBlocked ) {
+ * nWaitersBlocked--;
+ * }
+ * else {
+ * nWaitersGone++; // count spurious wakeups.
+ * }
+ * }
+ * if ( 0 == --nWaitersToUnblock ) {
+ * if ( 0 != nWaitersBlocked ) {
+ * sem_post( semBlockLock ); // open the gate.
+ * nSignalsWasLeft = 0; // do not open the gate
+ * // below again.
+ * }
+ * else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
+ * nWaitersGone = 0;
+ * }
+ * }
+ * }
+ * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
+ * // spurious semaphore :-)
+ * sem_wait( semBlockLock );
+ * nWaitersBlocked -= nWaitersGone; // something is going on here
+ * // - test of timeouts? :-)
+ * sem_post( semBlockLock );
+ * nWaitersGone = 0;
+ * }
+ * unlock( mtxUnblockLock );
+ *
+ * if ( 1 == nSignalsWasLeft ) {
+ * if ( 0 != nWaitersWasGone ) {
+ * // sem_adjust( semBlockQueue,-nWaitersWasGone );
+ * while ( nWaitersWasGone-- ) {
+ * sem_wait( semBlockQueue ); // better now than spurious later
+ * }
+ * } sem_post( semBlockLock ); // open the gate
+ * }
+ *
+ * lock( mtxExternal );
+ *
+ * return ( bTimedOut ) ? ETIMEOUT : 0;
+ * }
+ *
+ * signal(bAll) {
+ *
+ * [auto: register int result ]
+ * [auto: register int nSignalsToIssue]
+ *
+ * lock( mtxUnblockLock );
+ *
+ * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
+ * if ( 0 == nWaitersBlocked ) { // NO-OP
+ * return unlock( mtxUnblockLock );
+ * }
+ * if (bAll) {
+ * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
+ * nWaitersBlocked = 0;
+ * }
+ * else {
+ * nSignalsToIssue = 1;
+ * nWaitersToUnblock++;
+ * nWaitersBlocked--;
+ * }
+ * }
+ * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
+ * sem_wait( semBlockLock ); // close the gate
+ * if ( 0 != nWaitersGone ) {
+ * nWaitersBlocked -= nWaitersGone;
+ * nWaitersGone = 0;
+ * }
+ * if (bAll) {
+ * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
+ * nWaitersBlocked = 0;
+ * }
+ * else {
+ * nSignalsToIssue = nWaitersToUnblock = 1;
+ * nWaitersBlocked--;
+ * }
+ * }
+ * else { // NO-OP
+ * return unlock( mtxUnblockLock );
+ * }
+ *
+ * unlock( mtxUnblockLock );
+ * sem_post( semBlockQueue,nSignalsToIssue );
+ * return result;
+ * }
+ * -------------------------------------------------------------
+ *
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+/*
+ * Arguments for cond_wait_cleanup, since we can only pass a
+ * single void * to it.
+ */
+typedef struct {
+ pthread_mutex_t * mutexPtr;
+ pthread_cond_t cv;
+ int * resultPtr;
+ int signaled;
+} ptw32_cond_wait_cleanup_args_t;
+
+static void
+ptw32_cond_wait_cleanup(void * args)
+{
+ ptw32_cond_wait_cleanup_args_t * cleanup_args = (ptw32_cond_wait_cleanup_args_t *) args;
+ pthread_cond_t cv = cleanup_args->cv;
+ int * resultPtr = cleanup_args->resultPtr;
+ int nSignalsWasLeft;
+ int nWaitersWasGone = 0; /* Initialised to quell warnings. */
+ int result;
+
+ /*
+ * Whether we got here as a result of signal/broadcast or because of
+ * timeout on wait or thread cancellation we indicate that we are no
+ * longer waiting. The waiter is responsible for adjusting waiters
+ * (to)unblock(ed) counts (protected by unblock lock).
+ */
+ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
+ {
+ *resultPtr = result;
+ return;
+ }
+
+ if ( 0 != (nSignalsWasLeft = cv->nWaitersToUnblock) )
+ {
+ if ( !cleanup_args->signaled )
+ {
+ if ( 0 != cv->nWaitersBlocked )
+ {
+ (cv->nWaitersBlocked)--;
+ }
+ else
+ {
+ (cv->nWaitersGone)++;
+ }
+ }
+ if ( 0 == --(cv->nWaitersToUnblock) )
+ {
+ if ( 0 != cv->nWaitersBlocked )
+ {
+ if (sem_post( &(cv->semBlockLock) ) != 0)
+ {
+ *resultPtr = errno;
+ /*
+ * This is a fatal error for this CV,
+ * so we deliberately don't unlock
+ * cv->mtxUnblockLock before returning.
+ */
+ return;
+ }
+ nSignalsWasLeft = 0;
+ }
+ else if ( 0 != (nWaitersWasGone = cv->nWaitersGone) )
+ {
+ cv->nWaitersGone = 0;
+ }
+ }
+ }
+ else if ( INT_MAX/2 == ++(cv->nWaitersGone) )
+ {
+ if (sem_wait( &(cv->semBlockLock) ) != 0)
+ {
+ *resultPtr = errno;
+ /*
+ * This is a fatal error for this CV,
+ * so we deliberately don't unlock
+ * cv->mtxUnblockLock before returning.
+ */
+ return;
+ }
+ cv->nWaitersBlocked -= cv->nWaitersGone;
+ if (sem_post( &(cv->semBlockLock) ) != 0)
+ {
+ *resultPtr = errno;
+ /*
+ * This is a fatal error for this CV,
+ * so we deliberately don't unlock
+ * cv->mtxUnblockLock before returning.
+ */
+ return;
+ }
+ cv->nWaitersGone = 0;
+ }
+
+ if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
+ {
+ *resultPtr = result;
+ return;
+ }
+
+ if ( 1 == nSignalsWasLeft )
+ {
+ if ( 0 != nWaitersWasGone )
+ {
+ // sem_adjust( &(cv->semBlockQueue), -nWaitersWasGone );
+ while ( nWaitersWasGone-- )
+ {
+ if (sem_wait( &(cv->semBlockQueue)) != 0 )
+ {
+ *resultPtr = errno;
+ return;
+ }
+ }
+ }
+ if (sem_post(&(cv->semBlockLock)) != 0)
+ {
+ *resultPtr = errno;
+ return;
+ }
+ }
+
+ /*
+ * XSH: Upon successful return, the mutex has been locked and is owned
+ * by the calling thread
+ */
+ if ((result = pthread_mutex_lock(cleanup_args->mutexPtr)) != 0)
+ {
+ *resultPtr = result;
+ }
+
+} /* ptw32_cond_wait_cleanup */
+
+static INLINE int
+ptw32_cond_timedwait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec *abstime)
+{
+ int result = 0;
+ pthread_cond_t cv;
+ ptw32_cond_wait_cleanup_args_t cleanup_args;
+
+ if (cond == NULL || *cond == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static condition variable. We check
+ * again inside the guarded section of ptw32_cond_check_need_init()
+ * to avoid race conditions.
+ */
+ if (*cond == PTHREAD_COND_INITIALIZER)
+ {
+ result = ptw32_cond_check_need_init(cond);
+ }
+
+ if (result != 0 && result != EBUSY)
+ {
+ return result;
+ }
+
+ cv = *cond;
+
+ if (sem_wait(&(cv->semBlockLock)) != 0)
+ {
+ return errno;
+ }
+
+ cv->nWaitersBlocked++;
+
+ if (sem_post(&(cv->semBlockLock)) != 0)
+ {
+ return errno;
+ }
+
+ /*
+ * Setup this waiter cleanup handler
+ */
+ cleanup_args.mutexPtr = mutex;
+ cleanup_args.cv = cv;
+ cleanup_args.resultPtr = &result;
+ /*
+ * If we're canceled, or the cancelable wait fails for any reason,
+ * including a timeout, then tell the cleanup routine that we
+ * have not been signaled.
+ */
+ cleanup_args.signaled = 0;
+
+#ifdef _MSC_VER
+#pragma inline_depth(0)
+#endif
+ pthread_cleanup_push(ptw32_cond_wait_cleanup, (void *) &cleanup_args);
+
+ /*
+ * Now we can release 'mutex' and...
+ */
+ if ((result = pthread_mutex_unlock(mutex)) == 0)
+ {
+
+ /*
+ * ...wait to be awakened by
+ * pthread_cond_signal, or
+ * pthread_cond_broadcast, or
+ * timeout, or
+ * thread cancellation
+ *
+ * Note:
+ *
+ * sem_timedwait is 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
+ * counts if we are cancelled, timed out or signalled.
+ */
+ if (sem_timedwait(&(cv->semBlockQueue), abstime) != 0)
+ {
+ result = errno;
+ }
+ }
+
+ /*
+ * Not executed if we're canceled. Signaled is false if we timed out.
+ */
+ cleanup_args.signaled = (result == 0);
+
+ /*
+ * Always cleanup
+ */
+ pthread_cleanup_pop(1);
+#ifdef _MSC_VER
+#pragma inline_depth()
+#endif
+
+ /*
+ * "result" can be modified by the cleanup handler.
+ */
+ return result;
+
+} /* ptw32_cond_timedwait */
+
+
+int
+pthread_cond_wait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function waits on a condition variable until
+ * awakened by a signal or broadcast.
+ *
+ * Caller MUST be holding the mutex lock; the
+ * lock is released and the caller is blocked waiting
+ * on 'cond'. When 'cond' is signaled, the mutex
+ * is re-acquired before returning to the caller.
+ *
+ * PARAMETERS
+ * cond
+ * pointer to an instance of pthread_cond_t
+ *
+ * mutex
+ * pointer to an instance of pthread_mutex_t
+ *
+ *
+ * DESCRIPTION
+ * This function waits on a condition variable until
+ * awakened by a signal or broadcast.
+ *
+ * NOTES:
+ *
+ * 1) The function must be called with 'mutex' LOCKED
+ * by the calling thread, or undefined behaviour
+ * will result.
+ *
+ * 2) This routine atomically releases 'mutex' and causes
+ * the calling thread to block on the condition variable.
+ * The blocked thread may be awakened by
+ * pthread_cond_signal or
+ * pthread_cond_broadcast.
+ *
+ * Upon successful completion, the 'mutex' has been locked and
+ * is owned by the calling thread.
+ *
+ *
+ * RESULTS
+ * 0 caught condition; mutex released,
+ * EINVAL 'cond' or 'mutex' is invalid,
+ * EINVAL different mutexes for concurrent waits,
+ * EINVAL mutex is not held by the calling thread,
+ *
+ * ------------------------------------------------------
+ */
+{
+ /*
+ * The NULL abstime arg means INFINITE waiting.
+ */
+ return (ptw32_cond_timedwait(cond, mutex, NULL));
+
+} /* pthread_cond_wait */
+
+
+int
+pthread_cond_timedwait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec *abstime)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function waits on a condition variable either until
+ * awakened by a signal or broadcast; or until the time
+ * specified by abstime passes.
+ *
+ * PARAMETERS
+ * cond
+ * pointer to an instance of pthread_cond_t
+ *
+ * mutex
+ * pointer to an instance of pthread_mutex_t
+ *
+ * abstime
+ * pointer to an instance of (const struct timespec)
+ *
+ *
+ * DESCRIPTION
+ * This function waits on a condition variable either until
+ * awakened by a signal or broadcast; or until the time
+ * specified by abstime passes.
+ *
+ * NOTES:
+ * 1) The function must be called with 'mutex' LOCKED
+ * by the calling thread, or undefined behaviour
+ * will result.
+ *
+ * 2) This routine atomically releases 'mutex' and causes
+ * the calling thread to block on the condition variable.
+ * The blocked thread may be awakened by
+ * pthread_cond_signal or
+ * pthread_cond_broadcast.
+ *
+ *
+ * RESULTS
+ * 0 caught condition; mutex released,
+ * EINVAL 'cond', 'mutex', or abstime is invalid,
+ * EINVAL different mutexes for concurrent waits,
+ * EINVAL mutex is not held by the calling thread,
+ * ETIMEDOUT abstime ellapsed before cond was signaled.
+ *
+ * ------------------------------------------------------
+ */
+{
+ if (abstime == NULL)
+ {
+ return EINVAL;
+ }
+
+ return (ptw32_cond_timedwait(cond, mutex, abstime));
+
+} /* pthread_cond_timedwait */
diff --git a/misc.c b/misc.c
index b5fce04..4e3b286 100644
--- a/misc.c
+++ b/misc.c
@@ -38,416 +38,12 @@
#include "implement.h"
-int
-pthread_once (
- pthread_once_t * once_control,
- void (*init_routine) (void)
-)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * If any thread in a process with a once_control parameter
- * makes a call to pthread_once(), the first call will summon
- * the init_routine(), but subsequent calls will not. The
- * once_control parameter determines whether the associated
- * initialization routine has been called. The init_routine()
- * is complete upon return of pthread_once().
- * This function guarantees that one and only one thread
- * executes the initialization routine, init_routine when
- * access is controlled by the pthread_once_t control
- * key.
- *
- * PARAMETERS
- * once_control
- * pointer to an instance of pthread_once_t
- *
- * init_routine
- * pointer to an initialization routine
- *
- *
- * DESCRIPTION
- * See above.
- *
- * RESULTS
- * 0 success,
- * EINVAL once_control or init_routine is NULL
- *
- * ------------------------------------------------------
- */
-{
- int result;
+#include "pthread_once.c"
+#include "pthread_self.c"
+#include "pthread_equal.c"
+#include "pthread_setconcurrency.c"
+#include "pthread_getconcurrency.c"
+#include "w32_CancelableWait.c"
+#include "ptw32_new.c"
+#include "ptw32_calloc.c"
- if (once_control == NULL || init_routine == NULL)
- {
-
- result = EINVAL;
- goto FAIL0;
-
- }
- else
- {
- result = 0;
- }
-
- if (!once_control->done)
- {
- if (InterlockedIncrement (&(once_control->started)) == 0)
- {
- /*
- * First thread to increment the started variable
- */
- (*init_routine) ();
- once_control->done = TRUE;
-
- }
- else
- {
- /*
- * Block until other thread finishes executing the onceRoutine
- */
- while (!(once_control->done))
- {
- /*
- * The following gives up CPU cycles without pausing
- * unnecessarily
- */
- Sleep (0);
- }
- }
- }
-
- /*
- * Fall through Intentionally
- */
-
- /*
- * ------------
- * Failure Code
- * ------------
- */
-FAIL0:
- return (result);
-
-} /* pthread_once */
-
-
-pthread_t
-pthread_self (void)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function returns a reference to the current running
- * thread.
- *
- * PARAMETERS
- * N/A
- *
- *
- * DESCRIPTION
- * This function returns a reference to the current running
- * thread.
- *
- * RESULTS
- * pthread_t reference to the current thread
- *
- * ------------------------------------------------------
- */
-{
- pthread_t self;
-
-#ifdef _UWIN
- if(!ptw32_selfThreadKey)
- return(NULL);
-#endif
-
- self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
-
- if (self == NULL)
- {
- /*
- * Need to create an implicit 'self' for the currently
- * executing thread.
- */
- self = ptw32_new();
-
- if (self != NULL)
- {
- /*
- * This is a non-POSIX thread which has chosen to call
- * a POSIX threads function for some reason. We assume that
- * it isn't joinable, but we do assume that it's
- * (deferred) cancelable.
- */
- self->implicit = 1;
- self->detachState = PTHREAD_CREATE_DETACHED;
- self->thread = GetCurrentThreadId ();
-
-#ifdef NEED_DUPLICATEHANDLE
- /*
- * DuplicateHandle does not exist on WinCE.
- *
- * NOTE:
- * GetCurrentThread only returns a pseudo-handle
- * which is only valid in the current thread context.
- * Therefore, you should not pass the handle to
- * other threads for whatever purpose.
- */
- self->threadH = GetCurrentThread();
-#else
- if( !DuplicateHandle(
- GetCurrentProcess(),
- GetCurrentThread(),
- GetCurrentProcess(),
- &self->threadH,
- 0,
- FALSE,
- DUPLICATE_SAME_ACCESS ) )
- {
- free( self );
- return (NULL);
- }
-#endif
- }
-
- pthread_setspecific (ptw32_selfThreadKey, self);
- }
-
- return (self);
-
-} /* pthread_self */
-
-int
-pthread_equal (pthread_t t1, pthread_t t2)
- /*
- * ------------------------------------------------------
- * DOCPUBLIC
- * This function returns zero if t1 and t2 are equal, else
- * returns nonzero
- *
- * PARAMETERS
- * t1,
- * t2
- * references to an instances of thread_t
- *
- *
- * DESCRIPTION
- * This function returns nonzero if t1 and t2 are equal, else
- * returns zero.
- *
- * RESULTS
- * non-zero if t1 and t2 refer to the same thread,
- * 0 t1 and t2 do not refer to the same thread
- *
- * ------------------------------------------------------
- */
-{
- int result;
-
- /*
- * We also accept NULL == NULL - treating NULL as a thread
- * for this special case, because there is no error that we can return.
- */
- result = ( ( t1 == t2 ) && ( t1 == NULL || ( t1->thread == t2->thread ) ) );
-
- return (result);
-
-} /* pthread_equal */
-
-
-int
-pthread_setconcurrency(int level)
-{
- if (level < 0)
- {
- return EINVAL;
- }
- else
- {
- ptw32_concurrency = level;
- return 0;
- }
-}
-
-
-int
-pthread_getconcurrency(void)
-{
- return ptw32_concurrency;
-}
-
-
-static INLINE int
-ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout)
- /*
- * -------------------------------------------------------------------
- * This provides an extra hook into the pthread_cancel
- * mechanism that will allow you to wait on a Windows handle and make it a
- * cancellation point. This function blocks until the given WIN32 handle is
- * signaled or pthread_cancel has been called. It is implemented using
- * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32
- * event used to implement pthread_cancel.
- *
- * Given this hook it would be possible to implement more of the cancellation
- * points.
- * -------------------------------------------------------------------
- */
-{
- int result;
- pthread_t self;
- HANDLE handles[2];
- DWORD nHandles = 1;
- DWORD status;
-
- handles[0] = waitHandle;
-
- if ((self = pthread_self()) != NULL)
- {
- /*
- * Get cancelEvent handle
- */
- if (self->cancelState == PTHREAD_CANCEL_ENABLE)
- {
-
- if ((handles[1] = self->cancelEvent) != NULL)
- {
- nHandles++;
- }
- }
- }
- else
- {
- handles[1] = NULL;
- }
-
- status = WaitForMultipleObjects (
- nHandles,
- handles,
- FALSE,
- timeout);
-
-
- if (status == WAIT_FAILED)
- {
- result = EINVAL;
- }
- else if (status == WAIT_TIMEOUT)
- {
- result = ETIMEDOUT;
- }
- else if (status == WAIT_ABANDONED_0)
- {
- result = EINVAL;
- }
- else
- {
- /*
- * Either got the handle or the cancel event
- * was signaled
- */
- switch (status - WAIT_OBJECT_0)
- {
-
- case 0:
- /*
- * Got the handle
- */
- result = 0;
- break;
-
- case 1:
- /*
- * Got cancel request
- */
- ResetEvent (handles[1]);
-
- if (self != NULL && !self->implicit)
- {
- /*
- * Thread started with pthread_create.
- * Make sure we haven't been async-canceled in the meantime.
- */
- (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. */
- result = EINVAL;
- break;
-
- default:
- result = EINVAL;
- break;
- }
- }
-
- return (result);
-
-} /* CancelableWait */
-
-int
-pthreadCancelableWait (HANDLE waitHandle)
-{
- return (ptw32_cancelable_wait(waitHandle, INFINITE));
-}
-
-int
-pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout)
-{
- return (ptw32_cancelable_wait(waitHandle, timeout));
-}
-
-
-pthread_t
-ptw32_new (void)
-{
- pthread_t t;
-
- t = (pthread_t) calloc (1, sizeof (*t));
-
- if (t != NULL)
- {
- t->detachState = PTHREAD_CREATE_JOINABLE;
- t->cancelState = PTHREAD_CANCEL_ENABLE;
- t->cancelType = PTHREAD_CANCEL_DEFERRED;
- t->cancelLock = PTHREAD_MUTEX_INITIALIZER;
- t->cancelEvent = CreateEvent (
- 0,
- (int) TRUE, /* manualReset */
- (int) FALSE, /* setSignaled */
- NULL);
-
- if (t->cancelEvent == NULL)
- {
- free (t);
- t = NULL;
- }
- }
-
- return t;
-
-}
-
-
-#ifdef NEED_CALLOC
-void *
-ptw32_calloc(size_t n, size_t s) {
- unsigned int m = n*s;
- void *p;
-
- p = malloc(m);
- if (p == NULL) return NULL;
-
- memset(p, 0, m);
-
- return p;
-}
-#endif
diff --git a/nonportable.c b/nonportable.c
index daa73e7..4c8b449 100644
--- a/nonportable.c
+++ b/nonportable.c
@@ -37,296 +37,9 @@
#include "pthread.h"
#include "implement.h"
-/*
- * pthread_mutexattr_setkind_np()
- */
-int pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind)
-{
- return pthread_mutexattr_settype( attr, kind );
-}
-
-
-/*
- * pthread_mutexattr_getkind_np()
- */
-int pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind)
-{
- return pthread_mutexattr_gettype( attr, kind );
-}
-
-
-/*
- * pthread_getw32threadhandle_np()
- *
- * Returns the win32 thread handle that the POSIX
- * thread "thread" is running as.
- *
- * Applications can use the win32 handle to set
- * win32 specific attributes of the thread.
- */
-HANDLE
-pthread_getw32threadhandle_np(pthread_t thread)
-{
- return (thread != NULL) ? (thread->threadH) : 0;
-}
-
-
-/*
- * pthread_delay_np
- *
- * DESCRIPTION
- *
- * This routine causes a thread to delay execution for a specific period of time.
- * This period ends at the current time plus the specified interval. The routine
- * will not return before the end of the period is reached, but may return an
- * arbitrary amount of time after the period has gone by. This can be due to
- * system load, thread priorities, and system timer granularity.
- *
- * Specifying an interval of zero (0) seconds and zero (0) nanoseconds is
- * allowed and can be used to force the thread to give up the processor or to
- * deliver a pending cancelation request.
- *
- * The timespec structure contains the following two fields:
- *
- * tv_sec is an integer number of seconds.
- * tv_nsec is an integer number of nanoseconds.
- *
- * Return Values
- *
- * If an error condition occurs, this routine returns an integer value indicating
- * the type of error. Possible return values are as follows:
- *
- * 0
- * Successful completion.
- * [EINVAL]
- * The value specified by interval is invalid.
- *
- * Example
- *
- * The following code segment would wait for 5 and 1/2 seconds
- *
- * struct timespec tsWait;
- * int intRC;
- *
- * tsWait.tv_sec = 5;
- * tsWait.tv_nsec = 500000000L;
- * intRC = pthread_delay_np(&tsWait);
- */
-int
-pthread_delay_np (struct timespec * interval)
-{
- DWORD wait_time;
- DWORD secs_in_millisecs;
- DWORD millisecs;
- DWORD status;
- pthread_t self;
-
- if (interval == NULL)
- {
- return EINVAL;
- }
-
- if (interval->tv_sec == 0L && interval->tv_nsec == 0L)
- {
- pthread_testcancel();
- Sleep(0);
- pthread_testcancel();
- return (0);
- }
-
- /* convert secs to millisecs */
- secs_in_millisecs = interval->tv_sec * 1000L;
-
- /* convert nanosecs to millisecs (rounding up) */
- millisecs = (interval->tv_nsec + 999999L) / 1000000L;
-
- if (0 > (wait_time = secs_in_millisecs + millisecs))
- {
- return EINVAL;
- }
-
- if (NULL == (self = pthread_self()))
- {
- return ENOMEM;
- }
-
- if (self->cancelState == PTHREAD_CANCEL_ENABLE)
- {
- /*
- * Async cancelation won't catch us until wait_time is up.
- * Deferred cancelation will cancel us immediately.
- */
- if (WAIT_OBJECT_0 ==
- (status = WaitForSingleObject(self->cancelEvent, wait_time)) )
- {
- /*
- * Canceling!
- */
- (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);
- }
-
- (void) pthread_mutex_unlock(&self->cancelLock);
- return ESRCH;
- }
- else if (status != WAIT_TIMEOUT)
- {
- return EINVAL;
- }
- }
- else
- {
- Sleep( wait_time );
- }
-
- return (0);
-}
-
-
-/*
- * pthread_num_processors_np()
- *
- * Get the number of CPUs available to the process.
- */
-int
-pthread_num_processors_np(void)
-{
- int count;
-
- if ( ptw32_getprocessors(& count) != 0 )
- {
- count = 1;
- }
-
- return (count);
-}
-
-
-/*
- * Handle to kernel32.dll
- */
-static HINSTANCE ptw32_h_kernel32;
-
-BOOL
-pthread_win32_process_attach_np ()
-{
- BOOL result = TRUE;
-
- result = ptw32_processInitialize ();
-#ifdef _UWIN
- pthread_count++;
-#endif
-
-#ifndef TEST_ICE
-
- /*
- * Load KERNEL32 and try to get address of InterlockedCompareExchange
- */
- ptw32_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL"));
-
- ptw32_interlocked_compare_exchange =
- (PTW32_INTERLOCKED_LONG (WINAPI *)(PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, PTW32_INTERLOCKED_LONG))
-#if defined(NEED_UNICODE_CONSTS)
- GetProcAddress(ptw32_h_kernel32,
- (const TCHAR *)TEXT("InterlockedCompareExchange"));
-#else
- GetProcAddress(ptw32_h_kernel32,
- (LPCSTR) "InterlockedCompareExchange");
-#endif
-
- if (ptw32_interlocked_compare_exchange == NULL)
- {
- ptw32_interlocked_compare_exchange = ptw32_InterlockedCompareExchange;
-
- /*
- * If InterlockedCompareExchange is not being used, then free
- * the kernel32.dll handle now, rather than leaving it until
- * DLL_PROCESS_DETACH.
- *
- * Note: this is not a pedantic exercise in freeing unused
- * resources! It is a work-around for a bug in Windows 95
- * (see microsoft knowledge base article, Q187684) which
- * does Bad Things when FreeLibrary is called within
- * the DLL_PROCESS_DETACH code, in certain situations.
- * Since w95 just happens to be a platform which does not
- * provide InterlockedCompareExchange, the bug will be
- * effortlessly avoided.
- */
- (void) FreeLibrary(ptw32_h_kernel32);
- ptw32_h_kernel32 = 0;
- }
-
-#else /* TEST_ICE */
-
- ptw32_interlocked_compare_exchange = ptw32_InterlockedCompareExchange;
-
-#endif /* TEST_ICE */
-
- return result;
-}
-
-BOOL
-pthread_win32_process_detach_np ()
-{
- if (ptw32_processInitialized)
- {
- pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
-
- /*
- * Detached threads have their resources automatically
- * cleaned up upon exit (others must be 'joined').
- */
- if (self != NULL &&
- self->detachState == PTHREAD_CREATE_DETACHED)
- {
- pthread_setspecific (ptw32_selfThreadKey, NULL);
- ptw32_threadDestroy (self);
- }
-
- /*
- * The DLL is being unmapped into the process's address space
- */
- ptw32_processTerminate ();
-
- if (ptw32_h_kernel32)
- {
- (void) FreeLibrary(ptw32_h_kernel32);
- }
- }
-
- return TRUE;
-}
-
-BOOL
-pthread_win32_thread_attach_np ()
-{
- return TRUE;
-}
-
-BOOL
-pthread_win32_thread_detach_np ()
-{
- if (ptw32_processInitialized)
- {
- pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
-
- /*
- * Detached threads have their resources automatically
- * cleaned up upon exit (others must be 'joined').
- */
- if (self != NULL &&
- self->detachState == PTHREAD_CREATE_DETACHED)
- {
- pthread_setspecific (ptw32_selfThreadKey, NULL);
- ptw32_threadDestroy (self);
- }
- }
-
- return TRUE;
-}
+#include "np_mutexattr_setkind.c"
+#include "np_mutexattr_getkind.c"
+#include "np_getw32threadhandle.c"
+#include "np_delay.c"
+#include "np_num_processors.c"
+#include "np_win32_attach.c"
diff --git a/np_delay.c b/np_delay.c
new file mode 100644
index 0000000..d2a893e
--- /dev/null
+++ b/np_delay.c
@@ -0,0 +1,155 @@
+/*
+ * np_delay.c
+ *
+ * Description:
+ * This translation unit implements non-portable thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+/*
+ * pthread_delay_np
+ *
+ * DESCRIPTION
+ *
+ * This routine causes a thread to delay execution for a specific period of time.
+ * This period ends at the current time plus the specified interval. The routine
+ * will not return before the end of the period is reached, but may return an
+ * arbitrary amount of time after the period has gone by. This can be due to
+ * system load, thread priorities, and system timer granularity.
+ *
+ * Specifying an interval of zero (0) seconds and zero (0) nanoseconds is
+ * allowed and can be used to force the thread to give up the processor or to
+ * deliver a pending cancelation request.
+ *
+ * The timespec structure contains the following two fields:
+ *
+ * tv_sec is an integer number of seconds.
+ * tv_nsec is an integer number of nanoseconds.
+ *
+ * Return Values
+ *
+ * If an error condition occurs, this routine returns an integer value indicating
+ * the type of error. Possible return values are as follows:
+ *
+ * 0
+ * Successful completion.
+ * [EINVAL]
+ * The value specified by interval is invalid.
+ *
+ * Example
+ *
+ * The following code segment would wait for 5 and 1/2 seconds
+ *
+ * struct timespec tsWait;
+ * int intRC;
+ *
+ * tsWait.tv_sec = 5;
+ * tsWait.tv_nsec = 500000000L;
+ * intRC = pthread_delay_np(&tsWait);
+ */
+int
+pthread_delay_np (struct timespec * interval)
+{
+ DWORD wait_time;
+ DWORD secs_in_millisecs;
+ DWORD millisecs;
+ DWORD status;
+ pthread_t self;
+
+ if (interval == NULL)
+ {
+ return EINVAL;
+ }
+
+ if (interval->tv_sec == 0L && interval->tv_nsec == 0L)
+ {
+ pthread_testcancel();
+ Sleep(0);
+ pthread_testcancel();
+ return (0);
+ }
+
+ /* convert secs to millisecs */
+ secs_in_millisecs = interval->tv_sec * 1000L;
+
+ /* convert nanosecs to millisecs (rounding up) */
+ millisecs = (interval->tv_nsec + 999999L) / 1000000L;
+
+ if (0 > (wait_time = secs_in_millisecs + millisecs))
+ {
+ return EINVAL;
+ }
+
+ if (NULL == (self = pthread_self()))
+ {
+ return ENOMEM;
+ }
+
+ if (self->cancelState == PTHREAD_CANCEL_ENABLE)
+ {
+ /*
+ * Async cancelation won't catch us until wait_time is up.
+ * Deferred cancelation will cancel us immediately.
+ */
+ if (WAIT_OBJECT_0 ==
+ (status = WaitForSingleObject(self->cancelEvent, wait_time)) )
+ {
+ /*
+ * Canceling!
+ */
+ (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);
+ }
+
+ (void) pthread_mutex_unlock(&self->cancelLock);
+ return ESRCH;
+ }
+ else if (status != WAIT_TIMEOUT)
+ {
+ return EINVAL;
+ }
+ }
+ else
+ {
+ Sleep( wait_time );
+ }
+
+ return (0);
+}
diff --git a/np_getw32threadhandle.c b/np_getw32threadhandle.c
new file mode 100644
index 0000000..98f610e
--- /dev/null
+++ b/np_getw32threadhandle.c
@@ -0,0 +1,53 @@
+/*
+ * np_getw32threadhandle.c
+ *
+ * Description:
+ * This translation unit implements non-portable thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+/*
+ * pthread_getw32threadhandle_np()
+ *
+ * Returns the win32 thread handle that the POSIX
+ * thread "thread" is running as.
+ *
+ * Applications can use the win32 handle to set
+ * win32 specific attributes of the thread.
+ */
+HANDLE
+pthread_getw32threadhandle_np(pthread_t thread)
+{
+ return (thread != NULL) ? (thread->threadH) : 0;
+}
diff --git a/np_mutexattr_setkind.c b/np_mutexattr_setkind.c
new file mode 100644
index 0000000..df56ca6
--- /dev/null
+++ b/np_mutexattr_setkind.c
@@ -0,0 +1,57 @@
+/*
+ * np_mutexattr_setkind.c
+ *
+ * Description:
+ * This translation unit implements non-portable thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+/*
+ * pthread_mutexattr_setkind_np()
+ */
+int
+pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind)
+{
+ return pthread_mutexattr_settype( attr, kind );
+}
+
+
+/*
+ * pthread_mutexattr_getkind_np()
+ */
+int
+pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind)
+{
+ return pthread_mutexattr_gettype( attr, kind );
+}
diff --git a/np_num_processors.c b/np_num_processors.c
new file mode 100644
index 0000000..776e2f7
--- /dev/null
+++ b/np_num_processors.c
@@ -0,0 +1,56 @@
+/*
+ * np_num_processors.c
+ *
+ * Description:
+ * This translation unit implements non-portable thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+/*
+ * pthread_num_processors_np()
+ *
+ * Get the number of CPUs available to the process.
+ */
+int
+pthread_num_processors_np(void)
+{
+ int count;
+
+ if ( ptw32_getprocessors(& count) != 0 )
+ {
+ count = 1;
+ }
+
+ return (count);
+}
diff --git a/np_win32_attach.c b/np_win32_attach.c
new file mode 100644
index 0000000..f7833ee
--- /dev/null
+++ b/np_win32_attach.c
@@ -0,0 +1,162 @@
+/*
+ * np_win32_attach.c
+ *
+ * Description:
+ * This translation unit implements non-portable thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+/*
+ * Handle to kernel32.dll
+ */
+static HINSTANCE ptw32_h_kernel32;
+
+BOOL
+pthread_win32_process_attach_np ()
+{
+ BOOL result = TRUE;
+
+ result = ptw32_processInitialize ();
+#ifdef _UWIN
+ pthread_count++;
+#endif
+
+#ifndef TEST_ICE
+
+ /*
+ * Load KERNEL32 and try to get address of InterlockedCompareExchange
+ */
+ ptw32_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL"));
+
+ ptw32_interlocked_compare_exchange =
+ (PTW32_INTERLOCKED_LONG (WINAPI *)(PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, PTW32_INTERLOCKED_LONG))
+#if defined(NEED_UNICODE_CONSTS)
+ GetProcAddress(ptw32_h_kernel32,
+ (const TCHAR *)TEXT("InterlockedCompareExchange"));
+#else
+ GetProcAddress(ptw32_h_kernel32,
+ (LPCSTR) "InterlockedCompareExchange");
+#endif
+
+ if (ptw32_interlocked_compare_exchange == NULL)
+ {
+ ptw32_interlocked_compare_exchange = ptw32_InterlockedCompareExchange;
+
+ /*
+ * If InterlockedCompareExchange is not being used, then free
+ * the kernel32.dll handle now, rather than leaving it until
+ * DLL_PROCESS_DETACH.
+ *
+ * Note: this is not a pedantic exercise in freeing unused
+ * resources! It is a work-around for a bug in Windows 95
+ * (see microsoft knowledge base article, Q187684) which
+ * does Bad Things when FreeLibrary is called within
+ * the DLL_PROCESS_DETACH code, in certain situations.
+ * Since w95 just happens to be a platform which does not
+ * provide InterlockedCompareExchange, the bug will be
+ * effortlessly avoided.
+ */
+ (void) FreeLibrary(ptw32_h_kernel32);
+ ptw32_h_kernel32 = 0;
+ }
+
+#else /* TEST_ICE */
+
+ ptw32_interlocked_compare_exchange = ptw32_InterlockedCompareExchange;
+
+#endif /* TEST_ICE */
+
+ return result;
+}
+
+
+BOOL
+pthread_win32_process_detach_np ()
+{
+ if (ptw32_processInitialized)
+ {
+ pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
+
+ /*
+ * Detached threads have their resources automatically
+ * cleaned up upon exit (others must be 'joined').
+ */
+ if (self != NULL &&
+ self->detachState == PTHREAD_CREATE_DETACHED)
+ {
+ pthread_setspecific (ptw32_selfThreadKey, NULL);
+ ptw32_threadDestroy (self);
+ }
+
+ /*
+ * The DLL is being unmapped into the process's address space
+ */
+ ptw32_processTerminate ();
+
+ if (ptw32_h_kernel32)
+ {
+ (void) FreeLibrary(ptw32_h_kernel32);
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL
+pthread_win32_thread_attach_np ()
+{
+ return TRUE;
+}
+
+BOOL
+pthread_win32_thread_detach_np ()
+{
+ if (ptw32_processInitialized)
+ {
+ pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
+
+ /*
+ * Detached threads have their resources automatically
+ * cleaned up upon exit (others must be 'joined').
+ */
+ if (self != NULL &&
+ self->detachState == PTHREAD_CREATE_DETACHED)
+ {
+ pthread_setspecific (ptw32_selfThreadKey, NULL);
+ ptw32_threadDestroy (self);
+ }
+ }
+
+ return TRUE;
+}
diff --git a/pthread.c b/pthread.c
index 7fbfa9f..be70f38 100644
--- a/pthread.c
+++ b/pthread.c
@@ -36,13 +36,6 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-/*
- * This file is intended to form a single translation unit
- * consisting of the entire pthreads-win32 library.
- * The reason for doing this is to maximise inline optimisation
- * wherever possible.
- */
-
#include "pthread.h"
#include "implement.h"
diff --git a/pthread.def b/pthread.def
index b9f3148..1609045 100644
--- a/pthread.def
+++ b/pthread.def
@@ -1,162 +1,162 @@
-; pthread.def
-; Last updated: $Date: 2002/01/31 21:52:58 $
-
-; Currently unimplemented functions are commented out.
-
-;LIBRARY pthread
-
-EXPORTS
-;pthread_atfork
-pthread_attr_destroy
-pthread_attr_getdetachstate
-pthread_attr_getinheritsched
-pthread_attr_getschedparam
-pthread_attr_getschedpolicy
-pthread_attr_getscope
-pthread_attr_getstackaddr
-pthread_attr_getstacksize
-pthread_attr_init
-pthread_attr_setdetachstate
-pthread_attr_setinheritsched
-pthread_attr_setschedparam
-pthread_attr_setschedpolicy
-pthread_attr_setscope
-pthread_attr_setstackaddr
-pthread_attr_setstacksize
-pthread_cancel
-;
-; These two are implemented as macros in pthread.h
-;
-;pthread_cleanup_pop
-;pthread_cleanup_push
-;
-pthread_condattr_destroy
-pthread_condattr_getpshared
-pthread_condattr_init
-pthread_condattr_setpshared
-pthread_cond_broadcast
-pthread_cond_destroy
-pthread_cond_init
-pthread_cond_signal
-pthread_cond_timedwait
-pthread_cond_wait
-pthread_create
-pthread_detach
-pthread_equal
-pthread_exit
-pthread_getconcurrency
-pthread_getschedparam
-pthread_getspecific
-pthread_join
-pthread_key_create
-pthread_key_delete
-;pthread_kill
-pthread_mutexattr_destroy
-;pthread_mutexattr_getprioceiling
-;pthread_mutexattr_getprotocol
-pthread_mutexattr_getpshared
-pthread_mutexattr_gettype
-pthread_mutexattr_init
-;pthread_mutexattr_setprioceiling
-;pthread_mutexattr_setprotocol
-pthread_mutexattr_setpshared
-pthread_mutexattr_settype
-pthread_mutexattr_destroy
-pthread_mutex_init
-pthread_mutex_destroy
-pthread_mutex_lock
-pthread_mutex_trylock
-pthread_mutex_timedlock
-pthread_mutex_unlock
-pthread_once
-pthread_self
-pthread_setcancelstate
-pthread_setcanceltype
-pthread_setconcurrency
-pthread_setschedparam
-pthread_setspecific
-;pthread_sigmask
-pthread_testcancel
-;
-; Scheduling
-;
-sched_get_priority_min
-sched_get_priority_max
-sched_getscheduler
-sched_setscheduler
-sched_yield
-;
-; Semaphores
-;
-sem_init
-sem_destroy
-sem_trywait
-sem_wait
-sem_timedwait
-sem_post
-sem_open
-sem_close
-sem_unlink
-sem_getvalue
-;
-; This next one is a macro
-;sched_rr_get_interval
-;
-;
-; Read/Write Locks
-;
-pthread_rwlock_init
-pthread_rwlock_destroy
-pthread_rwlock_tryrdlock
-pthread_rwlock_trywrlock
-pthread_rwlock_rdlock
-pthread_rwlock_wrlock
-pthread_rwlock_unlock
-;
-; Spin locks
-;
-pthread_spin_init
-pthread_spin_destroy
-pthread_spin_lock
-pthread_spin_unlock
-pthread_spin_trylock
-;
-; Barriers
-;
-pthread_barrier_init
-pthread_barrier_destroy
-pthread_barrier_wait
-pthread_barrierattr_init
-pthread_barrierattr_destroy
-pthread_barrierattr_getpshared
-pthread_barrierattr_setpshared
-;
-; Non-portable/compatibility with other implementations
-;
-pthread_delay_np
-pthread_mutexattr_getkind_np
-pthread_mutexattr_setkind_np
-;
-; Non-portable local implementation only
-;
-pthread_getw32threadhandle_np
-pthread_num_processors_np
-pthreadCancelableWait
-pthreadCancelableTimedWait
-;
-; For use when linking statically
-;
-pthread_win32_process_attach_np
-pthread_win32_process_detach_np
-pthread_win32_thread_attach_np
-pthread_win32_thread_detach_np
-;
-; Needed if !defined(_MSC_VER) && !defined(__cplusplus)
-;
-ptw32_push_cleanup
-ptw32_pop_cleanup
-;
-; Not for use directly. Needed by macros in pthread.h
-; to return internal SEH code.
-;
-ptw32_get_exception_services_code
+; pthread.def
+; Last updated: $Date: 2002/02/11 01:53:22 $
+
+; Currently unimplemented functions are commented out.
+
+;LIBRARY pthread
+
+EXPORTS
+;pthread_atfork
+pthread_attr_destroy
+pthread_attr_getdetachstate
+pthread_attr_getinheritsched
+pthread_attr_getschedparam
+pthread_attr_getschedpolicy
+pthread_attr_getscope
+pthread_attr_getstackaddr
+pthread_attr_getstacksize
+pthread_attr_init
+pthread_attr_setdetachstate
+pthread_attr_setinheritsched
+pthread_attr_setschedparam
+pthread_attr_setschedpolicy
+pthread_attr_setscope
+pthread_attr_setstackaddr
+pthread_attr_setstacksize
+pthread_cancel
+;
+; These two are implemented as macros in pthread.h
+;
+;pthread_cleanup_pop
+;pthread_cleanup_push
+;
+pthread_condattr_destroy
+pthread_condattr_getpshared
+pthread_condattr_init
+pthread_condattr_setpshared
+pthread_cond_broadcast
+pthread_cond_destroy
+pthread_cond_init
+pthread_cond_signal
+pthread_cond_timedwait
+pthread_cond_wait
+pthread_create
+pthread_detach
+pthread_equal
+pthread_exit
+pthread_getconcurrency
+pthread_getschedparam
+pthread_getspecific
+pthread_join
+pthread_key_create
+pthread_key_delete
+;pthread_kill
+pthread_mutexattr_destroy
+;pthread_mutexattr_getprioceiling
+;pthread_mutexattr_getprotocol
+pthread_mutexattr_getpshared
+pthread_mutexattr_gettype
+pthread_mutexattr_init
+;pthread_mutexattr_setprioceiling
+;pthread_mutexattr_setprotocol
+pthread_mutexattr_setpshared
+pthread_mutexattr_settype
+pthread_mutexattr_destroy
+pthread_mutex_init
+pthread_mutex_destroy
+pthread_mutex_lock
+pthread_mutex_trylock
+pthread_mutex_timedlock
+pthread_mutex_unlock
+pthread_once
+pthread_self
+pthread_setcancelstate
+pthread_setcanceltype
+pthread_setconcurrency
+pthread_setschedparam
+pthread_setspecific
+;pthread_sigmask
+pthread_testcancel
+;
+; Scheduling
+;
+sched_get_priority_min
+sched_get_priority_max
+sched_getscheduler
+sched_setscheduler
+sched_yield
+;
+; Semaphores
+;
+sem_init
+sem_destroy
+sem_trywait
+sem_wait
+sem_timedwait
+sem_post
+sem_open
+sem_close
+sem_unlink
+sem_getvalue
+;
+; This next one is a macro
+;sched_rr_get_interval
+;
+;
+; Read/Write Locks
+;
+pthread_rwlock_init
+pthread_rwlock_destroy
+pthread_rwlock_tryrdlock
+pthread_rwlock_trywrlock
+pthread_rwlock_rdlock
+pthread_rwlock_wrlock
+pthread_rwlock_unlock
+;
+; Spin locks
+;
+pthread_spin_init
+pthread_spin_destroy
+pthread_spin_lock
+pthread_spin_unlock
+pthread_spin_trylock
+;
+; Barriers
+;
+pthread_barrier_init
+pthread_barrier_destroy
+pthread_barrier_wait
+pthread_barrierattr_init
+pthread_barrierattr_destroy
+pthread_barrierattr_getpshared
+pthread_barrierattr_setpshared
+;
+; Non-portable/compatibility with other implementations
+;
+pthread_delay_np
+pthread_mutexattr_getkind_np
+pthread_mutexattr_setkind_np
+;
+; Non-portable local implementation only
+;
+pthread_getw32threadhandle_np
+pthread_num_processors_np
+pthreadCancelableWait
+pthreadCancelableTimedWait
+;
+; For use when linking statically
+;
+pthread_win32_process_attach_np
+pthread_win32_process_detach_np
+pthread_win32_thread_attach_np
+pthread_win32_thread_detach_np
+;
+; Needed if !defined(_MSC_VER) && !defined(__cplusplus)
+;
+ptw32_push_cleanup
+ptw32_pop_cleanup
+;
+; Not for use directly. Needed by macros in pthread.h
+; to return internal SEH code.
+;
+ptw32_get_exception_services_code
diff --git a/pthread.dsp b/pthread.dsp
index e6b44b3..75d0bb9 100644
--- a/pthread.dsp
+++ b/pthread.dsp
@@ -1,219 +1,219 @@
-# Microsoft Developer Studio Project File - Name="PThread" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=PThread - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "PThread.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "PThread.mak" CFG="PThread - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "PThread - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "PThread - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "PThread - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PTHREAD_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /G6 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D _WIN32_WINNT=0x400 /D "PTHREAD_EXPORTS" /YX /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x809 /d "NDEBUG"
-# ADD RSC /l 0x809 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib /nologo /dll /machine:I386
-
-!ELSEIF "$(CFG)" == "PThread - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PTHREAD_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D _WIN32_WINNT=0x400 /D "PTHREAD_EXPORTS" /YX /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x809 /d "_DEBUG"
-# ADD RSC /l 0x809 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib /nologo /dll /map /debug /machine:I386 /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "PThread - Win32 Release"
-# Name "PThread - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\attr.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\barrier.c
-# End Source File
-# Begin Source File
-
-# Begin Source File
-
-SOURCE=.\cancel.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\cleanup.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\condvar.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\create.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\dll.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\exit.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\fork.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\global.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\misc.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\mutex.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\private.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\rwlock.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\sched.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\semaphore.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\signal.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\spin.c
-# End Source File
-# Begin Source File
-
-# Begin Source File
-
-SOURCE=.\sync.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\tsd.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\acconfig.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\config.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\implement.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\need_errno.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\pthread.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\sched.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\semaphore.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# Begin Source File
-
-SOURCE=.\pthread.def
-# End Source File
-# End Group
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="PThread" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=PThread - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "PThread.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "PThread.mak" CFG="PThread - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "PThread - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "PThread - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "PThread - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PTHREAD_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /G6 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D _WIN32_WINNT=0x400 /D "PTHREAD_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib /nologo /dll /machine:I386
+
+!ELSEIF "$(CFG)" == "PThread - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PTHREAD_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D _WIN32_WINNT=0x400 /D "PTHREAD_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib /nologo /dll /map /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "PThread - Win32 Release"
+# Name "PThread - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\attr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\barrier.c
+# End Source File
+# Begin Source File
+
+# Begin Source File
+
+SOURCE=.\cancel.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\cleanup.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\condvar.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\create.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\dll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\exit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\fork.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\global.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mutex.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\private.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rwlock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\sched.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\semaphore.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\signal.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\spin.c
+# End Source File
+# Begin Source File
+
+# Begin Source File
+
+SOURCE=.\sync.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tsd.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\acconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\config.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\implement.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\need_errno.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\pthread.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\sched.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\semaphore.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\pthread.def
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/pthread.dsw b/pthread.dsw
index 141635c..4b6e512 100644
--- a/pthread.dsw
+++ b/pthread.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "PThread"=.\PThread.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "PThread"=.\PThread.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/pthread_equal.c b/pthread_equal.c
new file mode 100644
index 0000000..78851b9
--- /dev/null
+++ b/pthread_equal.c
@@ -0,0 +1,76 @@
+/*
+ * pthread_equal.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_equal (pthread_t t1, pthread_t t2)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function returns zero if t1 and t2 are equal, else
+ * returns nonzero
+ *
+ * PARAMETERS
+ * t1,
+ * t2
+ * references to an instances of thread_t
+ *
+ *
+ * DESCRIPTION
+ * This function returns nonzero if t1 and t2 are equal, else
+ * returns zero.
+ *
+ * RESULTS
+ * non-zero if t1 and t2 refer to the same thread,
+ * 0 t1 and t2 do not refer to the same thread
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ /*
+ * We also accept NULL == NULL - treating NULL as a thread
+ * for this special case, because there is no error that we can return.
+ */
+ result = ( ( t1 == t2 ) && ( t1 == NULL || ( t1->thread == t2->thread ) ) );
+
+ return (result);
+
+} /* pthread_equal */
diff --git a/pthread_getconcurrency.c b/pthread_getconcurrency.c
new file mode 100644
index 0000000..b83576f
--- /dev/null
+++ b/pthread_getconcurrency.c
@@ -0,0 +1,45 @@
+/*
+ * pthread_getconcurrency.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_getconcurrency(void)
+{
+ return ptw32_concurrency;
+}
diff --git a/pthread_once.c b/pthread_once.c
new file mode 100644
index 0000000..fac1820
--- /dev/null
+++ b/pthread_once.c
@@ -0,0 +1,131 @@
+/*
+ * pthread_once.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_once (
+ pthread_once_t * once_control,
+ void (*init_routine) (void)
+)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * If any thread in a process with a once_control parameter
+ * makes a call to pthread_once(), the first call will summon
+ * the init_routine(), but subsequent calls will not. The
+ * once_control parameter determines whether the associated
+ * initialization routine has been called. The init_routine()
+ * is complete upon return of pthread_once().
+ * This function guarantees that one and only one thread
+ * executes the initialization routine, init_routine when
+ * access is controlled by the pthread_once_t control
+ * key.
+ *
+ * PARAMETERS
+ * once_control
+ * pointer to an instance of pthread_once_t
+ *
+ * init_routine
+ * pointer to an initialization routine
+ *
+ *
+ * DESCRIPTION
+ * See above.
+ *
+ * RESULTS
+ * 0 success,
+ * EINVAL once_control or init_routine is NULL
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ if (once_control == NULL || init_routine == NULL)
+ {
+
+ result = EINVAL;
+ goto FAIL0;
+
+ }
+ else
+ {
+ result = 0;
+ }
+
+ if (!once_control->done)
+ {
+ if (InterlockedIncrement (&(once_control->started)) == 0)
+ {
+ /*
+ * First thread to increment the started variable
+ */
+ (*init_routine) ();
+ once_control->done = TRUE;
+
+ }
+ else
+ {
+ /*
+ * Block until other thread finishes executing the onceRoutine
+ */
+ while (!(once_control->done))
+ {
+ /*
+ * The following gives up CPU cycles without pausing
+ * unnecessarily
+ */
+ Sleep (0);
+ }
+ }
+ }
+
+ /*
+ * Fall through Intentionally
+ */
+
+ /*
+ * ------------
+ * Failure Code
+ * ------------
+ */
+FAIL0:
+ return (result);
+
+} /* pthread_once */
diff --git a/pthread_self.c b/pthread_self.c
new file mode 100644
index 0000000..63423de
--- /dev/null
+++ b/pthread_self.c
@@ -0,0 +1,124 @@
+/*
+ * pthread_self.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+pthread_t
+pthread_self (void)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function returns a reference to the current running
+ * thread.
+ *
+ * PARAMETERS
+ * N/A
+ *
+ *
+ * DESCRIPTION
+ * This function returns a reference to the current running
+ * thread.
+ *
+ * RESULTS
+ * pthread_t reference to the current thread
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_t self;
+
+#ifdef _UWIN
+ if(!ptw32_selfThreadKey)
+ return(NULL);
+#endif
+
+ self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
+
+ if (self == NULL)
+ {
+ /*
+ * Need to create an implicit 'self' for the currently
+ * executing thread.
+ */
+ self = ptw32_new();
+
+ if (self != NULL)
+ {
+ /*
+ * This is a non-POSIX thread which has chosen to call
+ * a POSIX threads function for some reason. We assume that
+ * it isn't joinable, but we do assume that it's
+ * (deferred) cancelable.
+ */
+ self->implicit = 1;
+ self->detachState = PTHREAD_CREATE_DETACHED;
+ self->thread = GetCurrentThreadId ();
+
+#ifdef NEED_DUPLICATEHANDLE
+ /*
+ * DuplicateHandle does not exist on WinCE.
+ *
+ * NOTE:
+ * GetCurrentThread only returns a pseudo-handle
+ * which is only valid in the current thread context.
+ * Therefore, you should not pass the handle to
+ * other threads for whatever purpose.
+ */
+ self->threadH = GetCurrentThread();
+#else
+ if( !DuplicateHandle(
+ GetCurrentProcess(),
+ GetCurrentThread(),
+ GetCurrentProcess(),
+ &self->threadH,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS ) )
+ {
+ free( self );
+ return (NULL);
+ }
+#endif
+ }
+
+ pthread_setspecific (ptw32_selfThreadKey, self);
+ }
+
+ return (self);
+
+} /* pthread_self */
diff --git a/pthread_setconcurrency.c b/pthread_setconcurrency.c
new file mode 100644
index 0000000..52e84d3
--- /dev/null
+++ b/pthread_setconcurrency.c
@@ -0,0 +1,53 @@
+/*
+ * pthread_setconcurrency.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int
+pthread_setconcurrency(int level)
+{
+ if (level < 0)
+ {
+ return EINVAL;
+ }
+ else
+ {
+ ptw32_concurrency = level;
+ return 0;
+ }
+}
diff --git a/ptw32_calloc.c b/ptw32_calloc.c
new file mode 100644
index 0000000..ca7154b
--- /dev/null
+++ b/ptw32_calloc.c
@@ -0,0 +1,54 @@
+/*
+ * ptw32_calloc.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+#ifdef NEED_CALLOC
+void *
+ptw32_calloc(size_t n, size_t s) {
+ unsigned int m = n*s;
+ void *p;
+
+ p = malloc(m);
+ if (p == NULL) return NULL;
+
+ memset(p, 0, m);
+
+ return p;
+}
+#endif
diff --git a/ptw32_new.c b/ptw32_new.c
new file mode 100644
index 0000000..ca24ad7
--- /dev/null
+++ b/ptw32_new.c
@@ -0,0 +1,69 @@
+/*
+ * ptw32_new.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+pthread_t
+ptw32_new (void)
+{
+ pthread_t t;
+
+ t = (pthread_t) calloc (1, sizeof (*t));
+
+ if (t != NULL)
+ {
+ t->detachState = PTHREAD_CREATE_JOINABLE;
+ t->cancelState = PTHREAD_CANCEL_ENABLE;
+ t->cancelType = PTHREAD_CANCEL_DEFERRED;
+ t->cancelLock = PTHREAD_MUTEX_INITIALIZER;
+ t->cancelEvent = CreateEvent (
+ 0,
+ (int) TRUE, /* manualReset */
+ (int) FALSE, /* setSignaled */
+ NULL);
+
+ if (t->cancelEvent == NULL)
+ {
+ free (t);
+ t = NULL;
+ }
+ }
+
+ return t;
+
+}
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 3e3ee9c..4a4883e 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2002-02-07 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * delay1.c: New test.
+ * delay2.c: New test.
+ * exit4.c: New test.
+
2002-02-02 Ross Johnson <rpj@special.ise.canberra.edu.au>
* mutex8: New test.
diff --git a/w32_CancelableWait.c b/w32_CancelableWait.c
new file mode 100644
index 0000000..ba1c92a
--- /dev/null
+++ b/w32_CancelableWait.c
@@ -0,0 +1,168 @@
+/*
+ * w32_CancelableWait.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2002 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@ise.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+static INLINE int
+ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout)
+ /*
+ * -------------------------------------------------------------------
+ * This provides an extra hook into the pthread_cancel
+ * mechanism that will allow you to wait on a Windows handle and make it a
+ * cancellation point. This function blocks until the given WIN32 handle is
+ * signaled or pthread_cancel has been called. It is implemented using
+ * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32
+ * event used to implement pthread_cancel.
+ *
+ * Given this hook it would be possible to implement more of the cancellation
+ * points.
+ * -------------------------------------------------------------------
+ */
+{
+ int result;
+ pthread_t self;
+ HANDLE handles[2];
+ DWORD nHandles = 1;
+ DWORD status;
+
+ handles[0] = waitHandle;
+
+ if ((self = pthread_self()) != NULL)
+ {
+ /*
+ * Get cancelEvent handle
+ */
+ if (self->cancelState == PTHREAD_CANCEL_ENABLE)
+ {
+
+ if ((handles[1] = self->cancelEvent) != NULL)
+ {
+ nHandles++;
+ }
+ }
+ }
+ else
+ {
+ handles[1] = NULL;
+ }
+
+ status = WaitForMultipleObjects (
+ nHandles,
+ handles,
+ FALSE,
+ timeout);
+
+
+ if (status == WAIT_FAILED)
+ {
+ result = EINVAL;
+ }
+ else if (status == WAIT_TIMEOUT)
+ {
+ result = ETIMEDOUT;
+ }
+ else if (status == WAIT_ABANDONED_0)
+ {
+ result = EINVAL;
+ }
+ else
+ {
+ /*
+ * Either got the handle or the cancel event
+ * was signaled
+ */
+ switch (status - WAIT_OBJECT_0)
+ {
+
+ case 0:
+ /*
+ * Got the handle
+ */
+ result = 0;
+ break;
+
+ case 1:
+ /*
+ * Got cancel request
+ */
+ ResetEvent (handles[1]);
+
+ if (self != NULL && !self->implicit)
+ {
+ /*
+ * Thread started with pthread_create.
+ * Make sure we haven't been async-canceled in the meantime.
+ */
+ (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. */
+ result = EINVAL;
+ break;
+
+ default:
+ result = EINVAL;
+ break;
+ }
+ }
+
+ return (result);
+
+} /* CancelableWait */
+
+int
+pthreadCancelableWait (HANDLE waitHandle)
+{
+ return (ptw32_cancelable_wait(waitHandle, INFINITE));
+}
+
+int
+pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout)
+{
+ return (ptw32_cancelable_wait(waitHandle, timeout));
+}