summaryrefslogtreecommitdiff
path: root/win32/contrib/pthreads
diff options
context:
space:
mode:
Diffstat (limited to 'win32/contrib/pthreads')
-rw-r--r--win32/contrib/pthreads/ANNOUNCE525
-rw-r--r--win32/contrib/pthreads/CONTRIBUTORS36
-rw-r--r--win32/contrib/pthreads/COPYING.LIB482
-rw-r--r--win32/contrib/pthreads/ChangeLog3304
-rw-r--r--win32/contrib/pthreads/FAQ390
-rw-r--r--win32/contrib/pthreads/GNUmakefile109
-rw-r--r--win32/contrib/pthreads/MAINTAINERS4
-rw-r--r--win32/contrib/pthreads/Makefile90
-rw-r--r--win32/contrib/pthreads/Makefile.in69
-rw-r--r--win32/contrib/pthreads/NEWS118
-rw-r--r--win32/contrib/pthreads/Nmakefile24
-rw-r--r--win32/contrib/pthreads/Nmakefile.tests167
-rw-r--r--win32/contrib/pthreads/PROGRESS4
-rw-r--r--win32/contrib/pthreads/README269
-rw-r--r--win32/contrib/pthreads/README.CV3036
-rw-r--r--win32/contrib/pthreads/README.NONPORTABLE109
-rw-r--r--win32/contrib/pthreads/README.WinCE6
-rw-r--r--win32/contrib/pthreads/TODO20
-rw-r--r--win32/contrib/pthreads/WinCE-PORT208
-rw-r--r--win32/contrib/pthreads/acconfig.h3
-rw-r--r--win32/contrib/pthreads/attr.c533
-rw-r--r--win32/contrib/pthreads/barrier.c421
-rw-r--r--win32/contrib/pthreads/cancel.c388
-rw-r--r--win32/contrib/pthreads/cleanup.c138
-rw-r--r--win32/contrib/pthreads/condvar.c1219
-rw-r--r--win32/contrib/pthreads/config.guess940
-rw-r--r--win32/contrib/pthreads/config.h68
-rw-r--r--win32/contrib/pthreads/config.h.in61
-rw-r--r--win32/contrib/pthreads/config.sub956
-rw-r--r--win32/contrib/pthreads/configure1331
-rw-r--r--win32/contrib/pthreads/configure.in23
-rw-r--r--win32/contrib/pthreads/create.c261
-rw-r--r--win32/contrib/pthreads/dll.c85
-rw-r--r--win32/contrib/pthreads/errno.c82
-rw-r--r--win32/contrib/pthreads/exit.c91
-rw-r--r--win32/contrib/pthreads/fork.c29
-rw-r--r--win32/contrib/pthreads/global.c66
-rw-r--r--win32/contrib/pthreads/implement.h505
-rw-r--r--win32/contrib/pthreads/install-sh247
-rw-r--r--win32/contrib/pthreads/misc.c420
-rw-r--r--win32/contrib/pthreads/mutex.c784
-rw-r--r--win32/contrib/pthreads/need_errno.h132
-rw-r--r--win32/contrib/pthreads/nonportable.c248
-rw-r--r--win32/contrib/pthreads/private.c1022
-rw-r--r--win32/contrib/pthreads/pthread.def157
-rw-r--r--win32/contrib/pthreads/pthread.dsp207
-rw-r--r--win32/contrib/pthreads/pthread.dsw29
-rw-r--r--win32/contrib/pthreads/pthread.h1077
-rw-r--r--win32/contrib/pthreads/pthread.ncbbin0 -> 82944 bytes
-rw-r--r--win32/contrib/pthreads/pthread.optbin0 -> 48640 bytes
-rw-r--r--win32/contrib/pthreads/rwlock.c616
-rw-r--r--win32/contrib/pthreads/sched.c377
-rw-r--r--win32/contrib/pthreads/sched.h89
-rw-r--r--win32/contrib/pthreads/semaphore.c557
-rw-r--r--win32/contrib/pthreads/semaphore.h101
-rw-r--r--win32/contrib/pthreads/signal.c172
-rw-r--r--win32/contrib/pthreads/spin.c301
-rw-r--r--win32/contrib/pthreads/sync.c188
-rw-r--r--win32/contrib/pthreads/tsd.c333
59 files changed, 23227 insertions, 0 deletions
diff --git a/win32/contrib/pthreads/ANNOUNCE b/win32/contrib/pthreads/ANNOUNCE
new file mode 100644
index 000000000..dc80c680b
--- /dev/null
+++ b/win32/contrib/pthreads/ANNOUNCE
@@ -0,0 +1,525 @@
+ PTHREADS-WIN32 SNAPSHOT 2001-07-12
+ ----------------------------------
+ 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 Library
+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
+-------------------------------
+
+----------------------------------
+New: Spin locks (beta level code)
+----------------------------------
+These are part of POSIX 1003.1j.
+
+ #define _POSIX_SPIN_LOCKS
+ pthread_spin_init()
+ pthread_spin_destroy()
+ pthread_spin_lock()
+ pthread_spin_unlock()
+ pthread_spin_trylock()
+ PTHREAD_SPINLOCK_INITIALIZER
+
+Spin_lock spins (busy-waits) if more than one processor is available
+to the process, othewise it is equivalent to a POSIX_MUTEX_DEFAULT
+mutex. The spinlock routines do minimal error checking.
+
+--------------------------------
+New: Barriers (beta level code)
+--------------------------------
+These are part of POSIX 1003.1j.
+
+ #define _POSIX_BARRIERS
+ pthread_barrier_init()
+ pthread_barrier_destroy()
+ pthread_barrier_wait()
+ pthread_barrierattr_init()
+ pthread_barrierattr_destroy()
+ pthread_barrierattr_getpshared()
+ pthread_barrierattr_setpshared()
+
+---------
+Bug fixes
+---------
+In pthread_mutex_lock, return the error if an
+auto-initialiser initialisation fails.
+
+_POSIX_READER_WRITER_LOCKS is now defined.
+
+pthread_rwlock_wrlock() was a cancelation point.
+
+---------------------------
+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
+
+ 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_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
+
+ ---------------------------
+ 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_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 (returns an error ENOSYS)
+ pthread_attr_setscope (returns an error ENOSYS)
+ 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_win32_process_attach_np
+ pthread_win32_process_detach_np
+ pthread_win32_thread_attach_np
+ pthread_win32_thread_detach_np
+
+ ---------------------------
+ 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:
+You need gcc-2.95.2-1 modified as per pthreads-win32 FAQ answer (6), with
+binutils-19990818-1 and msvcrt runtime-2000-03-27. Mingw32 must use
+the thread-safe MSVCRT library (see the FAQ). You need to distribute
+the gcc.dll DLL from Mingw32 with your application.
+
+Mingw using C++ EH works. Distribute pthreadGCE.dll with your application.
+Mingw using C setjmp/longjmp works. Distribute pthreadGC.dll with your application.
+
+
+Cygwin: (http://sourceware.cygnus.com/cygwin/)
+Cygwin aims to provide a complete POSIX environment on top of Win32, including
+threads. When this is complete, developers using Cygwin will not need
+pthreads-win32. At this time, Cygwin has preliminary support for multithreaded
+development, however, this is not turned on by default. We have not tested
+pthreads-win32 against Cygwin.
+
+
+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/win32/contrib/pthreads/CONTRIBUTORS b/win32/contrib/pthreads/CONTRIBUTORS
new file mode 100644
index 000000000..91cdb7373
--- /dev/null
+++ b/win32/contrib/pthreads/CONTRIBUTORS
@@ -0,0 +1,36 @@
+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
+
diff --git a/win32/contrib/pthreads/COPYING.LIB b/win32/contrib/pthreads/COPYING.LIB
new file mode 100644
index 000000000..0eaebbf57
--- /dev/null
+++ b/win32/contrib/pthreads/COPYING.LIB
@@ -0,0 +1,482 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/win32/contrib/pthreads/ChangeLog b/win32/contrib/pthreads/ChangeLog
new file mode 100644
index 000000000..5061a515c
--- /dev/null
+++ b/win32/contrib/pthreads/ChangeLog
@@ -0,0 +1,3304 @@
+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 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ Contributed by - Alexander Terekhov.
+
+ * 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 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ Contributed by - 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 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ Contributed by - 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 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ Contributed by - 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 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ Contributed by - 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 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ Contributed by - 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 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ Contributed by - 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 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * misc.c (pthread_self): Restore Win32 "last error"
+ cleared by TlsGetValue() call in
+ pthread_getspecific()
+ - "Steven Reddie" <smr@essemer.com.au>
+
+2000-09-20 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * 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.
+ - reported by Arthur Kantor <akantor@bexusa.com>
+
+2000-09-13 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+
+ * 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
+ - "Jef Gearhart" <jgearhart@tpssys.com>
+
+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 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * sched.c (sched_get_priority_max): Handle different WinCE and
+ Win32 priority values together.
+ (sched_get_priority_min): Ditto.
+ - Tristan Savatier <tristan@mpegtv.com>
+
+ * create.c (pthread_create): Force new threads to wait until
+ pthread_create has the new thread's handle; we also retain
+ a local copy of the handle for internal use until
+ pthread_create returns.
+
+ * private.c (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 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.)
+
+ * 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.
+ - "David Baggett" <dmb@itasoftware.com>
+
+ * 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 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * Makefile: Remove inconsistencies in 'cl' args
+ - Erik Hensema <erik.hensema@group2000.nl>
+
+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.
+
+ * 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.
+ - Jason Nye <jnye@nbnet.nb.ca>
+ - Erik Hensema <erik.hensema@group2000.nl>
+
+1999-11-13 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * configure.in (AC_OUTPUT): Put generated output into GNUmakefile
+ rather than Makefile. Makefile will become the MSC nmake compatible
+ version
+ - Erik Hensema <erik.hensema@group2000.nl>
+
+ * misc.c (pthread_self): Add a note about GetCurrentThread
+ returning a pseudo-handle
+ - John Bossom (John.Bossom@cognos.com>
+
+1999-11-10 Ross Johnson <rpj@ixobrychus.canberra.edu.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.
+ - Todd Owen <towen@lucidcalm.dropbear.id.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 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * 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.
+ - Tristan Savatier <tristan@mpegtv.com>
+
+1999-10-30 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * 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:
+ - Erik Hensema <erik.hensema@group2000.nl>
+
+1999-10-23 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (ctime_r): Fix incorrect argument "_tm"
+ - Erik Hensema <erik.hensema@group2000.nl>
+
+1999-10-21 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * 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
+ - Aurelio Medina <aureliom@crt.com>
+
+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 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * 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.
+ - Lorin Hochstein <lmh@xiphos.ca> and
+ Peter Slacik <Peter.Slacik@tatramed.sk>;
+ the last waiter will now reset the CV's wasBroadcast flag
+ - Graham Dumpleton <Graham.Dumpleton@ra.pad.otc.telstra.com.au>.
+
+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.
+
+Sat Sep 10 12:56:13 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ The following code for POSIX read/write locks was contributed
+ by Aurelio Medina.
+
+ * 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.
+
+Wed Sep 8 12:56:13 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * mutex.c (pthread_mutex_destroy): Free mutex memory.
+ - Milan Gardian <mg@tatramed.sk>
+
+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 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * exit.c (pthread_exit): Put status into pthread_t->exitStatus
+ - John Bossom <john.Bossom@cognos.com>
+ * private.c (ptw32_threadStart): Set pthread->exitStatus
+ on exit of try{} block.
+ - John Bossom <john.Bossom@cognos.com>
+ * 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).
+ - John Bossom <john.Bossom@cognos.com>
+
+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 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * 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.
+ - Peter Slacik <Peter.Slacik@tatramed.sk>
+
+1999-07-09 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ The following changes fix a bug identified by
+ Lorin Hochstein <lmh@xiphos.ca> and solved by
+ 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.
+
+
+ * 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 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * condvar.c (pthread_cond_broadcast): Fix possible memory fault
+ - Mark E. Armstrong <avail@pacbell.net>
+
+Thu May 27 13:08:46 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * condvar.c (pthread_cond_broadcast): Fix logic bug
+ - Peter Slacik <Peter.Slacik@tatramed.sk>;
+ optimise sem_post loop
+ - Bossom, John <John.Bossom@Cognos.COM>.
+
+Fri May 14 12:13:18 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * attr.c (pthread_attr_setdetachstate): Fix logic bug
+ - Mike Russo <miker@eai.com>.
+
+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.
+
+ * pthread.h (ptw32_sem_t): Change to sem_t.
+
+ * semaphore.c (ptw32_sem_*): Change to sem_*; these functions
+ will be exported from the library; set errno on error.
+ - John Bossom <jebossom@cognos.com>
+ (ptw32_sem_timedwait): Moved to private.c.
+
+ * private.c (ptw32_sem_timedwait): Moved from semaphore.c;
+ set errno on error.
+
+ * errno.c (_errno): New file. New function.
+ - John Bossom
+
+ * pthread.h (pthread_t_): Add per-thread errno element.
+
+Fri Mar 26 14:11:45 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * semaphore.c (ptw32_sem_timedwait): Check for negative
+ milliseconds.
+ - Tor Lillqvist <tml@iki.fi>
+
+Wed Mar 24 11:32:07 1999 Ross Johnson <rpj@swan.canberra.edu.au>
+
+ * misc.c (CancelableWait): Initialise exceptionInformation[2].
+ (pthread_self): Get a real Win32 thread handle for implicit threads.
+ - John Bossom <jebossom@cognos.com>
+
+ * cancel.c (pthread_testcancel): Initialise exceptionInformation[2].
+ - John Bossom <jebossom@cognos.com>
+
+ * implement.h (SE_INFORMATION): Fix values.
+ - John Bossom <jebossom@cognos.com>
+
+ * private.c (ptw32_threadDestroy): Close the thread handle.
+ - John Bossom <jebossom@cognos.com>
+
+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.
+
+ * 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().
+ - Scott Lightner <scott@curriculum.com>
+
+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 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * dll.c: The Microsoft compiler pragmas probably are more
+ appropriately protected by _MSC_VER than by _WIN32.
+ - Tor Lillqvist <tml@iki.fi>.
+
+ * condvar.c (pthread_cond_timedwait): Fix function description
+ comments.
+
+ * 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.
+ - Tor Lillqvist <tml@iki.fi>.
+
+ * pthread.def: pthread_mutex_destroy was missing from the def file
+ - Tor Lillqvist <tml@iki.fi>.
+
+ * 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.
+ - Tor Lillqvist <tml@iki.fi>.
+
+ * 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 Ben Elliston <bje@cygnus.com>
+
+ * condvar.c (pthread_cond_init): Invert logic when testing the
+ return value from calloc().
+ - Tor Lillqvist <tml@iki.fi>.
+
+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 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * semaphore.c: Initial version. From John Bossom's implementation.
+ * semaphore.h: Initial version. From John Bossom's implementation.
+
+Mon Dec 28 09:54:39 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * pthread.h (pthread_attr_t_): Change to *pthread_attr_t.
+
+ * attr.c (pthread_attr_setstacksize): Merge with John Bossom's version.
+ (pthread_attr_getstacksize): Merge with John Bossom's version.
+ (pthread_attr_setstackaddr): Merge with John Bossom's version.
+ (pthread_attr_getstackaddr): Merge with John Bossom's version.
+ (pthread_attr_init): Merge with John Bossom's version.
+ (pthread_attr_destroy): Merge with John Bossom's version.
+ (pthread_attr_getdetachstate): Merge with John Bossom's version.
+ (pthread_attr_setdetachstate): Merge with John Bossom's version.
+ (is_attr): attr is now **attr (was *attr), so add extra NULL pointer
+ test.
+
+ * 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 Ross Johnson <rpj@ixobrychus.canberra.edu.au>
+
+ * cancel.c (pthread_setcancelstate): Replaced by John Bossom's version.
+ (pthread_setcanceltype): Replaced by John Bossom's version.
+ (pthread_testcancel): Replaced by John Bossom's version.
+ (pthread_cancel): Replaced by John Bossom's version.
+
+ * exit.c (pthread_exit): Replaced by John Bossom's version.
+
+ * misc.c (pthread_self): Replaced by John Bossom's version.
+ (pthread_equal): Replaced by John Bossom's version.
+
+ * sync.c (pthread_detach): Replaced by John Bossom's version.
+ (pthread_join): Replaced by John Bossom's version.
+
+ * create.c (pthread_create): Replaced by John Bossom's version.
+
+ * private.c (ptw32_processInitialize): New by John Bossom.
+ (ptw32_processTerminate): Non-public function by John Bossom.
+ (ptw32_threadStart): Non-public function by John Bossom.
+ (ptw32_threadDestroy): Non-public function by John Bossom.
+ (ptw32_cleanupStack): Non-public function by John Bossom.
+ (ptw32_tkAssocCreate): Non-public function by John Bossom.
+ (ptw32_tkAssocDestroy): Non-public function by John Bossom.
+ (ptw32_callUserDestroyRoutines): Non-public function by John Bossom.
+
+ * implement.h: Added John Bossom's non-API structures and
+ declarations.
+
+ * dll.c (PthreadsEntryPoint): Cast return value of GetProcAddress
+ to resolve compile warning from MSVC.
+
+ * dll.c (DLLmain): Replaced by John Bossom's version.
+ * 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/win32/contrib/pthreads/FAQ b/win32/contrib/pthreads/FAQ
new file mode 100644
index 000000000..44ae761fe
--- /dev/null
+++ b/win32/contrib/pthreads/FAQ
@@ -0,0 +1,390 @@
+ =========================================
+ PTHREADS-WIN32 Frequently Asked Questions
+ =========================================
+
+INDEX
+-----
+
+Q 1 Should I use Cygwin or Mingw32 as a development environment?
+
+Q 2 Now that pthreads-win32 builds under Mingw32, why do I get
+ memory access violations?
+
+Q 3 How do I use pthread.dll for Win32 (Visual C++ 5.0)
+
+Q 4 Cancelation doesn't work for me, why?
+
+Q 5 Thread won't block after two calls to mutex_lock
+
+Q 6 How do I generate pthreadGCE.dll and libpthreadw32.a for use with Mingw32?
+
+=============================================================================
+
+Q 1 Should I use Cygwin or Mingw32 as a development environment?
+---
+
+A 1
+---
+Important: see Q2 also.
+
+In short, use Mingw32 with the MSVCRT library to build applications that use
+the DLL. Cygwin's own internal support for POSIX threads is growing. Consult
+that project's documentation for more information.
+
+Date: Mon, 07 Dec 1998 15:11:37 +0100
+From: Anders Norlander <anorland@hem2.passagen.se>
+To: Ross Johnson <rpj@ise.canberra.edu.au>
+Cc: pthreads-win32 <pthreads-win32@air.net.au>
+Subject: Re: pthreads-win32: TryEnterCriticalSection patch (fwd)
+
+Ross Johnson wrote:
+>
+> Anders,
+>
+> You said you're using GCC. Is that from cygwin32 or mingw32? What is your
+> environment (so I can perhaps help other people out)? We have problems
+> with cygwin32 et al that have been built on Win95. They're missing
+> _{begin,end}threadex.
+
+Ross,
+
+I use mingw32 when compiling pthreads-win32, but unlike most people I
+use MSVCRT as the C library instead of CRTDLL. For those that don't
+feel like configuring and building the necessary components themselves,
+Mumit Khan has released an add on for mingw32 to make it use MSVCRT40.
+It is available at his ftp site, follow the minw32 links at
+http://www.xraylith.wisc.edu/~khan/software/gnu-win32/
+
+For cygwin it is a completely different matter. I suppose
+pthreads-win32 uses _beginthreadex and _endthreadex because the Win32
+docs say that programs calling functions in the C library should not
+use CreateThread and ExitThread. However, this applies only to
+Microsoft's (and possibly others) multithreaded C libraries that need
+to keep track of per thread data, it does not apply to cygwin.
+This code solves the problem:
+
+/* Check for old and new versions of cygwin */
+#if defined(__CYGWIN32__) || defined(__CYGWIN__)
+/* Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE
+ in order to avoid warnings because of return type */
+#define _beginthreadex(security, stack_size, start_proc, arg, flags,
+pid) \
+CreateThread(security, stack_size, (LPTHREAD_START_ROUTINE) start_proc,
+\
+ arg, flags, pid)
+#define _endthreadex ExitThread
+#endif
+
+I would be extremely careful using threads with cygwin, since it is
+not (yet) threadsafe.
+
+Regards,
+Anders
+
+------------------------------------------------------------------------------
+
+Q 2 Now that pthreads-win32 builds under Mingw32, why do I get
+--- memory access violations (segfaults)?
+
+A 2
+---
+Note: issue resolved.
+The latest Mingw32 package has thread-safe exception handling.
+Make sure you also read A 6 below to get a fully working build.
+
+
+The following email exchange describes the problem. Until this issue
+is resolved people without the Microsoft compiler can obtain the current
+MSVC prebuilt DLL (pthread.{dll,lib,h}) at:
+
+ftp://sources.redhat.com/pub/pthreads-win32/dll-latest
+
+Date: Wed, 10 Feb 1999 13:21:01 -0000
+From: "Ruland, Kevin" <Kevin.Ruland@anheuser-busch.com>
+Reply-To: POSIX threads on Win32 <pthreads-win32@air.net.au>
+To: 'POSIX threads on Win32' <pthreads-win32@air.net.au>
+Subject: Mingw32 exceptions not thread safe.
+
+Hello everyone.
+
+I asked Mumit Khan, maintainer of egcs for mingw and assorted guru, about
+the Known Problem listed below.
+
+> Known problems
+> --------------
+>
+> There is an unresolved bug which shows up as a segmentation fault
+> (memory access violation) when the library is built using g++. Build
+> the test program "eyal1.c" and run with an argument of "2" or
+> greater. The argument is the number of threads to run, excluding the
+> main thread, so the bug appears with 2 or more worker threads.
+>
+> Kevin Ruland has traced the exception to the try/catch blocks in
+> ptw32_threadStart().
+>
+
+The official word is:
+
+<Quote Mumit Khan [khan@xraylith.wisc.edu]>
+EGCS-1.1.1 for win32 (either cygwin or crtdll/msvc runtimes) do not have
+thread-safe exception support.
+
+For Cygwin, it'll happen when Cygwin runtime has mature thread safety and
+pthread is fully integrated. Then it's just a matter of rebuilding GCC (or
+just libgcc in this) with thread safe EH support.
+
+For Mingw crtdll/msvc, someone needs to write the thread-wrapper for win32
+threads. Anyone who knows win32 threads should be able to do this without
+much trouble at all. It's low on my priority list, so unless someone else
+volunteers, it'll have to wait.
+<\Quote>
+
+Kevin
+
+------------------------------------------------------------------------------
+
+Q 3 How do I use pthread.dll for Win32 (Visual C++ 5.0)
+---
+
+A 3
+---
+>
+> 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.
+
+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 4 Cancelation doesn't work for me, why?
+---
+
+A 4
+---
+> 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 5 Thread won't block after two calls to mutex_lock
+---
+
+A 5
+---
+> i was testing this pthread for win32 in my prog.
+> when i checked if it was blocking mutex_lock calls, i was surprised when it
+> didnt lock
+>
+> pthread_mutex_t DBlock;
+>
+> pthread_mutex_init( &DBlock, NULL );
+> pthread_mutex_lock( &DBlock );
+> pthread_mutex_lock( &DBlock );
+>
+> ^^ these two calls didnt block
+
+POSIX leaves the result "undefined" for a thread that tries
+to recursively lock the same mutex (one that it owns already).
+That means the actual semantics are left up to the
+implementation, but should not be relied upon for code that
+will be ported to different POSIX threads implementations.
+
+In the pthreads-win32 implementation a thread won't deadlock
+itself by relocking the mutex. Subsequent calls to
+pthread_mutex_lock() as in your example above increment
+the lock count but the thread continues on. Consequently,
+the thread must ensure that it unlocks the mutex once for
+each lock operation. That is, pthreads-win32 mutexes are
+always recursive.
+
+You may want to look at the other synchronisation devices
+available in the library, such as condition variables or
+read-write locks.
+
+Ross
+
+------------------------------------------------------------------------------
+
+Q 6 How do I generate pthreadGCE.dll and libpthreadw32.a for use with Mingw32?
+---
+
+A 6
+---
+Once you've followed Thomas Pfaff's instructions below to fix
+Mingw32, then you can simply run "make" to build the library and dll.
+
+
+From - Sat Dec 9 22:56:10 2000
+From: "Thomas Pfaff" <tpfaff@gmx.net>
+To: <mingw-users@lists.sourceforge.net>, <pthreads-win32@sources.redhat.com>
+Subject: mingw32 DLLs, threads and exceptions HOWTO
+Date: Thu, 7 Dec 2000 11:12:43 +0100
+
+Dear all,
+
+this is a summary that should help users to have thread safe exception
+handling over DLL exported functions.
+If you don't care about c++ exceptions you can stop reading here.
+
+The first time i struggled with c++ exceptions was when i tried to throw an
+exception in a dll exported function where the exception handler resides in
+the program module.
+Instead of catching the exception the program stopped with an abnormal
+termination.
+The reason was that the exception code is in libgcc.a. Since this is a
+static library the code and some static variables are both in the dll and in
+the program module, each module runs in its own context.
+It was Franco Bez that pointed me in the right direction, that is convert
+libgcc.a into a dll.
+
+That done i tried to build the pthreads-win32 library, but some tests failed
+with an access violation. Due to the fact that the dll was not build
+was -mthreads support, eh_context_static instead of eh_context_specific (the
+mthreads version) was used for exception handling.
+I did a rebuild of the gcc dll with -mthreads, now all tests are passed
+(except a nonportable exception test that relies on a MSVC feature).
+
+To build the gcc dll i did the following steps.
+
+1. create a temporary directory libgcc
+2. copy libgcc.a from gcc-2.95.2\lib\gcc-lib\i386-mingw32\gcc-2.95.2 to that
+directory
+3. ar -x libgcc.a
+4. create a directory tmp and move __main.o, _exit.o and __dummy.o in that
+directory
+5. build the dll
+gcc -shared -mthreads -o gcc.dll *.o
+strip gcc.dll
+Move this dll into your gcc\bin directory
+6. Move _chkstk.o and frame.o to the tmp directory, otherwise you break the
+builtin alloca.
+7. Build the import library libgcc.a
+dllwrap --export-all --dllname=gcc.dll --output-def=libgcc.def --output-lib=
+libgcc.a *.o
+ar -q libgcc.a tmp/*.o
+strip --strip-debug libgcc.a
+ranlib libgcc.a
+8. save your old libgcc.a, copy the new libgcc.a into
+gcc-2.95.2\lib\gcc-lib\i386-mingw32\gcc-2.95.2
+
+I am using gcc-2.95.2-1 with Mumits patched binutils-19990818-1and msvcrt
+runtime-2000-03-27.
+I don't know if this is still required with the current binutils and gcc
+since i have seen no sources until now.
+
+I believe that these steps are at least necessary if you are trying to use
+the pthreads-win32 library (which is required if you want to use gtk+ on
+win32).
+They will make mingw32 a real replacement for MSVC (at least for me).
+
+What is left:
+
+1. Include the mingwm10.dll function into the gcc.dll to have only one dll
+left.
+2. make -mthreads and -fnative-struct default compiler options.
+3. convert libstdc++ to a dll by adding the declspec dllexport and dllimport
+to every class definition.
+
+Regards,
+ Thomas
+
+------------------------------------------------------------------------------
+
diff --git a/win32/contrib/pthreads/GNUmakefile b/win32/contrib/pthreads/GNUmakefile
new file mode 100644
index 000000000..589d89966
--- /dev/null
+++ b/win32/contrib/pthreads/GNUmakefile
@@ -0,0 +1,109 @@
+#
+# Pthreads-win32 - POSIX Threads Library for Win32
+# Copyright (C) 1998
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA
+#
+
+#RM = rm
+#MV = mv
+#CP = cp
+
+RM = erase
+MV = rename
+CP = copy
+
+CC = gcc
+CXX = g++
+
+AR = ar
+
+OPT = -O3
+#OPT = -O2 -DNDEBUG -finline-functions
+
+GC_CFLAGS = -D__CLEANUP_C
+GCE_CFLAGS = -D__CLEANUP_CXX -x c++ -mthreads
+
+## Mingw32
+MAKE = make
+CFLAGS = $(OPT) -I. -D_WIN32_WINNT=0x400 -DHAVE_CONFIG_H -DPTW32_BUILD -Wall
+
+## Cygwin G++
+#CFLAGS = $(OPT) -x $(GLANG) -fhandle-exceptions -D_WIN32_WINNT=0x400 -I. -DHAVE_CONFIG_H -DPTW32_BUILD -Wall
+
+OBJS = attr.o barrier.o cancel.o cleanup.o condvar.o create.o dll.o errno.o \
+ exit.o fork.o global.o misc.o mutex.o nonportable.o \
+ private.o rwlock.o sched.o semaphore.o signal.o spin.o sync.o tsd.o
+
+INCL = implement.h semaphore.h pthread.h windows.h
+
+GC_DLL = pthreadGC.dll
+GCE_DLL = pthreadGCE.dll
+
+GC_LIB = libpthreadGC.a
+GCE_LIB = libpthreadGCE.a
+
+
+all:
+ @ echo Run one of the following command lines:
+ @ echo make clean GCE (to build the GNU C dll with C++ exception handling)
+ @ echo make clean GC (to build the GNU C dll with C cleanup code)
+
+auto:
+ @ $(MAKE) clean GCE
+ @ $(MAKE) clean GC
+
+GC:
+ $(MAKE) CLEANUP_FLAGS="$(GC_CFLAGS)" $(GC_DLL)
+
+GCE:
+ $(MAKE) CLEANUP_FLAGS="$(GCE_CFLAGS)" $(GCE_DLL)
+
+tests:
+ @ cd tests
+ @ $(MAKE) auto
+
+%.pre: %.c
+ $(CC) -E -o $@ $(CFLAGS) $^
+
+%.s: %.c
+ $(CC) -c $(CFLAGS) -Wa,-ahl $^ > $@
+
+.SUFFIXES: .dll .c .o
+
+.c.o:; $(CC) -c -o $@ $(CFLAGS) $(CLEANUP_FLAGS) $<
+
+
+$(GC_DLL): $(OBJS)
+ $(CC) $(OPT) -shared -o $@ $^
+ dlltool -k --dllname $@ --output-lib $(GC_LIB) --def pthread.def
+
+$(GCE_DLL): $(OBJS)
+ $(CXX) $(OPT) -mthreads -shared -o $@ $^
+ dlltool -k --dllname $@ --output-lib $(GCE_LIB) --def pthread.def
+
+clean:
+ -$(RM) *~
+ -$(RM) *.o
+ -$(RM) *.exe
+
+realclean: clean
+ -$(RM) $(GC_LIB)
+ -$(RM) $(GCE_LIB)
+ -$(RM) $(GC_DLL)
+ -$(RM) $(GCE_DLL)
+
+
diff --git a/win32/contrib/pthreads/MAINTAINERS b/win32/contrib/pthreads/MAINTAINERS
new file mode 100644
index 000000000..5b04e43f8
--- /dev/null
+++ b/win32/contrib/pthreads/MAINTAINERS
@@ -0,0 +1,4 @@
+CVS Repository maintainers
+
+Ross Johnson rpj@ise.canberra.edu.au
+Ben Elliston bje@cygnus.com
diff --git a/win32/contrib/pthreads/Makefile b/win32/contrib/pthreads/Makefile
new file mode 100644
index 000000000..723fa2b0d
--- /dev/null
+++ b/win32/contrib/pthreads/Makefile
@@ -0,0 +1,90 @@
+
+# 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\dll
+
+DLLDEST=$(DEVROOT)
+LIBDEST=$(DEVROOT)
+
+DLLS = pthreadVCE.dll pthreadVSE.dll pthreadVC.dll
+
+# C++ Exceptions
+VCEFLAGS = /GX /TP /DPtW32NoCatchWarn /D__CLEANUP_CXX
+#Structured Exceptions
+VSEFLAGS = /D__CLEANUP_SEH
+#C cleanup code
+VCFLAGS = /D__CLEANUP_C
+
+CFLAGS = /W3 /MT /nologo /Yd /Zi /I. /D_WIN32_WINNT=0x400 /DPTW32_BUILD
+
+OBJ= 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
+
+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): $(OBJ) pthread.def
+ cl /LD /Zi /nologo $(OBJ) \
+ /link /nodefaultlib:libcmt /implib:$*.lib \
+ msvcrt.lib /def:pthread.def /out:$@
+
+.c.obj:
+ cl $(EHFLAGS) $(CFLAGS) -c $<
diff --git a/win32/contrib/pthreads/Makefile.in b/win32/contrib/pthreads/Makefile.in
new file mode 100644
index 000000000..62c720104
--- /dev/null
+++ b/win32/contrib/pthreads/Makefile.in
@@ -0,0 +1,69 @@
+#
+# Pthreads-win32 - POSIX Threads Library for Win32
+# Copyright (C) 1998
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA
+#
+
+RM = erase
+
+CC = g++
+
+AR = ar
+
+LD = gcc -mdll -mthreads
+
+OPT = -g -O2
+
+## Mingw32
+CFLAGS = $(OPT) -I. -DHAVE_CONFIG_H -Wall -mthreads
+
+## Cygwin G++
+#CFLAGS = $(OPT) -fhandle-exceptions -I. -DHAVE_CONFIG_H -Wall
+
+OBJS = attr.o cancel.o cleanup.o condvar.o create.o dll.o errno.o \
+ exit.o fork.o global.o misc.o mutex.o private.o rwlock.o \
+ sched.o semaphore.o signal.o sync.o tsd.o
+
+INCL = implement.h semaphore.h pthread.h windows.h
+
+DLL = pthread.dll
+
+LIB = libpthread32.a
+
+
+all: $(LIB)
+
+$(LIB): $(DLL)
+ dlltool --def $(DLL:.dll=.def) --output-lib $@ --dllname $(DLL)
+
+.SUFFIXES: .dll
+
+$(DLL): $(OBJS)
+ $(LD) -o $@ $^ -Wl,--base-file,$*.base
+ dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@
+ $(LD) -o $@ $^ -Wl,--base-file,$*.base,$*.exp
+ dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@
+ $(LD) -o $@ $^ -Wl,$*.exp
+
+clean:
+ -$(RM) *~
+ -$(RM) $(LIB)
+ -$(RM) *.o
+ -$(RM) *.exe
+ -$(RM) $(DLL)
+ -$(RM) $(DLL:.dll=.base)
+ -$(RM) $(DLL:.dll=.exp)
diff --git a/win32/contrib/pthreads/NEWS b/win32/contrib/pthreads/NEWS
new file mode 100644
index 000000000..b52c0c602
--- /dev/null
+++ b/win32/contrib/pthreads/NEWS
@@ -0,0 +1,118 @@
+SNAPSHOT 2000-08-13
+-------------------
+
+New:
+- Renamed DLL and LIB files:
+ pthreadVSE.dll (MS VC++/Structured EH)
+ pthreadVSE.lib
+ pthreadVCE.dll (MS VC++/C++ EH)
+ pthreadVCE.lib
+ pthreadGCE.dll (GNU G++/C++ EH)
+ libpthreadw32.a
+
+ Both your application and the pthread dll should use the
+ same exception handling scheme.
+
+Bugs fixed:
+- MSVC++ C++ exception handling.
+
+Some new tests have been added.
+
+
+SNAPSHOT 2000-08-10
+-------------------
+
+New:
+- asynchronous cancelation on X86 (Jason Nye)
+- Makefile compatible with MS nmake to replace
+ buildlib.bat
+- GNUmakefile for Mingw32
+- tests/Makefile for MS nmake replaces runall.bat
+- tests/GNUmakefile for Mingw32
+
+Bugs fixed:
+- kernel32 load/free problem
+- attempt to hide internel exceptions from application
+ exception handlers (__try/__except and try/catch blocks)
+- Win32 thread handle leakage bug
+ (David Baggett/Paul Redondo/Eyal Lebedinsky)
+
+Some new tests have been added.
+
+
+SNAPSHOT 1999-11-02
+-------------------
+
+Bugs fixed:
+- ctime_r macro had an incorrect argument (Erik Hensema),
+- threads were not being created
+ PTHREAD_CANCEL_DEFERRED. This should have
+ had little effect as deferred is the only
+ supported type. (Ross Johnson).
+
+Some compatibility improvements added, eg.
+- pthread_setcancelstate accepts NULL pointer
+ for the previous value argument. Ditto for
+ pthread_setcanceltype. This is compatible
+ with Solaris but should not affect
+ standard applications (Erik Hensema)
+
+Some new tests have been added.
+
+
+SNAPSHOT 1999-10-17
+-------------------
+
+Bug fix - Cancelation of threads waiting on condition variables
+now works properly (Lorin Hochstein and Peter Slacik)
+
+
+SNAPSHOT 1999-08-12
+-------------------
+
+Fixed exception stack cleanup if calling pthread_exit()
+- (Lorin Hochstein and John Bossom).
+
+Fixed bugs in condition variables - (Peter Slacik):
+ - additional contention checks
+ - properly adjust number of waiting threads after timed
+ condvar timeout.
+
+
+SNAPSHOT 1999-05-30
+-------------------
+
+Some minor bugs have been fixed. See the ChangeLog file for details.
+
+Some more POSIX 1b functions are now included but ony return an
+error (ENOSYS) if called. They are:
+
+ sem_open
+ sem_close
+ sem_unlink
+ sem_getvalue
+
+
+SNAPSHOT 1999-04-07
+-------------------
+
+Some POSIX 1b functions which were internally supported are now
+available as exported functions:
+
+ sem_init
+ sem_destroy
+ sem_wait
+ sem_trywait
+ sem_post
+ sched_yield
+ sched_get_priority_min
+ sched_get_priority_max
+
+Some minor bugs have been fixed. See the ChangeLog file for details.
+
+
+SNAPSHOT 1999-03-16
+-------------------
+
+Initial release.
+
diff --git a/win32/contrib/pthreads/Nmakefile b/win32/contrib/pthreads/Nmakefile
new file mode 100644
index 000000000..53b11aae7
--- /dev/null
+++ b/win32/contrib/pthreads/Nmakefile
@@ -0,0 +1,24 @@
+/*
+ * nmake file for uwin pthread library
+ */
+
+VERSION = -
+CCFLAGS = -V -g $(CC.DLL)
+PTW32_BUILD == 1
+_MT == 1
+_timeb == timeb
+_ftime == ftime
+_errno == _ast_errno
+
+$(INCLUDEDIR) :INSTALLDIR: pthread.h sched.h
+
+pthread $(VERSION) :LIBRARY: pthread.def attr.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 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/win32/contrib/pthreads/Nmakefile.tests b/win32/contrib/pthreads/Nmakefile.tests
new file mode 100644
index 000000000..109a99563
--- /dev/null
+++ b/win32/contrib/pthreads/Nmakefile.tests
@@ -0,0 +1,167 @@
+/* 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
+equal1:: equal1.c
+exit2:: exit2.c
+exit3:: exit3.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
+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
+
+loadfree: :test:
+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
+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
+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
+exception1 :test: cancel4
+exception2 :test: exception1
+exception3 :test: exception2
+
diff --git a/win32/contrib/pthreads/PROGRESS b/win32/contrib/pthreads/PROGRESS
new file mode 100644
index 000000000..c85f3b185
--- /dev/null
+++ b/win32/contrib/pthreads/PROGRESS
@@ -0,0 +1,4 @@
+Please see the ANNOUNCE file "Level of Standards Conformance"
+or the web page:
+
+http://sourceware.cygnus.com/pthreads-win32/conformance.html
diff --git a/win32/contrib/pthreads/README b/win32/contrib/pthreads/README
new file mode 100644
index 000000000..cce698fc9
--- /dev/null
+++ b/win32/contrib/pthreads/README
@@ -0,0 +1,269 @@
+PTHREADS-WIN32
+==============
+
+Pthreads-win32 is free software, distributed under the GNU Library
+General Public License (LGPL). See the file 'COPYING.LIB' for terms
+and conditions.
+
+
+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.
+
+
+Library naming
+--------------
+
+Because the library is being built using various exception
+handling schemes and compilers - and because the library
+will not work reliably if these are mixed in an application,
+each different version of the library has it's own name.
+
+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.
+
+
+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
+
+
+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
+
+
+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 6.
+
+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/win32/contrib/pthreads/README.CV b/win32/contrib/pthreads/README.CV
new file mode 100644
index 000000000..522fa602b
--- /dev/null
+++ b/win32/contrib/pthreads/README.CV
@@ -0,0 +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! :)
+
diff --git a/win32/contrib/pthreads/README.NONPORTABLE b/win32/contrib/pthreads/README.NONPORTABLE
new file mode 100644
index 000000000..5095d47ce
--- /dev/null
+++ b/win32/contrib/pthreads/README.NONPORTABLE
@@ -0,0 +1,109 @@
+Non-portable functions included in pthreads-win32
+-------------------------------------------------
+
+HANDLE
+pthread_getw32threadhandle_np(pthread_t thread);
+
+ 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.
+
+
+int
+pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind)
+
+int
+pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind)
+
+ These two routines are included for Linux compatibility
+ and are direct equivalents to the standard routines
+ pthread_mutexattr_settype
+ pthread_mutexattr_gettype
+
+ pthread_mutexattr_setkind_np accepts the following
+ mutex kinds:
+ PTHREAD_MUTEX_FAST_NP
+ PTHREAD_MUTEX_ERRORCHECK_NP
+ PTHREAD_MUTEX_RECURSIVE_NP
+
+ These are really just equivalent to (respectively):
+ PTHREAD_MUTEX_NORMAL
+ PTHREAD_MUTEX_ERRORCHECK
+ PTHREAD_MUTEX_RECURSIVE
+
+int
+pthread_delay_np (const struct timespec *interval);
+
+ 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.
+
+ This routine is a cancelation point.
+
+ 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.
+
+
+BOOL
+pthread_win32_process_attach_np (void);
+
+BOOL
+pthread_win32_process_detach_np (void);
+
+BOOL
+pthread_win32_thread_attach_np (void);
+
+BOOL
+pthread_win32_thread_detach_np (void);
+
+ These functions contain the code normally run via dllMain
+ when the library is used as a dll but which need to be
+ called explicitly by an application when the library
+ is statically linked.
+
+ You will need to call pthread_win32_process_attach_np() before
+ you can call any pthread routines when statically linking.
+ You should call pthread_win32_process_detach_np() before
+ exiting your application to clean up.
+
+ pthread_win32_thread_attach_np() is currently a no-op, but
+ pthread_win32_thread_detach_np() is needed to clean up
+ after Win32 threads that have called pthreads routines
+ have exited.
+
+ These functions invariably return TRUE except for
+ pthread_win32_process_attach_np() which will return FALSE
+ if pthreads-win32 initialisation fails.
+
+
+int
+pthreadCancelableWait (HANDLE waitHandle);
+
+int
+pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout);
+
+ These two functions provide hooks into the pthread_cancel
+ mechanism that will allow you to wait on a Windows handle
+ and make it a cancellation point. Both functions block
+ until either the given w32 handle is signaled, or
+ pthread_cancel has been called. It is implemented using
+ WaitForMultipleObjects on 'waitHandle' and a manually
+ reset w32 event used to implement pthread_cancel.
diff --git a/win32/contrib/pthreads/README.WinCE b/win32/contrib/pthreads/README.WinCE
new file mode 100644
index 000000000..1e0642971
--- /dev/null
+++ b/win32/contrib/pthreads/README.WinCE
@@ -0,0 +1,6 @@
+WinCE port
+----------
+(See the file WinCE-PORT for a detailed explanation.)
+
+Make sure you define "WINCE" amongst your compiler flags (eg. -DWINCE).
+The config.h file will define all the necessary defines for you.
diff --git a/win32/contrib/pthreads/TODO b/win32/contrib/pthreads/TODO
new file mode 100644
index 000000000..de6de9238
--- /dev/null
+++ b/win32/contrib/pthreads/TODO
@@ -0,0 +1,20 @@
+====
+Automate the build/test cycle so that I can
+expand to test both library and applications in different
+environments and cross-environments.
+
+Eg.
+ Applications | SEH | C++ | G++ | C | GCC |
+ Library | | | | | |
+ ----------------+-----+-----+-----+-----+-----+
+ SEH | X | X | X | X | X |
+ ----------------+-----+-----+-----+-----+-----+
+ C++ (MSC) | X | X | X | X | X |
+ ----------------+-----+-----+-----+-----+-----+
+ G++ (GNU) | ? | ? | X | ? | X |
+ ----------------+-----+-----+-----+-----+-----+
+
+'?' indicates combinations that may not be doable.
+
+====
+
diff --git a/win32/contrib/pthreads/WinCE-PORT b/win32/contrib/pthreads/WinCE-PORT
new file mode 100644
index 000000000..4b11c737c
--- /dev/null
+++ b/win32/contrib/pthreads/WinCE-PORT
@@ -0,0 +1,208 @@
+Some interesting news:
+
+I have been able to port pthread-win32 to Windows-CE,
+which uses a subset of the WIN32 API.
+
+Since we intend to keep using pthread-win32 for our
+Commercial WinCE developments, I would be very interested
+if WinCE support could be added to the main source tree
+of pthread-win32. Also, I would like to be credited
+for this port :-)
+
+Now, here is the story...
+
+The port was performed and tested on a Casio "Cassiopeia"
+PalmSize PC, which runs a MIP processor. The OS in the
+Casio is WinCE version 2.11, but I used VC++ 6.0 with
+the WinCE SDK for version 2.01.
+
+I used pthread-win32 to port a heavily multithreaded
+commercial application (real-time MPEG video player)
+from Linux to WinCE. I consider the changes that
+I have done to be quite well tested.
+
+Overall the modifications that we had to do are minor.
+
+The WinCE port were based on pthread-win32-snap-1999-05-30,
+but I am certain that they can be integrated very easiely
+to more recent versions of the source.
+
+I have attached the modified source code:
+pthread-win32-snap-1999-05-30-WinCE.
+
+All the changes do not affect the code compiled on non-WinCE
+environment, provided that the macros used for WinCE compilation
+are not used, of course!
+
+Overall description of the WinCE port:
+-------------------------------------
+
+Most of the changes had to be made in areas where
+pthread-win32 was relying on some standard-C librairies
+(e.g. _ftime, calloc, errno), which are not available
+on WinCE. We have changed the code to use native Win32
+API instead (or in some cases we made wrappers).
+
+The Win32 Semaphores are not available,
+so we had to re-implement Semaphores using mutexes
+and events.
+
+Limitations / known problems of the WinCE port:
+----------------------------------------------
+
+Not all the semaphore routines have been ported
+(semaphores are defined by Posix but are not part
+pf pthread). I have just done enough to make
+pthread routines (that rely internally on semaphores)
+work, like signal conditions.
+
+I noticed that the Win32 threads work slightly
+differently on WinCE. This may have some impact
+on some tricky parts of pthread-win32, but I have
+not really investigated. For example, on WinCE,
+the process is killed if the main thread falls off
+the bottom (or calls pthread_exit), regardless
+of the existence of any other detached thread.
+Microsoft manual indicates that this behavior is
+deffirent from that of Windows Threads for other
+Win32 platforms.
+
+
+Detailed descriptions of the changes and rationals:
+
+------------------------------------
+- use a new macro NEED_ERRNO.
+
+If defined, the code in errno.c that defines a reentrant errno
+is compiled, regardless of _MT and _REENTRANT.
+
+Rational: On WinCE, there is no support for <stdio.h>, <errno.h> or
+any other standard C library, i.e. even if _MT or _REENTRANT
+is defined, errno is not provided by any library. NEED_ERRNO
+must be set to compile for WinCE.
+
+------------------------------------
+- In implement.h, change #include <semaphore.h> to #include "semaphore.h".
+
+Rational: semaphore.h is provided in pthread-win32 and should not
+be searched in the systems standard include. would not compile.
+This change does not seem to create problems on "classic" win32
+(e.g. win95).
+
+------------------------------------
+- use a new macro NEED_CALLOC.
+
+If defined, some code in misc.c will provide a replacement
+for calloc, which is not available on Win32.
+
+
+------------------------------------
+- use a new macro NEED_CREATETHREAD.
+
+If defined, implement.h defines the macro _beginthreadex
+and _endthreadex.
+
+Rational: On WinCE, the wrappers _beginthreadex and _endthreadex
+do not exist. The native Win32 routines must be used.
+
+------------------------------------
+- in misc.c:
+
+#ifdef NEED_DUPLICATEHANDLE
+ /* DuplicateHandle does not exist on WinCE */
+ self->threadH = GetCurrentThread();
+#else
+ if( !DuplicateHandle(
+ GetCurrentProcess(),
+ GetCurrentThread(),
+ GetCurrentProcess(),
+ &self->threadH,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS ) )
+ {
+ free( self );
+ return (NULL);
+ }
+#endif
+
+Rational: On WinCE, DuplicateHandle does not exist. I could not understand
+why DuplicateHandle must be used. It seems to me that getting the current
+thread handle with GetCurrentThread() is sufficient, and it seems to work
+perfectly fine, so maybe DuplicateHandle was just plain useless to begin with ?
+
+------------------------------------
+- In private.c, added some code at the beginning of ptw32_processInitialize
+to detect the case of multiple calls to ptw32_processInitialize.
+
+Rational: In order to debug pthread-win32, it is easier to compile
+it as a regular library (it is not possible to debug DLL's on winCE).
+In that case, the application must call ptw32_rocessInitialize()
+explicitely, to initialize pthread-win32. It is safer in this circumstance
+to handle the case where ptw32_processInitialize() is called on
+an already initialized library:
+
+int
+ptw32_processInitialize (void)
+{
+ if (ptw32_processInitialized) {
+ /*
+ * ignore if already initialized. this is useful for
+ * programs that uses a non-dll pthread
+ * library. such programs must call ptw32_processInitialize() explicitely,
+ * since this initialization routine is automatically called only when
+ * the dll is loaded.
+ */
+ return TRUE;
+ }
+ ptw32_processInitialized = TRUE;
+ [...]
+}
+
+------------------------------------
+- in private.c, if macro NEED_FTIME is defined, add routines to
+convert timespec_to_filetime and filetime_to_timespec, and modified
+code that was using _ftime() to use Win32 API instead.
+
+Rational: _ftime is not available on WinCE. It is necessary to use
+the native Win32 time API instead.
+
+Note: the routine timespec_to_filetime is provided as a convenience and a mean
+to test that filetime_to_timespec works, but it is not used by the library.
+
+------------------------------------
+- in semaphore.c, if macro NEED_SEM is defined, add code for the routines
+_increase_semaphore and _decrease_semaphore, and modify significantly
+the implementation of the semaphores so that it does not use CreateSemaphore.
+
+Rational: CreateSemaphore is not available on WinCE. I had to re-implement
+semaphores using mutexes and Events.
+
+Note: Only the semaphore routines that are used by pthread are implemented
+(i.e. signal conditions rely on a subset of the semaphores routines, and
+this subset works). Some other semaphore routines (e.g. sem_trywait) are
+not yet supported on my WinCE port (and since I don't need them, I am not
+planning to do anything about them).
+
+------------------------------------
+- in tsd.c, changed the code that defines TLS_OUT_OF_INDEXES
+
+/* TLS_OUT_OF_INDEXES not defined on WinCE */
+#ifndef TLS_OUT_OF_INDEXES
+#define TLS_OUT_OF_INDEXES 0xffffffff
+#endif
+
+Rational: TLS_OUT_OF_INDEXES is not defined in any standard include file
+on WinCE.
+
+------------------------------------
+- added file need_errno.h
+
+Rational: On WinCE, there is no errno.h file. need_errno.h is just a
+copy of windows version of errno.h, with minor modifications due to the fact
+that some of the error codes are defined by the WinCE socket library.
+In pthread.h, if NEED_ERRNO is defined, the file need_errno.h is
+included (instead of <errno.h>).
+
+
+-- eof
diff --git a/win32/contrib/pthreads/acconfig.h b/win32/contrib/pthreads/acconfig.h
new file mode 100644
index 000000000..7af1923ea
--- /dev/null
+++ b/win32/contrib/pthreads/acconfig.h
@@ -0,0 +1,3 @@
+/* Do we know about the C type sigset_t? */
+#undef HAVE_SIGSET_T
+
diff --git a/win32/contrib/pthreads/attr.c b/win32/contrib/pthreads/attr.c
new file mode 100644
index 000000000..67f7be9c8
--- /dev/null
+++ b/win32/contrib/pthreads/attr.c
@@ -0,0 +1,533 @@
+/*
+ * attr.c
+ *
+ * Description:
+ * This translation unit implements operations on thread attribute objects.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+/* ignore warning "unreferenced formal parameter" */
+#ifdef _MSC_VER
+#pragma warning( disable : 4100 )
+#endif
+
+#include "pthread.h"
+#include "implement.h"
+
+static INLINE int
+is_attr(const pthread_attr_t *attr)
+{
+ /* Return 0 if the attr object is valid, non-zero otherwise. */
+
+ return (attr == NULL ||
+ *attr == NULL ||
+ (*attr)->valid != PTW32_ATTR_VALID);
+}
+
+
+int
+pthread_attr_setstacksize(pthread_attr_t *attr,
+ size_t stacksize)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function specifies the size of the stack on
+ * which threads created with 'attr' will run.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_attr_t
+ *
+ * stacksize
+ * stack size, in bytes.
+ *
+ *
+ * DESCRIPTION
+ * This function specifies the size of the stack on
+ * which threads created with 'attr' will run.
+ *
+ * NOTES:
+ * 1) Function supported only if this macro is
+ * defined:
+ *
+ * _POSIX_THREAD_ATTR_STACKSIZE
+ *
+ * 2) Find the default first (using
+ * pthread_attr_getstacksize), then increase
+ * by multiplying.
+ *
+ * 3) Only use if thread needs more than the
+ * default.
+ *
+ * RESULTS
+ * 0 successfully set stack size,
+ * EINVAL 'attr' is invalid or stacksize too
+ * small or too big.
+ * ENOSYS function not supported
+ *
+ * ------------------------------------------------------
+ */
+{
+#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+
+ /* Verify that the stack size is within range. */
+ if (stacksize < PTHREAD_STACK_MIN)
+ {
+ return EINVAL;
+ }
+
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ /* Everything is okay. */
+ (*attr)->stacksize = stacksize;
+ return 0;
+
+#else
+
+ return ENOSYS;
+
+#endif /* _POSIX_THREAD_ATTR_STACKSIZE */
+
+}
+
+int
+pthread_attr_getstacksize(const pthread_attr_t *attr,
+ size_t *stacksize)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function determines the size of the stack on
+ * which threads created with 'attr' will run.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_attr_t
+ *
+ * stacksize
+ * pointer to size_t into which is returned the
+ * stack size, in bytes.
+ *
+ *
+ * DESCRIPTION
+ * This function determines the size of the stack on
+ * which threads created with 'attr' will run.
+ *
+ * NOTES:
+ * 1) Function supported only if this macro is
+ * defined:
+ *
+ * _POSIX_THREAD_ATTR_STACKSIZE
+ *
+ * 2) Use on newly created attributes object to
+ * find the default stack size.
+ *
+ * RESULTS
+ * 0 successfully retrieved stack size,
+ * EINVAL 'attr' is invalid
+ * ENOSYS function not supported
+ *
+ * ------------------------------------------------------
+ */
+{
+#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ /* Everything is okay. */
+ *stacksize = (*attr)->stacksize;
+ return 0;
+
+#else
+
+ return ENOSYS;
+
+#endif /* _POSIX_THREAD_ATTR_STACKSIZE */
+
+}
+
+
+int
+pthread_attr_setstackaddr(pthread_attr_t *attr,
+ void *stackaddr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Threads created with 'attr' will run on the stack
+ * starting at 'stackaddr'.
+ * Stack must be at least PTHREAD_STACK_MIN bytes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_attr_t
+ *
+ * stacksize
+ * stack size, in bytes.
+ *
+ *
+ * DESCRIPTION
+ * Threads created with 'attr' will run on the stack
+ * starting at 'stackaddr'.
+ * Stack must be at least PTHREAD_STACK_MIN bytes.
+ *
+ * NOTES:
+ * 1) Function supported only if this macro is
+ * defined:
+ *
+ * _POSIX_THREAD_ATTR_STACKADDR
+ *
+ * 2) Create only one thread for each stack
+ * address..
+ *
+ * 3) Ensure that stackaddr is aligned.
+ *
+ * RESULTS
+ * 0 successfully set stack address,
+ * EINVAL 'attr' is invalid
+ * ENOSYS function not supported
+ *
+ * ------------------------------------------------------
+ */
+{
+#if defined( _POSIX_THREAD_ATTR_STACKADDR )
+
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ (*attr)->stackaddr = stackaddr;
+ return 0;
+
+#else
+
+ return ENOSYS;
+
+#endif /* _POSIX_THREAD_ATTR_STACKADDR */
+}
+
+int
+pthread_attr_getstackaddr(const pthread_attr_t *attr,
+ void **stackaddr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function determines the address of the stack
+ * on which threads created with 'attr' will run.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_attr_t
+ *
+ * stackaddr
+ * pointer into which is returned the stack address.
+ *
+ *
+ * DESCRIPTION
+ * This function determines the address of the stack
+ * on which threads created with 'attr' will run.
+ *
+ * NOTES:
+ * 1) Function supported only if this macro is
+ * defined:
+ *
+ * _POSIX_THREAD_ATTR_STACKADDR
+ *
+ * 2) Create only one thread for each stack
+ * address..
+ *
+ * RESULTS
+ * 0 successfully retreived stack address,
+ * EINVAL 'attr' is invalid
+ * ENOSYS function not supported
+ *
+ * ------------------------------------------------------
+ */
+{
+#if defined( _POSIX_THREAD_ATTR_STACKADDR )
+
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ *stackaddr = (*attr)->stackaddr;
+ return 0;
+
+#else
+
+ return ENOSYS;
+
+#endif /* _POSIX_THREAD_ATTR_STACKADDR */
+}
+
+
+int
+pthread_attr_init(pthread_attr_t *attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Initializes a thread attributes object with default
+ * attributes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_attr_t
+ *
+ *
+ * DESCRIPTION
+ * Initializes a thread attributes object with default
+ * attributes.
+ *
+ * NOTES:
+ * 1) Used to define thread attributes
+ *
+ * RESULTS
+ * 0 successfully initialized attr,
+ * ENOMEM insufficient memory for attr.
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_attr_t attr_result;
+
+ if (attr == NULL)
+ {
+ /* This is disallowed. */
+ return EINVAL;
+ }
+
+ attr_result = (pthread_attr_t) malloc (sizeof (*attr_result));
+
+ if (attr_result == NULL)
+ {
+ return ENOMEM;
+ }
+
+#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+ /*
+ * Default to zero size. Unless changed explicitly this
+ * will allow Win32 to set the size to that of the
+ * main thread.
+ */
+ attr_result->stacksize = 0;
+#endif
+
+#ifdef _POSIX_THREAD_ATTR_STACKADDR
+ /* FIXME: Set this to something sensible when we support it. */
+ attr_result->stackaddr = NULL;
+#endif
+
+ attr_result->detachstate = PTHREAD_CREATE_JOINABLE;
+
+#if HAVE_SIGSET_T
+ memset(&(attr_result->sigmask), 0, sizeof(sigset_t));
+#endif /* HAVE_SIGSET_T */
+
+ /*
+ * Win32 sets new threads to THREAD_PRIORITY_NORMAL and
+ * not to that of the parent thread. We choose to default to
+ * this arrangement.
+ */
+ attr_result->param.sched_priority = THREAD_PRIORITY_NORMAL;
+ attr_result->inheritsched = PTHREAD_EXPLICIT_SCHED;
+
+ attr_result->valid = PTW32_ATTR_VALID;
+
+ *attr = attr_result;
+
+ return 0;
+}
+
+int
+pthread_attr_destroy(pthread_attr_t *attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Destroys a thread attributes object.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_attr_t
+ *
+ *
+ * DESCRIPTION
+ * Destroys a thread attributes object.
+ *
+ * NOTES:
+ * 1) Does not affect threads created with 'attr'.
+ *
+ * RESULTS
+ * 0 successfully destroyed attr,
+ * EINVAL 'attr' is invalid.
+ *
+ * ------------------------------------------------------
+ */
+{
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * Set the attribute object to a specific invalid value.
+ */
+ (*attr)->valid = 0;
+ free (*attr);
+ *attr = NULL;
+
+ return 0;
+}
+
+int
+pthread_attr_getdetachstate(const pthread_attr_t *attr,
+ int *detachstate)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function determines whether threads created with
+ * 'attr' will run detached.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_attr_t
+ *
+ * detachstate
+ * pointer to an integer into which is returned one
+ * of:
+ *
+ * PTHREAD_CREATE_JOINABLE
+ * Thread ID is valid, must be joined
+ *
+ * PTHREAD_CREATE_DETACHED
+ * Thread ID is invalid, cannot be joined,
+ * canceled, or modified
+ *
+ *
+ * DESCRIPTION
+ * This function determines whether threads created with
+ * 'attr' will run detached.
+ *
+ * NOTES:
+ * 1) You cannot join or cancel detached threads.
+ *
+ * RESULTS
+ * 0 successfully retrieved detach state,
+ * EINVAL 'attr' is invalid
+ *
+ * ------------------------------------------------------
+ */
+{
+ if (is_attr(attr) != 0 || detachstate == NULL)
+ {
+ *detachstate = PTHREAD_CREATE_DETACHED;
+ return EINVAL;
+ }
+
+ *detachstate = (*attr)->detachstate;
+ return 0;
+}
+
+int
+pthread_attr_setdetachstate(pthread_attr_t *attr,
+ int detachstate)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function specifies whether threads created with
+ * 'attr' will run detached.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_attr_t
+ *
+ * detachstate
+ * an integer containing one of:
+ *
+ * PTHREAD_CREATE_JOINABLE
+ * Thread ID is valid, must be joined
+ *
+ * PTHREAD_CREATE_DETACHED
+ * Thread ID is invalid, cannot be joined,
+ * canceled, or modified
+ *
+ *
+ * DESCRIPTION
+ * This function specifies whether threads created with
+ * 'attr' will run detached.
+ *
+ * NOTES:
+ * 1) You cannot join or cancel detached threads.
+ *
+ * RESULTS
+ * 0 successfully set detach state,
+ * EINVAL 'attr' or 'detachstate' is invalid
+ *
+ * ------------------------------------------------------
+ */
+{
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ if (detachstate != PTHREAD_CREATE_JOINABLE &&
+ detachstate != PTHREAD_CREATE_DETACHED)
+ {
+ return EINVAL;
+ }
+
+ (*attr)->detachstate = detachstate;
+ return 0;
+}
+
+
+int
+pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
+{
+#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
+ if (contentionscope != PTHREAD_SCOPE_SYSTEM)
+ {
+ return ENOTSUP;
+ }
+
+ return 0;
+#else
+ return ENOSYS;
+#endif
+}
+
+
+int
+pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
+{
+#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
+ *contentionscope = PTHREAD_SCOPE_SYSTEM;
+ return 0;
+#else
+ return ENOSYS;
+#endif
+}
+
diff --git a/win32/contrib/pthreads/barrier.c b/win32/contrib/pthreads/barrier.c
new file mode 100644
index 000000000..eb4542b51
--- /dev/null
+++ b/win32/contrib/pthreads/barrier.c
@@ -0,0 +1,421 @@
+/*
+ * barrier.c
+ *
+ * Description:
+ * This translation unit implements barrier primitives.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+#ifdef __MINGW32__
+#define _LONG long
+#define _LPLONG long*
+#else
+#define _LONG PVOID
+#define _LPLONG PVOID*
+#endif
+
+int
+pthread_barrier_init(pthread_barrier_t * barrier,
+ const pthread_barrierattr_t * attr,
+ unsigned int count)
+{
+ pthread_barrier_t b;
+
+ if (barrier == NULL || count == 0)
+ {
+ return EINVAL;
+ }
+
+ if (NULL != (b = (pthread_barrier_t) calloc(1, sizeof(*b))))
+ {
+ b->pshared = (attr != NULL && *attr != NULL
+ ? (*attr)->pshared
+ : PTHREAD_PROCESS_PRIVATE);
+
+ b->nCurrentBarrierHeight = b->nInitialBarrierHeight = count;
+ b->iStep = 0;
+
+ /*
+ * Two semaphores are used in the same way as two stepping
+ * stones might be used in crossing a stream. Once all
+ * threads are safely on one stone, the other stone can
+ * be moved ahead, and the threads can start moving to it.
+ * If some threads decide to eat their lunch before moving
+ * then the other threads have to wait.
+ */
+ if (0 == sem_init(&(b->semBarrierBreeched[0]), b->pshared, 0))
+ {
+ if (0 == sem_init(&(b->semBarrierBreeched[1]), b->pshared, 0))
+ {
+ *barrier = b;
+ return 0;
+ }
+ (void) sem_destroy(&(b->semBarrierBreeched[0]));
+ }
+ (void) free(b);
+ }
+
+ return ENOMEM;
+}
+
+int
+pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ int result = 0;
+ pthread_barrier_t b;
+
+ if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID)
+ {
+ return EINVAL;
+ }
+
+ b = *barrier;
+ *barrier = NULL;
+
+ if (0 == (result = sem_destroy(&(b->semBarrierBreeched[0]))))
+ {
+ if (0 == (result = sem_destroy(&(b->semBarrierBreeched[1]))))
+ {
+ (void) free(b);
+ return 0;
+ }
+ (void) sem_init(&(b->semBarrierBreeched[0]),
+ b->pshared,
+ 0);
+ }
+
+ *barrier = b;
+ return(result);
+}
+
+
+int
+pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ int result;
+ int step;
+ pthread_barrier_t b;
+
+ if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID)
+ {
+ return EINVAL;
+ }
+
+ b = *barrier;
+ step = b->iStep;
+
+ if (0 == InterlockedDecrement((long *) &(b->nCurrentBarrierHeight)))
+ {
+ /* Must be done before posting the semaphore. */
+ b->nCurrentBarrierHeight = b->nInitialBarrierHeight;
+
+ /*
+ * There is no race condition between the semaphore wait and post
+ * because we are using two alternating semas and all threads have
+ * entered barrier_wait and checked nCurrentBarrierHeight before this
+ * barrier's sema can be posted. Any threads that have not quite
+ * entered sem_wait below when the multiple_post has completed
+ * will nevertheless continue through the semaphore (barrier)
+ * and will not be left stranded.
+ */
+ result = (b->nInitialBarrierHeight > 1
+ ? sem_post_multiple(&(b->semBarrierBreeched[step]),
+ b->nInitialBarrierHeight - 1)
+ : 0);
+ }
+ else
+ {
+ BOOL switchCancelState;
+ int oldCancelState;
+ pthread_t self = pthread_self();
+
+ /*
+ * This routine is not a cancelation point, so temporarily
+ * prevent sem_wait() from being one.
+ * PTHREAD_CANCEL_ASYNCHRONOUS threads can still be canceled.
+ */
+ switchCancelState = (self->cancelType == PTHREAD_CANCEL_DEFERRED &&
+ 0 == pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
+ &oldCancelState));
+
+ result = sem_wait(&(b->semBarrierBreeched[step]));
+
+ if (switchCancelState)
+ {
+ (void) pthread_setcancelstate(oldCancelState, NULL);
+ }
+ }
+
+ /*
+ * The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD.
+ * It also sets up the alternate semaphore as the next barrier.
+ */
+ if (0 == result)
+ {
+ result = ((_LONG) step ==
+ InterlockedCompareExchange((_LPLONG) &(b->iStep),
+ (_LONG) (1L - step),
+ (_LONG) step)
+ ? PTHREAD_BARRIER_SERIAL_THREAD
+ : 0);
+ }
+
+ return(result);
+}
+
+
+int
+pthread_barrierattr_init (pthread_barrierattr_t * attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Initializes a barrier attributes object with default
+ * attributes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_barrierattr_t
+ *
+ *
+ * DESCRIPTION
+ * Initializes a barrier attributes object with default
+ * attributes.
+ *
+ * NOTES:
+ * 1) Used to define barrier types
+ *
+ * RESULTS
+ * 0 successfully initialized attr,
+ * ENOMEM insufficient memory for attr.
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_barrierattr_t ba;
+ int result = 0;
+
+ ba = (pthread_barrierattr_t) calloc (1, sizeof (*ba));
+
+ if (ba == NULL)
+ {
+ result = ENOMEM;
+ }
+
+ ba->pshared = PTHREAD_PROCESS_PRIVATE;
+
+ *attr = ba;
+
+ return (result);
+
+} /* pthread_barrierattr_init */
+
+
+int
+pthread_barrierattr_destroy (pthread_barrierattr_t * attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Destroys a barrier attributes object. The object can
+ * no longer be used.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_barrierattr_t
+ *
+ *
+ * DESCRIPTION
+ * Destroys a barrier attributes object. The object can
+ * no longer be used.
+ *
+ * NOTES:
+ * 1) Does not affect barrieres created using 'attr'
+ *
+ * RESULTS
+ * 0 successfully released attr,
+ * EINVAL 'attr' is invalid.
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if (attr == NULL || *attr == NULL)
+ {
+ result = EINVAL;
+ }
+ else
+ {
+ pthread_barrierattr_t ba = *attr;
+
+ *attr = NULL;
+ free (ba);
+
+ result = 0;
+ }
+
+ return (result);
+
+} /* pthread_barrierattr_destroy */
+
+
+int
+pthread_barrierattr_getpshared (const pthread_barrierattr_t * attr,
+ int *pshared)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Determine whether barriers created with 'attr' can be
+ * shared between processes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_barrierattr_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
+ * Mutexes creatd with 'attr' can be shared between
+ * processes if pthread_barrier_t variable is allocated
+ * in memory shared by these processes.
+ * NOTES:
+ * 1) pshared barriers MUST be allocated in shared
+ * memory.
+ * 2) The following macro is defined if shared barriers
+ * are supported:
+ * _POSIX_THREAD_PROCESS_SHARED
+ *
+ * RESULTS
+ * 0 successfully retrieved attribute,
+ * EINVAL 'attr' is invalid,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ if ((attr != NULL && *attr != NULL) &&
+ (pshared != NULL))
+ {
+ *pshared = (*attr)->pshared;
+ result = 0;
+ }
+ else
+ {
+ *pshared = PTHREAD_PROCESS_PRIVATE;
+ result = EINVAL;
+ }
+
+ return (result);
+
+} /* pthread_barrierattr_getpshared */
+
+
+int
+pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
+ int pshared)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Barriers created with 'attr' can be shared between
+ * processes if pthread_barrier_t variable is allocated
+ * in memory shared by these processes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_barrierattr_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_barrier_t variable is allocated
+ * in memory shared by these processes.
+ *
+ * NOTES:
+ * 1) pshared barriers MUST be allocated in shared
+ * memory.
+ *
+ * 2) The following macro is defined if shared barriers
+ * 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_barrierattr_setpshared */
diff --git a/win32/contrib/pthreads/cancel.c b/win32/contrib/pthreads/cancel.c
new file mode 100644
index 000000000..6243257be
--- /dev/null
+++ b/win32/contrib/pthreads/cancel.c
@@ -0,0 +1,388 @@
+/*
+ * cancel.c
+ *
+ * Description:
+ * POSIX thread functions related to thread cancellation.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+#if defined(_M_IX86) || defined(_X86_)
+#define PROGCTR(Context) ((Context).Eip)
+#endif
+
+#if defined(_MIPS_)
+#define PROGCTR(Context) ((Context).Fir)
+#endif
+
+#if defined(_ALPHA_)
+#define PROGCTR(Context) ((Context).Fir)
+#endif
+
+#if defined(_PPC_)
+#define PROGCTR(Context) ((Context).Iar)
+#endif
+
+#if !defined(PROGCTR)
+#error Module contains CPU-specific code; modify and recompile.
+#endif
+
+
+static void
+ptw32_cancel_self(void)
+{
+ ptw32_throw(PTW32_EPS_CANCEL);
+
+ /* Never reached */
+}
+
+
+/*
+ * ptw32_cancel_thread implements asynchronous cancellation.
+ */
+static INLINE void
+ptw32_cancel_thread(pthread_t thread)
+{
+ HANDLE threadH = thread->threadH;
+
+ (void) pthread_mutex_lock(&thread->cancelLock);
+
+ SuspendThread(threadH);
+
+ if (WaitForSingleObject(threadH, 0) == WAIT_TIMEOUT)
+ {
+ CONTEXT context;
+ context.ContextFlags = CONTEXT_CONTROL;
+ GetThreadContext(threadH, &context);
+ PROGCTR(context) = (DWORD) ptw32_cancel_self;
+ SetThreadContext(threadH, &context);
+ ResumeThread(threadH);
+ }
+
+ (void) pthread_mutex_unlock(&thread->cancelLock);
+}
+
+
+int
+pthread_setcancelstate (int state, int *oldstate)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function atomically sets the calling thread's
+ * cancelability state to 'state' and returns the previous
+ * cancelability state at the location referenced by
+ * 'oldstate'
+ *
+ * PARAMETERS
+ * state,
+ * oldstate
+ * PTHREAD_CANCEL_ENABLE
+ * cancellation is enabled,
+ *
+ * PTHREAD_CANCEL_DISABLE
+ * cancellation is disabled
+ *
+ *
+ * DESCRIPTION
+ * This function atomically sets the calling thread's
+ * cancelability state to 'state' and returns the previous
+ * cancelability state at the location referenced by
+ * 'oldstate'.
+ *
+ * NOTES:
+ * 1) Use to disable cancellation around 'atomic' code that
+ * includes cancellation points
+ *
+ * COMPATIBILITY ADDITIONS
+ * If 'oldstate' is NULL then the previous state is not returned
+ * but the function still succeeds. (Solaris)
+ *
+ * RESULTS
+ * 0 successfully set cancelability type,
+ * EINVAL 'state' is invalid
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+ pthread_t self = pthread_self();
+
+ if (self == NULL
+ || (state != PTHREAD_CANCEL_ENABLE
+ && state != PTHREAD_CANCEL_DISABLE))
+ {
+ return EINVAL;
+ }
+
+ /*
+ * Lock for async-cancel safety.
+ */
+ (void) pthread_mutex_lock(&self->cancelLock);
+
+ if (oldstate != NULL)
+ {
+ *oldstate = self->cancelState;
+ }
+
+ self->cancelState = state;
+
+ /*
+ * Check if there is a pending asynchronous cancel
+ */
+ if (self->cancelState == PTHREAD_CANCEL_ENABLE
+ && self->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
+ && WaitForSingleObject(self->cancelEvent, 0) == WAIT_OBJECT_0)
+ {
+ ResetEvent(self->cancelEvent);
+ (void) pthread_mutex_unlock(&self->cancelLock);
+ ptw32_throw(PTW32_EPS_CANCEL);
+
+ /* Never reached */
+ }
+
+ (void) pthread_mutex_unlock(&self->cancelLock);
+
+ return (result);
+
+} /* pthread_setcancelstate */
+
+
+int
+pthread_setcanceltype (int type, int *oldtype)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function atomically sets the calling thread's
+ * cancelability type to 'type' and returns the previous
+ * cancelability type at the location referenced by
+ * 'oldtype'
+ *
+ * PARAMETERS
+ * type,
+ * oldtype
+ * PTHREAD_CANCEL_DEFERRED
+ * only deferred cancelation is allowed,
+ *
+ * PTHREAD_CANCEL_ASYNCHRONOUS
+ * Asynchronous cancellation is allowed
+ *
+ *
+ * DESCRIPTION
+ * This function atomically sets the calling thread's
+ * cancelability type to 'type' and returns the previous
+ * cancelability type at the location referenced by
+ * 'oldtype'
+ *
+ * NOTES:
+ * 1) Use with caution; most code is not safe for use
+ * with asynchronous cancelability.
+ *
+ * COMPATIBILITY ADDITIONS
+ * If 'oldtype' is NULL then the previous type is not returned
+ * but the function still succeeds. (Solaris)
+ *
+ * RESULTS
+ * 0 successfully set cancelability type,
+ * EINVAL 'type' is invalid
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+ pthread_t self = pthread_self();
+
+ if (self == NULL
+ || (type != PTHREAD_CANCEL_DEFERRED
+ && type != PTHREAD_CANCEL_ASYNCHRONOUS))
+ {
+ return EINVAL;
+ }
+
+ /*
+ * Lock for async-cancel safety.
+ */
+ (void) pthread_mutex_lock(&self->cancelLock);
+
+ if (oldtype != NULL)
+ {
+ *oldtype = self->cancelType;
+ }
+
+ self->cancelType = type;
+
+ /*
+ * Check if there is a pending asynchronous cancel
+ */
+ if (self->cancelState == PTHREAD_CANCEL_ENABLE
+ && self->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
+ && WaitForSingleObject(self->cancelEvent, 0) == WAIT_OBJECT_0)
+ {
+ ResetEvent(self->cancelEvent);
+ (void) pthread_mutex_unlock(&self->cancelLock);
+ ptw32_throw(PTW32_EPS_CANCEL);
+
+ /* Never reached */
+ }
+
+ (void) pthread_mutex_unlock(&self->cancelLock);
+
+ return (result);
+
+} /* pthread_setcanceltype */
+
+void
+pthread_testcancel (void)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function creates a deferred cancellation point
+ * in the calling thread. The call has no effect if the
+ * current cancelability state is
+ * PTHREAD_CANCEL_DISABLE
+ *
+ * PARAMETERS
+ * N/A
+ *
+ *
+ * DESCRIPTION
+ * This function creates a deferred cancellation point
+ * in the calling thread. The call has no effect if the
+ * current cancelability state is
+ * PTHREAD_CANCEL_DISABLE
+ *
+ * NOTES:
+ * 1) Cancellation is asynchronous. Use pthread_join
+ * to wait for termination of thread if necessary
+ *
+ * RESULTS
+ * N/A
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_t self = pthread_self();
+
+ if (self != NULL
+ && self->cancelState == PTHREAD_CANCEL_ENABLE
+ && WaitForSingleObject (self->cancelEvent, 0) == WAIT_OBJECT_0
+ )
+ {
+ /*
+ * Canceling!
+ */
+ ptw32_throw(PTW32_EPS_CANCEL);
+ }
+} /* pthread_testcancel */
+
+int
+pthread_cancel (pthread_t thread)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function requests cancellation of 'thread'.
+ *
+ * PARAMETERS
+ * thread
+ * reference to an instance of pthread_t
+ *
+ *
+ * DESCRIPTION
+ * This function requests cancellation of 'thread'.
+ * NOTE: cancellation is asynchronous; use pthread_join to
+ * wait for termination of 'thread' if necessary.
+ *
+ * RESULTS
+ * 0 successfully requested cancellation,
+ * ESRCH no thread found corresponding to 'thread',
+ * ENOMEM implicit self thread create failed.
+ * ------------------------------------------------------
+ */
+{
+ int result;
+ int cancel_self;
+ pthread_t self;
+
+ if (thread == NULL )
+ {
+ return ESRCH;
+ }
+
+ result = 0;
+ if ((self = pthread_self()) == NULL)
+ {
+ return ENOMEM;
+ };
+
+ /*
+ * FIXME!!
+ *
+ * Can a thread cancel itself?
+ *
+ * The standard doesn't
+ * specify an error to be returned if the target
+ * thread is itself.
+ *
+ * If it may, then we need to ensure that a thread can't
+ * deadlock itself trying to cancel itself asyncronously
+ * (pthread_cancel is required to be an async-cancel
+ * safe function).
+ */
+ cancel_self = pthread_equal(thread, self);
+
+ /*
+ * Lock for async-cancel safety.
+ */
+ (void) pthread_mutex_lock(&self->cancelLock);
+
+ if (thread->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
+ && thread->cancelState == PTHREAD_CANCEL_ENABLE )
+ {
+ if (cancel_self)
+ {
+ (void) pthread_mutex_unlock(&self->cancelLock);
+ ptw32_throw(PTW32_EPS_CANCEL);
+
+ /* Never reached */
+ }
+
+ ptw32_cancel_thread(thread);
+ }
+ else
+ {
+ /*
+ * Set for deferred cancellation.
+ */
+ if (!SetEvent (thread->cancelEvent))
+ {
+ result = ESRCH;
+ }
+ }
+
+ (void) pthread_mutex_unlock(&self->cancelLock);
+
+ return (result);
+
+}
+
+
+
diff --git a/win32/contrib/pthreads/cleanup.c b/win32/contrib/pthreads/cleanup.c
new file mode 100644
index 000000000..9794b5fb5
--- /dev/null
+++ b/win32/contrib/pthreads/cleanup.c
@@ -0,0 +1,138 @@
+/*
+ * cleanup.c
+ *
+ * Description:
+ * This translation unit implements routines associated
+ * with cleaning up threads.
+ *
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+/*
+ * The functions ptw32_pop_cleanup and ptw32_push_cleanup
+ * are implemented here for applications written in C with no
+ * SEH or C++ destructor support.
+ */
+
+ptw32_cleanup_t *
+ptw32_pop_cleanup (int execute)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function pops the most recently pushed cleanup
+ * handler. If execute is nonzero, then the cleanup handler
+ * is executed if non-null.
+ *
+ * PARAMETERS
+ * execute
+ * if nonzero, execute the cleanup handler
+ *
+ *
+ * DESCRIPTION
+ * This function pops the most recently pushed cleanup
+ * handler. If execute is nonzero, then the cleanup handler
+ * is executed if non-null.
+ * NOTE: specify 'execute' as nonzero to avoid duplication
+ * of common cleanup code.
+ *
+ * RESULTS
+ * N/A
+ *
+ * ------------------------------------------------------
+ */
+{
+ ptw32_cleanup_t *cleanup = NULL;
+
+ cleanup = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey);
+
+ if (cleanup != NULL)
+ {
+ if (execute && (cleanup->routine != NULL))
+ {
+
+ (*cleanup->routine) (cleanup->arg);
+
+ }
+
+ pthread_setspecific (ptw32_cleanupKey, (void *) cleanup->prev);
+
+ }
+
+ return (cleanup);
+
+} /* ptw32_pop_cleanup */
+
+
+void
+ptw32_push_cleanup (ptw32_cleanup_t * cleanup,
+ ptw32_cleanup_callback_t routine,
+ void *arg)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function pushes a new cleanup handler onto the thread's stack
+ * of cleanup handlers. Each cleanup handler pushed onto the stack is
+ * popped and invoked with the argument 'arg' when
+ * a) the thread exits by calling 'pthread_exit',
+ * b) when the thread acts on a cancellation request,
+ * c) or when the thrad calls pthread_cleanup_pop with a nonzero
+ * 'execute' argument
+ *
+ * PARAMETERS
+ * cleanup
+ * a pointer to an instance of pthread_cleanup_t,
+ *
+ * routine
+ * pointer to a cleanup handler,
+ *
+ * arg
+ * parameter to be passed to the cleanup handler
+ *
+ *
+ * DESCRIPTION
+ * This function pushes a new cleanup handler onto the thread's stack
+ * of cleanup handlers. Each cleanup handler pushed onto the stack is
+ * popped and invoked with the argument 'arg' when
+ * a) the thread exits by calling 'pthread_exit',
+ * b) when the thread acts on a cancellation request,
+ * c) or when the thrad calls pthread_cleanup_pop with a nonzero
+ * 'execute' argument
+ * NOTE: pthread_push_cleanup, ptw32_pop_cleanup must be paired
+ * in the same lexical scope.
+ *
+ * RESULTS
+ * pthread_cleanup_t *
+ * pointer to the previous cleanup
+ *
+ * ------------------------------------------------------
+ */
+{
+ cleanup->routine = routine;
+ cleanup->arg = arg;
+
+ cleanup->prev = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey);
+
+ pthread_setspecific (ptw32_cleanupKey, (void *) cleanup);
+
+} /* ptw32_push_cleanup */
diff --git a/win32/contrib/pthreads/condvar.c b/win32/contrib/pthreads/condvar.c
new file mode 100644
index 000000000..c8876c4f2
--- /dev/null
+++ b/win32/contrib/pthreads/condvar.c
@@ -0,0 +1,1219 @@
+/*
+ * condvar.c
+ *
+ * Description:
+ * This translation unit implements condition variables and their primitives.
+ *
+ * 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;
+ * }
+ *
+ * -------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#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' is invalid,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ if ((attr != NULL && *attr != NULL) && (pshared != NULL))
+ {
+ *pshared = (*attr)->pshared;
+ result = 0;
+ }
+ else
+ {
+ *pshared = PTHREAD_PROCESS_PRIVATE;
+ 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->nWaitersUnblocked = 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) Safest after wakeup from 'cond', when
+ * no other threads will wait.
+ *
+ * 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;
+
+ /*
+ * Synchronize access to waiters blocked count (LEVEL-1)
+ */
+ if (sem_wait(&(cv->semBlockLock)) != 0)
+ {
+ return errno;
+ }
+
+ /*
+ * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
+ */
+ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
+ {
+ (void) sem_post(&(cv->semBlockLock));
+ return result;
+ }
+
+ /*
+ * Check whether cv is still busy (still has waiters)
+ */
+ if (cv->nWaitersBlocked - cv->nWaitersGone - cv->nWaitersUnblocked > 0)
+ {
+ 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.
+ */
+ *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;
+
+ 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:
+ *
+ * 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)
+ {
+ 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);
+
+ /*
+ * "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 */
diff --git a/win32/contrib/pthreads/config.guess b/win32/contrib/pthreads/config.guess
new file mode 100644
index 000000000..2d6119a9a
--- /dev/null
+++ b/win32/contrib/pthreads/config.guess
@@ -0,0 +1,940 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >dummy.s
+ .globl main
+ .ent main
+main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ ${CC-cc} dummy.s -o dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+ fi
+ rm -f dummy.s dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]`
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-cbm-sysv4
+ exit 0;;
+ amiga:NetBSD:*:*)
+ echo m68k-cbm-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ arc64:OpenBSD:*:*)
+ echo mips64el-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hkmips:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ arm32:NetBSD:*:*)
+ echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ SR2?01:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:*|MIS*:OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:NetBSD:*:*)
+ echo m68k-atari-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:NetBSD:*:*)
+ echo m68k-sun-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:NetBSD:*:*)
+ echo m68k-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:NetBSD:*:*)
+ echo powerpc-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ sed 's/^ //' << EOF >dummy.c
+ int main (argc, argv) int argc; char **argv; {
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy \
+ && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+ -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i?86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ sed 's/^ //' << EOF >dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:4)
+ if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=4.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[3478]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/7?? | 9000/8?[1679] )
+ sed 's/^ //' << EOF >dummy.c
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && HP_ARCH=`./dummy`
+ rm -f dummy.c dummy
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i?86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F300:UNIX_System_V:*:*)
+ FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ F301:UNIX_System_V:*:*)
+ echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+ exit 0 ;;
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ i?86:BSD/386:*:* | *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin32
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin32
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ *:Linux:*:*)
+ # uname on the ARM produces all sorts of strangeness, and we need to
+ # filter it out.
+ case "$UNAME_MACHINE" in
+ arm* | sa110*) UNAME_MACHINE="arm" ;;
+ esac
+
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us.
+ ld_help_string=`ld --help 2>&1`
+ ld_supported_emulations=`echo $ld_help_string \
+ | sed -ne '/supported emulations:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported emulations: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_emulations" in
+ i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;;
+ i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;;
+ sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;;
+ esac
+
+ if test "${UNAME_MACHINE}" = "alpha" ; then
+ sed 's/^ //' <<EOF >dummy.s
+ .globl main
+ .ent main
+ main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ LIBC=""
+ ${CC-cc} dummy.s -o dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+
+ objdump --private-headers dummy | \
+ grep ld.so.1 > /dev/null
+ if test "$?" = 0 ; then
+ LIBC="libc1"
+ fi
+ fi
+ rm -f dummy.s dummy
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+ elif test "${UNAME_MACHINE}" = "mips" ; then
+ cat >dummy.c <<EOF
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#ifdef __MIPSEB__
+ printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+ printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ else
+ # Either a pre-BFD a.out linker (linux-gnuoldld)
+ # or one that does not give us useful --help.
+ # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+ # If ld does not provide *any* "supported emulations:"
+ # that means it is gnuoldld.
+ echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
+ test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+ case "${UNAME_MACHINE}" in
+ i?86)
+ VENDOR=pc;
+ ;;
+ *)
+ VENDOR=unknown;
+ ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ cat >dummy.c <<EOF
+#include <features.h>
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+ i?86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i?86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i?86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ pc:*:*:*)
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i?86:LynxOS:2.*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:*:6*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+ printf ("vax-dec-bsd\n"); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
+rm -f dummy.c dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/win32/contrib/pthreads/config.h b/win32/contrib/pthreads/config.h
new file mode 100644
index 000000000..4f5679120
--- /dev/null
+++ b/win32/contrib/pthreads/config.h
@@ -0,0 +1,68 @@
+/* config.h.in Generated automatically from configure.in by autoheader. */
+
+#ifndef PTW32_CONFIG_H
+#define PTW32_CONFIG_H
+
+/* Do we know about the C type sigset_t? */
+#undef HAVE_SIGSET_T
+
+/* Define if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define if you don't have Win32 DuplicateHandle. (eg. WinCE) */
+#undef NEED_DUPLICATEHANDLE
+
+/* Define if you don't have Win32 _beginthreadex. (eg. WinCE) */
+#undef NEED_CREATETHREAD
+
+/* Define if you don't have Win32 errno. (eg. WinCE) */
+#undef NEED_ERRNO
+
+/* Define if you don't have Win32 calloc. (eg. WinCE) */
+#undef NEED_CALLOC
+
+/* Define if you don't have Win32 ftime. (eg. WinCE) */
+#undef NEED_FTIME
+
+/* Define if you don't have Win32 semaphores. (eg. WinCE) */
+#undef NEED_SEM
+
+/* Define if you need to convert string parameters to unicode. (eg. WinCE) */
+#undef NEED_UNICODE_CONSTS
+
+/* Define if your C (not C++) compiler supports "inline" functions. */
+#undef HAVE_C_INLINE
+
+/* Do we know about type mode_t? */
+#undef HAVE_MODE_T
+
+/* Define if you have the timespec struct */
+#undef HAVE_STRUCT_TIMESPEC
+
+/*
+ * Target specific groups
+ */
+#ifdef WINCE
+#define NEED_DUPLICATEHANDLE
+#define NEED_CREATETHREAD
+#define NEED_ERRNO
+#define NEED_CALLOC
+#define NEED_FTIME
+#define NEED_SEM
+#define NEED_UNICODE_CONSTS
+#endif
+
+#ifdef _UWIN
+#define HAVE_MODE_T
+#define HAVE_STRUCT_TIMESPEC
+#endif
+
+#ifdef __GNUC__
+#define HAVE_C_INLINE
+#endif
+
+#ifdef __MINGW32__
+#define HAVE_MODE_T
+#endif
+
+#endif \ No newline at end of file
diff --git a/win32/contrib/pthreads/config.h.in b/win32/contrib/pthreads/config.h.in
new file mode 100644
index 000000000..dad5a212d
--- /dev/null
+++ b/win32/contrib/pthreads/config.h.in
@@ -0,0 +1,61 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+#ifndef PTW32_CONFIG_H
+#define PTW32_CONFIG_H
+
+/* Do we know about the C type sigset_t? */
+#undef HAVE_SIGSET_T
+
+/* Define if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define if you don't have Win32 DuplicateHandle. (eg. WinCE) */
+#undef NEED_DUPLICATEHANDLE
+
+/* Define if you don't have Win32 _beginthreadex. (eg. WinCE) */
+#undef NEED_CREATETHREAD
+
+/* Define if you don't have Win32 errno. (eg. WinCE) */
+#undef NEED_ERRNO
+
+/* Define if you don't have Win32 calloc. (eg. WinCE) */
+#undef NEED_CALLOC
+
+/* Define if you don't have Win32 ftime. (eg. WinCE) */
+#undef NEED_FTIME
+
+/* Define if you don't have Win32 semaphores. (eg. WinCE) */
+#undef NEED_SEM
+
+/* Define if you need to convert string parameters to unicode. (eg. WinCE) */
+#undef NEED_UNICODE_CONSTS
+
+/* Do we know about type mode_t? */
+#undef HAVE_MODE_T
+
+/* Define if you have the timespec struct */
+#undef HAVE_STRUCT_TIMESPEC
+
+/*
+ * Target specific groups
+ */
+#ifdef WINCE
+#define NEED_DUPLICATEHANDLE
+#define NEED_CREATETHREAD
+#define NEED_ERRNO
+#define NEED_CALLOC
+#define NEED_FTIME
+#define NEED_SEM
+#define NEED_UNICODE_CONSTS
+#endif
+
+#ifdef _UWIN
+#define HAVE_MODE_T
+#define HAVE_STRUCT_TIMESPEC
+#endif
+
+#ifdef __MINGW32__
+#define HAVE_MODE_T
+#endif
+
+#endif \ No newline at end of file
diff --git a/win32/contrib/pthreads/config.sub b/win32/contrib/pthreads/config.sub
new file mode 100644
index 000000000..c90c43d9f
--- /dev/null
+++ b/win32/contrib/pthreads/config.sub
@@ -0,0 +1,956 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+ echo Configuration name missing. 1>&2
+ echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+ echo "or $0 ALIAS" 1>&2
+ echo where ALIAS is a recognized configuration type. 1>&2
+ exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+ *local*)
+ echo $1
+ exit 0
+ ;;
+ *)
+ ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ linux-gnu*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple)
+ os=
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+ | arme[lb] | pyramid | mn10200 | mn10300 \
+ | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \
+ | hppa2.0 \
+ | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \
+ | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \
+ | mips64 | mipsel | mips64el | mips64orion | mips64orionel \
+ | mipstx39 | mipstx39el \
+ | sparc | sparclet | sparclite | sparc64 | v850)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i[34567]86)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+ | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+ | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \
+ | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \
+ | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \
+ | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \
+ | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+ | sparc64-* | mips64-* | mipsel-* \
+ | mips64el-* | mips64orion-* | mips64orionel-* \
+ | mipstx39-* | mipstx39el-* \
+ | f301-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-cbm
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-cbm
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-cbm
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ [ctj]90-cray)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i[34567]86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i[34567]86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i[34567]86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i[34567]86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ mipsel*-linux*)
+ basic_machine=mipsel-unknown
+ os=-linux-gnu
+ ;;
+ mips*-linux*)
+ basic_machine=mips-unknown
+ os=-linux-gnu
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | nexen)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | k6 | 6x86)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | nexen-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | k6-* | 6x86-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=rs6000-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ mips)
+ if [ x$os = x-linux-gnu ]; then
+ basic_machine=mips-unknown
+ else
+ basic_machine=mips-mips
+ fi
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sparc)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f301-fujitsu)
+ os=-uxpv
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
diff --git a/win32/contrib/pthreads/configure b/win32/contrib/pthreads/configure
new file mode 100644
index 000000000..fcb74b107
--- /dev/null
+++ b/win32/contrib/pthreads/configure
@@ -0,0 +1,1331 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=pthread.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:551: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:575: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:605: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:656: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:688: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 699 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:704: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:730: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:735: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:744: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:763: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:796: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 811 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:817: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 828 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:834: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 845 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:851: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+ac_safe=`echo "windows.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for windows.h""... $ac_c" 1>&6
+echo "configure:877: checking for windows.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 882 "configure"
+#include "confdefs.h"
+#include <windows.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:887: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+{ echo "configure: error: Target system must be Win32" 1>&2; exit 1; }
+fi
+
+
+ac_safe=`echo "signal.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for signal.h""... $ac_c" 1>&6
+echo "configure:912: checking for signal.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 917 "configure"
+#include "confdefs.h"
+#include <signal.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:922: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ signal_h=yes
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test x$signal_h = xyes
+then
+ echo $ac_n "checking for sigset_t""... $ac_c" 1>&6
+echo "configure:946: checking for sigset_t" >&5
+if eval "test \"`echo '$''{'p32_cv_sigset_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 951 "configure"
+#include "confdefs.h"
+#include <signal.h>
+int main() {
+sigset_t x;
+; return 0; }
+EOF
+if { (eval echo configure:958: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ p32_cv_sigset_t=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ p32_cv_sigset_t=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$p32_cv_sigset_t" 1>&6
+
+ if test x$p32_cv_sigset_t = xyes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SIGSET_T 1
+EOF
+
+ fi
+fi
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/win32/contrib/pthreads/configure.in b/win32/contrib/pthreads/configure.in
new file mode 100644
index 000000000..f5ea117f2
--- /dev/null
+++ b/win32/contrib/pthreads/configure.in
@@ -0,0 +1,23 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT(pthread.h)
+AC_CANONICAL_HOST
+AC_CONFIG_HEADER(config.h)
+AC_PROG_CC
+
+dnl Abort here if there is no windows.h
+AC_CHECK_HEADER([windows.h],,AC_MSG_ERROR([Target system must be Win32]))
+
+AC_CHECK_HEADER([signal.h],signal_h=yes,)
+if test x$signal_h = xyes
+then
+ AC_CACHE_CHECK([for sigset_t], p32_cv_sigset_t,
+ AC_TRY_COMPILE([#include <signal.h>], [sigset_t x;],
+ p32_cv_sigset_t=yes, p32_cv_sigset_t=no))
+
+ if test x$p32_cv_sigset_t = xyes ; then
+ AC_DEFINE(HAVE_SIGSET_T)
+ fi
+fi
+
+AC_OUTPUT(GNUmakefile)
diff --git a/win32/contrib/pthreads/create.c b/win32/contrib/pthreads/create.c
new file mode 100644
index 000000000..e94ef7f91
--- /dev/null
+++ b/win32/contrib/pthreads/create.c
@@ -0,0 +1,261 @@
+/*
+ * create.c
+ *
+ * Description:
+ * This translation unit implements routines associated with spawning a new
+ * thread.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+#ifndef _UWIN
+#include <process.h>
+#endif
+
+int
+pthread_create (pthread_t * tid,
+ const pthread_attr_t * attr,
+ void *(*start) (void *),
+ void *arg)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function creates a thread running the start function,
+ * passing it the parameter value, 'arg'.
+ *
+ * PARAMETERS
+ * tid
+ * pointer to an instance of pthread_t
+ *
+ * attr
+ * optional pointer to an instance of pthread_attr_t
+ *
+ * start
+ * pointer to the starting routine for the new thread
+ *
+ * arg
+ * optional parameter passed to 'start'
+ *
+ *
+ * DESCRIPTION
+ * This function creates a thread running the start function,
+ * passing it the parameter value, 'arg'. The 'attr'
+ * argument specifies optional creation attributes.
+ * The thread is identity of the new thread is returned
+ * as 'tid'
+ *
+ * RESULTS
+ * 0 successfully created thread,
+ * EINVAL attr invalid,
+ * EAGAIN insufficient resources.
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_t thread;
+ HANDLE threadH = 0;
+ int result = EAGAIN;
+ int run = TRUE;
+ ThreadParms *parms = NULL;
+ long stackSize;
+
+ if ((thread = ptw32_new()) == NULL)
+ {
+ goto FAIL0;
+ }
+
+ thread->cancelEvent =
+ CreateEvent (
+ 0,
+ (int) TRUE, /* manualReset */
+ (int) FALSE, /* setSignaled */
+ NULL);
+
+ if (thread->cancelEvent == NULL)
+ {
+ goto FAIL0;
+ }
+
+ if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL)
+ {
+ goto FAIL0;
+ }
+
+ parms->tid = thread;
+ parms->start = start;
+ parms->arg = arg;
+
+ if (attr != NULL && *attr != NULL)
+ {
+ stackSize = (*attr)->stacksize;
+ thread->detachState = (*attr)->detachstate;
+
+#if HAVE_SIGSET_T
+
+ thread->sigmask = (*attr)->sigmask;
+
+#endif /* HAVE_SIGSET_T */
+
+ }
+ else
+ {
+ /*
+ * Default stackSize
+ */
+ stackSize = PTHREAD_STACK_MIN;
+ }
+
+ thread->state = run
+ ? PThreadStateInitial
+ : PThreadStateSuspended;
+
+ thread->keys = NULL;
+
+ /*
+ * Threads must be started in suspended mode and resumed if necessary
+ * after _beginthreadex returns us the handle. Otherwise we set up a
+ * race condition between the creating and the created threads.
+ * Note that we also retain a local copy of the handle for use
+ * by us in case thread->threadH gets NULLed later but before we've
+ * finished with it here.
+ */
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+
+ thread->threadH = threadH = (HANDLE)
+ _beginthreadex (
+ (void *) NULL, /* No security info */
+ (unsigned) stackSize, /* default stack size */
+ ptw32_threadStart,
+ parms,
+ (unsigned) CREATE_SUSPENDED,
+ (unsigned *) &(thread->thread));
+
+ if (threadH != 0)
+ {
+ /*
+ * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads
+ * don't inherit their creator's priority. They are started with
+ * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying
+ * an 'attr' arg to pthread_create() is equivalent to defaulting to
+ * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL.
+ */
+ if (attr != NULL && *attr != NULL)
+ {
+ (void) SetThreadPriority(thread->threadH,
+ PTHREAD_INHERIT_SCHED == (*attr)->inheritsched
+ ? GetThreadPriority(GetCurrentThread())
+ : (*attr)->param.sched_priority );
+ }
+
+ if (run)
+ {
+ ResumeThread(threadH);
+ }
+ }
+
+#else /* __MINGW32__ && ! __MSVCRT__ */
+
+ /*
+ * This lock will force pthread_threadStart() to wait until we have
+ * the thread handle.
+ */
+ (void) pthread_mutex_lock(&thread->cancelLock);
+
+ thread->threadH = threadH = (HANDLE)
+ _beginthread (
+ ptw32_threadStart,
+ (unsigned) stackSize, /* default stack size */
+ parms);
+
+ /*
+ * Make the return code match _beginthreadex's.
+ */
+ if (threadH == (HANDLE) -1L)
+ {
+ thread->threadH = threadH = 0;
+ }
+ else
+ {
+ if (! run)
+ {
+ /*
+ * beginthread does not allow for create flags, so we do it now.
+ * Note that beginthread itself creates the thread in SUSPENDED
+ * mode, and then calls ResumeThread to start it.
+ */
+ SuspendThread (threadH);
+ }
+
+ /*
+ * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads
+ * don't inherit their creator's priority. They are started with
+ * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying
+ * an 'attr' arg to pthread_create() is equivalent to defaulting to
+ * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL.
+ */
+ if (attr != NULL && *attr != NULL)
+ {
+ (void) SetThreadPriority(thread->threadH,
+ PTHREAD_INHERIT_SCHED == (*attr)->inheritsched
+ ? GetThreadPriority(GetCurrentThread())
+ : (*attr)->param.sched_priority );
+ }
+ }
+
+ (void) pthread_mutex_unlock(&thread->cancelLock);
+
+#endif /* __MINGW32__ && ! __MSVCRT__ */
+
+ result = (threadH != 0) ? 0 : EAGAIN;
+
+ /*
+ * Fall Through Intentionally
+ */
+
+ /*
+ * ------------
+ * Failure Code
+ * ------------
+ */
+
+FAIL0:
+ if (result != 0)
+ {
+
+ ptw32_threadDestroy (thread);
+ thread = NULL;
+
+ if (parms != NULL)
+ {
+ free (parms);
+ }
+ }
+ *tid = thread;
+
+#ifdef _UWIN
+ if (result == 0)
+ pthread_count++;
+#endif
+ return (result);
+
+} /* pthread_create */
+
diff --git a/win32/contrib/pthreads/dll.c b/win32/contrib/pthreads/dll.c
new file mode 100644
index 000000000..1e30bdd42
--- /dev/null
+++ b/win32/contrib/pthreads/dll.c
@@ -0,0 +1,85 @@
+/*
+ * dll.c
+ *
+ * Description:
+ * This translation unit implements DLL initialisation.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+#if 1
+#include <stdio.h>
+#endif
+
+#ifdef _MSC_VER
+/*
+ * lpvReserved yields an unreferenced formal parameter;
+ * ignore it
+ */
+#pragma warning( disable : 4100 )
+#endif
+
+#ifdef __cplusplus
+/*
+ * Dear c++: Please don't mangle this name. -thanks
+ */
+extern "C"
+#endif /* __cplusplus */
+
+BOOL WINAPI
+DllMain (
+ HINSTANCE hinstDll,
+ DWORD fdwReason,
+ LPVOID lpvReserved
+)
+{
+ BOOL result = TRUE;
+
+ switch (fdwReason)
+ {
+
+ case DLL_PROCESS_ATTACH:
+ result = pthread_win32_process_attach_np();
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /*
+ * A thread is being created
+ */
+ result = pthread_win32_thread_attach_np();
+ break;
+
+ case DLL_THREAD_DETACH:
+ /*
+ * A thread is exiting cleanly
+ */
+ result = pthread_win32_thread_detach_np();
+ break;
+
+ case DLL_PROCESS_DETACH:
+ (void) pthread_win32_thread_detach_np();
+ result = pthread_win32_process_detach_np();
+ break;
+ }
+ return (result);
+
+} /* DllMain */
diff --git a/win32/contrib/pthreads/errno.c b/win32/contrib/pthreads/errno.c
new file mode 100644
index 000000000..d31e57ceb
--- /dev/null
+++ b/win32/contrib/pthreads/errno.c
@@ -0,0 +1,82 @@
+/*
+ * errno.c
+ *
+ * Description:
+ * This translation unit implements routines associated with spawning a new
+ * thread.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#if (! defined(HAVE_ERRNO)) && (! defined(_REENTRANT)) && (! defined(_MT))
+
+#include "pthread.h"
+#include "implement.h"
+
+static int reallyBad = ENOMEM;
+
+/*
+ * Re-entrant errno.
+ *
+ * Each thread has it's own errno variable in pthread_t.
+ *
+ * The benefit of using the pthread_t structure
+ * instead of another TSD key is TSD keys are limited
+ * on Win32 to 64 per process. Secondly, to implement
+ * it properly without using pthread_t you'd need
+ * to dynamically allocate an int on starting the thread
+ * and store it manually into TLS and then ensure that you free
+ * it on thread termination. We get all that for free
+ * by simply storing the errno on the pthread_t structure.
+ *
+ * MSVC and Mingw32 already have there own thread-safe errno.
+ *
+ * #if defined( _REENTRANT ) || defined( _MT )
+ * #define errno *_errno()
+ *
+ * int *_errno( void );
+ * #else
+ * extern int errno;
+ * #endif
+ *
+ */
+
+int * _errno( void )
+{
+ pthread_t self;
+ int *result;
+
+ if( ( self = pthread_self() ) == NULL )
+ {
+ /*
+ * Yikes! unable to allocate a thread!
+ * Throw an exception? return an error?
+ */
+ result = &reallyBad;
+ }
+ else
+ {
+ result = &(self->ptErrno);
+ }
+
+ return( result );
+
+} /* _errno */
+
+#endif /* (! HAVE_ERRNO) || (!_REENTRANT && (!_MT || !_MD)) */
diff --git a/win32/contrib/pthreads/exit.c b/win32/contrib/pthreads/exit.c
new file mode 100644
index 000000000..ca9e60ef1
--- /dev/null
+++ b/win32/contrib/pthreads/exit.c
@@ -0,0 +1,91 @@
+/*
+ * exit.c
+ *
+ * Description:
+ * This translation unit implements routines associated with exiting from
+ * a thread.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+#ifndef _UWIN
+# include <process.h>
+#endif
+
+void
+pthread_exit (void *value_ptr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function terminates the calling thread, returning
+ * the value 'value_ptr' to any joining thread.
+ *
+ * PARAMETERS
+ * value_ptr
+ * a generic data value (i.e. not the address of a value)
+ *
+ *
+ * DESCRIPTION
+ * This function terminates the calling thread, returning
+ * the value 'value_ptr' to any joining thread.
+ * NOTE: thread should be joinable.
+ *
+ * RESULTS
+ * N/A
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_t self;
+
+ /* If the current thread is implicit it was not started through
+ pthread_create(), therefore we cleanup and end the thread
+ here. Otherwise we raise an exception to unwind the exception
+ stack. The exception will be caught by ptw32_threadStart(),
+ which will cleanup and end the thread for us.
+ */
+
+ self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
+#ifdef _UWIN
+ if(--pthread_count <= 0)
+ exit((int)value_ptr);
+#endif
+
+ if (self == NULL || self->implicit)
+ {
+ ptw32_callUserDestroyRoutines(self);
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ _endthreadex ((unsigned) value_ptr);
+#else
+ _endthread ();
+#endif
+
+ /* Never reached */
+ }
+
+ self->exitStatus = value_ptr;
+
+// ptw32_throw(PTW32_EPS_EXIT);
+
+ /* Never reached. */
+
+}
diff --git a/win32/contrib/pthreads/fork.c b/win32/contrib/pthreads/fork.c
new file mode 100644
index 000000000..e2ace2595
--- /dev/null
+++ b/win32/contrib/pthreads/fork.c
@@ -0,0 +1,29 @@
+/*
+ * fork.c
+ *
+ * Description:
+ * Implementation of fork() for POSIX threads.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+
+#include "pthread.h"
+#include "implement.h"
+
diff --git a/win32/contrib/pthreads/global.c b/win32/contrib/pthreads/global.c
new file mode 100644
index 000000000..f260fec98
--- /dev/null
+++ b/win32/contrib/pthreads/global.c
@@ -0,0 +1,66 @@
+/*
+ * global.c
+ *
+ * Description:
+ * This translation unit instantiates data associated with the implementation
+ * as a whole.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+int ptw32_processInitialized = FALSE;
+pthread_key_t ptw32_selfThreadKey = NULL;
+pthread_key_t ptw32_cleanupKey = NULL;
+
+int ptw32_concurrency = 0;
+
+/*
+ * Global lock for testing internal state of PTHREAD_MUTEX_INITIALIZER
+ * created mutexes.
+ */
+CRITICAL_SECTION ptw32_mutex_test_init_lock;
+
+/*
+ * Global lock for testing internal state of PTHREAD_COND_INITIALIZER
+ * created condition variables.
+ */
+CRITICAL_SECTION ptw32_cond_test_init_lock;
+
+/*
+ * Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER
+ * created read/write locks.
+ */
+CRITICAL_SECTION ptw32_rwlock_test_init_lock;
+
+/*
+ * Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER
+ * created spin locks.
+ */
+CRITICAL_SECTION ptw32_spinlock_test_init_lock;
+
+#ifdef _UWIN
+/*
+ * Keep a count of the number of threads.
+ */
+int pthread_count = 0;
+#endif
diff --git a/win32/contrib/pthreads/implement.h b/win32/contrib/pthreads/implement.h
new file mode 100644
index 000000000..948dc2fab
--- /dev/null
+++ b/win32/contrib/pthreads/implement.h
@@ -0,0 +1,505 @@
+/*
+ * implement.h
+ *
+ * Definitions that don't need to be public.
+ *
+ * Keeps all the internals out of pthread.h
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#ifndef _IMPLEMENT_H
+#define _IMPLEMENT_H
+
+#if !defined(malloc)
+#include <malloc.h>
+#endif
+
+#if !defined(INT_MAX)
+#include <limits.h>
+#endif
+
+/* use local include files during development */
+#include "semaphore.h"
+#include "sched.h"
+
+#if defined(HAVE_C_INLINE) || defined(__cplusplus)
+#define INLINE inline
+#else
+#define INLINE
+#endif
+
+typedef enum {
+ /*
+ * This enumeration represents the state of the thread;
+ * The thread is still "alive" if the numeric value of the
+ * state is greater or equal "PThreadStateRunning".
+ */
+ PThreadStateInitial = 0, /* Thread not running */
+ PThreadStateRunning, /* Thread alive & kicking */
+ PThreadStateSuspended, /* Thread alive but suspended */
+ PThreadStateCanceling, /* Thread alive but and is */
+ /* in the process of terminating */
+ /* due to a cancellation request */
+ PThreadStateException, /* Thread alive but exiting */
+ /* due to an exception */
+ PThreadStateLast
+}
+PThreadState;
+
+
+typedef enum {
+ /*
+ * This enumeration represents the reason why a thread has
+ * terminated/is terminating.
+ */
+ PThreadDemisePeaceful = 0, /* Death due natural causes */
+ PThreadDemiseCancelled, /* Death due to user cancel */
+ PThreadDemiseException, /* Death due to unhandled */
+ /* exception */
+ PThreadDemiseNotDead /* I'm not dead! */
+}
+PThreadDemise;
+
+struct pthread_t_ {
+#ifdef _UWIN
+ DWORD dummy[5];
+#endif
+ DWORD thread;
+ HANDLE threadH;
+ PThreadState state;
+ PThreadDemise demise;
+ void *exitStatus;
+ void *parms;
+ int ptErrno;
+ int detachState;
+ pthread_mutex_t cancelLock; /* Used for async-cancel safety */
+ int cancelState;
+ int cancelType;
+ HANDLE cancelEvent;
+#ifdef __CLEANUP_C
+ jmp_buf start_mark;
+#endif /* __CLEANUP_C */
+#if HAVE_SIGSET_T
+ sigset_t sigmask;
+#endif /* HAVE_SIGSET_T */
+ int implicit:1;
+ void *keys;
+};
+
+
+/*
+ * Special value to mark attribute objects as valid.
+ */
+#define PTW32_ATTR_VALID ((unsigned long) 0xC4C0FFEE)
+
+struct pthread_attr_t_ {
+ unsigned long valid;
+ void *stackaddr;
+ size_t stacksize;
+ int detachstate;
+ struct sched_param param;
+ int inheritsched;
+#if HAVE_SIGSET_T
+ sigset_t sigmask;
+#endif /* HAVE_SIGSET_T */
+};
+
+
+/*
+ * ====================
+ * ====================
+ * Semaphores, Mutexes and Condition Variables
+ * ====================
+ * ====================
+ */
+
+struct sem_t_ {
+#ifdef NEED_SEM
+ unsigned int value;
+ CRITICAL_SECTION sem_lock_cs;
+ HANDLE event;
+#else /* NEED_SEM */
+ HANDLE sem;
+#endif /* NEED_SEM */
+};
+
+#define PTW32_OBJECT_AUTO_INIT ((void *) -1)
+#define PTW32_OBJECT_INVALID NULL
+
+struct pthread_mutex_t_ {
+ LONG lock_idx;
+ int recursive_count;
+ int kind;
+ pthread_t ownerThread;
+ HANDLE wait_sema;
+ CRITICAL_SECTION try_lock_cs;
+};
+
+struct pthread_mutexattr_t_ {
+ int pshared;
+ int kind;
+};
+
+/*
+ * Possible values, other than PTW32_OBJECT_INVALID,
+ * for the "interlock" element in a spinlock.
+ *
+ * In this implementation, when a spinlock is initialised,
+ * the number of cpus available to the process is checked.
+ * If there is only one cpu then "interlock" is set equal to
+ * PTW32_SPIN_USE_MUTEX and u.mutex is a initialised mutex.
+ * If the number of cpus is greater than 1 then "interlock"
+ * is set equal to PTW32_SPIN_UNLOCKED and the number is
+ * stored in u.cpus. This arrangement allows the spinlock
+ * routines to attempt an InterlockedCompareExchange on "interlock"
+ * immediately and, if that fails, to try the inferior mutex.
+ *
+ * "u.cpus" isn't used for anything yet, but could be used at
+ * some point to optimise spinlock behaviour.
+ */
+#define PTW32_SPIN_UNLOCKED (1)
+#define PTW32_SPIN_LOCKED (2)
+#define PTW32_SPIN_USE_MUTEX (3)
+
+struct pthread_spinlock_t_ {
+ long interlock; /* Locking element for multi-cpus. */
+ union {
+ int cpus; /* No. of cpus if multi cpus, or */
+ pthread_mutex_t mutex; /* mutex if single cpu. */
+ } u;
+};
+
+struct pthread_barrier_t_ {
+ unsigned int nCurrentBarrierHeight;
+ unsigned int nInitialBarrierHeight;
+ int iStep;
+ int pshared;
+ sem_t semBarrierBreeched[2];
+};
+
+struct pthread_barrierattr_t_ {
+ int pshared;
+};
+
+struct pthread_key_t_ {
+ DWORD key;
+ void (*destructor) (void *);
+ pthread_mutex_t threadsLock;
+ void *threads;
+};
+
+
+typedef struct ThreadParms ThreadParms;
+typedef struct ThreadKeyAssoc ThreadKeyAssoc;
+
+struct ThreadParms {
+ pthread_t tid;
+ void *(*start) (void *);
+ void *arg;
+};
+
+
+struct pthread_cond_t_ {
+ long nWaitersBlocked; /* Number of threads blocked */
+ long nWaitersGone; /* Number of threads timed out */
+ 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 */
+};
+
+
+struct pthread_condattr_t_ {
+ int pshared;
+};
+
+#define PTW32_RWLOCK_MAGIC 0xfacade2
+
+struct pthread_rwlock_t_ {
+ pthread_mutex_t mtxExclusiveAccess;
+ pthread_mutex_t mtxSharedAccessCompleted;
+ pthread_cond_t cndSharedAccessCompleted;
+ int nSharedAccessCount;
+ int nExclusiveAccessCount;
+ int nCompletedSharedAccessCount;
+ int nMagic;
+};
+
+struct pthread_rwlockattr_t_ {
+ int pshared;
+};
+
+
+struct ThreadKeyAssoc {
+ /*
+ * Purpose:
+ * This structure creates an association between a
+ * thread and a key.
+ * It is used to implement the implicit invocation
+ * of a user defined destroy routine for thread
+ * specific data registered by a user upon exiting a
+ * thread.
+ *
+ * Attributes:
+ * lock
+ * protects access to the rest of the structure
+ *
+ * thread
+ * reference to the thread that owns the association.
+ * As long as this is not NULL, the association remains
+ * referenced by the pthread_t.
+ *
+ * key
+ * reference to the key that owns the association.
+ * As long as this is not NULL, the association remains
+ * referenced by the pthread_key_t.
+ *
+ * nextKey
+ * The pthread_t->keys attribute is the head of a
+ * chain of associations that runs through the nextKey
+ * link. This chain provides the 1 to many relationship
+ * between a pthread_t and all pthread_key_t on which
+ * it called pthread_setspecific.
+ *
+ * nextThread
+ * The pthread_key_t->threads attribute is the head of
+ * a chain of assoctiations that runs through the
+ * nextThreads link. This chain provides the 1 to many
+ * relationship between a pthread_key_t and all the
+ * PThreads that have called pthread_setspecific for
+ * this pthread_key_t.
+ *
+ *
+ * Notes:
+ * 1) As long as one of the attributes, thread or key, is
+ * not NULL, the association is being referenced; once
+ * both are NULL, the association must be released.
+ *
+ * 2) Under WIN32, an association is only created by
+ * pthread_setspecific if the user provided a
+ * destroyRoutine when they created the key.
+ *
+ *
+ */
+ pthread_mutex_t lock;
+ pthread_t thread;
+ pthread_key_t key;
+ ThreadKeyAssoc *nextKey;
+ ThreadKeyAssoc *nextThread;
+};
+
+
+#ifdef __CLEANUP_SEH
+/*
+ * --------------------------------------------------------------
+ * MAKE_SOFTWARE_EXCEPTION
+ * This macro constructs a software exception code following
+ * the same format as the standard Win32 error codes as defined
+ * in WINERROR.H
+ * Values are 32 bit values layed out as follows:
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---+-+-+-----------------------+-------------------------------+
+ * |Sev|C|R| Facility | Code |
+ * +---+-+-+-----------------------+-------------------------------+
+ *
+ * Severity Values:
+ */
+#define SE_SUCCESS 0x00
+#define SE_INFORMATION 0x01
+#define SE_WARNING 0x02
+#define SE_ERROR 0x03
+
+#define MAKE_SOFTWARE_EXCEPTION( _severity, _facility, _exception ) \
+( (DWORD) ( ( (_severity) << 30 ) | /* Severity code */ \
+ ( 1 << 29 ) | /* MS=0, User=1 */ \
+ ( 0 << 28 ) | /* Reserved */ \
+ ( (_facility) << 16 ) | /* Facility Code */ \
+ ( (_exception) << 0 ) /* Exception Code */ \
+ ) )
+
+/*
+ * We choose one specific Facility/Error code combination to
+ * identify our software exceptions vs. WIN32 exceptions.
+ * We store our actual component and error code within
+ * the optional information array.
+ */
+#define EXCEPTION_PTW32_SERVICES \
+ MAKE_SOFTWARE_EXCEPTION( SE_ERROR, \
+ PTW32_SERVICES_FACILITY, \
+ PTW32_SERVICES_ERROR )
+
+#define PTW32_SERVICES_FACILITY 0xBAD
+#define PTW32_SERVICES_ERROR 0xDEED
+
+#endif /* __CLEANUP_SEH */
+
+/*
+ * Services available through EXCEPTION_PTW32_SERVICES
+ * and also used [as parameters to ptw32_throw()] as
+ * generic exception selectors.
+ */
+
+#define PTW32_EPS_EXIT (1)
+#define PTW32_EPS_CANCEL (2)
+
+/* Mutex constants */
+enum {
+ PTW32_MUTEX_LOCK_IDX_INIT = -1,
+ PTW32_MUTEX_OWNER_ANONYMOUS = 1
+};
+
+
+/* Declared in global.c */
+extern int ptw32_processInitialized;
+extern pthread_key_t ptw32_selfThreadKey;
+extern pthread_key_t ptw32_cleanupKey;
+
+extern int ptw32_mutex_default_kind;
+
+extern int ptw32_concurrency;
+
+extern CRITICAL_SECTION ptw32_mutex_test_init_lock;
+extern CRITICAL_SECTION ptw32_cond_test_init_lock;
+extern CRITICAL_SECTION ptw32_rwlock_test_init_lock;
+extern CRITICAL_SECTION ptw32_spinlock_test_init_lock;
+
+#ifdef _UWIN
+extern int pthread_count;
+#endif
+
+/* Declared in misc.c */
+#ifdef NEED_CALLOC
+#define calloc(n, s) ptw32_calloc(n, s)
+void *ptw32_calloc(size_t n, size_t s);
+#endif
+
+/* Declared in private.c */
+void ptw32_throw(DWORD exception);
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * =====================
+ * =====================
+ * Forward Declarations
+ * =====================
+ * =====================
+ */
+int ptw32_processInitialize (void);
+
+void ptw32_processTerminate (void);
+
+void ptw32_threadDestroy (pthread_t tid);
+
+void ptw32_pop_cleanup_all (int execute);
+
+pthread_t ptw32_new (void);
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+unsigned __stdcall
+#else
+void
+#endif
+ptw32_threadStart (void * vthreadParms);
+
+void ptw32_callUserDestroyRoutines (pthread_t thread);
+
+int ptw32_tkAssocCreate (ThreadKeyAssoc ** assocP,
+ pthread_t thread,
+ pthread_key_t key);
+
+void ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc);
+
+int ptw32_sem_timedwait (sem_t * sem,
+ const struct timespec * abstime);
+
+#ifdef NEED_SEM
+void ptw32_decrease_semaphore(sem_t * sem);
+BOOL ptw32_increase_semaphore(sem_t * sem,
+ unsigned int n);
+#endif /* NEED_SEM */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#ifdef _UWIN_
+# ifdef _MT
+# ifdef __cplusplus
+ extern "C" {
+# endif
+ _CRTIMP unsigned long __cdecl _beginthread (void (__cdecl *) (void *),
+ unsigned, void *);
+ _CRTIMP void __cdecl _endthread(void);
+ _CRTIMP unsigned long __cdecl _beginthreadex(void *, unsigned,
+ unsigned (__stdcall *) (void *), void *, unsigned, unsigned *);
+ _CRTIMP void __cdecl _endthreadex(unsigned);
+# ifdef __cplusplus
+ }
+# endif
+# endif
+#else
+# include <process.h>
+#endif
+
+/*
+ * Check for old and new versions of cygwin. See the FAQ file:
+ *
+ * Question 1 - How do I get pthreads-win32 to link under Cygwin or Mingw32?
+ *
+ * Patch by Anders Norlander <anorland@hem2.passagen.se>
+ */
+#if defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(NEED_CREATETHREAD)
+
+/*
+ * Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE
+ * in order to avoid warnings because of return type
+ */
+
+#define _beginthreadex(security, \
+ stack_size, \
+ start_proc, \
+ arg, \
+ flags, \
+ pid) \
+ CreateThread(security, \
+ stack_size, \
+ (LPTHREAD_START_ROUTINE) start_proc, \
+ arg, \
+ flags, \
+ pid)
+
+#define _endthreadex ExitThread
+
+#endif /* __CYGWIN32__ || __CYGWIN__ || NEED_CREATETHREAD*/
+
+
+#endif /* _IMPLEMENT_H */
+
diff --git a/win32/contrib/pthreads/install-sh b/win32/contrib/pthreads/install-sh
new file mode 100644
index 000000000..7303f8565
--- /dev/null
+++ b/win32/contrib/pthreads/install-sh
@@ -0,0 +1,247 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/win32/contrib/pthreads/misc.c b/win32/contrib/pthreads/misc.c
new file mode 100644
index 000000000..aa06013b4
--- /dev/null
+++ b/win32/contrib/pthreads/misc.c
@@ -0,0 +1,420 @@
+/*
+ * misc.c
+ *
+ * Description:
+ * This translation unit implements miscellaneous thread functions.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#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 */
+
+
+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 mutex or the cancel event
+ * was signaled
+ */
+ switch (status - WAIT_OBJECT_0)
+ {
+
+ case 0:
+ /*
+ * Got the mutex
+ */
+ result = 0;
+ break;
+
+ case 1:
+ /*
+ * Got cancel request
+ */
+ ResetEvent (handles[1]);
+
+ if (self != NULL && !self->implicit)
+ {
+ /*
+ * Thread started with pthread_create
+ */
+ ptw32_throw(PTW32_EPS_CANCEL);
+ }
+
+ /* 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;
+ }
+
+ 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/win32/contrib/pthreads/mutex.c b/win32/contrib/pthreads/mutex.c
new file mode 100644
index 000000000..7896570c1
--- /dev/null
+++ b/win32/contrib/pthreads/mutex.c
@@ -0,0 +1,784 @@
+/*
+ * mutex.c
+ *
+ * Description:
+ * This translation unit implements mutual exclusion (mutex) primitives.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+
+static INLINE int
+ptw32_mutex_check_need_init(pthread_mutex_t *mutex)
+{
+ int result = 0;
+
+ /*
+ * The following guarded test is specifically for statically
+ * initialised mutexes (via PTHREAD_MUTEX_INITIALIZER).
+ *
+ * Note that by not providing this synchronisation we risk
+ * introducing race conditions into applications which are
+ * correctly written.
+ *
+ * Approach
+ * --------
+ * We know that static mutexes 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_mutex_test_init_lock);
+
+ /*
+ * We got here possibly under race
+ * conditions. Check again inside the critical section
+ * and only initialise if the mutex is valid (not been destroyed).
+ * If a static mutex has been destroyed, the application can
+ * re-initialise it only by calling pthread_mutex_init()
+ * explicitly.
+ */
+ if (*mutex == PTHREAD_MUTEX_INITIALIZER)
+ {
+ result = pthread_mutex_init(mutex, NULL);
+ }
+ else if (*mutex == NULL)
+ {
+ /*
+ * The mutex has been destroyed while we were waiting to
+ * initialise it, so the operation that caused the
+ * auto-initialisation should fail.
+ */
+ result = EINVAL;
+ }
+
+ LeaveCriticalSection(&ptw32_mutex_test_init_lock);
+
+ return(result);
+}
+
+int
+pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
+{
+ int result = 0;
+ pthread_mutex_t mx;
+
+ if (mutex == NULL)
+ {
+ return EINVAL;
+ }
+
+ mx = (pthread_mutex_t) calloc(1, sizeof(*mx));
+
+ if (mx == NULL)
+ {
+ result = ENOMEM;
+ goto FAIL0;
+ }
+
+ if (attr != NULL
+ && *attr != NULL
+ && (*attr)->pshared == PTHREAD_PROCESS_SHARED
+ )
+ {
+ /*
+ * Creating mutex that can be shared between
+ * processes.
+ */
+#if _POSIX_THREAD_PROCESS_SHARED
+
+ /*
+ * Not implemented yet.
+ */
+
+#error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet.
+
+
+#else
+
+ result = ENOSYS;
+ goto FAIL0;
+
+#endif /* _POSIX_THREAD_PROCESS_SHARED */
+
+ }
+
+ mx->lock_idx = PTW32_MUTEX_LOCK_IDX_INIT;
+ mx->recursive_count = 0;
+ mx->kind = (attr == NULL || *attr == NULL
+ ? PTHREAD_MUTEX_DEFAULT
+ : (*attr)->kind);
+ mx->ownerThread = NULL;
+ InitializeCriticalSection( &mx->try_lock_cs );
+ mx->wait_sema = CreateSemaphore( NULL, 0, 1, NULL );
+
+ if( NULL == mx->wait_sema )
+ {
+ DeleteCriticalSection( &mx->try_lock_cs );
+ result = EAGAIN;
+ }
+
+ if (result != 0 && mx != NULL)
+ {
+ free(mx);
+ mx = NULL;
+ }
+
+FAIL0:
+ *mutex = mx;
+
+ return(result);
+}
+
+int
+pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ int result = 0;
+ pthread_mutex_t mx;
+
+ if (mutex == NULL
+ || *mutex == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * Check to see if we have something to delete.
+ */
+ if (*mutex != PTHREAD_MUTEX_INITIALIZER)
+ {
+ mx = *mutex;
+
+ result = pthread_mutex_trylock(&mx);
+
+ /*
+ * The mutex type may not be RECURSIVE therefore trylock may return EBUSY if
+ * we already own the mutex. Here we are assuming that it's OK to destroy
+ * a mutex that we own and have locked recursively. Is this correct?
+ *
+ * For FAST mutexes we record the owner as ANONYMOUS for speed. In this
+ * case we assume that the thread calling pthread_mutex_destroy() is the
+ * owner, if the mutex is owned at all.
+ */
+ if (result == 0
+ || mx->ownerThread == (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS
+ || pthread_equal( mx->ownerThread, pthread_self() ) )
+ {
+ /*
+ * FIXME!!!
+ * The mutex isn't held by another thread but we could still
+ * be too late invalidating the mutex below since another thread
+ * may alredy have entered mutex_lock and the check for a valid
+ * *mutex != NULL.
+ */
+ *mutex = NULL;
+
+ result = pthread_mutex_unlock(&mx);
+
+ if (result == 0)
+ {
+ DeleteCriticalSection( &mx->try_lock_cs );
+ CloseHandle( mx->wait_sema );
+ free(mx);
+ }
+ else
+ {
+ /*
+ * Restore the mutex before we return the error.
+ */
+ *mutex = mx;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * See notes in ptw32_mutex_check_need_init() above also.
+ */
+ EnterCriticalSection(&ptw32_mutex_test_init_lock);
+
+ /*
+ * Check again.
+ */
+ if (*mutex == PTHREAD_MUTEX_INITIALIZER)
+ {
+ /*
+ * This is all we need to do to destroy a statically
+ * initialised mutex that has not yet been used (initialised).
+ * If we get to here, another thread
+ * waiting to initialise this mutex will get an EINVAL.
+ */
+ *mutex = NULL;
+ }
+ else
+ {
+ /*
+ * The mutex has been initialised while we were waiting
+ * so assume it's in use.
+ */
+ result = EBUSY;
+ }
+
+ LeaveCriticalSection(&ptw32_mutex_test_init_lock);
+ }
+
+ return(result);
+}
+
+int
+pthread_mutexattr_init (pthread_mutexattr_t * attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Initializes a mutex attributes object with default
+ * attributes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_mutexattr_t
+ *
+ *
+ * DESCRIPTION
+ * Initializes a mutex attributes object with default
+ * attributes.
+ *
+ * NOTES:
+ * 1) Used to define mutex types
+ *
+ * RESULTS
+ * 0 successfully initialized attr,
+ * ENOMEM insufficient memory for attr.
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_mutexattr_t ma;
+ int result = 0;
+
+ ma = (pthread_mutexattr_t) calloc (1, sizeof (*ma));
+
+ if (ma == NULL)
+ {
+ result = ENOMEM;
+ }
+
+ ma->pshared = PTHREAD_PROCESS_PRIVATE;
+ ma->kind = PTHREAD_MUTEX_DEFAULT;
+
+ *attr = ma;
+
+ return (result);
+
+} /* pthread_mutexattr_init */
+
+
+int
+pthread_mutexattr_destroy (pthread_mutexattr_t * attr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Destroys a mutex attributes object. The object can
+ * no longer be used.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_mutexattr_t
+ *
+ *
+ * DESCRIPTION
+ * Destroys a mutex attributes object. The object can
+ * no longer be used.
+ *
+ * NOTES:
+ * 1) Does not affect mutexes created using 'attr'
+ *
+ * RESULTS
+ * 0 successfully released attr,
+ * EINVAL 'attr' is invalid.
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if (attr == NULL || *attr == NULL)
+ {
+ result = EINVAL;
+ }
+ else
+ {
+ pthread_mutexattr_t ma = *attr;
+
+ *attr = NULL;
+ free (ma);
+
+ result = 0;
+ }
+
+ return (result);
+
+} /* pthread_mutexattr_destroy */
+
+
+int
+pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr,
+ int *pshared)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * Determine whether mutexes created with 'attr' can be
+ * shared between processes.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_mutexattr_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
+ * 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 retrieved attribute,
+ * EINVAL 'attr' is invalid,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ if ((attr != NULL && *attr != NULL) &&
+ (pshared != NULL))
+ {
+ *pshared = (*attr)->pshared;
+ result = 0;
+ }
+ else
+ {
+ *pshared = PTHREAD_PROCESS_PRIVATE;
+ result = EINVAL;
+ }
+
+ return (result);
+
+} /* pthread_mutexattr_getpshared */
+
+
+int
+pthread_mutexattr_setpshared (pthread_mutexattr_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_mutexattr_setpshared */
+
+
+int
+pthread_mutexattr_settype (pthread_mutexattr_t * attr,
+ int kind)
+ /*
+ * ------------------------------------------------------
+ *
+ * DOCPUBLIC
+ * The pthread_mutexattr_settype() and
+ * pthread_mutexattr_gettype() functions respectively set and
+ * get the mutex type attribute. This attribute is set in the
+ * type parameter to these functions.
+ *
+ * PARAMETERS
+ * attr
+ * pointer to an instance of pthread_mutexattr_t
+ *
+ * type
+ * must be one of:
+ *
+ * PTHREAD_MUTEX_DEFAULT
+ *
+ * PTHREAD_MUTEX_NORMAL
+ *
+ * PTHREAD_MUTEX_ERRORCHECK
+ *
+ * PTHREAD_MUTEX_RECURSIVE
+ *
+ * DESCRIPTION
+ * The pthread_mutexattr_settype() and
+ * pthread_mutexattr_gettype() functions respectively set and
+ * get the mutex type attribute. This attribute is set in the
+ * type parameter to these functions. The default value of the
+ * type attribute is PTHREAD_MUTEX_DEFAULT.
+ *
+ * The type of mutex is contained in the type attribute of the
+ * mutex attributes. Valid mutex types include:
+ *
+ * PTHREAD_MUTEX_NORMAL
+ * This type of mutex does not detect deadlock. A
+ * thread attempting to relock this mutex without
+ * first unlocking it will deadlock. Attempting to
+ * unlock a mutex locked by a different thread
+ * results in undefined behavior. Attempting to
+ * unlock an unlocked mutex results in undefined
+ * behavior.
+ *
+ * PTHREAD_MUTEX_ERRORCHECK
+ * This type of mutex provides error checking. A
+ * thread attempting to relock this mutex without
+ * first unlocking it will return with an error. A
+ * thread attempting to unlock a mutex which another
+ * thread has locked will return with an error. A
+ * thread attempting to unlock an unlocked mutex will
+ * return with an error.
+ *
+ * PTHREAD_MUTEX_DEFAULT
+ * Same as PTHREAD_MUTEX_NORMAL.
+ *
+ * PTHREAD_MUTEX_RECURSIVE
+ * A thread attempting to relock this mutex without
+ * first unlocking it will succeed in locking the
+ * mutex. The relocking deadlock which can occur with
+ * mutexes of type PTHREAD_MUTEX_NORMAL cannot occur
+ * with this type of mutex. Multiple locks of this
+ * mutex require the same number of unlocks to
+ * release the mutex before another thread can
+ * acquire the mutex. A thread attempting to unlock a
+ * mutex which another thread has locked will return
+ * with an error. A thread attempting to unlock an
+ * unlocked mutex will return with an error. This
+ * type of mutex is only supported for mutexes whose
+ * process shared attribute is
+ * PTHREAD_PROCESS_PRIVATE.
+ *
+ * RESULTS
+ * 0 successfully set attribute,
+ * EINVAL 'attr' or 'type' is invalid,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if ((attr != NULL && *attr != NULL))
+ {
+ switch (kind)
+ {
+ case PTHREAD_MUTEX_FAST_NP:
+ case PTHREAD_MUTEX_RECURSIVE_NP:
+ case PTHREAD_MUTEX_ERRORCHECK_NP:
+ (*attr)->kind = kind;
+ break;
+ default:
+ result = EINVAL;
+ break;
+ }
+ }
+ else
+ {
+ result = EINVAL;
+ }
+
+ return (result);
+} /* pthread_mutexattr_settype */
+
+
+int
+pthread_mutexattr_gettype (pthread_mutexattr_t * attr,
+ int *kind)
+{
+ int result = 0;
+
+ if (attr != NULL && *attr != NULL && kind != NULL)
+ {
+ *kind = (*attr)->kind;
+ }
+ else
+ {
+ result = EINVAL;
+ }
+
+ return (result);
+}
+
+
+int
+pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ int result = 0;
+ pthread_mutex_t mx;
+
+
+ if (mutex == NULL || *mutex == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static mutex. We check
+ * again inside the guarded section of ptw32_mutex_check_need_init()
+ * to avoid race conditions.
+ */
+ if (*mutex == PTHREAD_MUTEX_INITIALIZER)
+ {
+ if ((result = ptw32_mutex_check_need_init(mutex)) != 0)
+ {
+ return(result);
+ }
+ }
+
+ mx = *mutex;
+
+ if( 0 == InterlockedIncrement( &mx->lock_idx ) )
+ {
+ mx->recursive_count = 1;
+ mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP
+ ? pthread_self()
+ : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS);
+ }
+ else
+ {
+ if( mx->kind != PTHREAD_MUTEX_FAST_NP &&
+ pthread_equal( mx->ownerThread, pthread_self() ) )
+ {
+ mx->lock_idx--;
+
+ if( mx->kind == PTHREAD_MUTEX_RECURSIVE_NP )
+ {
+ mx->recursive_count++;
+ }
+ else
+ {
+ result = EDEADLK;
+ }
+ }
+ else
+ {
+ WaitForSingleObject( mx->wait_sema, INFINITE );
+ mx->recursive_count = 1;
+ mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP
+ ? pthread_self()
+ : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS);
+ }
+ }
+
+ return(result);
+}
+
+int
+pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ int result = 0;
+ pthread_mutex_t mx;
+
+ if (mutex == NULL || *mutex == NULL)
+ {
+ return EINVAL;
+ }
+
+ mx = *mutex;
+
+ /*
+ * If the thread calling us holds the mutex then there is no
+ * race condition. If another thread holds the
+ * lock then we shouldn't be in here.
+ */
+ if (mx != PTHREAD_MUTEX_INITIALIZER)
+ {
+ if (mx->ownerThread == (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS
+ || pthread_equal(mx->ownerThread, pthread_self()))
+ {
+ if( mx->kind != PTHREAD_MUTEX_RECURSIVE_NP
+ || 0 == --mx->recursive_count )
+ {
+ mx->ownerThread = NULL;
+
+ EnterCriticalSection( &mx->try_lock_cs );
+
+ if( InterlockedDecrement( &mx->lock_idx ) >= 0 )
+ {
+ /* Someone is waiting on that mutex */
+ ReleaseSemaphore( mx->wait_sema, 1, NULL );
+ }
+
+ LeaveCriticalSection( &mx->try_lock_cs );
+ }
+ }
+ else
+ {
+ result = EPERM;
+ }
+ }
+ else
+ {
+ result = EINVAL;
+ }
+
+ return(result);
+}
+
+int
+pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ int result = 0;
+ pthread_mutex_t mx;
+
+ if (mutex == NULL || *mutex == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static mutex. We check
+ * again inside the guarded section of ptw32_mutex_check_need_init()
+ * to avoid race conditions.
+ */
+ if (*mutex == PTHREAD_MUTEX_INITIALIZER)
+ {
+ result = ptw32_mutex_check_need_init(mutex);
+ }
+
+ mx = *mutex;
+
+ if (result == 0)
+ {
+ /* Try to lock only if mutex seems available */
+ if( PTW32_MUTEX_LOCK_IDX_INIT == mx->lock_idx )
+ {
+ EnterCriticalSection( &mx->try_lock_cs );
+
+ if( 0 == InterlockedIncrement( &mx->lock_idx ) )
+ {
+ mx->recursive_count = 1;
+ mx->ownerThread = (mx->kind != PTHREAD_MUTEX_FAST_NP
+ ? pthread_self()
+ : (pthread_t) PTW32_MUTEX_OWNER_ANONYMOUS);
+ }
+ else
+ {
+ mx->lock_idx--;
+ result = EBUSY;
+ }
+
+ LeaveCriticalSection( &mx->try_lock_cs );
+ }
+ else
+ {
+ result = EBUSY;
+ }
+ }
+
+ return(result);
+}
diff --git a/win32/contrib/pthreads/need_errno.h b/win32/contrib/pthreads/need_errno.h
new file mode 100644
index 000000000..d52313575
--- /dev/null
+++ b/win32/contrib/pthreads/need_errno.h
@@ -0,0 +1,132 @@
+/***
+* errno.h - system wide error numbers (set by system calls)
+*
+* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
+*
+* Purpose:
+* This file defines the system-wide error numbers (set by
+* system calls). Conforms to the XENIX standard. Extended
+* for compatibility with Uniforum standard.
+* [System V]
+*
+* [Public]
+*
+****/
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#ifndef _INC_ERRNO
+#define _INC_ERRNO
+
+#if !defined(_WIN32) && !defined(_MAC)
+#error ERROR: Only Mac or Win32 targets supported!
+#endif
+
+#include <winsock.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/* Define _CRTIMP */
+
+#ifndef _CRTIMP
+#ifdef _DLL
+#define _CRTIMP __declspec(dllimport)
+#else /* ndef _DLL */
+#define _CRTIMP
+#endif /* _DLL */
+#endif /* _CRTIMP */
+
+
+/* Define __cdecl for non-Microsoft compilers */
+
+#if ( !defined(_MSC_VER) && !defined(__cdecl) )
+#define __cdecl
+#endif
+
+/* Define _CRTAPI1 (for compatibility with the NT SDK) */
+
+#ifndef _CRTAPI1
+#if _MSC_VER >= 800 && _M_IX86 >= 300
+#define _CRTAPI1 __cdecl
+#else
+#define _CRTAPI1
+#endif
+#endif
+
+
+/* declare reference to errno */
+
+#if (defined(_MT) || defined(_MD) || defined(_DLL)) && !defined(_MAC)
+_CRTIMP extern int * __cdecl _errno(void);
+#define errno (*_errno())
+#else /* ndef _MT && ndef _MD && ndef _DLL */
+_CRTIMP extern int errno;
+#endif /* _MT || _MD || _DLL */
+
+/* Error Codes */
+
+#define EPERM 1
+#define ENOENT 2
+#define ESRCH 3
+#define EINTR 4
+#define EIO 5
+#define ENXIO 6
+#define E2BIG 7
+#define ENOEXEC 8
+#define EBADF 9
+#define ECHILD 10
+#define EAGAIN 11
+#define ENOMEM 12
+#define EACCES 13
+#define EFAULT 14
+#define EBUSY 16
+#define EEXIST 17
+#define EXDEV 18
+#define ENODEV 19
+#define ENOTDIR 20
+#define EISDIR 21
+#define EINVAL 22
+#define ENFILE 23
+#define EMFILE 24
+#define ENOTTY 25
+#define EFBIG 27
+#define ENOSPC 28
+#define ESPIPE 29
+#define EROFS 30
+#define EMLINK 31
+#define EPIPE 32
+#define EDOM 33
+#define ERANGE 34
+#define EDEADLK 36
+
+/* defined differently in winsock.h on WinCE */
+#ifndef ENAMETOOLONG
+#define ENAMETOOLONG 38
+#endif
+
+#define ENOLCK 39
+#define ENOSYS 40
+
+/* defined differently in winsock.h on WinCE */
+#ifndef ENOTEMPTY
+#define ENOTEMPTY 41
+#endif
+
+#define EILSEQ 42
+
+/*
+ * Support EDEADLOCK for compatibiity with older MS-C versions.
+ */
+#define EDEADLOCK EDEADLK
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _INC_ERRNO */
diff --git a/win32/contrib/pthreads/nonportable.c b/win32/contrib/pthreads/nonportable.c
new file mode 100644
index 000000000..078842ff0
--- /dev/null
+++ b/win32/contrib/pthreads/nonportable.c
@@ -0,0 +1,248 @@
+/*
+ * nonportable.c
+ *
+ * Description:
+ * This translation unit implements non-portable thread functions.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#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;
+}
+
+
+/*
+ * Provide pthread_delay_np posix function for NT
+ *
+ * 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, secs_in_millisecs, millisecs;
+
+ /*
+ * We are a cancelation point.
+ */
+ pthread_testcancel();
+
+ if (interval->tv_sec < 0 || interval->tv_nsec < 0)
+ {
+ return (EINVAL);
+ }
+
+ secs_in_millisecs = interval->tv_sec * 1000L; /* convert secs to millisecs */
+
+ /*
+ * Pedantically, we're ensuring that we don't return before the time is up,
+ * even by a fraction of a millisecond.
+ */
+ millisecs = (interval->tv_nsec + 999999L) / 1000000L; /* convert nanosecs to millisecs */
+
+ wait_time = secs_in_millisecs + millisecs;
+
+ Sleep(wait_time);
+
+ pthread_testcancel();
+
+ return (0);
+}
+
+
+/*
+ * pthread_getprocessors_np()
+ *
+ * Get the number of CPUs available to the process.
+ *
+ * If the available number of CPUs is 1 then pthread_spin_lock()
+ * will block rather than spin if the lock is already owned.
+ *
+ * pthread_spin_init() calls this routine when initialising
+ * a spinlock. If the number of available processors changes
+ * (after a call to SetProcessAffinityMask()) then only
+ * newly initialised spinlocks will notice.
+ */
+int
+pthread_getprocessors_np(int * count)
+{
+ DWORD vProcessCPUs;
+ DWORD vSystemCPUs;
+ int result = 0;
+
+ if (GetProcessAffinityMask(GetCurrentProcess(),
+ &vProcessCPUs,
+ &vSystemCPUs))
+ {
+ DWORD bit;
+ int CPUs = 0;
+
+ for (bit = 1; bit != 0; bit <<= 1)
+ {
+ if (vProcessCPUs & bit)
+ {
+ CPUs++;
+ }
+ }
+ *count = CPUs;
+ }
+ else
+ {
+ result = EAGAIN;
+ }
+
+ return(result);
+}
+
+
+BOOL
+pthread_win32_process_attach_np ()
+{
+ BOOL result = TRUE;
+
+ result = ptw32_processInitialize ();
+#ifdef _UWIN
+ pthread_count++;
+#endif
+
+ 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 ();
+ }
+
+ 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/win32/contrib/pthreads/private.c b/win32/contrib/pthreads/private.c
new file mode 100644
index 000000000..9b10afb11
--- /dev/null
+++ b/win32/contrib/pthreads/private.c
@@ -0,0 +1,1022 @@
+/*
+ * private.c
+ *
+ * Description:
+ * This translation unit implements routines which are private to
+ * the implementation and may be used throughout it.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#ifndef _UWIN
+# include <process.h>
+#endif
+#ifndef NEED_FTIME
+#include <sys/timeb.h>
+#endif
+#include "pthread.h"
+#include "semaphore.h"
+#include "implement.h"
+
+
+int
+ptw32_processInitialize (void)
+ /*
+ * ------------------------------------------------------
+ * DOCPRIVATE
+ * This function performs process wide initialization for
+ * the pthread library.
+ *
+ * PARAMETERS
+ * N/A
+ *
+ * DESCRIPTION
+ * This function performs process wide initialization for
+ * the pthread library.
+ * If successful, this routine sets the global variable
+ * ptw32_processInitialized to TRUE.
+ *
+ * RESULTS
+ * TRUE if successful,
+ * FALSE otherwise
+ *
+ * ------------------------------------------------------
+ */
+{
+ if (ptw32_processInitialized) {
+ /*
+ * ignore if already initialized. this is useful for
+ * programs that uses a non-dll pthread
+ * library. such programs must call ptw32_processInitialize() explicitely,
+ * since this initialization routine is automatically called only when
+ * the dll is loaded.
+ */
+ return TRUE;
+ }
+
+ ptw32_processInitialized = TRUE;
+
+ /*
+ * Initialize Keys
+ */
+ if ((pthread_key_create (&ptw32_selfThreadKey, NULL) != 0) ||
+ (pthread_key_create (&ptw32_cleanupKey, NULL) != 0))
+ {
+
+ ptw32_processTerminate ();
+ }
+
+ /*
+ * Set up the global test and init check locks.
+ */
+ InitializeCriticalSection(&ptw32_mutex_test_init_lock);
+ InitializeCriticalSection(&ptw32_cond_test_init_lock);
+ InitializeCriticalSection(&ptw32_rwlock_test_init_lock);
+ InitializeCriticalSection(&ptw32_spinlock_test_init_lock);
+
+ return (ptw32_processInitialized);
+
+} /* processInitialize */
+
+void
+ptw32_processTerminate (void)
+ /*
+ * ------------------------------------------------------
+ * DOCPRIVATE
+ * This function performs process wide termination for
+ * the pthread library.
+ *
+ * PARAMETERS
+ * N/A
+ *
+ * DESCRIPTION
+ * This function performs process wide termination for
+ * the pthread library.
+ * This routine sets the global variable
+ * ptw32_processInitialized to FALSE
+ *
+ * RESULTS
+ * N/A
+ *
+ * ------------------------------------------------------
+ */
+{
+ if (ptw32_processInitialized)
+ {
+
+ if (ptw32_selfThreadKey != NULL)
+ {
+ /*
+ * Release ptw32_selfThreadKey
+ */
+ pthread_key_delete (ptw32_selfThreadKey);
+
+ ptw32_selfThreadKey = NULL;
+ }
+
+ if (ptw32_cleanupKey != NULL)
+ {
+ /*
+ * Release ptw32_cleanupKey
+ */
+ pthread_key_delete (ptw32_cleanupKey);
+
+ ptw32_cleanupKey = NULL;
+ }
+
+ /*
+ * Destroy the global test and init check locks.
+ */
+ DeleteCriticalSection(&ptw32_spinlock_test_init_lock);
+ DeleteCriticalSection(&ptw32_rwlock_test_init_lock);
+ DeleteCriticalSection(&ptw32_cond_test_init_lock);
+ DeleteCriticalSection(&ptw32_mutex_test_init_lock);
+
+ ptw32_processInitialized = FALSE;
+ }
+
+} /* processTerminate */
+
+#ifdef __CLEANUP_SEH
+
+static DWORD
+ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei)
+{
+ switch (ep->ExceptionRecord->ExceptionCode)
+ {
+ case EXCEPTION_PTW32_SERVICES:
+ {
+ DWORD param;
+ DWORD numParams = ep->ExceptionRecord->NumberParameters;
+
+ numParams = (numParams > 3) ? 3 : numParams;
+
+ for (param = 0; param < numParams; param++)
+ {
+ ei[param] = ep->ExceptionRecord->ExceptionInformation[param];
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+ break;
+ }
+ default:
+ {
+ /*
+ * A system unexpected exception has occurred running the user's
+ * routine. We need to cleanup before letting the exception
+ * out of thread scope.
+ */
+ pthread_t self = pthread_self();
+
+ (void) pthread_mutex_destroy(&self->cancelLock);
+ ptw32_callUserDestroyRoutines(self);
+
+ return EXCEPTION_CONTINUE_SEARCH;
+ break;
+ }
+ }
+}
+
+#elif defined(__CLEANUP_CXX)
+
+#if defined(_MSC_VER)
+#include <eh.h>
+static terminate_function ptw32_oldTerminate;
+#else
+#include <new.h>
+static terminate_handler ptw32_oldTerminate;
+#endif
+
+#if 0
+#include <stdio.h>
+static pthread_mutex_t termLock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+void
+ptw32_terminate ()
+{
+ pthread_t self = pthread_self();
+#if 0
+ FILE * fp;
+ pthread_mutex_lock(&termLock);
+ fp = fopen("pthread.log", "a");
+ fprintf(fp, "Terminate\n");
+ fclose(fp);
+ pthread_mutex_unlock(&termLock);
+#endif
+ set_terminate(ptw32_oldTerminate);
+ (void) pthread_mutex_destroy(&self->cancelLock);
+ ptw32_callUserDestroyRoutines(self);
+ terminate();
+}
+
+#endif /* _MSC_VER */
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+unsigned __stdcall
+#else
+void
+#endif
+ptw32_threadStart (void * vthreadParms)
+{
+ ThreadParms *threadParms = (ThreadParms *) vthreadParms;
+ pthread_t self;
+ void *(*start) (void *);
+ void *arg;
+
+#ifdef __CLEANUP_SEH
+ DWORD ei[] = {0,0,0};
+#endif
+
+#ifdef __CLEANUP_C
+ int setjmp_rc;
+#endif
+
+ void * status = (void *) 0;
+
+ self = threadParms->tid;
+ start = threadParms->start;
+ arg = threadParms->arg;
+
+ free (threadParms);
+
+#if defined (__MINGW32__) && ! defined (__MSVCRT__)
+ /*
+ * beginthread does not return the thread id and is running
+ * before it returns us the thread handle, and so we do it here.
+ */
+ self->thread = GetCurrentThreadId ();
+ if (pthread_mutex_lock(&self->cancelLock) == 0)
+ {
+ /*
+ * We got the lock which means that our creator has
+ * our thread handle. Unlock and continue on.
+ */
+ (void) pthread_mutex_unlock(&self->cancelLock);
+ }
+#endif
+
+ pthread_setspecific (ptw32_selfThreadKey, self);
+
+#ifdef __CLEANUP_SEH
+
+ __try
+ {
+ /*
+ * Run the caller's routine;
+ */
+ status = self->exitStatus = (*start) (arg);
+#ifdef _UWIN
+ if (--pthread_count <= 0)
+ exit(0);
+#endif
+
+ }
+ __except (ExceptionFilter(GetExceptionInformation(), ei))
+ {
+ switch (ei[0])
+ {
+ case PTW32_EPS_CANCEL:
+ status = PTHREAD_CANCELED;
+#ifdef _UWIN
+ if (--pthread_count <= 0)
+ exit(0);
+#endif
+ break;
+ case PTW32_EPS_EXIT:
+ status = self->exitStatus;
+ break;
+ default:
+ status = PTHREAD_CANCELED;
+ break;
+ }
+ }
+
+#else /* __CLEANUP_SEH */
+
+#ifdef __CLEANUP_C
+
+ setjmp_rc = setjmp( self->start_mark );
+
+ if( 0 == setjmp_rc ) {
+
+ /*
+ * Run the caller's routine;
+ */
+ status = self->exitStatus = (*start) (arg);
+ }
+
+ else {
+
+ switch (setjmp_rc)
+ {
+ case PTW32_EPS_CANCEL:
+ status = PTHREAD_CANCELED;
+ break;
+ case PTW32_EPS_EXIT:
+ status = self->exitStatus;
+ break;
+ default:
+ status = PTHREAD_CANCELED;
+ break;
+ }
+ }
+
+#else /* __CLEANUP_C */
+
+#ifdef __CLEANUP_CXX
+
+ ptw32_oldTerminate = set_terminate(&ptw32_terminate);
+
+ try
+ {
+ /*
+ * Run the caller's routine in a nested try block so that we
+ * can run the user's terminate function, which may call
+ * pthread_exit() or be canceled.
+ */
+ try
+ {
+ status = self->exitStatus = (*start) (arg);
+ }
+ catch (ptw32_exception &)
+ {
+ /*
+ * Pass these through to the outer block.
+ */
+ throw;
+ }
+ catch(...)
+ {
+ /*
+ * We want to run the user's terminate function if supplied.
+ * That function may call pthread_exit() or be canceled, which will
+ * be handled by the outer try block.
+ *
+ * ptw32_terminate() will be called if there is no user
+ * supplied function.
+ */
+
+#if defined(_MSC_VER)
+ terminate_function term_func = set_terminate(0);
+#else
+ terminate_handler term_func = set_terminate(0);
+#endif
+
+ set_terminate(term_func);
+
+ if (term_func != 0) {
+ term_func();
+ }
+
+ throw;
+ }
+ }
+ catch (ptw32_exception_cancel &)
+ {
+ /*
+ * Thread was cancelled.
+ */
+ status = self->exitStatus = PTHREAD_CANCELED;
+ }
+ catch (ptw32_exception_exit &)
+ {
+ /*
+ * Thread was exited via pthread_exit().
+ */
+ status = self->exitStatus;
+ }
+ catch (...)
+ {
+ /*
+ * A system unexpected exception has occurred running the user's
+ * terminate routine. We get control back within this block - cleanup
+ * and release the exception out of thread scope.
+ */
+ status = self->exitStatus = PTHREAD_CANCELED;
+ (void) pthread_mutex_destroy(&self->cancelLock);
+ (void) set_terminate(ptw32_oldTerminate);
+ ptw32_callUserDestroyRoutines(self);
+ throw;
+
+ /*
+ * Never reached.
+ */
+ }
+
+ (void) set_terminate(ptw32_oldTerminate);
+
+#else
+
+#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
+
+#endif /* __CLEANUP_CXX */
+#endif /* __CLEANUP_C */
+#endif /* __CLEANUP_SEH */
+
+
+ (void) pthread_mutex_destroy(&self->cancelLock);
+
+#if 1
+ if (self->detachState == PTHREAD_CREATE_DETACHED)
+ {
+ /*
+ * We need to cleanup the pthread now in case we have
+ * been statically linked, in which case the cleanup
+ * in dllMain won't get done. Joinable threads will
+ * be cleaned up by pthread_join().
+ *
+ * Note that implicitly created pthreads (those created
+ * for Win32 threads which have called pthreads routines)
+ * must be cleaned up explicitly by the application
+ * (by calling pthread_win32_thread_detach_np()) if
+ * this library has been statically linked. For the dll,
+ * dllMain will do the cleanup automatically.
+ */
+ (void) pthread_win32_thread_detach_np ();
+ }
+ else
+ {
+ ptw32_callUserDestroyRoutines (self);
+ }
+#else
+ ptw32_callUserDestroyRoutines (self);
+#endif
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ _endthreadex ((unsigned) status);
+#else
+ _endthread ();
+#endif
+
+ /*
+ * Never reached.
+ */
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ return (unsigned) status;
+#endif
+
+} /* ptw32_threadStart */
+
+void
+ptw32_threadDestroy (pthread_t thread)
+{
+ if (thread != NULL)
+ {
+ ptw32_callUserDestroyRoutines (thread);
+
+ if (thread->cancelEvent != NULL)
+ {
+ CloseHandle (thread->cancelEvent);
+ }
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ /* See documentation for endthread vs endthreadex. */
+ if( thread->threadH != 0 )
+ {
+ CloseHandle( thread->threadH );
+ }
+#endif
+
+ free (thread);
+ }
+
+} /* ptw32_threadDestroy */
+
+int
+ptw32_tkAssocCreate (ThreadKeyAssoc ** assocP,
+ pthread_t thread,
+ pthread_key_t key)
+ /*
+ * -------------------------------------------------------------------
+ * This routine creates an association that
+ * is unique for the given (thread,key) combination.The association
+ * is referenced by both the thread and the key.
+ * This association allows us to determine what keys the
+ * current thread references and what threads a given key
+ * references.
+ * See the detailed description
+ * at the beginning of this file for further details.
+ *
+ * Notes:
+ * 1) New associations are pushed to the beginning of the
+ * chain so that the internal ptw32_selfThreadKey association
+ * is always last, thus allowing selfThreadExit to
+ * be implicitly called by pthread_exit last.
+ *
+ * Parameters:
+ * assocP
+ * address into which the association is returned.
+ * thread
+ * current running thread. If NULL, then association
+ * is only added to the key. A NULL thread indicates
+ * that the user called pthread_setspecific prior
+ * to starting a thread. That's ok.
+ * key
+ * key on which to create an association.
+ * Returns:
+ * 0 - if successful,
+ * ENOMEM - not enough memory to create assoc or other object
+ * EINVAL - an internal error occurred
+ * ENOSYS - an internal error occurred
+ * -------------------------------------------------------------------
+ */
+{
+ int result;
+ ThreadKeyAssoc *assoc;
+
+ /*
+ * Have to create an association and add it
+ * to both the key and the thread.
+ */
+ assoc = (ThreadKeyAssoc *) calloc (1, sizeof (*assoc));
+
+ if (assoc == NULL)
+ {
+ result = ENOMEM;
+ goto FAIL0;
+ }
+
+ /*
+ * Initialise only when used for the first time.
+ */
+ assoc->lock = PTHREAD_MUTEX_INITIALIZER;
+ assoc->thread = thread;
+ assoc->key = key;
+
+ /*
+ * Register assoc with key
+ */
+ if ((result = pthread_mutex_lock (&(key->threadsLock))) != 0)
+ {
+ goto FAIL2;
+ }
+
+ assoc->nextThread = (ThreadKeyAssoc *) key->threads;
+ key->threads = (void *) assoc;
+
+ pthread_mutex_unlock (&(key->threadsLock));
+
+ if (thread != NULL)
+ {
+ /*
+ * Register assoc with thread
+ */
+ assoc->nextKey = (ThreadKeyAssoc *) thread->keys;
+ thread->keys = (void *) assoc;
+ }
+
+ *assocP = assoc;
+
+ return (result);
+
+ /*
+ * -------------
+ * Failure Code
+ * -------------
+ */
+FAIL2:
+ pthread_mutex_destroy (&(assoc->lock));
+ free (assoc);
+
+FAIL0:
+
+ return (result);
+
+} /* ptw32_tkAssocCreate */
+
+
+void
+ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc)
+ /*
+ * -------------------------------------------------------------------
+ * This routine releases all resources for the given ThreadKeyAssoc
+ * once it is no longer being referenced
+ * ie) both the key and thread have stopped referencing it.
+ *
+ * Parameters:
+ * assoc
+ * an instance of ThreadKeyAssoc.
+ * Returns:
+ * N/A
+ * -------------------------------------------------------------------
+ */
+{
+
+ if ((assoc != NULL) &&
+ (assoc->key == NULL && assoc->thread == NULL))
+ {
+
+ pthread_mutex_destroy (&(assoc->lock));
+
+ free (assoc);
+ }
+
+} /* ptw32_tkAssocDestroy */
+
+
+void
+ptw32_callUserDestroyRoutines (pthread_t thread)
+ /*
+ * -------------------------------------------------------------------
+ * DOCPRIVATE
+ *
+ * This the routine runs through all thread keys and calls
+ * the destroy routines on the user's data for the current thread.
+ * It simulates the behaviour of POSIX Threads.
+ *
+ * PARAMETERS
+ * thread
+ * an instance of pthread_t
+ *
+ * RETURNS
+ * N/A
+ * -------------------------------------------------------------------
+ */
+{
+ ThreadKeyAssoc **nextP;
+ ThreadKeyAssoc *assoc;
+
+ if (thread != NULL)
+ {
+ /*
+ * Run through all Thread<-->Key associations
+ * for the current thread.
+ * If the pthread_key_t still exits (ie the assoc->key
+ * is not NULL) then call the user's TSD destroy routine.
+ * Notes:
+ * If assoc->key is NULL, then the user previously called
+ * PThreadKeyDestroy. The association is now only referenced
+ * by the current thread and must be released; otherwise
+ * the assoc will be destroyed when the key is destroyed.
+ */
+ nextP = (ThreadKeyAssoc **) & (thread->keys);
+ assoc = *nextP;
+
+ while (assoc != NULL)
+ {
+
+ if (pthread_mutex_lock (&(assoc->lock)) == 0)
+ {
+ pthread_key_t k;
+ if ((k = assoc->key) != NULL)
+ {
+ /*
+ * Key still active; pthread_key_delete
+ * will block on this same mutex before
+ * it can release actual key; therefore,
+ * key is valid and we can call the destroy
+ * routine;
+ */
+ void *value = NULL;
+
+ value = pthread_getspecific (k);
+ if (value != NULL && k->destructor != NULL)
+ {
+
+#ifdef __cplusplus
+
+ try
+ {
+ /*
+ * Run the caller's cleanup routine.
+ */
+ (*(k->destructor)) (value);
+ }
+ catch (...)
+ {
+ /*
+ * A system unexpected exception has occurred
+ * running the user's destructor.
+ * We get control back within this block in case
+ * the application has set up it's own terminate
+ * handler. Since we are leaving the thread we
+ * should not get any internal pthreads
+ * exceptions.
+ */
+ terminate();
+ }
+
+#else /* __cplusplus */
+
+ /*
+ * Run the caller's cleanup routine.
+ */
+ (*(k->destructor)) (value);
+
+#endif /* __cplusplus */
+ }
+ }
+
+ /*
+ * mark assoc->thread as NULL to indicate the
+ * thread no longer references this association
+ */
+ assoc->thread = NULL;
+
+ /*
+ * Remove association from the pthread_t chain
+ */
+ *nextP = assoc->nextKey;
+
+ pthread_mutex_unlock (&(assoc->lock));
+
+ ptw32_tkAssocDestroy (assoc);
+
+ assoc = *nextP;
+ }
+ }
+ }
+
+} /* ptw32_callUserDestroyRoutines */
+
+
+
+#ifdef NEED_FTIME
+
+/*
+ * time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds
+ */
+#define TIMESPEC_TO_FILETIME_OFFSET \
+ ( ((LONGLONG) 27111902 << 32) + (LONGLONG) 3577643008 )
+
+static INLINE void
+timespec_to_filetime(const struct timespec *ts, FILETIME *ft)
+ /*
+ * -------------------------------------------------------------------
+ * converts struct timespec
+ * where the time is expressed in seconds and nanoseconds from Jan 1, 1970.
+ * into FILETIME (as set by GetSystemTimeAsFileTime), where the time is
+ * expressed in 100 nanoseconds from Jan 1, 1601,
+ * -------------------------------------------------------------------
+ */
+{
+ *(LONGLONG *)ft = ts->tv_sec * 10000000 + (ts->tv_nsec + 50) / 100 + TIMESPEC_TO_FILETIME_OFFSET;
+}
+
+static INLINE void
+filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
+ /*
+ * -------------------------------------------------------------------
+ * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is
+ * expressed in 100 nanoseconds from Jan 1, 1601,
+ * into struct timespec
+ * where the time is expressed in seconds and nanoseconds from Jan 1, 1970.
+ * -------------------------------------------------------------------
+ */
+{
+ ts->tv_sec = (int)((*(LONGLONG *)ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
+ ts->tv_nsec = (int)((*(LONGLONG *)ft - TIMESPEC_TO_FILETIME_OFFSET - ((LONGLONG)ts->tv_sec * (LONGLONG)10000000)) * 100);
+}
+
+#endif /* NEED_FTIME */
+
+int
+ptw32_sem_timedwait (sem_t * sem, const struct timespec * abstime)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function waits on a semaphore possibly until
+ * 'abstime' time.
+ *
+ * PARAMETERS
+ * sem
+ * pointer to an instance of sem_t
+ *
+ * abstime
+ * pointer to an instance of struct timespec
+ *
+ * DESCRIPTION
+ * This function waits on a semaphore. If the
+ * semaphore value is greater than zero, it decreases
+ * its value by one. If the semaphore value is zero, then
+ * the calling thread (or process) is blocked until it can
+ * successfully decrease the value or until interrupted by
+ * a signal.
+ *
+ * If 'abstime' is a NULL pointer then this function will
+ * block until it can successfully decrease the value or
+ * until interrupted by a signal.
+ *
+ * RESULTS
+ * 0 successfully decreased semaphore,
+ * -1 failed, error in errno
+ * ERRNO
+ * EINVAL 'sem' is not a valid semaphore,
+ * ENOSYS semaphores are not supported,
+ * EINTR the function was interrupted by a signal,
+ * EDEADLK a deadlock condition was detected.
+ * ETIMEDOUT abstime elapsed before success.
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+#ifdef NEED_FTIME
+
+ struct timespec currSysTime;
+
+#else /* NEED_FTIME */
+
+ struct _timeb currSysTime;
+
+#endif /* NEED_FTIME */
+
+ const DWORD NANOSEC_PER_MILLISEC = 1000000;
+ const DWORD MILLISEC_PER_SEC = 1000;
+ DWORD milliseconds;
+
+ if (sem == NULL)
+ {
+ result = EINVAL;
+ }
+ else
+ {
+ if (abstime == NULL)
+ {
+ milliseconds = INFINITE;
+ }
+ else
+ {
+ /*
+ * Calculate timeout as milliseconds from current system time.
+ */
+
+ /* get current system time */
+
+#ifdef NEED_FTIME
+
+ {
+ FILETIME ft;
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+ /*
+ * GetSystemTimeAsFileTime(&ft); would be faster,
+ * but it does not exist on WinCE
+ */
+
+ filetime_to_timespec(&ft, &currSysTime);
+ }
+
+ /*
+ * subtract current system time from abstime
+ */
+ milliseconds = (abstime->tv_sec - currSysTime.tv_sec) * MILLISEC_PER_SEC;
+ milliseconds += ((abstime->tv_nsec - currSysTime.tv_nsec) + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC;
+
+#else /* NEED_FTIME */
+ _ftime(&currSysTime);
+
+ /*
+ * subtract current system time from abstime
+ */
+ milliseconds = (abstime->tv_sec - currSysTime.time) * MILLISEC_PER_SEC;
+ milliseconds += ((abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC) -
+ currSysTime.millitm;
+
+#endif /* NEED_FTIME */
+
+
+ if (((int) milliseconds) < 0)
+ milliseconds = 0;
+ }
+
+#ifdef NEED_SEM
+
+ result = (pthreadCancelableTimedWait ((*sem)->event, milliseconds));
+
+#else /* NEED_SEM */
+
+ result = (pthreadCancelableTimedWait ((*sem)->sem, milliseconds));
+
+#endif
+
+ }
+
+ if (result != 0)
+ {
+
+ errno = result;
+ return -1;
+
+ }
+
+#ifdef NEED_SEM
+
+ ptw32_decrease_semaphore(sem);
+
+#endif /* NEED_SEM */
+
+ return 0;
+
+} /* ptw32_sem_timedwait */
+
+
+DWORD
+ptw32_get_exception_services_code(void)
+{
+#ifdef __CLEANUP_SEH
+
+ return EXCEPTION_PTW32_SERVICES;
+
+#else
+
+ return (DWORD) NULL;
+
+#endif
+}
+
+
+void
+ptw32_throw(DWORD exception)
+{
+#ifdef __CLEANUP_C
+ pthread_t self = pthread_self();
+#endif
+
+
+#ifdef __CLEANUP_SEH
+ DWORD exceptionInformation[3];
+#endif
+
+ if (exception != PTW32_EPS_CANCEL &&
+ exception != PTW32_EPS_EXIT)
+ {
+ /* Should never enter here */
+ exit(1);
+ }
+
+#ifdef __CLEANUP_SEH
+
+
+ exceptionInformation[0] = (DWORD) (exception);
+ exceptionInformation[1] = (DWORD) (0);
+ exceptionInformation[2] = (DWORD) (0);
+
+ RaiseException (
+ EXCEPTION_PTW32_SERVICES,
+ 0,
+ 3,
+ exceptionInformation);
+
+#else /* __CLEANUP_SEH */
+
+#ifdef __CLEANUP_C
+
+ ptw32_pop_cleanup_all( 1 );
+
+ longjmp( self->start_mark, exception );
+
+#else /* __CLEANUP_C */
+
+#ifdef __CLEANUP_CXX
+
+ switch (exception)
+ {
+ case PTW32_EPS_CANCEL:
+ throw ptw32_exception_cancel();
+ break;
+ case PTW32_EPS_EXIT:
+ throw ptw32_exception_exit();
+ break;
+ }
+
+#else
+
+#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* __CLEANUP_C */
+
+#endif /* __CLEANUP_SEH */
+
+ /* Never reached */
+}
+
+void
+ptw32_pop_cleanup_all(int execute)
+{
+ while( NULL != ptw32_pop_cleanup(execute) ) {
+ }
+}
diff --git a/win32/contrib/pthreads/pthread.def b/win32/contrib/pthreads/pthread.def
new file mode 100644
index 000000000..bdf92ed69
--- /dev/null
+++ b/win32/contrib/pthreads/pthread.def
@@ -0,0 +1,157 @@
+; pthread.def
+; Last updated: $Date: 2003/04/20 16:42:08 $
+
+; 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_unlock
+pthread_once
+pthread_self
+pthread_setcancelstate
+pthread_setcanceltype
+pthread_setconcurrency
+pthread_setschedparam
+pthread_setspecific
+;pthread_sigmask
+pthread_testcancel
+;
+; POSIX 1.b
+;
+sched_get_priority_min
+sched_get_priority_max
+sched_getscheduler
+sched_setscheduler
+sched_yield
+sem_init
+sem_destroy
+sem_trywait
+sem_wait
+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_getprocessors_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/win32/contrib/pthreads/pthread.dsp b/win32/contrib/pthreads/pthread.dsp
new file mode 100644
index 000000000..5706f6d00
--- /dev/null
+++ b/win32/contrib/pthreads/pthread.dsp
@@ -0,0 +1,207 @@
+# 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=.\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=.\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/win32/contrib/pthreads/pthread.dsw b/win32/contrib/pthreads/pthread.dsw
new file mode 100644
index 000000000..141635c50
--- /dev/null
+++ b/win32/contrib/pthreads/pthread.dsw
@@ -0,0 +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>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/win32/contrib/pthreads/pthread.h b/win32/contrib/pthreads/pthread.h
new file mode 100644
index 000000000..31e2cf918
--- /dev/null
+++ b/win32/contrib/pthreads/pthread.h
@@ -0,0 +1,1077 @@
+/* This is the POSIX thread API (POSIX 1003).
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#if !defined( PTHREAD_H )
+#define PTHREAD_H
+
+#ifdef _UWIN
+# define HAVE_STRUCT_TIMESPEC 1
+# define HAVE_SIGNAL_H 1
+# undef HAVE_CONFIG_H
+# pragma comment(lib, "pthread")
+#endif
+
+/*
+ * -------------------------------------------------------------
+ *
+ *
+ * Module: pthread.h
+ *
+ * Purpose:
+ * Provides an implementation of PThreads based upon the
+ * standard:
+ *
+ * POSIX 1003.1c-1995 (POSIX.1c)
+ *
+ * Parts of the implementation also comply with the
+ * Open Group Unix 98 specification in order to enhance
+ * code portability between Windows, various commercial
+ * Unix implementations, and Linux.
+ *
+ * Authors:
+ * There have been many contributors to this library.
+ * The initial implementation was contributed by
+ * John Bossom, and several others have provided major
+ * sections or revisions of parts of the implementation.
+ * Often significant effort has been contributed to
+ * find and fix important bugs and other problems to
+ * improve the reliability of the library, which sometimes
+ * is not reflected in the amount of code which changed as
+ * result.
+ * As much as possible, the contributors are acknowledged
+ * in the ChangeLog file in the source code distribution
+ * where their changes are noted in detail.
+ *
+ * Contributors are listed in the MAINTAINERS file.
+ *
+ * As usual, all bouquets go to the contributors, and all
+ * brickbats go to the project maintainer.
+ *
+ * Maintainer:
+ * The code base for this project is coordinated and
+ * eventually pre-tested, packaged, and made available by
+ *
+ * Ross Johnson <rpj@ise.canberra.edu.au>
+ *
+ * QA Testers:
+ * Ultimately, the library is tested in the real world by
+ * a host of competent and demanding scientists and
+ * engineers who report bugs and/or provide solutions
+ * which are then fixed or incorporated into subsequent
+ * versions of the library. Each time a bug is fixed, a
+ * test case is written to prove the fix and ensure
+ * that later changes to the code don't reintroduce the
+ * same error. The number of test cases is slowly growing
+ * and therefore so is the code reliability.
+ *
+ * Compliance:
+ * See the file ANNOUNCE for the list of implemented
+ * and not-implemented routines and defined options.
+ * Of course, these are all defined is this file as well.
+ *
+ * Web site:
+ * The source code and other information about this library
+ * are available from
+ *
+ * http://sources.redhat.com/pthreads-win32/
+ *
+ * -------------------------------------------------------------
+ */
+
+/*
+ * -----------------
+ * autoconf switches
+ * -----------------
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <windows.h>
+
+#ifndef NEED_FTIME
+#include <time.h>
+#else /* NEED_FTIME */
+/* use native WIN32 time API */
+#endif /* NEED_FTIME */
+
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif /* HAVE_SIGNAL_H */
+
+#include <setjmp.h>
+
+#ifndef HAVE_STRUCT_TIMESPEC
+struct timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+#endif /* HAVE_STRUCT_TIMESPEC */
+
+#ifndef SIG_BLOCK
+#define SIG_BLOCK 0
+#endif /* SIG_BLOCK */
+
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK 1
+#endif /* SIG_UNBLOCK */
+
+#ifndef SIG_SETMASK
+#define SIG_SETMASK 2
+#endif /* SIG_SETMASK */
+
+/*
+ * note: ETIMEDOUT is correctly defined in winsock.h
+ */
+#include <winsock.h>
+
+#ifdef NEED_ERRNO
+# include "need_errno.h"
+#else
+# include <errno.h>
+#endif
+
+#include <sched.h>
+
+/*
+ * In case ETIMEDOUT hasn't been defined above somehow.
+ */
+#ifndef ETIMEDOUT
+# define ETIMEDOUT 10060 /* This is the value in winsock.h. */
+#endif
+
+/*
+ * Several systems don't define ENOTSUP. If not, we use
+ * the same value as Solaris.
+ */
+#ifndef ENOTSUP
+# define ENOTSUP 48
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * -------------------------------------------------------------
+ *
+ * POSIX 1003.1c-1995 Options
+ * ===========================
+ *
+ * _POSIX_THREADS (set)
+ * If set, you can use threads
+ *
+ * _POSIX_THREAD_ATTR_STACKSIZE (set)
+ * If set, you can control the size of a thread's
+ * stack
+ * pthread_attr_getstacksize
+ * pthread_attr_setstacksize
+ *
+ * _POSIX_THREAD_ATTR_STACKADDR (not set)
+ * If set, you can allocate and control a thread's
+ * stack. If not supported, the following functions
+ * will return ENOSYS, indicating they are not
+ * supported:
+ * pthread_attr_getstackaddr
+ * pthread_attr_setstackaddr
+ *
+ * _POSIX_THREAD_PRIORITY_SCHEDULING (set)
+ * If set, you can use realtime scheduling.
+ * Indicates the availability of:
+ * pthread_attr_getinheritsched
+ * pthread_attr_getschedparam
+ * pthread_attr_getschedpolicy
+ * pthread_attr_getscope
+ * pthread_attr_setinheritsched
+ * pthread_attr_setschedparam
+ * pthread_attr_setschedpolicy
+ * pthread_attr_setscope
+ * pthread_getschedparam
+ * pthread_setschedparam
+ * sched_get_priority_max
+ * sched_get_priority_min
+ * sched_rr_set_interval
+ *
+ * _POSIX_THREAD_PRIO_INHERIT (not set)
+ * If set, you can create priority inheritance
+ * mutexes.
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PRIO_PROTECT (not set)
+ * If set, you can create priority ceiling mutexes
+ * Indicates the availability of:
+ * pthread_mutex_getprioceiling
+ * pthread_mutex_setprioceiling
+ * pthread_mutexattr_getprioceiling
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprioceiling
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PROCESS_SHARED (not set)
+ * If set, you can create mutexes and condition
+ * variables that can be shared with another
+ * process.If set, indicates the availability
+ * of:
+ * pthread_mutexattr_getpshared
+ * pthread_mutexattr_setpshared
+ * pthread_condattr_getpshared
+ * pthread_condattr_setpshared
+ *
+ * _POSIX_THREAD_SAFE_FUNCTIONS (set)
+ * If set you can use the special *_r library
+ * functions that provide thread-safe behaviour
+ *
+ * + These functions provide both 'inherit' and/or
+ * 'protect' protocol, based upon these macro
+ * settings.
+ *
+ * POSIX 1003.1c-1995 Limits
+ * ===========================
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ * Maximum number of attempts to destroy
+ * a thread's thread-specific data on
+ * termination (must be at least 4)
+ *
+ * PTHREAD_KEYS_MAX
+ * Maximum number of thread-specific data keys
+ * available per process (must be at least 128)
+ *
+ * PTHREAD_STACK_MIN
+ * Minimum supported stack size for a thread
+ *
+ * PTHREAD_THREADS_MAX
+ * Maximum number of threads supported per
+ * process (must be at least 64).
+ *
+ *
+ * POSIX 1003.1j/D10-1999 Options
+ * ==============================
+ *
+ * _POSIX_READER_WRITER_LOCKS (set)
+ * If set, you can use read/write locks
+ *
+ * _POSIX_SPIN_LOCKS (set)
+ * If set, you can use spin locks
+ *
+ * _POSIX_BARRIERS (set)
+ * If set, you can use barriers
+ *
+ * -------------------------------------------------------------
+ */
+
+/*
+ * POSIX Options
+ */
+#ifndef _POSIX_THREADS
+#define _POSIX_THREADS
+#endif
+
+#ifndef _POSIX_READER_WRITER_LOCKS
+#define _POSIX_READER_WRITER_LOCKS
+#endif
+
+#ifndef _POSIX_SPIN_LOCKS
+#define _POSIX_SPIN_LOCKS
+#endif
+
+#ifndef _POSIX_BARRIERS
+#define _POSIX_BARRIERS
+#endif
+
+#define _POSIX_THREAD_SAFE_FUNCTIONS
+#define _POSIX_THREAD_ATTR_STACKSIZE
+#define _POSIX_THREAD_PRIORITY_SCHEDULING
+
+#if defined( KLUDGE )
+/*
+ * The following are not supported
+ */
+#define _POSIX_THREAD_ATTR_STACKADDR
+#define _POSIX_THREAD_PRIO_INHERIT
+#define _POSIX_THREAD_PRIO_PROTECT
+#define _POSIX_THREAD_PROCESS_SHARED
+
+#endif /* KLUDGE */
+
+/*
+ * POSIX Limits
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ * Standard states this must be at least
+ * 4.
+ *
+ * PTHREAD_KEYS_MAX
+ * WIN32 permits only 64 TLS keys per process.
+ * This limitation could be worked around by
+ * simply simulating keys.
+ *
+ * PTHREADS_STACK_MIN
+ * POSIX specifies 0 which is also the value WIN32
+ * interprets as allowing the system to
+ * set the size to that of the main thread. The
+ * maximum stack size in Win32 is 1Meg. WIN32
+ * allocates more stack as required up to the 1Meg
+ * limit.
+ *
+ * PTHREAD_THREADS_MAX
+ * Not documented by WIN32. Wrote a test program
+ * that kept creating threads until it failed
+ * revealed this approximate number.
+ *
+ */
+#define PTHREAD_DESTRUCTOR_ITERATIONS 4
+#define PTHREAD_KEYS_MAX 64
+#define PTHREAD_STACK_MIN 0
+#define PTHREAD_THREADS_MAX 2019
+
+
+#ifdef _UWIN
+# include <sys/types.h>
+#else
+typedef struct pthread_t_ *pthread_t;
+typedef struct pthread_attr_t_ *pthread_attr_t;
+typedef struct pthread_once_t_ pthread_once_t;
+typedef struct pthread_key_t_ *pthread_key_t;
+typedef struct pthread_mutex_t_ *pthread_mutex_t;
+typedef struct pthread_mutexattr_t_ *pthread_mutexattr_t;
+typedef struct pthread_cond_t_ *pthread_cond_t;
+typedef struct pthread_condattr_t_ *pthread_condattr_t;
+#endif
+typedef struct pthread_rwlock_t_ *pthread_rwlock_t;
+typedef struct pthread_rwlockattr_t_ *pthread_rwlockattr_t;
+typedef struct pthread_spinlock_t_ *pthread_spinlock_t;
+typedef struct pthread_barrier_t_ *pthread_barrier_t;
+typedef struct pthread_barrierattr_t_ *pthread_barrierattr_t;
+
+/*
+ * ====================
+ * ====================
+ * POSIX Threads
+ * ====================
+ * ====================
+ */
+
+enum {
+/*
+ * pthread_attr_{get,set}detachstate
+ */
+ PTHREAD_CREATE_JOINABLE = 0, /* Default */
+ PTHREAD_CREATE_DETACHED = 1,
+
+/*
+ * pthread_attr_{get,set}inheritsched
+ */
+ PTHREAD_INHERIT_SCHED = 0,
+ PTHREAD_EXPLICIT_SCHED = 1, /* Default */
+
+/*
+ * pthread_{get,set}scope
+ */
+ PTHREAD_SCOPE_PROCESS = 0,
+ PTHREAD_SCOPE_SYSTEM = 1, /* Default */
+
+/*
+ * pthread_setcancelstate paramters
+ */
+ PTHREAD_CANCEL_ENABLE = 0, /* Default */
+ PTHREAD_CANCEL_DISABLE = 1,
+
+/*
+ * pthread_setcanceltype parameters
+ */
+ PTHREAD_CANCEL_ASYNCHRONOUS = 0,
+ PTHREAD_CANCEL_DEFERRED = 1, /* Default */
+
+/*
+ * pthread_mutexattr_{get,set}pshared
+ * pthread_condattr_{get,set}pshared
+ */
+ PTHREAD_PROCESS_PRIVATE = 0,
+ PTHREAD_PROCESS_SHARED = 1,
+
+/*
+ * pthread_barrier_wait
+ */
+ PTHREAD_BARRIER_SERIAL_THREAD = -1
+};
+
+/*
+ * ====================
+ * ====================
+ * Cancelation
+ * ====================
+ * ====================
+ */
+#define PTHREAD_CANCELED ((void *) -1)
+
+
+/*
+ * ====================
+ * ====================
+ * Once Key
+ * ====================
+ * ====================
+ */
+#define PTHREAD_ONCE_INIT { FALSE, -1 }
+
+struct pthread_once_t_
+{
+ int done; /* indicates if user function executed */
+ long started; /* First thread to increment this value */
+ /* to zero executes the user function */
+};
+
+
+/*
+ * ====================
+ * ====================
+ * Object initialisers
+ * ====================
+ * ====================
+ */
+#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1)
+
+#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1)
+
+#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1)
+
+#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1)
+
+enum
+{
+ PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
+};
+
+
+/* There are three implementations of cancel cleanup.
+ * Note that pthread.h is included in both application
+ * compilation units and also internally for the library.
+ * The code here and within the library aims to work
+ * for all reasonable combinations of environments.
+ *
+ * The three implementations are:
+ *
+ * WIN32 SEH
+ * C
+ * C++
+ *
+ * Please note that exiting a push/pop block via
+ * "return", "exit", "break", or "continue" will
+ * lead to different behaviour amongst applications
+ * depending upon whether the library was built
+ * using SEH, C++, or C. For example, a library built
+ * with SEH will call the cleanup routine, while both
+ * C++ and C built versions will not.
+ */
+
+/*
+ * define defaults for cleanup code
+ */
+#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C )
+
+#if defined(_MSC_VER)
+#define __CLEANUP_SEH
+#elif defined(__cplusplus)
+#define __CLEANUP_CXX
+#else
+#define __CLEANUP_C
+#endif
+
+#endif
+
+#if defined( __CLEANUP_SEH ) && defined(__GNUC__)
+#error ERROR [__FILE__, line __LINE__]: GNUC does not support SEH.
+#endif
+
+typedef struct ptw32_cleanup_t ptw32_cleanup_t;
+typedef void (__cdecl *ptw32_cleanup_callback_t)(void *);
+
+struct ptw32_cleanup_t
+{
+ ptw32_cleanup_callback_t routine;
+ void *arg;
+ struct ptw32_cleanup_t *prev;
+};
+
+#ifdef __CLEANUP_SEH
+ /*
+ * WIN32 SEH version of cancel cleanup.
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \
+ _cleanup.arg = (_arg); \
+ __try \
+ { \
+
+#define pthread_cleanup_pop( _execute ) \
+ } \
+ __finally \
+ { \
+ if( _execute || AbnormalTermination()) \
+ { \
+ (*(_cleanup.routine))( _cleanup.arg ); \
+ } \
+ } \
+ }
+
+#else /* __CLEANUP_SEH */
+
+#ifdef __CLEANUP_C
+
+ /*
+ * C implementation of PThreads cancel cleanup
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \
+
+#define pthread_cleanup_pop( _execute ) \
+ (void) ptw32_pop_cleanup( _execute ); \
+ }
+
+#else /* __CLEANUP_C */
+
+#ifdef __CLEANUP_CXX
+
+ /*
+ * C++ version of cancel cleanup.
+ * - John E. Bossom.
+ */
+
+ class PThreadCleanup {
+ /*
+ * PThreadCleanup
+ *
+ * Purpose
+ * This class is a C++ helper class that is
+ * used to implement pthread_cleanup_push/
+ * pthread_cleanup_pop.
+ * The destructor of this class automatically
+ * pops the pushed cleanup routine regardless
+ * of how the code exits the scope
+ * (i.e. such as by an exception)
+ */
+ ptw32_cleanup_callback_t cleanUpRout;
+ void * obj;
+ int executeIt;
+
+ public:
+ PThreadCleanup() :
+ cleanUpRout( NULL ),
+ obj( NULL ),
+ executeIt( 0 )
+ /*
+ * No cleanup performed
+ */
+ {
+ }
+
+ PThreadCleanup(
+ ptw32_cleanup_callback_t routine,
+ void * arg ) :
+ cleanUpRout( routine ),
+ obj( arg ),
+ executeIt( 1 )
+ /*
+ * Registers a cleanup routine for 'arg'
+ */
+ {
+ }
+
+ ~PThreadCleanup()
+ {
+ if ( executeIt && ((void *) cleanUpRout != NULL) )
+ {
+ (void) (*cleanUpRout)( obj );
+ }
+ }
+
+ void execute( int exec )
+ {
+ executeIt = exec;
+ }
+ };
+
+ /*
+ * C++ implementation of PThreads cancel cleanup;
+ * This implementation takes advantage of a helper
+ * class who's destructor automatically calls the
+ * cleanup routine if we exit our scope weirdly
+ */
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \
+ (void *) (_arg) );
+
+#define pthread_cleanup_pop( _execute ) \
+ cleanup.execute( _execute ); \
+ }
+
+#else
+
+#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* __CLEANUP_C */
+
+#endif /* __CLEANUP_SEH */
+
+/*
+ * ===============
+ * ===============
+ * Methods
+ * ===============
+ * ===============
+ */
+
+/*
+ * PThread Attribute Functions
+ */
+int pthread_attr_init (pthread_attr_t * attr);
+
+int pthread_attr_destroy (pthread_attr_t * attr);
+
+int pthread_attr_getdetachstate (const pthread_attr_t * attr,
+ int *detachstate);
+
+int pthread_attr_getstackaddr (const pthread_attr_t * attr,
+ void **stackaddr);
+
+int pthread_attr_getstacksize (const pthread_attr_t * attr,
+ size_t * stacksize);
+
+int pthread_attr_setdetachstate (pthread_attr_t * attr,
+ int detachstate);
+
+int pthread_attr_setstackaddr (pthread_attr_t * attr,
+ void *stackaddr);
+
+int pthread_attr_setstacksize (pthread_attr_t * attr,
+ size_t stacksize);
+
+int pthread_attr_getschedparam (const pthread_attr_t *attr,
+ struct sched_param *param);
+
+int pthread_attr_setschedparam (pthread_attr_t *attr,
+ const struct sched_param *param);
+
+int pthread_attr_setschedpolicy (pthread_attr_t *,
+ int);
+
+int pthread_attr_getschedpolicy (pthread_attr_t *,
+ int *);
+
+int pthread_attr_setinheritsched(pthread_attr_t * attr,
+ int inheritsched);
+
+int pthread_attr_getinheritsched(pthread_attr_t * attr,
+ int * inheritsched);
+
+int pthread_attr_setscope (pthread_attr_t *,
+ int);
+
+int pthread_attr_getscope (const pthread_attr_t *,
+ int *);
+
+/*
+ * PThread Functions
+ */
+int pthread_create (pthread_t * tid,
+ const pthread_attr_t * attr,
+ void *(*start) (void *),
+ void *arg);
+
+int pthread_detach (pthread_t tid);
+
+int pthread_equal (pthread_t t1,
+ pthread_t t2);
+
+void pthread_exit (void *value_ptr);
+
+int pthread_join (pthread_t thread,
+ void **value_ptr);
+
+pthread_t pthread_self (void);
+
+int pthread_cancel (pthread_t thread);
+
+int pthread_setcancelstate (int state,
+ int *oldstate);
+
+int pthread_setcanceltype (int type,
+ int *oldtype);
+
+void pthread_testcancel (void);
+
+int pthread_once (pthread_once_t * once_control,
+ void (*init_routine) (void));
+
+ptw32_cleanup_t *ptw32_pop_cleanup (int execute);
+
+void ptw32_push_cleanup (ptw32_cleanup_t * cleanup,
+ void (*routine) (void *),
+ void *arg);
+
+/*
+ * Thread Specific Data Functions
+ */
+int pthread_key_create (pthread_key_t * key,
+ void (*destructor) (void *));
+
+int pthread_key_delete (pthread_key_t key);
+
+int pthread_setspecific (pthread_key_t key,
+ const void *value);
+
+void *pthread_getspecific (pthread_key_t key);
+
+
+/*
+ * Mutex Attribute Functions
+ */
+int pthread_mutexattr_init (pthread_mutexattr_t * attr);
+
+int pthread_mutexattr_destroy (pthread_mutexattr_t * attr);
+
+int pthread_mutexattr_getpshared (const pthread_mutexattr_t
+ * attr,
+ int *pshared);
+
+int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
+ int pshared);
+
+int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind);
+int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind);
+
+/*
+ * Barrier Attribute Functions
+ */
+int pthread_barrierattr_init (pthread_barrierattr_t * attr);
+
+int pthread_barrierattr_destroy (pthread_barrierattr_t * attr);
+
+int pthread_barrierattr_getpshared (const pthread_barrierattr_t
+ * attr,
+ int *pshared);
+
+int pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
+ int pshared);
+
+/*
+ * Mutex Functions
+ */
+int pthread_mutex_init (pthread_mutex_t * mutex,
+ const pthread_mutexattr_t * attr);
+
+int pthread_mutex_destroy (pthread_mutex_t * mutex);
+
+int pthread_mutex_lock (pthread_mutex_t * mutex);
+
+int pthread_mutex_trylock (pthread_mutex_t * mutex);
+
+int pthread_mutex_unlock (pthread_mutex_t * mutex);
+
+/*
+ * Spinlock Functions
+ */
+int pthread_spin_init (pthread_spinlock_t * lock, int pshared);
+
+int pthread_spin_destroy (pthread_spinlock_t * lock);
+
+int pthread_spin_lock (pthread_spinlock_t * lock);
+
+int pthread_spin_trylock (pthread_spinlock_t * lock);
+
+int pthread_spin_unlock (pthread_spinlock_t * lock);
+
+/*
+ * Barrier Functions
+ */
+int pthread_barrier_init (pthread_barrier_t * barrier,
+ const pthread_barrierattr_t * attr,
+ unsigned int count);
+
+int pthread_barrier_destroy (pthread_barrier_t * barrier);
+
+int pthread_barrier_wait (pthread_barrier_t * barrier);
+
+/*
+ * Condition Variable Attribute Functions
+ */
+int pthread_condattr_init (pthread_condattr_t * attr);
+
+int pthread_condattr_destroy (pthread_condattr_t * attr);
+
+int pthread_condattr_getpshared (const pthread_condattr_t * attr,
+ int *pshared);
+
+int pthread_condattr_setpshared (pthread_condattr_t * attr,
+ int pshared);
+
+/*
+ * Condition Variable Functions
+ */
+int pthread_cond_init (pthread_cond_t * cond,
+ const pthread_condattr_t * attr);
+
+int pthread_cond_destroy (pthread_cond_t * cond);
+
+int pthread_cond_wait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex);
+
+int pthread_cond_timedwait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec *abstime);
+
+int pthread_cond_signal (pthread_cond_t * cond);
+
+int pthread_cond_broadcast (pthread_cond_t * cond);
+
+/*
+ * Scheduling
+ */
+int pthread_setschedparam (pthread_t thread,
+ int policy,
+ const struct sched_param *param);
+
+int pthread_getschedparam (pthread_t thread,
+ int *policy,
+ struct sched_param *param);
+
+int pthread_setconcurrency (int);
+
+int pthread_getconcurrency (void);
+
+/*
+ * Read-Write Lock Functions
+ */
+int pthread_rwlock_init(pthread_rwlock_t *lock,
+ const pthread_rwlockattr_t *attr);
+
+int pthread_rwlock_destroy(pthread_rwlock_t *lock);
+
+int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
+
+int pthread_rwlock_trywrlock(pthread_rwlock_t *);
+
+int pthread_rwlock_rdlock(pthread_rwlock_t *lock);
+
+int pthread_rwlock_wrlock(pthread_rwlock_t *lock);
+
+int pthread_rwlock_unlock(pthread_rwlock_t *lock);
+
+
+/*
+ * Non-portable functions
+ */
+
+/*
+ * Compatibility with Linux.
+ */
+int pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind);
+int pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind);
+
+/*
+ * Possibly supported by other POSIX threads implementations
+ */
+int pthread_delay_np (struct timespec * interval);
+
+/*
+ * Returns the Win32 HANDLE for the POSIX thread.
+ */
+HANDLE pthread_getw32threadhandle_np(pthread_t thread);
+
+/*
+ * Returns the number of CPUs available to the process.
+ */
+int pthread_getprocessors_np(int * count);
+
+/*
+ * Useful if an application wants to statically link
+ * the lib rather than load the DLL at run-time.
+ */
+int pthread_win32_process_attach_np(void);
+int pthread_win32_process_detach_np(void);
+int pthread_win32_thread_attach_np(void);
+int pthread_win32_thread_detach_np(void);
+
+
+/*
+ * Protected Methods
+ *
+ * This function blocks until the given WIN32 handle
+ * is signaled or pthread_cancel had been called.
+ * This function allows the caller to hook into the
+ * PThreads cancel mechanism. It is implemented using
+ *
+ * WaitForMultipleObjects
+ *
+ * on 'waitHandle' and a manually reset WIN32 Event
+ * used to implement pthread_cancel. The 'timeout'
+ * argument to TimedWait is simply passed to
+ * WaitForMultipleObjects.
+ */
+int pthreadCancelableWait (HANDLE waitHandle);
+int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout);
+
+/*
+ * Thread-Safe C Runtime Library Mappings.
+ */
+#ifndef _UWIN
+#if 1
+#if (! defined(HAVE_ERRNO)) && (! defined(_REENTRANT)) && (! defined(_MT))
+int * _errno( void );
+#endif
+#else
+#if (! defined(NEED_ERRNO)) || (! defined( _REENTRANT ) && (! defined( _MT ) || ! defined( _MD )))
+#if defined(PTW32_BUILD)
+__declspec( dllexport ) int * _errno( void );
+#else
+int * _errno( void );
+#endif
+#endif
+#endif
+#endif
+
+/*
+ * WIN32 C runtime library had been made thread-safe
+ * without affecting the user interface. Provide
+ * mappings from the UNIX thread-safe versions to
+ * the standard C runtime library calls.
+ * Only provide function mappings for functions that
+ * actually exist on WIN32.
+ */
+
+#if !defined(__MINGW32__)
+#define strtok_r( _s, _sep, _lasts ) \
+ ( *(_lasts) = strtok( (_s), (_sep) ) )
+#endif /* !__MINGW32__ */
+
+#define asctime_r( _tm, _buf ) \
+ ( strcpy( (_buf), asctime( (_tm) ) ), \
+ (_buf) )
+
+#define ctime_r( _clock, _buf ) \
+ ( strcpy( (_buf), ctime( (_clock) ) ), \
+ (_buf) )
+
+#define gmtime_r( _clock, _result ) \
+ ( *(_result) = *gmtime( (_clock) ), \
+ (_result) )
+
+#define localtime_r( _clock, _result ) \
+ ( *(_result) = *localtime( (_clock) ), \
+ (_result) )
+
+#define rand_r( _seed ) \
+ ( _seed == _seed? rand() : rand() )
+
+
+#ifdef __cplusplus
+
+/*
+ * Internal exceptions
+ */
+class ptw32_exception {};
+class ptw32_exception_cancel : public ptw32_exception {};
+class ptw32_exception_exit : public ptw32_exception {};
+
+#endif
+
+/* FIXME: This is only required if the library was built using SEH */
+/*
+ * Get internal SEH tag
+ */
+DWORD ptw32_get_exception_services_code(void);
+
+#ifndef PTW32_BUILD
+
+#ifdef __CLEANUP_SEH
+
+/*
+ * Redefine the SEH __except keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#define __except( E ) \
+ __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \
+ ? EXCEPTION_CONTINUE_SEARCH : ( E ) )
+
+#endif /* __CLEANUP_SEH */
+
+#ifdef __cplusplus
+
+/*
+ * Redefine the C++ catch keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#ifdef _MSC_VER
+ /*
+ * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll'
+ * if you want Pthread-Win32 cancelation and pthread_exit to work.
+ */
+
+#ifndef PtW32NoCatchWarn
+
+#pragma message("When compiling applications with MSVC++ and C++ exception handling:")
+#pragma message(" Replace any 'catch( ... )' with 'PtW32CatchAll' in POSIX threads")
+#pragma message(" if you want POSIX thread cancelation and pthread_exit to work.")
+
+#endif
+
+#define PtW32CatchAll \
+ catch( ptw32_exception & ) { throw; } \
+ catch( ... )
+
+#else /* _MSC_VER */
+
+#define catch( E ) \
+ catch( ptw32_exception & ) { throw; } \
+ catch( E )
+
+#endif /* _MSC_VER */
+
+#endif /* __cplusplus */
+
+#endif /* ! PTW32_BUILD */
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#endif /* PTHREAD_H */
diff --git a/win32/contrib/pthreads/pthread.ncb b/win32/contrib/pthreads/pthread.ncb
new file mode 100644
index 000000000..b349a3cfb
--- /dev/null
+++ b/win32/contrib/pthreads/pthread.ncb
Binary files differ
diff --git a/win32/contrib/pthreads/pthread.opt b/win32/contrib/pthreads/pthread.opt
new file mode 100644
index 000000000..638aaac20
--- /dev/null
+++ b/win32/contrib/pthreads/pthread.opt
Binary files differ
diff --git a/win32/contrib/pthreads/rwlock.c b/win32/contrib/pthreads/rwlock.c
new file mode 100644
index 000000000..2bb62f1e5
--- /dev/null
+++ b/win32/contrib/pthreads/rwlock.c
@@ -0,0 +1,616 @@
+/*
+ * rwlock.c
+ *
+ * Description:
+ * This translation unit implements read/write lock primitives.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include <errno.h>
+#include <limits.h>
+
+#include "pthread.h"
+#include "implement.h"
+
+static INLINE int
+ptw32_rwlock_check_need_init(pthread_rwlock_t *rwlock)
+{
+ int result = 0;
+
+ /*
+ * The following guarded test is specifically for statically
+ * initialised rwlocks (via PTHREAD_RWLOCK_INITIALIZER).
+ *
+ * Note that by not providing this synchronisation we risk
+ * introducing race conditions into applications which are
+ * correctly written.
+ *
+ * Approach
+ * --------
+ * We know that static rwlocks 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_rwlock_test_init_lock);
+
+ /*
+ * We got here possibly under race
+ * conditions. Check again inside the critical section
+ * and only initialise if the rwlock is valid (not been destroyed).
+ * If a static rwlock has been destroyed, the application can
+ * re-initialise it only by calling pthread_rwlock_init()
+ * explicitly.
+ */
+ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
+ {
+ result = pthread_rwlock_init(rwlock, NULL);
+ }
+ else if (*rwlock == NULL)
+ {
+ /*
+ * The rwlock has been destroyed while we were waiting to
+ * initialise it, so the operation that caused the
+ * auto-initialisation should fail.
+ */
+ result = EINVAL;
+ }
+
+ LeaveCriticalSection(&ptw32_rwlock_test_init_lock);
+
+ return result;
+}
+
+int
+pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+ int result;
+ pthread_rwlock_t rwl = 0;
+
+ if (rwlock == NULL)
+ {
+ return EINVAL;
+ }
+
+ if (attr != NULL && *attr != NULL)
+ {
+ result = EINVAL; /* Not supported */
+ goto DONE;
+ }
+
+ rwl = (pthread_rwlock_t) calloc(1, sizeof(*rwl));
+
+ if (rwl == NULL)
+ {
+ result = ENOMEM;
+ goto DONE;
+ }
+
+ rwl->nSharedAccessCount = 0;
+ rwl->nExclusiveAccessCount = 0;
+ rwl->nCompletedSharedAccessCount = 0;
+
+ result = pthread_mutex_init(&rwl->mtxExclusiveAccess, NULL);
+ if (result != 0)
+ {
+ goto FAIL0;
+ }
+
+ result = pthread_mutex_init(&rwl->mtxSharedAccessCompleted, NULL);
+ if (result != 0)
+ {
+ goto FAIL1;
+ }
+
+ result = pthread_cond_init(&rwl->cndSharedAccessCompleted, NULL);
+ if (result != 0)
+ {
+ goto FAIL2;
+ }
+
+ rwl->nMagic = PTW32_RWLOCK_MAGIC;
+
+ result = 0;
+ goto DONE;
+
+FAIL2:
+ (void) pthread_mutex_destroy(&(rwl->mtxSharedAccessCompleted));
+
+FAIL1:
+ (void) pthread_mutex_destroy(&(rwl->mtxExclusiveAccess));
+
+FAIL0:
+ (void) free(rwl);
+ rwl = NULL;
+
+DONE:
+ *rwlock = rwl;
+
+ return result;
+}
+
+int
+pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
+{
+ pthread_rwlock_t rwl;
+ int result = 0, result1 = 0, result2 = 0;
+
+ if (rwlock == NULL || *rwlock == NULL)
+ {
+ return EINVAL;
+ }
+
+ if (*rwlock != PTHREAD_RWLOCK_INITIALIZER)
+ {
+ rwl = *rwlock;
+
+ if (rwl->nMagic != PTW32_RWLOCK_MAGIC)
+ {
+ return EINVAL;
+ }
+
+ if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0)
+ {
+ return result;
+ }
+
+ if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+ return result;
+ }
+
+ /*
+ * Check whether any threads own/wait for the lock (wait for ex.access);
+ * report "BUSY" if so.
+ */
+ if (rwl->nExclusiveAccessCount > 0
+ || rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount)
+ {
+ result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted));
+ result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+ result2 = EBUSY;
+ }
+ else
+ {
+ rwl->nMagic = 0;
+
+ if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ pthread_mutex_unlock(&rwl->mtxExclusiveAccess);
+ return result;
+ }
+
+ if ((result = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))) != 0)
+ {
+ return result;
+ }
+
+ *rwlock = NULL; /* Invalidate rwlock before anything else */
+ result = pthread_cond_destroy(&(rwl->cndSharedAccessCompleted));
+ result1 = pthread_mutex_destroy(&(rwl->mtxSharedAccessCompleted));
+ result2 = pthread_mutex_destroy(&(rwl->mtxExclusiveAccess));
+ (void) free(rwl);
+ }
+ }
+ else
+ {
+ /*
+ * See notes in ptw32_rwlock_check_need_init() above also.
+ */
+ EnterCriticalSection(&ptw32_rwlock_test_init_lock);
+
+ /*
+ * Check again.
+ */
+ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
+ {
+ /*
+ * This is all we need to do to destroy a statically
+ * initialised rwlock that has not yet been used (initialised).
+ * If we get to here, another thread
+ * waiting to initialise this rwlock will get an EINVAL.
+ */
+ *rwlock = NULL;
+ }
+ else
+ {
+ /*
+ * The rwlock has been initialised while we were waiting
+ * so assume it's in use.
+ */
+ result = EBUSY;
+ }
+
+ LeaveCriticalSection(&ptw32_rwlock_test_init_lock);
+ }
+
+ return ((result != 0) ? result : ((result1 != 0) ? result1 : result2));
+}
+
+int
+pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
+{
+ int result;
+ pthread_rwlock_t rwl;
+
+ if (rwlock == NULL || *rwlock == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static rwlock. We check
+ * again inside the guarded section of ptw32_rwlock_check_need_init()
+ * to avoid race conditions.
+ */
+ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
+ {
+ result = ptw32_rwlock_check_need_init(rwlock);
+
+ if (result != 0 && result != EBUSY)
+ {
+ return result;
+ }
+ }
+
+ rwl = *rwlock;
+
+ if (rwl->nMagic != PTW32_RWLOCK_MAGIC)
+ {
+ return EINVAL;
+ }
+
+ if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0)
+ {
+ return result;
+ }
+
+ if (++rwl->nSharedAccessCount == INT_MAX)
+ {
+ if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+ return result;
+ }
+
+ rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
+ rwl->nCompletedSharedAccessCount = 0;
+
+ if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+ return result;
+ }
+ }
+
+ return (pthread_mutex_unlock(&(rwl->mtxExclusiveAccess)));
+}
+
+static void
+ptw32_rwlock_cancelwrwait(void * arg)
+{
+ pthread_rwlock_t rwl = (pthread_rwlock_t) arg;
+
+ rwl->nSharedAccessCount = -rwl->nCompletedSharedAccessCount;
+ rwl->nCompletedSharedAccessCount = 0;
+
+ (void) pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted));
+ (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+}
+
+int
+pthread_rwlock_wrlock(pthread_rwlock_t * rwlock)
+{
+ int result;
+ pthread_rwlock_t rwl;
+
+ if (rwlock == NULL || *rwlock == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static rwlock. We check
+ * again inside the guarded section of ptw32_rwlock_check_need_init()
+ * to avoid race conditions.
+ */
+ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
+ {
+ result = ptw32_rwlock_check_need_init(rwlock);
+
+ if (result != 0 && result != EBUSY)
+ {
+ return result;
+ }
+ }
+
+ rwl = *rwlock;
+
+ if (rwl->nMagic != PTW32_RWLOCK_MAGIC)
+ {
+ return EINVAL;
+ }
+
+ if ((result = pthread_mutex_lock(&(rwl->mtxExclusiveAccess))) != 0)
+ {
+ return result;
+ }
+
+ if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+ return result;
+ }
+
+ if (rwl->nExclusiveAccessCount == 0)
+ {
+ if (rwl->nCompletedSharedAccessCount > 0)
+ {
+ rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
+ rwl->nCompletedSharedAccessCount = 0;
+ }
+
+ if (rwl->nSharedAccessCount > 0)
+ {
+ /*
+ * pthread_rwlock_wrlock() is not a cancelation point
+ * so temporarily prevent pthread_cond_wait() from being one.
+ */
+ pthread_t self = pthread_self();
+ int oldCancelState;
+
+ rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount;
+
+ if (self->cancelType == PTHREAD_CANCEL_DEFERRED)
+ {
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldCancelState);
+ }
+
+ /* Could still be PTHREAD_CANCEL_ASYNCHRONOUS. */
+ pthread_cleanup_push(ptw32_rwlock_cancelwrwait, (void*)rwl);
+
+ do
+ {
+ result = pthread_cond_wait(&(rwl->cndSharedAccessCompleted),
+ &(rwl->mtxSharedAccessCompleted));
+ }
+ while (result == 0 && rwl->nCompletedSharedAccessCount < 0);
+
+ if (self->cancelType == PTHREAD_CANCEL_DEFERRED)
+ {
+ pthread_setcancelstate(oldCancelState, NULL);
+ }
+
+ pthread_cleanup_pop ((result != 0) ? 1 : 0);
+
+ if (result == 0)
+ {
+ rwl->nSharedAccessCount = 0;
+ }
+ }
+ }
+
+ if (result == 0)
+ {
+ rwl->nExclusiveAccessCount++;
+ }
+
+ return result;
+}
+
+int
+pthread_rwlock_unlock(pthread_rwlock_t * rwlock)
+{
+ int result, result1;
+ pthread_rwlock_t rwl;
+
+ if (rwlock == NULL || *rwlock == NULL)
+ {
+ return(EINVAL);
+ }
+
+ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
+ {
+ /*
+ * Assume any race condition here is harmless.
+ */
+ return 0;
+ }
+
+ rwl = *rwlock;
+
+ if (rwl->nMagic != PTW32_RWLOCK_MAGIC)
+ {
+ return EINVAL;
+ }
+
+ if (rwl->nExclusiveAccessCount == 0)
+ {
+ if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ return result;
+ }
+
+ if (++rwl->nCompletedSharedAccessCount == 0)
+ {
+ result = pthread_cond_signal(&(rwl->cndSharedAccessCompleted));
+ }
+
+ result1 = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted));
+ }
+ else
+ {
+ rwl->nExclusiveAccessCount--;
+
+ result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted));
+ result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+
+ }
+
+ return ((result != 0) ? result : result1);
+}
+
+int
+pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock)
+{
+ int result;
+ pthread_rwlock_t rwl;
+
+ if (rwlock == NULL || *rwlock == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static rwlock. We check
+ * again inside the guarded section of ptw32_rwlock_check_need_init()
+ * to avoid race conditions.
+ */
+ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
+ {
+ result = ptw32_rwlock_check_need_init(rwlock);
+
+ if (result != 0 && result != EBUSY)
+ {
+ return result;
+ }
+ }
+
+ rwl = *rwlock;
+
+ if (rwl->nMagic != PTW32_RWLOCK_MAGIC)
+ {
+ return EINVAL;
+ }
+
+ if ((result = pthread_mutex_trylock(&(rwl->mtxExclusiveAccess))) != 0)
+ {
+ return result;
+ }
+
+ if (++rwl->nSharedAccessCount == INT_MAX)
+ {
+ if ((result = pthread_mutex_lock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+ return result;
+ }
+
+ rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
+ rwl->nCompletedSharedAccessCount = 0;
+
+ if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+ return result;
+ }
+ }
+
+ return (pthread_mutex_unlock(&rwl->mtxExclusiveAccess));
+}
+
+int
+pthread_rwlock_trywrlock(pthread_rwlock_t * rwlock)
+{
+ int result, result1;
+ pthread_rwlock_t rwl;
+
+ if (rwlock == NULL || *rwlock == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * We do a quick check to see if we need to do more work
+ * to initialise a static rwlock. We check
+ * again inside the guarded section of ptw32_rwlock_check_need_init()
+ * to avoid race conditions.
+ */
+ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
+ {
+ result = ptw32_rwlock_check_need_init(rwlock);
+
+ if (result != 0 && result != EBUSY)
+ {
+ return result;
+ }
+ }
+
+ rwl = *rwlock;
+
+ if (rwl->nMagic != PTW32_RWLOCK_MAGIC)
+ {
+ return EINVAL;
+ }
+
+ if ((result = pthread_mutex_trylock(&(rwl->mtxExclusiveAccess))) != 0)
+ {
+ return result;
+ }
+
+ if ((result = pthread_mutex_trylock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ result1 = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+ return ((result1 != 0) ? result1 : result);
+ }
+
+ if (rwl->nExclusiveAccessCount == 0)
+ {
+ if (rwl->nCompletedSharedAccessCount > 0)
+ {
+ rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
+ rwl->nCompletedSharedAccessCount = 0;
+ }
+
+ if (rwl->nSharedAccessCount > 0)
+ {
+ if ((result = pthread_mutex_unlock(&(rwl->mtxSharedAccessCompleted))) != 0)
+ {
+ (void) pthread_mutex_unlock(&(rwl->mtxExclusiveAccess));
+ return result;
+ }
+
+ if ((result = pthread_mutex_unlock(&(rwl->mtxExclusiveAccess))) == 0)
+ {
+ result = EBUSY;
+ }
+ }
+ else
+ {
+ rwl->nExclusiveAccessCount = 1;
+ }
+ }
+ else
+ {
+ result = EBUSY;
+ }
+
+ return result;
+}
diff --git a/win32/contrib/pthreads/sched.c b/win32/contrib/pthreads/sched.c
new file mode 100644
index 000000000..ee5c1bed4
--- /dev/null
+++ b/win32/contrib/pthreads/sched.c
@@ -0,0 +1,377 @@
+/*
+ * sched.c
+ *
+ * Description:
+ * POSIX thread functions that deal with thread scheduling.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+#include "sched.h"
+
+static int
+is_attr(const pthread_attr_t *attr)
+{
+ return (attr == NULL ||
+ *attr == NULL ||
+ (*attr)->valid != PTW32_ATTR_VALID) ? 1 : 0;
+}
+
+
+int
+pthread_attr_setschedpolicy(pthread_attr_t *attr,
+ int policy)
+{
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ if (policy != SCHED_OTHER)
+ {
+ return ENOTSUP;
+ }
+
+ return 0;
+}
+
+
+int
+pthread_attr_getschedpolicy(pthread_attr_t *attr,
+ int * policy)
+{
+ if (is_attr(attr) != 0 || policy == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * Validate the policy arg.
+ * Check that a policy constant wasn't passed rather than &policy.
+ */
+ if (policy <= (int *) SCHED_MAX)
+ {
+ return EINVAL;
+ }
+
+ *policy = SCHED_OTHER;
+
+ return 0;
+}
+
+
+int
+pthread_attr_setschedparam(pthread_attr_t *attr,
+ const struct sched_param *param)
+{
+ int priority;
+
+ if (is_attr(attr) != 0 || param == NULL)
+ {
+ return EINVAL;
+ }
+
+ priority = param->sched_priority;
+
+ /* Validate priority level. */
+ if (priority < sched_get_priority_min(SCHED_OTHER) ||
+ priority > sched_get_priority_max(SCHED_OTHER))
+ {
+ return EINVAL;
+ }
+
+ memcpy(&(*attr)->param, param, sizeof(*param));
+ return 0;
+}
+
+
+int
+pthread_attr_getschedparam(const pthread_attr_t *attr,
+ struct sched_param *param)
+{
+ if (is_attr(attr) != 0 || param == NULL)
+ {
+ return EINVAL;
+ }
+
+ memcpy(param, &(*attr)->param, sizeof(*param));
+ return 0;
+}
+
+
+int
+pthread_attr_setinheritsched(pthread_attr_t * attr,
+ int inheritsched)
+{
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ if (PTHREAD_INHERIT_SCHED != inheritsched
+ && PTHREAD_EXPLICIT_SCHED != inheritsched)
+ {
+ return EINVAL;
+ }
+
+ (*attr)->inheritsched = inheritsched;
+ return 0;
+}
+
+
+int
+pthread_attr_getinheritsched(pthread_attr_t * attr,
+ int * inheritsched)
+{
+ if (is_attr(attr) != 0 || inheritsched == NULL)
+ {
+ return EINVAL;
+ }
+
+ *inheritsched = (*attr)->inheritsched;
+ return 0;
+}
+
+
+int
+pthread_setschedparam(pthread_t thread, int policy,
+ const struct sched_param *param)
+{
+ /* Validate the thread id. */
+ if (thread == NULL || thread->threadH == 0)
+ {
+ return EINVAL;
+ }
+
+ /* Validate the scheduling policy. */
+ if (policy < SCHED_MIN || policy > SCHED_MAX)
+ {
+ return EINVAL;
+ }
+
+ /* Ensure the policy is SCHED_OTHER. */
+ if (policy != SCHED_OTHER)
+ {
+ return ENOTSUP;
+ }
+
+ /* Validate priority level. */
+ if (param->sched_priority < sched_get_priority_min(policy) ||
+ param->sched_priority > sched_get_priority_max(policy))
+ {
+ return EINVAL;
+ }
+
+ /* This is practically guaranteed to return TRUE. */
+ (void) SetThreadPriority(thread->threadH, param->sched_priority);
+
+ return 0;
+}
+
+
+int
+pthread_getschedparam(pthread_t thread, int *policy,
+ struct sched_param *param)
+{
+ int prio;
+
+ /* Validate the thread id. */
+ if (thread == NULL || thread->threadH == 0)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * Validate the policy and param args.
+ * Check that a policy constant wasn't passed rather than &policy.
+ */
+ if (policy <= (int *) SCHED_MAX || param == NULL)
+ {
+ return EINVAL;
+ }
+
+ /* Fill out the policy. */
+ *policy = SCHED_OTHER;
+
+ /* Fill out the sched_param structure. */
+ prio = GetThreadPriority(thread->threadH);
+ if (prio == THREAD_PRIORITY_ERROR_RETURN)
+ {
+ return EINVAL;
+ }
+
+ param->sched_priority = prio;
+ return 0;
+}
+
+
+/*
+ * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and
+ * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine.
+ *
+ * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5
+ * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny:
+ * highest priority use smaller numbers) and the following happens:
+ *
+ * sched_get_priority_min() returns 5
+ * sched_get_priority_max() returns 1
+ */
+
+
+#define sched_Max(a,b) ((a)<(b)?(b):(a))
+#define sched_Min(a,b) ((a)>(b)?(b):(a))
+
+
+int
+sched_get_priority_max(int policy)
+{
+ if (policy < SCHED_MIN || policy > SCHED_MAX)
+ {
+ return EINVAL;
+ }
+
+#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
+ /* WinCE? */
+ return sched_Max(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL);
+#else
+ /* This is independent of scheduling policy in Win32. */
+ return sched_Max(THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_HIGHEST);
+#endif
+}
+
+
+int
+sched_get_priority_min(int policy)
+{
+ if (policy < SCHED_MIN || policy > SCHED_MAX)
+ {
+ return EINVAL;
+ }
+
+#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
+ /* WinCE? */
+ return sched_Min(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL);
+#else
+ /* This is independent of scheduling policy in Win32. */
+ return sched_Min(THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_HIGHEST);
+#endif
+}
+
+
+int
+sched_setscheduler(pid_t pid, int policy)
+{
+ /*
+ * Win32 only has one policy which we call SCHED_OTHER.
+ * However, we try to provide other valid side-effects
+ * such as EPERM and ESRCH errors. Choosing to check
+ * for a valid policy last allows us to get the most value out
+ * of this function.
+ */
+ if (0 != pid)
+ {
+ int selfPid = (int) GetCurrentProcessId();
+
+ if (pid != selfPid)
+ {
+ HANDLE h = OpenProcess(PROCESS_SET_INFORMATION, FALSE, (DWORD) pid);
+
+ if (NULL == h)
+ {
+ errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH;
+ return -1;
+ }
+ }
+ }
+
+ if (SCHED_OTHER != policy)
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ /*
+ * Don't set anything because there is nothing to set.
+ * Just return the current (the only possible) value.
+ */
+ return SCHED_OTHER;
+}
+
+
+int
+sched_getscheduler(pid_t pid)
+{
+ /*
+ * Win32 only has one policy which we call SCHED_OTHER.
+ * However, we try to provide other valid side-effects
+ * such as EPERM and ESRCH errors.
+ */
+ if (0 != pid)
+ {
+ int selfPid = (int) GetCurrentProcessId();
+
+ if (pid != selfPid)
+ {
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD) pid);
+
+ if (NULL == h)
+ {
+ errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH;
+ return -1;
+ }
+ }
+ }
+
+ return SCHED_OTHER;
+}
+
+
+int
+sched_yield(void)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function indicates that the calling thread is
+ * willing to give up some time slices to other threads.
+ *
+ * PARAMETERS
+ * N/A
+ *
+ *
+ * DESCRIPTION
+ * This function indicates that the calling thread is
+ * willing to give up some time slices to other threads.
+ * NOTE: Since this is part of POSIX 1003.1b
+ * (realtime extensions), it is defined as returning
+ * -1 if an error occurs and sets errno to the actual
+ * error.
+ *
+ * RESULTS
+ * 0 successfully created semaphore,
+ * ENOSYS sched_yield not supported,
+ *
+ * ------------------------------------------------------
+ */
+{
+ Sleep(0);
+
+ return 0;
+}
diff --git a/win32/contrib/pthreads/sched.h b/win32/contrib/pthreads/sched.h
new file mode 100644
index 000000000..c9aaeb8a4
--- /dev/null
+++ b/win32/contrib/pthreads/sched.h
@@ -0,0 +1,89 @@
+/*
+ * Module: sched.h
+ *
+ * Purpose:
+ * Provides an implementation of POSIX realtime extensions
+ * as defined in
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+#ifndef _SCHED_H
+#define _SCHED_H
+
+#if defined(__MINGW32__) || defined(_UWIN)
+/* For pid_t */
+# include <sys/types.h>
+/* Required by Unix 98 */
+# include <time.h>
+#else
+typedef int pid_t;
+#endif
+
+/* Thread scheduling policies */
+
+enum {
+ SCHED_OTHER = 0,
+ SCHED_FIFO,
+ SCHED_RR,
+ SCHED_MIN = SCHED_OTHER,
+ SCHED_MAX = SCHED_RR
+};
+
+struct sched_param {
+ int sched_priority;
+};
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+int sched_yield (void);
+
+int sched_get_priority_min (int policy);
+
+int sched_get_priority_max (int policy);
+
+int sched_setscheduler (pid_t pid, int policy);
+
+int sched_getscheduler (pid_t pid);
+
+/*
+ * Note that this macro returns ENOTSUP rather than
+ * ENOSYS as might be expected. However, returning ENOSYS
+ * should mean that sched_get_priority_{min,max} are
+ * not implemented as well as sched_rr_get_interval.
+ * This is not the case, since we just don't support
+ * round-robin scheduling. Therefore I have chosen to
+ * return the same value as sched_setscheduler when
+ * SCHED_RR is passed to it.
+ */
+#define sched_rr_get_interval(_pid, _interval) \
+ ( errno = ENOTSUP, (int) -1 )
+
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+
+#endif /* !_SCHED_H */
+
diff --git a/win32/contrib/pthreads/semaphore.c b/win32/contrib/pthreads/semaphore.c
new file mode 100644
index 000000000..2f43d05c9
--- /dev/null
+++ b/win32/contrib/pthreads/semaphore.c
@@ -0,0 +1,557 @@
+/*
+ * -------------------------------------------------------------
+ *
+ * Module: semaphore.c
+ *
+ * Purpose:
+ * Semaphores aren't actually part of the PThreads standard.
+ * They are defined by the POSIX Standard:
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * -------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+/* ignore warning "unreferenced formal parameter" */
+#ifdef _MSC_VER
+#pragma warning( disable : 4100 )
+#endif
+
+#include "pthread.h"
+#include "semaphore.h"
+#include "implement.h"
+
+int
+sem_init (sem_t * sem, int pshared, unsigned int value)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function initializes an unnamed semaphore. the
+ * initial value of the semaphore is 'value'
+ *
+ * PARAMETERS
+ * sem
+ * pointer to an instance of sem_t
+ *
+ * pshared
+ * if zero, this semaphore may only be shared between
+ * threads in the same process.
+ * if nonzero, the semaphore can be shared between
+ * processes
+ *
+ * value
+ * initial value of the semaphore counter
+ *
+ * DESCRIPTION
+ * This function initializes an unnamed semaphore. The
+ * initial value of the semaphore is set to 'value'.
+ *
+ * RESULTS
+ * 0 successfully created semaphore,
+ * -1 failed, error in errno
+ * ERRNO
+ * EINVAL 'sem' is not a valid semaphore,
+ * ENOSPC a required resource has been exhausted,
+ * ENOSYS semaphores are not supported,
+ * EPERM the process lacks appropriate privilege
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+ sem_t s;
+
+ if (pshared != 0)
+ {
+ /*
+ * Creating a semaphore that can be shared between
+ * processes
+ */
+ result = EPERM;
+
+ }
+ else
+ {
+ s = (sem_t) calloc (1, sizeof (*s));
+
+#ifdef NEED_SEM
+
+ if (NULL == s)
+ {
+ result = ENOMEM;
+ }
+ else
+ {
+ s->value = value;
+ s->event = CreateEvent (NULL,
+ FALSE, /* manual reset */
+ FALSE, /* initial state */
+ NULL);
+ if (0 == s->Event)
+ {
+ result = ENOSPC;
+ }
+ else
+ {
+ if (value != 0)
+ {
+ SetEvent(s->event);
+ }
+
+ InitializeCriticalSection(&s->sem_lock_cs);
+ }
+
+#else /* NEED_SEM */
+
+ s->sem = CreateSemaphore (NULL, /* Always NULL */
+ value, /* Initial value */
+ 0x7FFFFFFFL, /* Maximum value */
+ NULL); /* Name */
+
+ if (0 == s->sem)
+ {
+ result = ENOSPC;
+ }
+
+#endif /* NEED_SEM */
+
+ }
+
+ if (result != 0)
+ {
+ errno = result;
+ return -1;
+ }
+
+ *sem = s;
+
+ return 0;
+
+} /* sem_init */
+
+
+int
+sem_destroy (sem_t * sem)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function destroys an unnamed semaphore.
+ *
+ * PARAMETERS
+ * sem
+ * pointer to an instance of sem_t
+ *
+ * DESCRIPTION
+ * This function destroys an unnamed semaphore.
+ *
+ * RESULTS
+ * 0 successfully destroyed semaphore,
+ * -1 failed, error in errno
+ * ERRNO
+ * EINVAL 'sem' is not a valid semaphore,
+ * ENOSYS semaphores are not supported,
+ * EBUSY threads (or processes) are currently
+ * blocked on 'sem'
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+ sem_t s;
+
+ if (sem == NULL || *sem == NULL)
+ {
+ result = EINVAL;
+ }
+ else
+ {
+ s = *sem;
+ *sem = NULL;
+
+#ifdef NEED_SEM
+
+ if (! CloseHandle(s->event))
+ {
+ *sem = s;
+ result = EINVAL;
+ }
+ else
+ {
+ DeleteCriticalSection(&s->sem_lock_cs);
+ free(s);
+ }
+
+#else /* NEED_SEM */
+
+ if (! CloseHandle (s->sem))
+ {
+ *sem = s;
+ result = EINVAL;
+ }
+
+#endif /* NEED_SEM */
+
+ }
+
+ if (result != 0)
+ {
+ errno = result;
+ return -1;
+ }
+
+ return 0;
+
+} /* sem_destroy */
+
+
+int
+sem_trywait (sem_t * sem)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function tries to wait on a semaphore.
+ *
+ * PARAMETERS
+ * sem
+ * pointer to an instance of sem_t
+ *
+ * DESCRIPTION
+ * This function tries to wait on a semaphore. If the
+ * semaphore value is greater than zero, it decreases
+ * its value by one. If the semaphore value is zero, then
+ * this function returns immediately with the error EAGAIN
+ *
+ * RESULTS
+ * 0 successfully decreased semaphore,
+ * -1 failed, error in errno
+ * ERRNO
+ * EAGAIN the semaphore was already locked,
+ * EINVAL 'sem' is not a valid semaphore,
+ * ENOSYS semaphores are not supported,
+ * EINTR the function was interrupted by a signal,
+ * EDEADLK a deadlock condition was detected.
+ *
+ * ------------------------------------------------------
+ */
+{
+#ifdef NEED_SEM
+
+ /*
+ * not yet implemented!
+ */
+ int result = EINVAL;
+ return -1;
+
+#else /* NEED_SEM */
+
+ int result = 0;
+
+ if (sem == NULL || *sem == NULL)
+ {
+ result = EINVAL;
+ }
+ else if (WaitForSingleObject ((*sem)->sem, 0) == WAIT_TIMEOUT)
+ {
+ result = EAGAIN;
+ }
+
+ if (result != 0)
+ {
+ errno = result;
+ return -1;
+ }
+
+ return 0;
+
+#endif /* NEED_SEM */
+
+} /* sem_trywait */
+
+
+#ifdef NEED_SEM
+
+void
+ptw32_decrease_semaphore(sem_t * sem)
+{
+ register sem_t s = *sem;
+
+ EnterCriticalSection(&s->sem_lock_cs);
+
+ if (s->value != 0)
+ {
+ s->value--;
+ if (s->value != 0)
+ {
+ SetEvent(s->event);
+ }
+ }
+ else
+ {
+ /* this case should not happen! */
+ }
+
+ LeaveCriticalSection(&s->sem_lock_cs);
+}
+
+BOOL
+ptw32_increase_semaphore(sem_t * sem, unsigned int n)
+{
+ BOOL result;
+ register sem_t s = *sem;
+
+ EnterCriticalSection(&s->sem_lock_cs);
+
+ if (s->value + n > s->value)
+ {
+ s->value += n;
+ SetEvent(s->event);
+ result = TRUE;
+ }
+ else
+ {
+ result = FALSE;
+ }
+
+ LeaveCriticalSection(&s->sem_lock_cs);
+ return result;
+}
+
+#endif /* NEED_SEM */
+
+int
+sem_wait (sem_t * sem)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function waits on a semaphore.
+ *
+ * PARAMETERS
+ * sem
+ * pointer to an instance of sem_t
+ *
+ * DESCRIPTION
+ * This function waits on a semaphore. If the
+ * semaphore value is greater than zero, it decreases
+ * its value by one. If the semaphore value is zero, then
+ * the calling thread (or process) is blocked until it can
+ * successfully decrease the value or until interrupted by
+ * a signal.
+ *
+ * RESULTS
+ * 0 successfully decreased semaphore,
+ * -1 failed, error in errno
+ * ERRNO
+ * EINVAL 'sem' is not a valid semaphore,
+ * ENOSYS semaphores are not supported,
+ * EINTR the function was interrupted by a signal,
+ * EDEADLK a deadlock condition was detected.
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if (sem == NULL || *sem == NULL)
+ {
+ result = EINVAL;
+ }
+ else
+ {
+
+#ifdef NEED_SEM
+
+ result = pthreadCancelableWait ((*sem)->event);
+
+#else /* NEED_SEM */
+
+ result = pthreadCancelableWait ((*sem)->sem);
+
+#endif /* NEED_SEM */
+
+ }
+
+ if (result != 0)
+ {
+ errno = result;
+ return -1;
+ }
+
+#ifdef NEED_SEM
+
+ ptw32_decrease_semaphore(sem);
+
+#endif /* NEED_SEM */
+
+ return 0;
+
+} /* sem_wait */
+
+
+int
+sem_post (sem_t * sem)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function posts a wakeup to a semaphore.
+ *
+ * PARAMETERS
+ * sem
+ * pointer to an instance of sem_t
+ *
+ * DESCRIPTION
+ * This function posts a wakeup to a semaphore. If there
+ * are waiting threads (or processes), one is awakened;
+ * otherwise, the semaphore value is incremented by one.
+ *
+ * RESULTS
+ * 0 successfully posted semaphore,
+ * -1 failed, error in errno
+ * ERRNO
+ * EINVAL 'sem' is not a valid semaphore,
+ * ENOSYS semaphores are not supported,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if (sem == NULL || *sem == NULL)
+ {
+ result = EINVAL;
+ }
+
+#ifdef NEED_SEM
+
+ else if (! ptw32_increase_semaphore (sem, 1))
+
+#else /* NEED_SEM */
+
+ else if (! ReleaseSemaphore ((*sem)->sem, 1, 0))
+
+#endif /* NEED_SEM */
+
+ {
+ result = EINVAL;
+ }
+
+ if (result != 0)
+ {
+ errno = result;
+ return -1;
+ }
+
+ return 0;
+
+} /* sem_post */
+
+
+int
+sem_post_multiple (sem_t * sem, int count )
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function posts multiple wakeups to a semaphore.
+ *
+ * PARAMETERS
+ * sem
+ * pointer to an instance of sem_t
+ *
+ * count
+ * counter, must be greater than zero.
+ *
+ * DESCRIPTION
+ * This function posts multiple wakeups to a semaphore. If there
+ * are waiting threads (or processes), n <= count are awakened;
+ * the semaphore value is incremented by count - n.
+ *
+ * RESULTS
+ * 0 successfully posted semaphore,
+ * -1 failed, error in errno
+ * ERRNO
+ * EINVAL 'sem' is not a valid semaphore
+ * or count is less than or equal to zero.
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if (sem == NULL || *sem == NULL || count <= 0)
+ {
+ result = EINVAL;
+ }
+
+#ifdef NEED_SEM
+
+ else if (! ptw32_increase_semaphore (sem, count))
+
+#else /* NEED_SEM */
+
+ else if (! ReleaseSemaphore ((*sem)->sem, count, 0))
+
+#endif /* NEED_SEM */
+
+ {
+ result = EINVAL;
+ }
+
+ if (result != 0)
+ {
+ errno = result;
+ return -1;
+ }
+
+ return 0;
+
+} /* sem_post_multiple */
+
+
+int
+sem_open (const char * name, int oflag, mode_t mode, unsigned int value)
+{
+ errno = ENOSYS;
+ return -1;
+} /* sem_open */
+
+
+int
+sem_close (sem_t * sem)
+{
+ errno = ENOSYS;
+ return -1;
+} /* sem_close */
+
+
+int
+sem_unlink (const char * name)
+{
+ errno = ENOSYS;
+ return -1;
+} /* sem_unlink */
+
+
+int
+sem_getvalue (sem_t * sem, int * sval)
+{
+ errno = ENOSYS;
+ return -1;
+} /* sem_getvalue */
+
diff --git a/win32/contrib/pthreads/semaphore.h b/win32/contrib/pthreads/semaphore.h
new file mode 100644
index 000000000..a0255cf6f
--- /dev/null
+++ b/win32/contrib/pthreads/semaphore.h
@@ -0,0 +1,101 @@
+/*
+ * Module: semaphore.h
+ *
+ * Purpose:
+ * Semaphores aren't actually part of the PThreads standard.
+ * They are defined by the POSIX Standard:
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+#if !defined( SEMAPHORE_H )
+#define SEMAPHORE_H
+
+/*
+ * This is a duplicate of what is in the autoconf config.h,
+ * which is only used when building the pthread-win32 libraries.
+ */
+
+#ifndef PTW32_CONFIG_H
+# if defined(WINCE)
+# define NEED_ERRNO
+# define NEED_SEM
+# endif
+# if defined(_UWIN) || defined(__MINGW32__)
+# define HAVE_MODE_T
+# endif
+#endif
+
+/*
+ *
+ */
+
+#ifdef NEED_SEM
+#include "need_errno.h"
+#else
+#include <errno.h>
+#endif
+
+#define _POSIX_SEMAPHORES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#ifndef HAVE_MODE_T
+typedef unsigned int mode_t;
+#endif
+
+
+typedef struct sem_t_ * sem_t;
+
+int sem_init (sem_t * sem,
+ int pshared,
+ unsigned int value);
+
+int sem_destroy (sem_t * sem);
+
+int sem_trywait (sem_t * sem);
+
+int sem_wait (sem_t * sem);
+
+int sem_post (sem_t * sem);
+
+int sem_post_multiple (sem_t * sem,
+ int count);
+
+int sem_open (const char * name,
+ int oflag,
+ mode_t mode,
+ unsigned int value);
+
+int sem_close (sem_t * sem);
+
+int sem_unlink (const char * name);
+
+int sem_getvalue (sem_t * sem,
+ int * sval);
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#endif /* !SEMAPHORE_H */
diff --git a/win32/contrib/pthreads/signal.c b/win32/contrib/pthreads/signal.c
new file mode 100644
index 000000000..867dc4cc7
--- /dev/null
+++ b/win32/contrib/pthreads/signal.c
@@ -0,0 +1,172 @@
+/*
+ * signal.c
+ *
+ * Description:
+ * Thread-aware signal functions.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+/*
+ * Strategy for implementing pthread_kill()
+ * ========================================
+ *
+ * Win32 does not implement signals.
+ * Signals are simply software interrupts.
+ * pthread_kill() asks the system to deliver a specified
+ * signal (interrupt) to a specified thread in the same
+ * process.
+ * Signals are always asynchronous (no deferred signals).
+ * Pthread-win32 has an async cancelation mechanism.
+ * A similar system can be written to deliver signals
+ * within the same process (on ix86 processors at least).
+ *
+ * Each thread maintains information about which
+ * signals it will respond to. Handler routines
+ * are set on a per-process basis - not per-thread.
+ * When signalled, a thread will check it's sigmask
+ * and, if the signal is not being ignored, call the
+ * handler routine associated with the signal. The
+ * thread must then (except for some signals) return to
+ * the point where it was interrupted.
+ *
+ * Ideally the system itself would check the target thread's
+ * mask before possibly needlessly bothering the thread
+ * itself. This could be done by pthread_kill(), that is,
+ * in the signaling thread since it has access to
+ * all pthread_t structures. It could also retrieve
+ * the handler routine address to minimise the target
+ * threads response overhead. This may also simplify
+ * serialisation of the access to the per-thread signal
+ * structures.
+ *
+ * pthread_kill() eventually calls a routine similar to
+ * ptw32_cancel_thread() which manipulates the target
+ * threads processor context to cause the thread to
+ * run the handler launcher routine. pthread_kill() must
+ * save the target threads current context so that the
+ * handler launcher routine can restore the context after
+ * the signal handler has returned. Some handlers will not
+ * return, eg. the default SIGKILL handler may simply
+ * call pthread_exit().
+ *
+ * The current context is saved in the target threads
+ * pthread_t structure.
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+#if HAVE_SIGSET_T
+
+static void
+ptw32_signal_thread()
+{
+}
+
+static void
+ptw32_signal_callhandler()
+{
+}
+
+int
+pthread_sigmask(int how, sigset_t const *set, sigset_t *oset)
+{
+ pthread_t thread = pthread_self();
+
+ if (thread == NULL)
+ {
+ return ENOENT;
+ }
+
+ /* Validate the `how' argument.*/
+ if (set != NULL)
+ {
+ switch (how)
+ {
+ case SIG_BLOCK:
+ break;
+ case SIG_UNBLOCK:
+ break;
+ case SIG_SETMASK:
+ break;
+ default:
+ /* Invalid `how' argument. */
+ return EINVAL;
+ }
+ }
+
+ /* Copy the old mask before modifying it. */
+ if (oset != NULL)
+ {
+ memcpy(oset, &(thread->sigmask), sizeof(sigset_t));
+ }
+
+ if (set != NULL)
+ {
+ unsigned int i;
+
+ /* FIXME: this code assumes that sigmask is an even multiple of
+ the size of a long integer. */
+
+ unsigned long *src = (unsigned long const *) set;
+ unsigned long *dest = (unsigned long *) &(thread->sigmask);
+
+ switch (how)
+ {
+ case SIG_BLOCK:
+ for (i = 0; i < (sizeof(sigset_t) / sizeof(unsigned long)); i++)
+ {
+ /* OR the bit field longword-wise. */
+ *dest++ |= *src++;
+ }
+ break;
+ case SIG_UNBLOCK:
+ for (i = 0; i < (sizeof(sigset_t) / sizeof(unsigned long)); i++)
+ {
+ /* XOR the bitfield longword-wise. */
+ *dest++ ^= *src++;
+ }
+ case SIG_SETMASK:
+ /* Replace the whole sigmask. */
+ memcpy(&(thread->sigmask), set, sizeof(sigset_t));
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int pthread_kill(pthread_t thread,
+ int signo)
+{
+}
+
+int sigwait(const sigset_t *set,
+ int *sig)
+{
+}
+
+int sigaction(int signum,
+ const struct sigaction *act,
+ struct sigaction *oldact)
+{
+}
+
+#endif /* HAVE_SIGSET_T */
diff --git a/win32/contrib/pthreads/spin.c b/win32/contrib/pthreads/spin.c
new file mode 100644
index 000000000..6bf95cc22
--- /dev/null
+++ b/win32/contrib/pthreads/spin.c
@@ -0,0 +1,301 @@
+/*
+ * spin.c
+ *
+ * Description:
+ * This translation unit implements spin lock primitives.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+#ifdef __MINGW32__
+#define _LONG long
+#define _LPLONG long*
+#else
+#define _LONG PVOID
+#define _LPLONG PVOID*
+#endif
+
+static INLINE int
+ptw32_spinlock_check_need_init(pthread_spinlock_t *lock)
+{
+ int result = 0;
+
+ /*
+ * The following guarded test is specifically for statically
+ * initialised spinlocks (via PTHREAD_SPINLOCK_INITIALIZER).
+ *
+ * Note that by not providing this synchronisation we risk
+ * introducing race conditions into applications which are
+ * correctly written.
+ */
+ EnterCriticalSection(&ptw32_spinlock_test_init_lock);
+
+ /*
+ * We got here possibly under race
+ * conditions. Check again inside the critical section
+ * and only initialise if the spinlock is valid (not been destroyed).
+ * If a static spinlock has been destroyed, the application can
+ * re-initialise it only by calling pthread_spin_init()
+ * explicitly.
+ */
+ if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
+ {
+ result = pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE);
+ }
+ else if (*lock == NULL)
+ {
+ /*
+ * The spinlock has been destroyed while we were waiting to
+ * initialise it, so the operation that caused the
+ * auto-initialisation should fail.
+ */
+ result = EINVAL;
+ }
+
+ LeaveCriticalSection(&ptw32_spinlock_test_init_lock);
+
+ return(result);
+}
+
+
+int
+pthread_spin_init(pthread_spinlock_t *lock, int pshared)
+{
+ pthread_spinlock_t s;
+ int result = 0;
+
+ if (lock == NULL)
+ {
+ return EINVAL;
+ }
+
+ s = (pthread_spinlock_t) calloc(1, sizeof(*s));
+
+ if (s == NULL)
+ {
+ return ENOMEM;
+ }
+
+ if (0 != pthread_getprocessors_np(&(s->u.cpus)))
+ {
+ s->u.cpus = 1;
+ }
+
+ if (s->u.cpus > 1)
+ {
+ if (pshared == PTHREAD_PROCESS_SHARED)
+ {
+ /*
+ * Creating spinlock that can be shared between
+ * processes.
+ */
+#if _POSIX_THREAD_PROCESS_SHARED
+
+ /*
+ * Not implemented yet.
+ */
+
+#error ERROR [__FILE__, line __LINE__]: Process shared spin locks are not supported yet.
+
+
+#else
+
+ result = ENOSYS;
+ goto FAIL0;
+
+#endif /* _POSIX_THREAD_PROCESS_SHARED */
+
+ }
+
+ s->interlock = PTW32_SPIN_UNLOCKED;
+ }
+ else
+ {
+ pthread_mutexattr_t ma;
+ result = pthread_mutexattr_init(&ma);
+
+ if (0 == result)
+ {
+ ma->pshared = pshared;
+ result = pthread_mutex_init(&(s->u.mutex), &ma);
+ if (0 == result)
+ {
+ s->interlock = PTW32_SPIN_USE_MUTEX;
+ }
+ }
+ }
+
+FAIL0:
+ *lock = (0 == result ? s : NULL);
+ return(result);
+}
+
+int
+pthread_spin_destroy(pthread_spinlock_t *lock)
+{
+ register pthread_spinlock_t s;
+
+ if (lock == NULL || *lock == NULL)
+ {
+ return EINVAL;
+ }
+
+ if ((s = *lock) != PTHREAD_SPINLOCK_INITIALIZER)
+ {
+ if (s->interlock == PTW32_SPIN_USE_MUTEX)
+ {
+ return pthread_mutex_destroy(&(s->u.mutex));
+ }
+
+ if ( (_LONG) PTW32_SPIN_UNLOCKED ==
+ InterlockedCompareExchange((_LPLONG) &(s->interlock),
+ (_LONG) PTW32_OBJECT_INVALID,
+ (_LONG) PTW32_SPIN_UNLOCKED))
+ {
+ return 0;
+ }
+
+ return EINVAL;
+ }
+ else
+ {
+ int result = 0;
+
+ /*
+ * See notes in ptw32_spinlock_check_need_init() above also.
+ */
+ EnterCriticalSection(&ptw32_spinlock_test_init_lock);
+
+ /*
+ * Check again.
+ */
+ if (*lock == PTHREAD_SPINLOCK_INITIALIZER)
+ {
+ /*
+ * This is all we need to do to destroy a statically
+ * initialised spinlock that has not yet been used (initialised).
+ * If we get to here, another thread
+ * waiting to initialise this mutex will get an EINVAL.
+ */
+ *lock = NULL;
+ }
+ else
+ {
+ /*
+ * The spinlock has been initialised while we were waiting
+ * so assume it's in use.
+ */
+ result = EBUSY;
+ }
+
+ LeaveCriticalSection(&ptw32_spinlock_test_init_lock);
+ return(result);
+ }
+}
+
+/*
+ * NOTE: For speed, these routines don't check if "lock" is valid.
+ */
+int
+pthread_spin_lock(pthread_spinlock_t *lock)
+{
+ register pthread_spinlock_t s = *lock;
+
+ if (s == PTHREAD_SPINLOCK_INITIALIZER)
+ {
+ int result;
+
+ if ((result = ptw32_spinlock_check_need_init(lock)) != 0)
+ {
+ return(result);
+ }
+ }
+
+ while ( (_LONG) PTW32_SPIN_LOCKED ==
+ InterlockedCompareExchange((_LPLONG) &(s->interlock),
+ (_LONG) PTW32_SPIN_LOCKED,
+ (_LONG) PTW32_SPIN_UNLOCKED) )
+ {}
+
+ if (s->interlock == PTW32_SPIN_LOCKED)
+ {
+ return 0;
+ }
+ else if (s->interlock == PTW32_SPIN_USE_MUTEX)
+ {
+ return pthread_mutex_lock(&(s->u.mutex));
+ }
+
+ return EINVAL;
+}
+
+int
+pthread_spin_unlock(pthread_spinlock_t *lock)
+{
+ register pthread_spinlock_t s = *lock;
+
+ if (s->interlock == PTW32_SPIN_USE_MUTEX)
+ {
+ return pthread_mutex_unlock(&(s->u.mutex));
+ }
+
+ if ((_LONG) PTW32_SPIN_LOCKED ==
+ InterlockedCompareExchange((_LPLONG) &(s->interlock),
+ (_LONG) PTW32_SPIN_UNLOCKED,
+ (_LONG) PTW32_SPIN_LOCKED ) )
+ {
+ return 0;
+ }
+
+ return EINVAL;
+}
+
+int
+pthread_spin_trylock(pthread_spinlock_t *lock)
+{
+ pthread_spinlock_t s = *lock;
+
+ if (s == PTHREAD_SPINLOCK_INITIALIZER)
+ {
+ int result;
+
+ if ((result = ptw32_spinlock_check_need_init(lock)) != 0)
+ {
+ return(result);
+ }
+ }
+
+ if ((_LONG) PTW32_SPIN_UNLOCKED ==
+ InterlockedCompareExchange((_LPLONG) &(s->interlock),
+ (_LONG) PTW32_SPIN_LOCKED,
+ (_LONG) PTW32_SPIN_UNLOCKED ) )
+ {
+ return 0;
+ }
+
+ if (s->interlock == PTW32_SPIN_USE_MUTEX)
+ {
+ return pthread_mutex_trylock(&(s->u.mutex));
+ }
+
+ return EINVAL;
+}
diff --git a/win32/contrib/pthreads/sync.c b/win32/contrib/pthreads/sync.c
new file mode 100644
index 000000000..c0ed99e50
--- /dev/null
+++ b/win32/contrib/pthreads/sync.c
@@ -0,0 +1,188 @@
+/*
+ * sync.c
+ *
+ * Description:
+ * This translation unit implements functions related to thread
+ * synchronisation.
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+int
+pthread_detach (pthread_t tid)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function detaches the given thread.
+ *
+ * PARAMETERS
+ * thread
+ * an instance of a pthread_t
+ *
+ *
+ * DESCRIPTION
+ * This function detaches the given thread. You may
+ * detach the main thread or to detach a joinable thread
+ * (You should have used pthread_attr_t to create the
+ * thread as detached!)
+ * NOTE: detached threads cannot be joined nor canceled;
+ * storage is freed immediately on termination.
+ *
+ * RESULTS
+ * 0 successfully detached the thread,
+ * EINVAL thread is not a joinable thread,
+ * ENOSPC a required resource has been exhausted,
+ * ESRCH no thread could be found for 'thread',
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result;
+
+ if (tid == NULL ||
+ tid->detachState == PTHREAD_CREATE_DETACHED)
+ {
+
+ result = EINVAL;
+
+ }
+ else
+ {
+ result = 0;
+ tid->detachState = PTHREAD_CREATE_DETACHED;
+ }
+
+ return (result);
+
+} /* pthread_detach */
+
+int
+pthread_join (pthread_t thread, void **value_ptr)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function waits for 'thread' to terminate and
+ * returns the thread's exit value if 'value_ptr' is not
+ * NULL. This also detaches the thread on successful
+ * completion.
+ *
+ * PARAMETERS
+ * thread
+ * an instance of pthread_t
+ *
+ * value_ptr
+ * pointer to an instance of pointer to void
+ *
+ *
+ * DESCRIPTION
+ * This function waits for 'thread' to terminate and
+ * returns the thread's exit value if 'value_ptr' is not
+ * NULL. This also detaches the thread on successful
+ * completion.
+ * NOTE: detached threads cannot be joined or canceled
+ *
+ * RESULTS
+ * 0 'thread' has completed
+ * EINVAL thread is not a joinable thread,
+ * ESRCH no thread could be found with ID 'thread',
+ * ENOENT thread couldn't find it's own valid handle,
+ * EDEADLK attempt to join thread with self
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+ pthread_t self;
+
+ self = pthread_self ();
+ if (self == NULL)
+ {
+ return ENOENT;
+ }
+
+ if (pthread_equal (self, thread) != 0)
+ {
+ result = EDEADLK;
+ }
+ else if (thread->detachState == PTHREAD_CREATE_DETACHED)
+ {
+ result = EINVAL;
+ }
+ else
+ {
+ /*
+ * Pthread_join is a cancelation point.
+ * If we are canceled then our target thread must not be
+ * detached (destroyed). This is guarranteed because
+ * pthreadCancelableWait will not return if we
+ * are canceled.
+ */
+ result = pthreadCancelableWait(thread->threadH);
+
+ if (result == 0)
+ {
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+
+ if (value_ptr != NULL
+ && !GetExitCodeThread (thread->threadH, (LPDWORD) value_ptr))
+ {
+ result = ESRCH;
+ }
+ else
+ {
+ /*
+ * The result of making multiple simultaneous calls to
+ * pthread_join() specifying the same target is undefined.
+ */
+ ptw32_threadDestroy (thread);
+ }
+
+#else /* __MINGW32__ && ! __MSVCRT__ */
+
+ /*
+ * If using CRTDLL, the thread may have exited, and endthread
+ * will have closed the handle.
+ */
+ if (value_ptr != NULL)
+ {
+ *value_ptr = self->exitStatus;
+ }
+
+ /*
+ * The result of making multiple simultaneous calls to
+ * pthread_join() specifying the same target is undefined.
+ */
+ ptw32_threadDestroy (thread);
+
+#endif /* __MINGW32__ && ! __MSVCRT__ */
+
+ }
+ else
+ {
+ result = ESRCH;
+ }
+ }
+
+ return (result);
+
+} /* pthread_join */
diff --git a/win32/contrib/pthreads/tsd.c b/win32/contrib/pthreads/tsd.c
new file mode 100644
index 000000000..999dc34e5
--- /dev/null
+++ b/win32/contrib/pthreads/tsd.c
@@ -0,0 +1,333 @@
+/*
+ * tsd.c
+ *
+ * Description:
+ * POSIX thread functions which implement thread-specific data (TSD).
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright (C) 1998
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA
+ */
+
+#include "pthread.h"
+#include "implement.h"
+
+/* TLS_OUT_OF_INDEXES not defined on WinCE */
+#ifndef TLS_OUT_OF_INDEXES
+#define TLS_OUT_OF_INDEXES 0xffffffff
+#endif
+
+int
+pthread_key_create (pthread_key_t * key, void (*destructor) (void *))
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function creates a thread-specific data key visible
+ * to all threads. All existing and new threads have a value
+ * NULL for key until set using pthread_setspecific. When any
+ * thread with a non-NULL value for key terminates, 'destructor'
+ * is called with key's current value for that thread.
+ *
+ * PARAMETERS
+ * key
+ * pointer to an instance of pthread_key_t
+ *
+ *
+ * DESCRIPTION
+ * This function creates a thread-specific data key visible
+ * to all threads. All existing and new threads have a value
+ * NULL for key until set using pthread_setspecific. When any
+ * thread with a non-NULL value for key terminates, 'destructor'
+ * is called with key's current value for that thread.
+ *
+ * RESULTS
+ * 0 successfully created semaphore,
+ * EAGAIN insufficient resources or PTHREAD_KEYS_MAX
+ * exceeded,
+ * ENOMEM insufficient memory to create the key,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+ pthread_key_t newkey;
+
+ if ((newkey = (pthread_key_t) calloc (1, sizeof (*newkey))) == NULL)
+ {
+ result = ENOMEM;
+ }
+ else if ((newkey->key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ {
+ result = EAGAIN;
+
+ free (newkey);
+ newkey = NULL;
+ }
+ else if (destructor != NULL)
+ {
+ /*
+ * Have to manage associations between thread and key;
+ * Therefore, need a lock that allows multiple threads
+ * to gain exclusive access to the key->threads list.
+ *
+ * The mutex will only be created when it is first locked.
+ */
+ newkey->threadsLock = PTHREAD_MUTEX_INITIALIZER;
+ newkey->destructor = destructor;
+ }
+
+ *key = newkey;
+
+ return (result);
+}
+
+int
+pthread_key_delete (pthread_key_t key)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function deletes a thread-specific data key. This
+ * does not change the value of the thread spcific data key
+ * for any thread and does not run the key's destructor
+ * in any thread so it should be used with caution.
+ *
+ * PARAMETERS
+ * key
+ * pointer to an instance of pthread_key_t
+ *
+ *
+ * DESCRIPTION
+ * This function deletes a thread-specific data key. This
+ * does not change the value of the thread spcific data key
+ * for any thread and does not run the key's destructor
+ * in any thread so it should be used with caution.
+ *
+ * RESULTS
+ * 0 successfully deleted the key,
+ * EINVAL key is invalid,
+ *
+ * ------------------------------------------------------
+ */
+{
+ int result = 0;
+
+ if (key != NULL)
+ {
+ if (key->threads != NULL &&
+ key->destructor != NULL &&
+ pthread_mutex_lock (&(key->threadsLock)) == 0)
+ {
+ /*
+ * Run through all Thread<-->Key associations
+ * for this key.
+ * If the pthread_t still exits (ie the assoc->thread
+ * is not NULL) then leave the assoc for the thread to
+ * destroy.
+ * Notes:
+ * If assoc->thread is NULL, then the associated thread
+ * is no longer referencing this assoc.
+ * The association is only referenced
+ * by this key and must be released; otherwise
+ * the assoc will be destroyed when the thread is destroyed.
+ */
+ ThreadKeyAssoc *assoc;
+
+ assoc = (ThreadKeyAssoc *) key->threads;
+
+ while (assoc != NULL)
+ {
+ if (pthread_mutex_lock (&(assoc->lock)) == 0)
+ {
+ ThreadKeyAssoc *next;
+
+ assoc->key = NULL;
+ next = assoc->nextThread;
+ assoc->nextThread = NULL;
+
+ pthread_mutex_unlock (&(assoc->lock));
+
+ ptw32_tkAssocDestroy (assoc);
+
+ assoc = next;
+ }
+ }
+ pthread_mutex_unlock (&(key->threadsLock));
+ }
+
+ TlsFree (key->key);
+ if (key->destructor != NULL)
+ {
+ pthread_mutex_destroy (&(key->threadsLock));
+ }
+
+#if defined( _DEBUG )
+ memset ((char *) key, 0, sizeof (*key));
+#endif
+ free (key);
+ }
+
+ return (result);
+}
+
+
+int
+pthread_setspecific (pthread_key_t key, const void *value)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function sets the value of the thread specific
+ * key in the calling thread.
+ *
+ * PARAMETERS
+ * key
+ * an instance of pthread_key_t
+ * value
+ * the value to set key to
+ *
+ *
+ * DESCRIPTION
+ * This function sets the value of the thread specific
+ * key in the calling thread.
+ *
+ * RESULTS
+ * 0 successfully set value
+ * EAGAIN could not set value
+ * ENOENT SERIOUS!!
+ *
+ * ------------------------------------------------------
+ */
+{
+ pthread_t self;
+ int result = 0;
+
+ if (key != ptw32_selfThreadKey)
+ {
+ /*
+ * Using pthread_self will implicitly create
+ * an instance of pthread_t for the current
+ * thread if one wasn't explicitly created
+ */
+ self = pthread_self ();
+ if (self == NULL)
+ {
+ return ENOENT;
+ }
+ }
+ else
+ {
+ /*
+ * Resolve catch-22 of registering thread with threadSelf
+ * key
+ */
+ self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
+ if (self == NULL)
+ {
+ self = (pthread_t) value;
+ }
+ }
+
+ result = 0;
+
+ if (key != NULL)
+ {
+ ThreadKeyAssoc *assoc;
+
+ if (self != NULL &&
+ key->destructor != NULL &&
+ value != NULL)
+ {
+ /*
+ * Only require associations if we have to
+ * call user destroy routine.
+ * Don't need to locate an existing association
+ * when setting data to NULL for WIN32 since the
+ * data is stored with the operating system; not
+ * on the association; setting assoc to NULL short
+ * circuits the search.
+ */
+ assoc = (ThreadKeyAssoc *) self->keys;
+ /*
+ * Locate existing association
+ */
+ while (assoc != NULL)
+ {
+ if (assoc->key == key)
+ {
+ /*
+ * Association already exists
+ */
+ break;
+ }
+ assoc = assoc->nextKey;
+ }
+
+ /*
+ * create an association if not found
+ */
+ if (assoc == NULL)
+ {
+ result = ptw32_tkAssocCreate (&assoc, self, key);
+ }
+ }
+
+ if (result == 0)
+ {
+ if ( ! TlsSetValue (key->key, (LPVOID) value))
+ {
+ result = EAGAIN;
+ }
+ }
+ }
+
+ return (result);
+} /* pthread_setspecific */
+
+
+void *
+pthread_getspecific (pthread_key_t key)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function returns the current value of key in the
+ * calling thread. If no value has been set for 'key' in
+ * the thread, NULL is returned.
+ *
+ * PARAMETERS
+ * key
+ * an instance of pthread_key_t
+ *
+ *
+ * DESCRIPTION
+ * This function returns the current value of key in the
+ * calling thread. If no value has been set for 'key' in
+ * the thread, NULL is returned.
+ *
+ * RESULTS
+ * key value or NULL on failure
+ *
+ * ------------------------------------------------------
+ */
+{
+ int lasterror = GetLastError();
+
+ void *ptr = TlsGetValue (key->key);
+
+ SetLastError( lasterror );
+
+ return ptr;
+}
+