]> sourceware.org Git - newlib-cygwin.git/blobdiff - winsup/cygwin/thread.cc
* cygwin.din (pthread_attr_getstack): Export.
[newlib-cygwin.git] / winsup / cygwin / thread.cc
index d5a393691338c245426c4a558b353774a9f43d66..0085320ade95da9363c4a246c011e4b94b00ebdf 100644 (file)
@@ -1,9 +1,7 @@
 /* thread.cc: Locking and threading module functions
 
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
-
-   Originally written by Marco Fuykschot <marco@ddi.nl>
-   Substantialy enhanced by Robert Collins <rbtcollins@hotmail.com>
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+   2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -18,7 +16,7 @@ details. */
    the constraints we either pretend to be conformant, or return an error
    code.
 
-   Some caveats: PROCESS_SHARED objects while they pretend to be process
+   Some caveats: PROCESS_SHARED objects, while they pretend to be process
    shared, may not actually work.  Some test cases are needed to determine
    win32's behaviour.  My suspicion is that the win32 handle needs to be
    opened with different flags for proper operation.
@@ -26,182 +24,302 @@ details. */
    R.Collins, April 2001.  */
 
 #ifdef HAVE_CONFIG_H
-# include "config.h"
 #endif
 
 #include "winsup.h"
-#include <limits.h>
-#include "cygerrno.h"
-#include <assert.h>
+#include "miscfuncs.h"
+#include "path.h"
 #include <stdlib.h>
-#include <syslog.h>
 #include "pinfo.h"
+#include "sigproc.h"
 #include "perprocess.h"
-#include "security.h"
-#include "exceptions.h"
-#include <semaphore.h>
-#include <stdio.h>
-#include <sys/timeb.h>
-#include <sys/fcntl.h>
+#include "cygtls.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "ntdll.h"
+
+extern "C" void __fp_lock_all ();
+extern "C" void __fp_unlock_all ();
+extern "C" int valid_sched_parameters(const struct sched_param *);
+extern "C" int sched_set_thread_priority(HANDLE thread, int priority);
+static inline verifyable_object_state
+  verifyable_object_isvalid (void const * objectptr, thread_magic_t magic,
+                            void *static_ptr1 = NULL,
+                            void *static_ptr2 = NULL,
+                            void *static_ptr3 = NULL);
 
 extern int threadsafe;
 
+const pthread_t pthread_mutex::_new_mutex = (pthread_t) 1;
+const pthread_t pthread_mutex::_unlocked_mutex = (pthread_t) 2;
+const pthread_t pthread_mutex::_destroyed_mutex = (pthread_t) 3;
+
+inline bool
+pthread_mutex::no_owner()
+{
+    int res;
+    if (!owner)
+      {
+       debug_printf ("NULL owner value");
+       res = 1;
+      }
+    else if (owner == _destroyed_mutex)
+      {
+       paranoid_printf ("attempt to use destroyed mutex");
+       res = 1;
+      }
+    else if (owner == _new_mutex || owner == _unlocked_mutex)
+      res = 1;
+    else
+      res = 0;
+    return res;
+}
+
+#undef __getreent
 extern "C" struct _reent *
 __getreent ()
 {
-  struct __reent_t *_r =
-    (struct __reent_t *) MT_INTERFACE->reent_key.get ();
+  return &_my_tls.local_clib;
+}
 
-  if (_r == 0)
-    {
-#ifdef _CYG_THREAD_FAILSAFE
-      system_printf ("local thread storage not inited");
-#endif
-      /* Return _impure_ptr as long as MTinterface is not initialized */
-      return _impure_ptr;
-    }
+extern "C" void
+__cygwin_lock_init (_LOCK_T *lock)
+{
+  *lock = _LOCK_T_INITIALIZER;
+}
+
+extern "C" void
+__cygwin_lock_init_recursive (_LOCK_T *lock)
+{
+  *lock = _LOCK_T_RECURSIVE_INITIALIZER;
+}
 
-  return _r->_clib;
+extern "C" void
+__cygwin_lock_fini (_LOCK_T *lock)
+{
+  pthread_mutex_destroy ((pthread_mutex_t*) lock);
 }
 
-struct _winsup_t *
-_reent_winsup ()
+extern "C" void
+__cygwin_lock_lock (_LOCK_T *lock)
 {
-  struct __reent_t *_r =
-    (struct __reent_t *) MT_INTERFACE->reent_key.get ();
+  paranoid_printf ("threadcount %d.  locking", MT_INTERFACE->threadcount);
+  pthread_mutex_lock ((pthread_mutex_t*) lock);
+}
+
+extern "C" int
+__cygwin_lock_trylock (_LOCK_T *lock)
+{
+  return pthread_mutex_trylock ((pthread_mutex_t*) lock);
+}
 
-  if (_r == 0)
-    {
-#ifdef _CYG_THREAD_FAILSAFE
-      system_printf ("local thread storage not inited");
-#endif
-      return NULL;
-    }
 
-  return _r->_winsup;
+extern "C" void
+__cygwin_lock_unlock (_LOCK_T *lock)
+{
+  pthread_mutex_unlock ((pthread_mutex_t*) lock);
+  paranoid_printf ("threadcount %d.  unlocked", MT_INTERFACE->threadcount);
 }
 
-inline LPCRITICAL_SECTION
-ResourceLocks::Lock (int _resid)
+static inline verifyable_object_state
+verifyable_object_isvalid (void const *objectptr, thread_magic_t magic, void *static_ptr1,
+                          void *static_ptr2, void *static_ptr3)
 {
-#ifdef _CYG_THREAD_FAILSAFE
-  if (!inited)
-    system_printf ("lock called before initialization");
+  myfault efault;
+  if (efault.faulted (objectptr))
+    return INVALID_OBJECT;
 
-  thread_printf
-    ("Get Resource lock %d ==> %p for %p , real : %d , threadid %d ", _resid,
-     &lock, user_data, myself->pid, GetCurrentThreadId ());
-#endif
-  return &lock;
+  verifyable_object **object = (verifyable_object **) objectptr;
+
+  if ((static_ptr1 && *object == static_ptr1) ||
+      (static_ptr2 && *object == static_ptr2) ||
+      (static_ptr3 && *object == static_ptr3))
+    return VALID_STATIC_OBJECT;
+  if ((*object)->magic != magic)
+    return INVALID_OBJECT;
+  return VALID_OBJECT;
 }
 
-void
-SetResourceLock (int _res_id, int _mode, const char *_function)
+/* static members */
+inline bool
+pthread_attr::is_good_object (pthread_attr_t const *attr)
 {
-#ifdef _CYG_THREAD_FAILSAFE
-  thread_printf ("Set resource lock %d mode %d for %s start",
-                _res_id, _mode, _function);
-#endif
-  EnterCriticalSection (user_data->resourcelocks->Lock (_res_id));
+  if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
+}
 
-#ifdef _CYG_THREAD_FAILSAFE
-  user_data->resourcelocks->owner = GetCurrentThreadId ();
-  user_data->resourcelocks->count++;
-#endif
+inline bool
+pthread_condattr::is_good_object (pthread_condattr_t const *attr)
+{
+  if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
 }
 
-void
-ReleaseResourceLock (int _res_id, int _mode, const char *_function)
+inline bool
+pthread_rwlockattr::is_good_object (pthread_rwlockattr_t const *attr)
+{
+  if (verifyable_object_isvalid (attr, PTHREAD_RWLOCKATTR_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
+}
+
+inline bool
+pthread_key::is_good_object (pthread_key_t const *key)
 {
-#ifdef _CYG_THREAD_FAILSAFE
-  thread_printf ("Release resource lock %d mode %d for %s done", _res_id,
-                _mode, _function);
+  if (verifyable_object_isvalid (key, PTHREAD_KEY_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
+}
 
-  AssertResourceOwner (_res_id, _mode);
-  user_data->resourcelocks->count--;
-  if (user_data->resourcelocks->count == 0)
-    user_data->resourcelocks->owner = 0;
-#endif
+inline bool
+pthread_spinlock::is_good_object (pthread_spinlock_t const *mutex)
+{
+  if (verifyable_object_isvalid (mutex, PTHREAD_SPINLOCK_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
+}
 
-  LeaveCriticalSection (user_data->resourcelocks->Lock (_res_id));
+inline bool
+pthread_mutex::is_good_object (pthread_mutex_t const *mutex)
+{
+  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
 }
 
-#ifdef _CYG_THREAD_FAILSAFE
-void
-AssertResourceOwner (int _res_id, int _mode)
+inline bool
+pthread_mutex::is_initializer (pthread_mutex_t const *mutex)
 {
+  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC,
+                                PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+                                PTHREAD_NORMAL_MUTEX_INITIALIZER_NP,
+                                PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) != VALID_STATIC_OBJECT)
+    return false;
+  return true;
+}
 
-  thread_printf
-    ("Assert Resource lock %d ==> for %p , real : %d , threadid %d count %d owner %d",
-     _res_id, user_data, myself->pid, GetCurrentThreadId (),
-     user_data->resourcelocks->count, user_data->resourcelocks->owner);
-  if (user_data && (user_data->resourcelocks->owner != GetCurrentThreadId ()))
-    system_printf ("assertion failed, not the resource owner");
+inline bool
+pthread_mutex::is_initializer_or_object (pthread_mutex_t const *mutex)
+{
+  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC,
+                                PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+                                PTHREAD_NORMAL_MUTEX_INITIALIZER_NP,
+                                PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) == INVALID_OBJECT)
+    return false;
+  return true;
 }
 
-#endif
+/* FIXME: Accommodate PTHREAD_MUTEX_ERRORCHECK */
+inline bool
+pthread_mutex::can_be_unlocked ()
+{
+  pthread_t self = pthread::self ();
+  /* Check if the mutex is owned by the current thread and can be unlocked.
+   * Also check for the ANONYMOUS owner to cover NORMAL mutexes as well. */
+  bool res = type == PTHREAD_MUTEX_NORMAL || no_owner ()
+            || (recursion_counter == 1 && pthread::equal (owner, self));
+  pthread_printf ("recursion_counter %d res %d", recursion_counter, res);
+  return res;
+}
 
-void
-ResourceLocks::Init ()
+inline bool
+pthread_mutexattr::is_good_object (pthread_mutexattr_t const * attr)
 {
-  InitializeCriticalSection (&lock);
-  inited = true;
+  if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
+}
 
-#ifdef _CYG_THREAD_FAILSAFE
-  owner = 0;
-  count = 0;
-#endif
+inline bool __attribute__ ((used))
+pthread::is_good_object (pthread_t const *thread)
+{
+  if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
+}
 
-  thread_printf ("lock %p inited by %p , %d", &lock, user_data, myself->pid);
+/* Thread synchronisation */
+inline bool
+pthread_cond::is_good_object (pthread_cond_t const *cond)
+{
+  if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
 }
 
-void
-ResourceLocks::Delete ()
+inline bool
+pthread_cond::is_initializer (pthread_cond_t const *cond)
 {
-  if (inited)
-    {
-      thread_printf ("Close Resource Locks %p ", &lock);
-      DeleteCriticalSection (&lock);
-      inited = false;
-    }
+  if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) != VALID_STATIC_OBJECT)
+    return false;
+  return true;
+}
+
+inline bool
+pthread_cond::is_initializer_or_object (pthread_cond_t const *cond)
+{
+  if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) == INVALID_OBJECT)
+    return false;
+  return true;
+}
+
+/* RW locks */
+inline bool
+pthread_rwlock::is_good_object (pthread_rwlock_t const *rwlock)
+{
+  if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
+}
+
+inline bool
+pthread_rwlock::is_initializer (pthread_rwlock_t const *rwlock)
+{
+  if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) != VALID_STATIC_OBJECT)
+    return false;
+  return true;
+}
+
+inline bool
+pthread_rwlock::is_initializer_or_object (pthread_rwlock_t const *rwlock)
+{
+  if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) == INVALID_OBJECT)
+    return false;
+  return true;
+}
+
+inline bool
+semaphore::is_good_object (sem_t const * sem)
+{
+  if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT)
+    return false;
+  return true;
 }
 
 void
 MTinterface::Init ()
 {
-  reents._clib = _impure_ptr;
-  reents._winsup = &winsup_reent;
-  winsup_reent._process_logmask = LOG_UPTO (LOG_DEBUG);
-  reent_key.set (&reents);
-
   pthread_mutex::init_mutex ();
   pthread_cond::init_mutex ();
   pthread_rwlock::init_mutex ();
 }
 
 void
-MTinterface::fixup_before_fork (void)
+MTinterface::fixup_before_fork ()
 {
   pthread_key::fixup_before_fork ();
 }
 
 /* This function is called from a single threaded process */
 void
-MTinterface::fixup_after_fork (void)
+MTinterface::fixup_after_fork ()
 {
   pthread_key::fixup_after_fork ();
 
-#ifndef __SIGNALS_ARE_MULTITHREADED__
-  /* As long as the signal handling not multithreaded
-     switch reents storage back to _impure_ptr for the mainthread
-     to support fork from threads other than the mainthread */
-  reents._clib = _impure_ptr;
-  reents._winsup = &winsup_reent;
-  winsup_reent._process_logmask = LOG_UPTO (LOG_DEBUG);
-  reent_key.set (&reents);
-#endif
-
-  threadcount = 1;
+  threadcount = 0;
   pthread::init_mainthread ();
 
   pthread::fixup_after_fork ();
@@ -217,7 +335,7 @@ MTinterface::fixup_after_fork (void)
 void
 pthread::init_mainthread ()
 {
-  pthread *thread = get_tls_self_pointer ();
+  pthread *thread = _my_tls.tid;
   if (!thread)
     {
       thread = new pthread ();
@@ -225,42 +343,48 @@ pthread::init_mainthread ()
        api_fatal ("failed to create mainthread object");
     }
 
-  thread->init_current_thread ();
+  set_tls_self_pointer (thread);
+  thread->thread_id = GetCurrentThreadId ();
+  if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
+                       GetCurrentProcess (), &thread->win32_obj_id,
+                       0, FALSE, DUPLICATE_SAME_ACCESS))
+    api_fatal ("failed to create mainthread handle");
+  if (!thread->create_cancel_event ())
+    api_fatal ("couldn't create cancel event for main thread");
+  VerifyHandle (thread->win32_obj_id);
+  thread->postcreate ();
 }
 
 pthread *
 pthread::self ()
 {
-  pthread *thread = get_tls_self_pointer ();
-  if (thread)
-    return thread;
-  return pthread_null::get_null_pthread ();
+  pthread *thread = _my_tls.tid;
+  if (!thread)
+    {
+      thread = pthread_null::get_null_pthread ();
+      set_tls_self_pointer (thread);
+    }
+  return thread;
 }
 
 void
-pthread::set_tls_self_pointer (pthread *thisThread)
+pthread::set_tls_self_pointer (pthread *thread)
 {
-  MT_INTERFACE->thread_self_key.set (thisThread);
+  thread->cygtls = &_my_tls;
+  _my_tls.tid = thread;
 }
 
-pthread *
-pthread::get_tls_self_pointer ()
-{
-  return (pthread *) MT_INTERFACE->thread_self_key.get ();
-}
-
-
-
 List<pthread> pthread::threads;
 
 /* member methods */
 pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0),
-                   valid (false), suspended (false),
+                   valid (false), suspended (false), canceled (false),
                    cancelstate (0), canceltype (0), cancel_event (0),
                    joiner (NULL), next (NULL), cleanup_stack (NULL)
 {
   if (this != pthread_null::get_null_pthread ())
     threads.insert (this);
+  parent_tls = &_my_tls;
 }
 
 pthread::~pthread ()
@@ -274,10 +398,17 @@ pthread::~pthread ()
     threads.remove (this);
 }
 
-void
-pthread::set_thread_id_to_current ()
+bool
+pthread::create_cancel_event ()
 {
-  thread_id = GetCurrentThreadId ();
+  cancel_event = ::CreateEvent (&sec_none_nih, true, false, NULL);
+  if (!cancel_event)
+    {
+      system_printf ("couldn't create cancel event, %E");
+      /* we need the event for correct behaviour */
+      return false;
+    }
+  return true;
 }
 
 void
@@ -305,41 +436,42 @@ pthread::precreate (pthread_attr *newattr)
       return;
     }
   /* Change the mutex type to NORMAL to speed up mutex operations */
-  mutex.type = PTHREAD_MUTEX_NORMAL;
-
-  cancel_event = ::CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
-  if (!cancel_event)
-    {
-      system_printf ("couldn't create cancel event, this %p LastError %E", this);
-      /* we need the event for correct behaviour */
-      magic = 0;
-      return;
-    }
+  mutex.set_type (PTHREAD_MUTEX_NORMAL);
+  if (!create_cancel_event ())
+    magic = 0;
 }
 
-void
+bool
 pthread::create (void *(*func) (void *), pthread_attr *newattr,
                 void *threadarg)
 {
+  bool retval;
+
   precreate (newattr);
   if (!magic)
-      return;
-   function = func;
-   arg = threadarg;
+    return false;
 
+  function = func;
+  arg = threadarg;
+
+  mutex.lock ();
   win32_obj_id = ::CreateThread (&sec_none_nih, attr.stacksize,
-                               (LPTHREAD_START_ROUTINE) thread_init_wrapper,
-                               this, CREATE_SUSPENDED, &thread_id);
+                               thread_init_wrapper, this, 0, &thread_id);
 
   if (!win32_obj_id)
     {
-      thread_printf ("CreateThread failed: this %p LastError %E", this);
+      thread_printf ("CreateThread failed: this %p, %E", this);
       magic = 0;
     }
-  else {
+  else
+    {
       postcreate ();
-      ResumeThread (win32_obj_id);
-  }
+      while (!cygtls)
+       yield ();
+    }
+  retval = magic;
+  mutex.unlock ();
+  return retval;
 }
 
 void
@@ -377,6 +509,8 @@ pthread::exit (void *value_ptr)
       mutex.unlock ();
     }
 
+  if (_my_tls.local_clib.__sdidinit < 0)
+    _my_tls.local_clib.__sdidinit = 0;
   (_reclaim_reent) (_REENT);
 
   if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0)
@@ -386,7 +520,7 @@ pthread::exit (void *value_ptr)
 }
 
 int
-pthread::cancel (void)
+pthread::cancel ()
 {
   class pthread *thread = this;
   class pthread *self = pthread::self ();
@@ -404,10 +538,10 @@ pthread::cancel (void)
     {
       // cancel deferred
       mutex.unlock ();
+      canceled = true;
       SetEvent (cancel_event);
       return 0;
     }
-
   else if (equal (thread, self))
     {
       mutex.unlock ();
@@ -429,218 +563,401 @@ pthread::cancel (void)
   ResumeThread (win32_obj_id);
 
   return 0;
-/*
-  TODO: insert  pthread_testcancel into the required functions
-  the required function list is: *indicates done, X indicates not present in cygwin.
-aio_suspend ()
-*close ()
-*creat ()
-fcntl ()
-fsync ()
-getmsg ()
-getpmsg ()
-lockf ()
-mq_receive ()
-mq_send ()
-msgrcv ()
-msgsnd ()
-msync ()
-nanosleep ()
-open ()
-*pause ()
-poll ()
-pread ()
-*pthread_cond_timedwait ()
-*pthread_cond_wait ()
-*pthread_join ()
-*pthread_testcancel ()
-putmsg ()
-putpmsg ()
-pwrite ()
-read ()
-readv ()
-select ()
-*sem_wait ()
-*sigpause ()
-*sigsuspend ()
-sigtimedwait ()
-sigwait ()
-sigwaitinfo ()
-*sleep ()
-*system ()
-tcdrain ()
-*usleep ()
-*wait ()
-*wait3()
-waitid ()
-*waitpid ()
-write ()
-writev ()
-
-the optional list is:
-catclose ()
-catgets ()
-catopen ()
-closedir ()
-closelog ()
-ctermid ()
-dbm_close ()
-dbm_delete ()
-dbm_fetch ()
-dbm_nextkey ()
-dbm_open ()
-dbm_store ()
-dlclose ()
-dlopen ()
-endgrent ()
-endpwent ()
-endutxent ()
-fclose ()
-fcntl ()
-fflush ()
-fgetc ()
-fgetpos ()
-fgets ()
-fgetwc ()
-fgetws ()
-fopen ()
-fprintf ()
-fputc ()
-fputs ()
-fputwc ()
-fputws ()
-fread ()
-freopen ()
-fscanf ()
-fseek ()
-fseeko ()
-fsetpos ()
-ftell ()
-ftello ()
-ftw ()
-fwprintf ()
-fwrite ()
-fwscanf ()
-getc ()
-getc_unlocked ()
-getchar ()
-getchar_unlocked ()
-getcwd ()
-getdate ()
-getgrent ()
-getgrgid ()
-getgrgid_r ()
-getgrnam ()
-getgrnam_r ()
-getlogin ()
-getlogin_r ()
-getpwent ()
-*getpwnam ()
-*getpwnam_r ()
-*getpwuid ()
-*getpwuid_r ()
-gets ()
-getutxent ()
-getutxid ()
-getutxline ()
-getw ()
-getwc ()
-getwchar ()
-getwd ()
-glob ()
-iconv_close ()
-iconv_open ()
-ioctl ()
-lseek ()
-mkstemp ()
-nftw ()
-opendir ()
-openlog ()
-pclose ()
-perror ()
-popen ()
-printf ()
-putc ()
-putc_unlocked ()
-putchar ()
-putchar_unlocked ()
-puts ()
-pututxline ()
-putw ()
-putwc ()
-putwchar ()
-readdir ()
-readdir_r ()
-remove ()
-rename ()
-rewind ()
-rewinddir ()
-scanf ()
-seekdir ()
-semop ()
-setgrent ()
-setpwent ()
-setutxent ()
-strerror ()
-syslog ()
-tmpfile ()
-tmpnam ()
-ttyname ()
-ttyname_r ()
-ungetc ()
-ungetwc ()
-unlink ()
-vfprintf ()
-vfwprintf ()
-vprintf ()
-vwprintf ()
-wprintf ()
-wscanf ()
-
-Note, that for fcntl (), for any value of the cmd argument.
-
-And we must not introduce cancellation points anywhere else that's part of the posix or
-opengroup specs.
- */
 }
 
+/* TODO: Insert pthread_testcancel into the required functions.
+
+   Here are the lists of required and optional functions per POSIX.1-2001
+   and POSIX.1-2008. A star (*) indicates that the Cygwin function already
+   is a cancellation point (aka "calls pthread_testcancel"), an o (o)
+   indicates that the function is not implemented in Cygwin.
+
+   Required cancellation points:
+
+    * accept ()
+    o aio_suspend ()
+    o clock_nanosleep ()
+    * close ()
+    * connect ()
+    * creat ()
+    * fcntl () F_SETLKW
+    * fdatasync ()
+    * fsync ()
+    o getmsg ()
+    o getpmsg ()
+    * lockf () F_LOCK
+    * mq_receive ()
+    * mq_send ()
+    * mq_timedreceive ()
+    * mq_timedsend ()
+      msgrcv ()
+      msgsnd ()
+    * msync ()
+    * nanosleep ()
+    * open ()
+    * openat ()
+    * pause ()
+      poll ()
+    * pread ()
+      pselect ()
+    * pthread_cond_timedwait ()
+    * pthread_cond_wait ()
+    * pthread_join ()
+    * pthread_testcancel ()
+    o putmsg ()
+    o putpmsg ()
+    * pwrite ()
+    * read ()
+    * readv ()
+    * recv ()
+    * recvfrom ()
+    * recvmsg ()
+      select ()
+    * sem_timedwait ()
+    * sem_wait ()
+    * send ()
+    * sendmsg ()
+    * sendto ()
+    * sigpause ()
+    * sigsuspend ()
+    o sigtimedwait ()
+    * sigwait ()
+    * sigwaitinfo ()
+    * sleep ()
+    * system ()
+    * tcdrain ()
+    * usleep ()
+    * wait ()
+    * wait3()
+    o waitid ()
+    * waitpid ()
+    * write ()
+    * writev ()
+
+   Optional cancellation points:
+
+      access ()
+      asctime ()
+      asctime_r ()
+      catclose ()      Implemented externally: libcatgets
+      catgets ()       Implemented externally: libcatgets
+      catopen ()       Implemented externally: libcatgets
+      chmod ()
+      chown ()
+      closedir ()
+      closelog ()
+      ctermid ()
+      ctime ()
+      ctime_r ()
+      dbm_close ()     Implemented externally: libgdbm
+      dbm_delete ()    Implemented externally: libgdbm
+      dbm_fetch ()     Implemented externally: libgdbm
+      dbm_nextkey ()   Implemented externally: libgdbm
+      dbm_open ()      Implemented externally: libgdbm
+      dbm_store ()     Implemented externally: libgdbm
+      dlclose ()
+      dlopen ()
+      dprintf ()
+      endgrent ()
+      endhostent ()
+    o endnetent ()
+      endprotoent ()
+      endpwent ()
+      endservent ()
+      endutxent ()
+      faccessat ()
+      fchmod ()
+      fchmodat ()
+      fchown ()
+      fchownat ()
+    * fclose ()
+    * fcntl () (any value)
+      fflush ()
+      fgetc ()
+      fgetpos ()
+      fgets ()
+      fgetwc ()
+      fgetws ()
+    o fmtmsg ()
+      fopen ()
+      fpathconf ()
+      fprintf ()
+      fputc ()
+      fputs ()
+      fputwc ()
+      fputws ()
+      fread ()
+      freopen ()
+      fscanf ()
+      fseek ()
+      fseeko ()
+      fsetpos ()
+      fstat ()
+      fstatat ()
+      ftell ()
+      ftello ()
+      ftw ()
+      futimens ()
+      fwprintf ()
+      fwrite ()
+      fwscanf ()
+      getaddrinfo ()
+      getc ()
+      getc_unlocked ()
+      getchar ()
+      getchar_unlocked ()
+      getcwd ()
+    o getdate ()
+      getdelim ()
+      getgrent ()
+      getgrgid ()
+      getgrgid_r ()
+      getgrnam ()
+      getgrnam_r ()
+      gethostbyaddr ()
+      gethostbyname ()
+      gethostent ()
+      gethostid ()
+      gethostname ()
+      getline ()
+      getlogin ()
+      getlogin_r ()
+      getnameinfo ()
+    o getnetbyaddr ()
+    o getnetbyname ()
+    o getnetent ()
+      getopt () (if opterr is nonzero)
+      getprotobyname ()
+      getprotobynumber ()
+      getprotoent ()
+      getpwent ()
+    * getpwnam ()
+    * getpwnam_r ()
+    * getpwuid ()
+    * getpwuid_r ()
+      gets ()
+      getservbyname ()
+      getservbyport ()
+      getservent ()
+      getutxent ()
+      getutxid ()
+      getutxline ()
+      getwc ()
+      getwchar ()
+      getwd ()
+      glob ()
+      iconv_close ()   Implemented externally: libiconv
+      iconv_open ()    Implemented externally: libiconv
+      ioctl ()
+      link ()
+      linkat ()
+    o lio_listio ()
+      localtime ()
+      localtime_r ()
+    * lockf ()
+      lseek ()
+      lstat ()
+      mkdir ()
+      mkdirat ()
+      mkdtemp ()
+      mkfifo ()
+      mkfifoat ()
+      mknod ()
+      mknodat ()
+      mkstemp ()
+      mktime ()
+      nftw ()
+      opendir ()
+      openlog ()
+      pathconf ()
+      pclose ()
+      perror ()
+      popen ()
+      posix_fadvise ()
+      posix_fallocate ()
+      posix_madvise ()
+      posix_openpt ()
+    o posix_spawn ()
+    o posix_spawnp ()
+    o posix_trace_clear ()
+    o posix_trace_close ()
+    o posix_trace_create ()
+    o posix_trace_create_withlog ()
+    o posix_trace_eventtypelist_getnext_id ()
+    o posix_trace_eventtypelist_rewind ()
+    o posix_trace_flush ()
+    o posix_trace_get_attr ()
+    o posix_trace_get_filter ()
+    o posix_trace_get_status ()
+    o posix_trace_getnext_event ()
+    o posix_trace_open ()
+    o posix_trace_rewind ()
+    o posix_trace_set_filter ()
+    o posix_trace_shutdown ()
+    o posix_trace_timedgetnext_event ()
+    o posix_typed_mem_open ()
+      printf ()
+    o psiginfo ()
+    o psignal ()
+      pthread_rwlock_rdlock ()
+      pthread_rwlock_timedrdlock ()
+      pthread_rwlock_timedwrlock ()
+      pthread_rwlock_wrlock ()
+      putc ()
+      putc_unlocked ()
+      putchar ()
+      putchar_unlocked ()
+      puts ()
+      pututxline ()
+      putwc ()
+      putwchar ()
+      readdir ()
+      readdir_r ()
+      readlink ()
+      readlinkat ()
+      remove ()
+      rename ()
+      renameat ()
+      rewind ()
+      rewinddir ()
+      scandir ()
+      scanf ()
+      seekdir ()
+      semop ()
+      setgrent ()
+      sethostent ()
+    o setnetent ()
+      setprotoent ()
+      setpwent ()
+      setservent ()
+      setutxent ()
+      sigpause ()
+      stat ()
+      strerror ()
+      strerror_r ()
+      strftime ()
+      symlink ()
+      symlinkat ()
+      sync ()
+      syslog ()
+      tmpfile ()
+      tmpnam ()
+      ttyname ()
+      ttyname_r ()
+      tzset ()
+      ungetc ()
+      ungetwc ()
+      unlink ()
+      unlinkat ()
+      utime ()
+      utimensat ()
+      utimes ()
+      vdprintf ()
+      vfprintf ()
+      vfwprintf ()
+      vprintf ()
+      vwprintf ()
+      wcsftime ()
+      wordexp ()
+      wprintf ()
+      wscanf ()
+
+   An implementation may also mark other functions not specified in the
+   standard as cancellation points.  In particular, an implementation is
+   likely to mark any nonstandard function that may block as a
+   cancellation point. */
+
 void
-pthread::testcancel (void)
+pthread::testcancel ()
 {
   if (cancelstate == PTHREAD_CANCEL_DISABLE)
     return;
 
-  if (WaitForSingleObject (cancel_event, 0) == WAIT_OBJECT_0)
-    cancel_self ();
+  /* We check for the canceled flag first.  This allows to use the
+     pthread_testcancel function a lot without adding the overhead of
+     an OS call.  Only if the thread is marked as canceled, we wait for
+     cancel_event being really set, on the off-chance that pthread_cancel
+     gets interrupted before calling SetEvent. */
+  if (canceled)
+    {
+      WaitForSingleObject (cancel_event, INFINITE);
+      cancel_self ();
+    }
+}
+
+/* Return cancel event handle if it exists *and* cancel is not disabled.
+   This function is supposed to be used from other functions which are
+   cancelable and need the cancel event in a WFMO call. */
+HANDLE
+pthread::get_cancel_event ()
+{
+  pthread_t thread = pthread::self ();
+
+  return (thread && thread->cancel_event
+         && thread->cancelstate != PTHREAD_CANCEL_DISABLE)
+         ? thread->cancel_event : NULL;
 }
 
 void
-pthread::static_cancel_self (void)
+pthread::static_cancel_self ()
 {
   pthread::self ()->cancel_self ();
 }
 
-
 DWORD
-pthread::cancelable_wait (HANDLE object, DWORD timeout, const bool do_cancel)
+cancelable_wait (HANDLE object, DWORD timeout,
+                const cw_cancel_action cancel_action,
+                const enum cw_sig_wait sig_wait)
 {
   DWORD res;
-  HANDLE wait_objects[2];
-  pthread_t thread = self ();
-
-  if (!is_good_object (&thread) || thread->cancelstate == PTHREAD_CANCEL_DISABLE)
-    return WaitForSingleObject (object, timeout);
+  DWORD num = 0;
+  HANDLE wait_objects[3];
+  pthread_t thread = pthread::self ();
+
+  /* Do not change the wait order.
+     The object must have higher priority than the cancel event,
+     because WaitForMultipleObjects will return the smallest index
+     if both objects are signaled. */
+  wait_objects[num++] = object;
+  DWORD cancel_n;
+  if (cancel_action == cw_no_cancel || !pthread::is_good_object (&thread) ||
+      thread->cancelstate == PTHREAD_CANCEL_DISABLE)
+    cancel_n = WAIT_TIMEOUT + 1;
+  else
+    {
+      cancel_n = WAIT_OBJECT_0 + num++;
+      wait_objects[cancel_n] = thread->cancel_event;
+    }
 
-  // Do not change the wait order
-  // The object must have higher priority than the cancel event,
-  // because WaitForMultipleObjects will return the smallest index
-  // if both objects are signaled
-  wait_objects[0] = object;
-  wait_objects[1] = thread->cancel_event;
+  DWORD sig_n;
+  if (sig_wait == cw_sig_nosig)
+    sig_n = WAIT_TIMEOUT + 1;
+  else
+    {
+      sig_n = WAIT_OBJECT_0 + num++;
+      wait_objects[sig_n] = signal_arrived;
+    }
 
-  res = WaitForMultipleObjects (2, wait_objects, FALSE, timeout);
-  if (do_cancel && res == WAIT_CANCELED)
-    pthread::static_cancel_self ();
+  while (1)
+    {
+      res = WaitForMultipleObjects (num, wait_objects, FALSE, timeout);
+      if (res == cancel_n)
+       {
+         if (cancel_action == cw_cancel_self)
+           pthread::static_cancel_self ();
+         res = WAIT_CANCELED;
+       }
+      else if (res != sig_n)
+       /* all set */;
+      else if (sig_wait == cw_sig_eintr)
+       res = WAIT_SIGNALED;
+      else
+       {
+         _my_tls.call_signal_handler ();
+         continue;
+       }
+      break;
+    }
   return res;
 }
 
@@ -736,19 +1053,6 @@ pthread::get_thread_id ()
   return thread_id;
 }
 
-void
-pthread::init_current_thread ()
-{
-  cancel_event = ::CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
-  if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
-                       GetCurrentProcess (), &win32_obj_id,
-                       0, FALSE, DUPLICATE_SAME_ACCESS))
-    win32_obj_id = NULL;
-  set_thread_id_to_current ();
-  set_tls_self_pointer (this);
-  valid = true;
-}
-
 void
 pthread::_fixup_after_fork ()
 {
@@ -758,6 +1062,7 @@ pthread::_fixup_after_fork ()
       magic = 0;
       valid = false;
       win32_obj_id = NULL;
+      canceled = false;
       cancel_event = NULL;
     }
 }
@@ -766,30 +1071,21 @@ void
 pthread::suspend_except_self ()
 {
   if (valid && this != pthread::self ())
-    SuspendThread (win32_obj_id); 
+    SuspendThread (win32_obj_id);
 }
 
 void
 pthread::resume ()
 {
   if (valid)
-    ResumeThread (win32_obj_id); 
-}
-
-/* static members */
-bool
-pthread_attr::is_good_object (pthread_attr_t const *attr)
-{
-  if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
+    ResumeThread (win32_obj_id);
 }
 
 /* instance members */
 
 pthread_attr::pthread_attr ():verifyable_object (PTHREAD_ATTR_MAGIC),
 joinable (PTHREAD_CREATE_JOINABLE), contentionscope (PTHREAD_SCOPE_PROCESS),
-inheritsched (PTHREAD_INHERIT_SCHED), stacksize (0)
+inheritsched (PTHREAD_INHERIT_SCHED), stackaddr (NULL), stacksize (0)
 {
   schedparam.sched_priority = 0;
 }
@@ -798,14 +1094,6 @@ pthread_attr::~pthread_attr ()
 {
 }
 
-bool
-pthread_condattr::is_good_object (pthread_condattr_t const *attr)
-{
-  if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
-}
-
 pthread_condattr::pthread_condattr ():verifyable_object
   (PTHREAD_CONDATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE)
 {
@@ -855,7 +1143,7 @@ pthread_cond::pthread_cond (pthread_condattr *attr) :
    * Change the mutex type to NORMAL.
    * This mutex MUST be of type normal
   */
-  mtx_in.type = PTHREAD_MUTEX_NORMAL;
+  mtx_in.set_type (PTHREAD_MUTEX_NORMAL);
 
   verifyable_mutex_obj = &mtx_out;
   if (!pthread_mutex::is_good_object (&verifyable_mutex_obj))
@@ -865,12 +1153,12 @@ pthread_cond::pthread_cond (pthread_condattr *attr) :
       return;
     }
   /* Change the mutex type to NORMAL to speed up mutex operations */
-  mtx_out.type = PTHREAD_MUTEX_NORMAL;
+  mtx_out.set_type (PTHREAD_MUTEX_NORMAL);
 
   sem_wait = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL);
   if (!sem_wait)
     {
-      debug_printf ("CreateSemaphore failed. %E");
+      pthread_printf ("CreateSemaphore failed. %E");
       magic = 0;
       return;
     }
@@ -952,7 +1240,7 @@ pthread_cond::wait (pthread_mutex_t mutex, DWORD dwMilliseconds)
   ++mutex->condwaits;
   mutex->unlock ();
 
-  rv = pthread::cancelable_wait (sem_wait, dwMilliseconds, false);
+  rv = cancelable_wait (sem_wait, dwMilliseconds, cw_no_cancel_self, cw_sig_eintr);
 
   mtx_out.lock ();
 
@@ -987,6 +1275,13 @@ pthread_cond::wait (pthread_mutex_t mutex, DWORD dwMilliseconds)
 
   if (rv == WAIT_CANCELED)
     pthread::static_cancel_self ();
+  else if (rv == WAIT_SIGNALED)
+    /* SUSv3 states:  If a signal is delivered to a thread waiting for a
+       condition variable, upon return from the signal handler the thread
+       resumes waiting for the condition variable as if it was not
+       interrupted, or it shall return zero due to spurious wakeup.
+       We opt for the latter choice here. */
+    return 0;
   else if (rv == WAIT_TIMEOUT)
     return ETIMEDOUT;
 
@@ -1008,14 +1303,6 @@ pthread_cond::_fixup_after_fork ()
     api_fatal ("pthread_cond::_fixup_after_fork () failed to recreate win32 semaphore");
 }
 
-bool
-pthread_rwlockattr::is_good_object (pthread_rwlockattr_t const *attr)
-{
-  if (verifyable_object_isvalid (attr, PTHREAD_RWLOCKATTR_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
-}
-
 pthread_rwlockattr::pthread_rwlockattr ():verifyable_object
   (PTHREAD_RWLOCKATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE)
 {
@@ -1070,7 +1357,7 @@ pthread_rwlock::pthread_rwlock (pthread_rwlockattr *attr) :
       return;
     }
   /* Change the mutex type to NORMAL to speed up mutex operations */
-  mtx.type = PTHREAD_MUTEX_NORMAL;
+  mtx.set_type (PTHREAD_MUTEX_NORMAL);
 
   verifyable_cond_obj = &cond_readers;
   if (!pthread_cond::is_good_object (&verifyable_cond_obj))
@@ -1106,9 +1393,13 @@ pthread_rwlock::rdlock ()
 
   mtx.lock ();
 
-  if (lookup_reader (self))
+  reader = lookup_reader (self);
+  if (reader)
     {
-      result = EDEADLK;
+      if (reader->n < ULONG_MAX)
+       ++reader->n;
+      else
+       errno = EAGAIN;
       goto DONE;
     }
 
@@ -1131,6 +1422,7 @@ pthread_rwlock::rdlock ()
     }
 
   reader->thread = self;
+  reader->n = 1;
   add_reader (reader);
 
  DONE:
@@ -1151,10 +1443,15 @@ pthread_rwlock::tryrdlock ()
     result = EBUSY;
   else
     {
-      struct RWLOCK_READER *reader = new struct RWLOCK_READER;
-      if (reader)
+      struct RWLOCK_READER *reader;
+
+      reader = lookup_reader (self);
+      if (reader && reader->n < ULONG_MAX)
+       ++reader->n;
+      else if ((reader = new struct RWLOCK_READER))
        {
          reader->thread = self;
+         reader->n = 1;
          add_reader (reader);
        }
       else
@@ -1244,6 +1541,8 @@ pthread_rwlock::unlock ()
          result = EPERM;
          goto DONE;
        }
+      if (--reader->n > 0)
+       goto DONE;
 
       remove_reader (reader);
       delete reader;
@@ -1260,7 +1559,7 @@ pthread_rwlock::unlock ()
 void
 pthread_rwlock::add_reader (struct RWLOCK_READER *rd)
 {
-  List_insert (readers_mx, readers, rd);
+  List_insert (readers, rd);
 }
 
 void
@@ -1339,14 +1638,6 @@ pthread_rwlock::_fixup_after_fork ()
 /* This stores pthread_key information across fork() boundaries */
 List<pthread_key> pthread_key::keys;
 
-bool
-pthread_key::is_good_object (pthread_key_t const *key)
-{
-  if (verifyable_object_isvalid (key, PTHREAD_KEY_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
-}
-
 /* non-static members */
 
 pthread_key::pthread_key (void (*aDestructor) (void *)):verifyable_object (PTHREAD_KEY_MAGIC), destructor (aDestructor)
@@ -1369,23 +1660,6 @@ pthread_key::~pthread_key ()
     }
 }
 
-int
-pthread_key::set (const void *value)
-{
-  /* the OS function doesn't perform error checking */
-  TlsSetValue (tls_index, (void *) value);
-  return 0;
-}
-
-void *
-pthread_key::get () const
-{
-  int saved_error = ::GetLastError ();
-  void *result = TlsGetValue (tls_index);
-  ::SetLastError (saved_error);
-  return result;
-}
-
 void
 pthread_key::_fixup_before_fork ()
 {
@@ -1415,84 +1689,15 @@ pthread_key::run_destructor ()
     }
 }
 
-/* pshared mutexs:
-
-   REMOVED FROM CURRENT. These can be reinstated with the daemon, when all the
-   gymnastics can be a lot easier.
-
-   the mutex_t (size 4) is not used as a verifyable object because we cannot
-   guarantee the same address space for all processes.
-   we use the following:
-   high bit set (never a valid address).
-   second byte is reserved for the priority.
-   third byte is reserved
-   fourth byte is the mutex id. (max 255 cygwin mutexs system wide).
-   creating mutex's does get slower and slower, but as creation is a one time
-   job, it should never become an issue
-
-   And if you're looking at this and thinking, why not an array in cygwin for all mutexs,
-   - you incur a penalty on _every_ mutex call and you have toserialise them all.
-   ... Bad karma.
-
-   option 2? put everything in userspace and update the ABI?
-   - bad karma as well - the HANDLE, while identical across process's,
-   Isn't duplicated, it's reopened. */
+/* pshared mutexs */
 
 /* static members */
-bool
-pthread_mutex::is_good_object (pthread_mutex_t const *mutex)
-{
-  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
-}
-
-bool
-pthread_mutex::is_good_initializer (pthread_mutex_t const *mutex)
-{
-  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) != VALID_STATIC_OBJECT)
-    return false;
-  return true;
-}
-
-bool
-pthread_mutex::is_good_initializer_or_object (pthread_mutex_t const *mutex)
-{
-  if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) == INVALID_OBJECT)
-    return false;
-  return true;
-}
-
-bool
-pthread_mutex::is_good_initializer_or_bad_object (pthread_mutex_t const *mutex)
-{
-  verifyable_object_state objectState = verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER);
-  if (objectState == VALID_OBJECT)
-       return false;
-  return true;
-}
-
-bool
-pthread_mutex::can_be_unlocked (pthread_mutex_t const *mutex)
-{
-  pthread_t self = pthread::self ();
-
-  if (!is_good_object (mutex))
-    return false;
-  /*
-   * Check if the mutex is owned by the current thread and can be unlocked
-   */
-  return ((*mutex)->recursion_counter == 1 && pthread::equal ((*mutex)->owner, self));
-}
 
 List<pthread_mutex> pthread_mutex::mutexes;
 
 /* This is used for mutex creation protection within a single process only */
 fast_mutex NO_COPY pthread_mutex::mutex_initialization_lock;
 
-/* We can only be called once.
-   TODO: (no rush) use a non copied memory section to
-   hold an initialization flag.  */
 void
 pthread_mutex::init_mutex ()
 {
@@ -1501,50 +1706,59 @@ pthread_mutex::init_mutex ()
 }
 
 pthread_mutex::pthread_mutex (pthread_mutexattr *attr) :
-  verifyable_object (PTHREAD_MUTEX_MAGIC),
+  verifyable_object (0),       /* set magic to zero initially */
   lock_counter (0),
-  win32_obj_id (NULL), recursion_counter (0),
-  condwaits (0), owner (NULL), type (PTHREAD_MUTEX_DEFAULT),
+  win32_obj_id (NULL), owner (_new_mutex),
+#ifdef DEBUGGING
+  tid (0),
+#endif
+  recursion_counter (0), condwaits (0),
+  type (PTHREAD_MUTEX_ERRORCHECK),
   pshared (PTHREAD_PROCESS_PRIVATE)
 {
-  win32_obj_id = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL);
+  win32_obj_id = ::CreateEvent (&sec_none_nih, false, false, NULL);
   if (!win32_obj_id)
-    {
-      magic = 0;
-      return;
-    }
+    return;
   /*attr checked in the C call */
-  if (attr)
-    {
-      if (attr->pshared == PTHREAD_PROCESS_SHARED)
-       {
-         // fail
-         magic = 0;
-         return;
-       }
-
-      type = attr->mutextype;
-    }
+  if (!attr)
+    /* handled in the caller */;
+  else if (attr->pshared != PTHREAD_PROCESS_SHARED)
+    type = attr->mutextype;
+  else
+    return;            /* Not implemented */
 
+  magic = PTHREAD_MUTEX_MAGIC;
   mutexes.insert (this);
 }
 
 pthread_mutex::~pthread_mutex ()
 {
   if (win32_obj_id)
-    CloseHandle (win32_obj_id);
+    {
+      CloseHandle (win32_obj_id);
+      win32_obj_id = NULL;
+    }
 
   mutexes.remove (this);
+  owner = _destroyed_mutex;
+  magic = 0;
 }
 
 int
-pthread_mutex::_lock (pthread_t self)
+pthread_mutex::lock ()
 {
+  pthread_t self = ::pthread_self ();
   int result = 0;
 
-  if (InterlockedIncrement ((long *)&lock_counter) == 1)
+  if (InterlockedIncrement ((long *) &lock_counter) == 1)
     set_owner (self);
-  else if (type != PTHREAD_MUTEX_NORMAL && pthread::equal (owner, self))
+  else if (type == PTHREAD_MUTEX_NORMAL /* potentially causes deadlock */
+          || !pthread::equal (owner, self))
+    {
+      cancelable_wait (win32_obj_id, INFINITE, cw_no_cancel, cw_sig_resume);
+      set_owner (self);
+    }
+  else
     {
       InterlockedDecrement ((long *) &lock_counter);
       if (type == PTHREAD_MUTEX_RECURSIVE)
@@ -1552,18 +1766,45 @@ pthread_mutex::_lock (pthread_t self)
       else
        result = EDEADLK;
     }
-  else
-    {
-      WaitForSingleObject (win32_obj_id, INFINITE);
-      set_owner (self);
-    }
 
+  pthread_printf ("mutex %p, self %p, owner %p, lock_counter %d, recursion_counter %d",
+                 this, self, owner, lock_counter, recursion_counter);
   return result;
 }
 
 int
-pthread_mutex::_trylock (pthread_t self)
+pthread_mutex::unlock ()
+{
+  int res = 0;
+  pthread_t self = ::pthread_self ();
+  if (type == PTHREAD_MUTEX_NORMAL)
+    /* no error checking */;
+  else if (no_owner ())
+    res = type == PTHREAD_MUTEX_ERRORCHECK ? EINVAL : 0;
+  else if (!pthread::equal (owner, self))
+    res = EPERM;
+  if (!res && recursion_counter > 0 && --recursion_counter == 0)
+    /* Don't try to unlock anything if recursion_counter == 0.
+       This means the mutex was never locked or that we've forked. */
+    {
+      owner = (pthread_t) _unlocked_mutex;
+#ifdef DEBUGGING
+      tid = 0;
+#endif
+      if (InterlockedDecrement ((long *) &lock_counter))
+       ::SetEvent (win32_obj_id); // Another thread is waiting
+      res = 0;
+    }
+
+  pthread_printf ("mutex %p, owner %p, self %p, lock_counter %d, recursion_counter %d, type %d, res %d",
+                 this, owner, self, lock_counter, recursion_counter, type, res);
+  return res;
+}
+
+int
+pthread_mutex::trylock ()
 {
+  pthread_t self = ::pthread_self ();
   int result = 0;
 
   if (InterlockedCompareExchange ((long *) &lock_counter, 1, 0) == 0)
@@ -1577,32 +1818,15 @@ pthread_mutex::_trylock (pthread_t self)
 }
 
 int
-pthread_mutex::_unlock (pthread_t self)
-{
-  if (!pthread::equal (owner, self))
-    return EPERM;
-
-  if (--recursion_counter == 0)
-    {
-      owner = NULL;
-      if (InterlockedDecrement ((long *)&lock_counter))
-       // Another thread is waiting
-       ::ReleaseSemaphore (win32_obj_id, 1, NULL);
-    }
-
-  return 0;
-}
-
-int
-pthread_mutex::_destroy (pthread_t self)
+pthread_mutex::destroy ()
 {
-  if (condwaits || _trylock (self))
+  if (condwaits || trylock ())
     // Do not destroy a condwaited or locked mutex
     return EBUSY;
-  else if (recursion_counter != 1)
+  else if (recursion_counter > 1)
     {
       // Do not destroy a recursive locked mutex
-      --recursion_counter;
+      recursion_counter--;
       return EBUSY;
     }
 
@@ -1613,34 +1837,24 @@ pthread_mutex::_destroy (pthread_t self)
 void
 pthread_mutex::_fixup_after_fork ()
 {
-  debug_printf ("mutex %x in _fixup_after_fork", this);
+  pthread_printf ("mutex %p", this);
   if (pshared != PTHREAD_PROCESS_PRIVATE)
-    api_fatal ("pthread_mutex::_fixup_after_fork () doesn'tunderstand PROCESS_SHARED mutex's");
-
-  if (owner == NULL)
-    /* mutex has no owner, reset to initial */
-    lock_counter = 0;
-  else if (lock_counter != 0)
-    /* All waiting threads are gone after a fork */
-    lock_counter = 1;
-
-  win32_obj_id = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL);
-  if (!win32_obj_id)
-    api_fatal ("pthread_mutex::_fixup_after_fork () failed to recreate win32 semaphore for mutex");
+    api_fatal ("pthread_mutex::_fixup_after_fork () doesn't understand PROCESS_SHARED mutex's");
 
+  /* All waiting threads are gone after a fork */
+  recursion_counter = 0;
+  lock_counter = 0;
   condwaits = 0;
-}
-
-bool
-pthread_mutexattr::is_good_object (pthread_mutexattr_t const * attr)
-{
-  if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
+#ifdef DEBUGGING
+  tid = 0xffffffff;    /* Don't know the tid after a fork */
+#endif
+  win32_obj_id = ::CreateEvent (&sec_none_nih, false, false, NULL);
+  if (!win32_obj_id)
+    api_fatal ("pthread_mutex::_fixup_after_fork () failed to recreate win32 event for mutex");
 }
 
 pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC),
-pshared (PTHREAD_PROCESS_PRIVATE), mutextype (PTHREAD_MUTEX_DEFAULT)
+pshared (PTHREAD_PROCESS_PRIVATE), mutextype (PTHREAD_MUTEX_ERRORCHECK)
 {
 }
 
@@ -1648,293 +1862,80 @@ pthread_mutexattr::~pthread_mutexattr ()
 {
 }
 
-List<semaphore> semaphore::semaphores;
-
-semaphore::semaphore (int pshared, unsigned int value)
-: verifyable_object (SEM_MAGIC),
-  shared (pshared),
-  currentvalue (value),
-  name (NULL)
-{
-  SECURITY_ATTRIBUTES sa = (pshared != PTHREAD_PROCESS_PRIVATE)
-                          ? sec_all : sec_none_nih;
-  this->win32_obj_id = ::CreateSemaphore (&sa, value, LONG_MAX, NULL);
-  if (!this->win32_obj_id)
-    magic = 0;
-
-  semaphores.insert (this);
-}
-
-semaphore::semaphore (const char *sem_name, int oflag, mode_t mode,
-                                 unsigned int value)
-: verifyable_object (SEM_MAGIC),
-  shared (PTHREAD_PROCESS_SHARED),
-  currentvalue (value),                /* Unused for named semaphores. */
-  name (NULL)
-{
-  if (oflag & O_CREAT)
-    {
-      SECURITY_ATTRIBUTES sa = sec_all;
-      if (allow_ntsec)
-       set_security_attribute (mode, &sa, alloca (4096), 4096);
-      this->win32_obj_id = ::CreateSemaphore (&sa, value, LONG_MAX, sem_name);
-      if (!this->win32_obj_id)
-        magic = 0;
-      if (GetLastError () == ERROR_ALREADY_EXISTS && (oflag & O_EXCL))
-       {
-         __seterrno ();
-         CloseHandle (this->win32_obj_id);
-         magic = 0;
-       }
-    }
-  else
-    {
-      this->win32_obj_id = ::OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE,
-                                           sem_name);
-      if (!this->win32_obj_id)
-       {
-         __seterrno ();
-         magic = 0;
-       }
-    }
-  if (magic)
-    {
-      name = new char [strlen (sem_name + 1)];
-      if (!name)
-       {
-         set_errno (ENOSPC);
-         CloseHandle (this->win32_obj_id);
-         magic = 0;
-       }
-      else
-        strcpy (name, sem_name);
-    }
-
-  semaphores.insert (this);
-}
-
-semaphore::~semaphore ()
-{
-  if (win32_obj_id)
-    CloseHandle (win32_obj_id);
+/* pshared spinlocks
 
-  delete [] name;
-
-  semaphores.remove (this);
-}
+   The infrastructure is provided by the underlying pthread_mutex class.
+   The rest is a simplification implementing spin locking. */
 
-void
-semaphore::_post ()
+pthread_spinlock::pthread_spinlock (int pshared) :
+  pthread_mutex (NULL)
 {
-  if (ReleaseSemaphore (win32_obj_id, 1, &currentvalue))
-    currentvalue++;
+  magic = PTHREAD_SPINLOCK_MAGIC;
+  set_type (PTHREAD_MUTEX_NORMAL);
+  set_shared (pshared);
 }
 
 int
-semaphore::_getvalue (int *sval)
+pthread_spinlock::lock ()
 {
-  long val;
-
-  switch (WaitForSingleObject (win32_obj_id, 0))
-    {
-      case WAIT_OBJECT_0:
-       ReleaseSemaphore (win32_obj_id, 1, &val);
-       *sval = val + 1;
-       break;
-      case WAIT_TIMEOUT:
-       *sval = 0;
-       break;
-      default:
-        set_errno (EAGAIN);
-       return -1;
-    }
-  return 0;
-}
+  pthread_t self = ::pthread_self ();
+  int result = -1;
 
-int
-semaphore::_trywait ()
-{
-  /* FIXME: signals should be able to interrupt semaphores...
-   *We probably need WaitForMultipleObjects here.
-   */
-  if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
+  do
     {
-      set_errno (EAGAIN);
-      return -1;
+      if (InterlockedExchange ((long *) &lock_counter, 1) == 0)
+       {
+         set_owner (self);
+         result = 0;
+       }
+      else if (pthread::equal (owner, self))
+       result = EDEADLK;
+      else /* Minimal timeout to minimize CPU usage while still spinning. */
+       cancelable_wait (win32_obj_id, 1L, cw_no_cancel, cw_sig_resume);
     }
-  currentvalue--;
-  return 0;
+  while (result == -1);
+  pthread_printf ("spinlock %p, self %p, owner %p", this, self, owner);
+  return result;
 }
 
 int
-semaphore::_timedwait (const struct timespec *abstime)
-{
-  struct timeval tv;
-  long waitlength;
-
-  if (__check_invalid_read_ptr (abstime, sizeof *abstime))
-    {
-      /* According to SUSv3, abstime need not be checked for validity,
-         if the semaphore can be locked immediately. */
-      if (!_trywait ())
-        return 0;
-      set_errno (EINVAL);
-      return -1;
-    }
-
-  gettimeofday (&tv, NULL);
-  waitlength = abstime->tv_sec * 1000 + abstime->tv_nsec / (1000 * 1000);
-  waitlength -= tv.tv_sec * 1000 + tv.tv_usec / 1000;
-  if (waitlength < 0)
-    waitlength = 0;
-  switch (pthread::cancelable_wait (win32_obj_id, waitlength))
-    {
-    case WAIT_OBJECT_0:
-      currentvalue--;
-      break;
-    case WAIT_TIMEOUT:
-      set_errno (ETIMEDOUT);
-      return -1;
-    default:
-      debug_printf ("cancelable_wait failed. %E");
-      __seterrno ();
-      return -1;
-    }
-  return 0;
-}
-
-void
-semaphore::_wait ()
+pthread_spinlock::unlock ()
 {
-  switch (pthread::cancelable_wait (win32_obj_id, INFINITE))
-    {
-    case WAIT_OBJECT_0:
-      currentvalue--;
-      break;
-    default:
-      debug_printf ("cancelable_wait failed. %E");
-      return;
-    }
-}
+  pthread_t self = ::pthread_self ();
+  int result = 0;
 
-void
-semaphore::_fixup_after_fork ()
-{
-  if (shared == PTHREAD_PROCESS_PRIVATE)
+  if (!pthread::equal (owner, self))
+    result = EPERM;
+  else
     {
-      debug_printf ("sem %x in _fixup_after_fork", this);
-      /* FIXME: duplicate code here and in the constructor. */
-      this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue,
-                                             LONG_MAX, NULL);
-      if (!win32_obj_id)
-       api_fatal ("failed to create new win32 semaphore, error %d");
+      owner = (pthread_t) _unlocked_mutex;
+#ifdef DEBUGGING
+      tid = 0;
+#endif
+      InterlockedExchange ((long *) &lock_counter, 0);
+      ::SetEvent (win32_obj_id);
+      result = 0;
     }
+  pthread_printf ("spinlock %p, owner %p, self %p, res %d",
+                 this, owner, self, result);
+  return result;
 }
 
-verifyable_object::verifyable_object (long verifyer):
-magic (verifyer)
-{
-}
-
-verifyable_object::~verifyable_object ()
-{
-  magic = 0;
-}
-
-/* Generic memory acccess routine - where should it live ? */
-int __stdcall
-check_valid_pointer (void const *pointer)
-{
-  if (!pointer || IsBadWritePtr ((void *) pointer, sizeof (verifyable_object)))
-    return EFAULT;
-  return 0;
-}
-
-verifyable_object_state
-verifyable_object_isvalid (void const * objectptr, long magic, void *static_ptr)
-{
-  verifyable_object **object = (verifyable_object **)objectptr;
-  if (check_valid_pointer (object))
-    return INVALID_OBJECT;
-  if (static_ptr && *object == static_ptr)
-    return VALID_STATIC_OBJECT;
-  if (!*object)
-    return INVALID_OBJECT;
-  if (check_valid_pointer (*object))
-    return INVALID_OBJECT;
-  if ((*object)->magic != magic)
-    return INVALID_OBJECT;
-  return VALID_OBJECT;
-}
-
-verifyable_object_state
-verifyable_object_isvalid (void const * objectptr, long magic)
-{
-  return verifyable_object_isvalid (objectptr, magic, NULL);
-}
-
-inline void
-__reent_t::init_clib (struct _reent& var)
-{
-  var = ((struct _reent) _REENT_INIT (var));
-  var._stdin = _GLOBAL_REENT->_stdin;
-  var._stdout = _GLOBAL_REENT->_stdout;
-  var._stderr = _GLOBAL_REENT->_stderr;
-  var.__sdidinit = _GLOBAL_REENT->__sdidinit;
-  var.__cleanup = _GLOBAL_REENT->__cleanup;
-  _clib = &var;
-};
-
-/* Pthreads */
-void *
-pthread::thread_init_wrapper (void *_arg)
+DWORD WINAPI
+pthread::thread_init_wrapper (void *arg)
 {
-  // Setup the local/global storage of this thread
-
-  pthread *thread = (pthread *) _arg;
-  struct __reent_t local_reent;
-  struct _winsup_t local_winsup;
-  struct _reent local_clib;
-
-  struct sigaction _sigs[NSIG];
-  sigset_t _sig_mask;          /* one set for everything to ignore. */
-
-  /* According to onno@stack.urc.tue.nl, the exception handler record must
-     be on the stack.  */
-  exception_list cygwin_except_entry;
-
-  /* Initialize SIGSEGV handling, etc. */
-  init_exceptions (&cygwin_except_entry);
-
-  // setup signal structures
-  thread->sigs = _sigs;
-  thread->sigmask = &_sig_mask;
-  thread->sigtodo = NULL;
-
-  memset (&local_winsup, 0, sizeof (struct _winsup_t));
-
-  local_reent.init_clib (local_clib);
-  local_reent._winsup = &local_winsup;
-
-  local_winsup._process_logmask = LOG_UPTO (LOG_DEBUG);
-
-  MT_INTERFACE->reent_key.set (&local_reent);
-
-  thread->set_thread_id_to_current ();
+  pthread *thread = (pthread *) arg;
   set_tls_self_pointer (thread);
 
   thread->mutex.lock ();
+
   // if thread is detached force cleanup on exit
   if (thread->attr.joinable == PTHREAD_CREATE_DETACHED && thread->joiner == NULL)
     thread->joiner = thread;
+  _my_tls.sigmask = thread->parent_tls->sigmask;
   thread->mutex.unlock ();
 
-#ifdef _CYG_THREAD_FAILSAFE
-  if (_REENT == _impure_ptr)
-    system_printf ("local storage for thread isn't setup correctly");
-#endif
-
-  thread_printf ("started thread %p %p %p %p %p %p", _arg, &local_clib,
+  thread_printf ("started thread %p %p %p %p %p %p", arg, &_my_tls.local_clib,
                 _impure_ptr, thread, thread->function, thread->arg);
 
   // call the user's thread
@@ -1942,20 +1943,7 @@ pthread::thread_init_wrapper (void *_arg)
 
   thread->exit (ret);
 
-#if 0
-// ??? This code only runs if the thread exits by returning.
-// it's all now in __pthread_exit ();
-#endif
-  /* never reached */
-  return 0;
-}
-
-bool
-pthread::is_good_object (pthread_t const *thread)
-{
-  if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
+  return 0;    // just for show.  Never returns.
 }
 
 unsigned long
@@ -1968,13 +1956,11 @@ int
 pthread::create (pthread_t *thread, const pthread_attr_t *attr,
                  void *(*start_routine) (void *), void *arg)
 {
-  DECLARE_TLS_STORAGE;
   if (attr && !pthread_attr::is_good_object (attr))
     return EINVAL;
 
   *thread = new pthread ();
-  (*thread)->create (start_routine, attr ? *attr : NULL, arg);
-  if (!is_good_object (thread))
+  if (!(*thread)->create (start_routine, attr ? *attr : NULL, arg))
     {
       delete (*thread);
       *thread = NULL;
@@ -2017,38 +2003,26 @@ pthread::cancel (pthread_t thread)
   return thread->cancel ();
 }
 
-/* Races in pthread_atfork:
-   We are race safe in that any additions to the lists are made via
-   InterlockedExchangePointer.
-   However, if the user application doesn't perform syncronisation of some sort
-   It's not guaranteed that a near simultaneous call to pthread_atfork and fork
-   will result in the new atfork handlers being calls.
-   More rigorous internal syncronisation isn't needed as the user program isn't
-   guaranteeing their own state.
-
-   as far as multiple calls to pthread_atfork, the worst case is simultaneous calls
-   will result in an indeterminate order for parent and child calls (what gets inserted
-   first isn't guaranteed.)
-
-   There is one potential race... Does the result of InterlockedExchangePointer
-   get committed to the return location _before_ any context switches can occur?
-   If yes, we're safe, if no, we're not.  */
 void
-pthread::atforkprepare (void)
+pthread::atforkprepare ()
 {
-  MT_INTERFACE->fixup_before_fork ();
-
   callback *cb = MT_INTERFACE->pthread_prepare;
   while (cb)
     {
       cb->cb ();
       cb = cb->next;
     }
+
+  __fp_lock_all ();
+
+  MT_INTERFACE->fixup_before_fork ();
 }
 
 void
-pthread::atforkparent (void)
+pthread::atforkparent ()
 {
+  __fp_unlock_all ();
+
   callback *cb = MT_INTERFACE->pthread_parent;
   while (cb)
     {
@@ -2058,10 +2032,12 @@ pthread::atforkparent (void)
 }
 
 void
-pthread::atforkchild (void)
+pthread::atforkchild ()
 {
   MT_INTERFACE->fixup_after_fork ();
 
+  __fp_unlock_all ();
+
   callback *cb = MT_INTERFACE->pthread_child;
   while (cb)
     {
@@ -2109,7 +2085,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void
   if (prepcb)
   {
     prepcb->cb = prepare;
-    prepcb->next = (callback *) InterlockedExchangePointer ((LONG *) &MT_INTERFACE->pthread_prepare, (long int) prepcb);
+    List_insert (MT_INTERFACE->pthread_prepare, prepcb);
   }
   if (parentcb)
   {
@@ -2118,7 +2094,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void
     while (*t)
       t = &(*t)->next;
     /* t = pointer to last next in the list */
-    parentcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) parentcb);
+    List_insert (*t, parentcb);
   }
   if (childcb)
   {
@@ -2127,7 +2103,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void
     while (*t)
       t = &(*t)->next;
     /* t = pointer to last next in the list */
-    childcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) childcb);
+    List_insert (*t, childcb);
   }
   return 0;
 }
@@ -2261,11 +2237,35 @@ pthread_attr_setscope (pthread_attr_t *attr, int contentionscope)
   return 0;
 }
 
+extern "C" int
+pthread_attr_getstack (const pthread_attr_t *attr, void **addr, size_t *size)
+{
+  if (!pthread_attr::is_good_object (attr))
+    return EINVAL;
+  /* uses lowest address of stack on all platforms */
+  *addr = (void *)((int)(*attr)->stackaddr - (*attr)->stacksize);
+  *size = (*attr)->stacksize;
+  return 0;
+}
+
+extern "C" int
+pthread_attr_getstackaddr (const pthread_attr_t *attr, void **addr)
+{
+  if (!pthread_attr::is_good_object (attr))
+    return EINVAL;
+  /* uses stack address, which is the higher address on platforms
+     where the stack grows downwards, such as x86 */
+  *addr = (*attr)->stackaddr;
+  return 0;
+}
+
 extern "C" int
 pthread_attr_setstacksize (pthread_attr_t *attr, size_t size)
 {
   if (!pthread_attr::is_good_object (attr))
     return EINVAL;
+  if (size < PTHREAD_STACK_MIN)
+    return EINVAL;    
   (*attr)->stacksize = size;
   return 0;
 }
@@ -2322,7 +2322,7 @@ pthread::join (pthread_t *thread, void **return_val)
       (*thread)->attr.joinable = PTHREAD_CREATE_DETACHED;
       (*thread)->mutex.unlock ();
 
-      switch (cancelable_wait ((*thread)->win32_obj_id, INFINITE, false))
+      switch (cancelable_wait ((*thread)->win32_obj_id, INFINITE, cw_no_cancel_self, cw_sig_resume))
        {
        case WAIT_OBJECT_0:
          if (return_val)
@@ -2405,11 +2405,56 @@ pthread::resume (pthread_t *thread)
   return 0;
 }
 
+extern "C" int
+pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
+{
+  const size_t sizeof_tbi = sizeof (THREAD_BASIC_INFORMATION);
+  PTHREAD_BASIC_INFORMATION tbi;
+  NTSTATUS ret;
+
+  if (!pthread::is_good_object (&thread))
+    return ESRCH;
+
+  /* attr may not be pre-initialized */
+  if (!pthread_attr::is_good_object (attr))
+  {
+    int rv = pthread_attr_init (attr);
+    if (rv != 0)
+      return rv;
+  }
+
+  (*attr)->joinable = thread->attr.joinable;
+  (*attr)->contentionscope = thread->attr.contentionscope;
+  (*attr)->inheritsched = thread->attr.inheritsched;
+  (*attr)->schedparam = thread->attr.schedparam;
+
+  tbi = (PTHREAD_BASIC_INFORMATION) malloc (sizeof_tbi);
+  ret = NtQueryInformationThread (thread->win32_obj_id, ThreadBasicInformation,
+                                  tbi, sizeof_tbi, NULL);
+
+  if (NT_SUCCESS (ret))
+    {
+      PNT_TIB tib = tbi->TebBaseAddress;
+      (*attr)->stackaddr = tib->StackBase;
+      /* stack grows downwards on x86 systems */
+      (*attr)->stacksize = (int)tib->StackBase - (int)tib->StackLimit;
+    }
+  else
+    {
+      debug_printf ("NtQueryInformationThread(ThreadBasicInformation), "
+                    "status %p", ret);
+      (*attr)->stackaddr = thread->attr.stackaddr;
+      (*attr)->stacksize = thread->attr.stacksize;
+    }
+
+  return 0;
+}
+
 /* provided for source level compatability.
    See http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.html
 */
 extern "C" int
-pthread_getconcurrency (void)
+pthread_getconcurrency ()
 {
   return MT_INTERFACE->concurrency;
 }
@@ -2428,15 +2473,10 @@ pthread_getschedparam (pthread_t thread, int *policy,
   return 0;
 }
 
-/* Thread SpecificData */
+/* Thread Specific Data */
 extern "C" int
 pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
 {
-  /* The opengroup docs don't define if we should check this or not,
-     but creation is relatively rare.  */
-  if (pthread_key::is_good_object (key))
-    return EBUSY;
-
   *key = new pthread_key (destructor);
 
   if (!pthread_key::is_good_object (key))
@@ -2488,6 +2528,17 @@ pthread_setschedparam (pthread_t thread, int policy,
   return rv;
 }
 
+extern "C" int
+pthread_setschedprio (pthread_t thread, int priority)
+{
+  if (!pthread::is_good_object (&thread))
+    return ESRCH;
+  int rv =
+    sched_set_thread_priority (thread->win32_obj_id, priority);
+  if (!rv)
+    thread->attr.schedparam.sched_priority = priority;
+  return rv;
+}
 
 extern "C" int
 pthread_setspecific (pthread_key_t key, const void *value)
@@ -2508,44 +2559,10 @@ pthread_getspecific (pthread_key_t key)
 
 }
 
-/* Thread synchronisation */
-bool
-pthread_cond::is_good_object (pthread_cond_t const *cond)
-{
-  if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
-}
-
-bool
-pthread_cond::is_good_initializer (pthread_cond_t const *cond)
-{
-  if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) != VALID_STATIC_OBJECT)
-    return false;
-  return true;
-}
-
-bool
-pthread_cond::is_good_initializer_or_object (pthread_cond_t const *cond)
-{
-  if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) == INVALID_OBJECT)
-    return false;
-  return true;
-}
-
-bool
-pthread_cond::is_good_initializer_or_bad_object (pthread_cond_t const *cond)
-{
-  verifyable_object_state objectState = verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER);
-  if (objectState == VALID_OBJECT)
-       return false;
-  return true;
-}
-
 extern "C" int
 pthread_cond_destroy (pthread_cond_t *cond)
 {
-  if (pthread_cond::is_good_initializer (cond))
+  if (pthread_cond::is_initializer (cond))
     return 0;
   if (!pthread_cond::is_good_object (cond))
     return EINVAL;
@@ -2563,33 +2580,39 @@ pthread_cond_destroy (pthread_cond_t *cond)
 int
 pthread_cond::init (pthread_cond_t *cond, const pthread_condattr_t *attr)
 {
+  pthread_cond_t new_cond;
+
   if (attr && !pthread_condattr::is_good_object (attr))
     return EINVAL;
 
   cond_initialization_lock.lock ();
 
-  if (!is_good_initializer_or_bad_object (cond))
+  new_cond = new pthread_cond (attr ? (*attr) : NULL);
+  if (!is_good_object (&new_cond))
     {
+      delete new_cond;
       cond_initialization_lock.unlock ();
-      return EBUSY;
+      return EAGAIN;
     }
 
-  *cond = new pthread_cond (attr ? (*attr) : NULL);
-  if (!is_good_object (cond))
+  myfault efault;
+  if (efault.faulted ())
     {
-      delete (*cond);
-      *cond = NULL;
+      delete new_cond;
       cond_initialization_lock.unlock ();
-      return EAGAIN;
+      return EINVAL;
     }
+
+  *cond = new_cond;
   cond_initialization_lock.unlock ();
+
   return 0;
 }
 
 extern "C" int
 pthread_cond_broadcast (pthread_cond_t *cond)
 {
-  if (pthread_cond::is_good_initializer (cond))
+  if (pthread_cond::is_initializer (cond))
     return 0;
   if (!pthread_cond::is_good_object (cond))
     return EINVAL;
@@ -2602,7 +2625,7 @@ pthread_cond_broadcast (pthread_cond_t *cond)
 extern "C" int
 pthread_cond_signal (pthread_cond_t *cond)
 {
-  if (pthread_cond::is_good_initializer (cond))
+  if (pthread_cond::is_initializer (cond))
     return 0;
   if (!pthread_cond::is_good_object (cond))
     return EINVAL;
@@ -2618,10 +2641,10 @@ __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex,
 {
   if (!pthread_mutex::is_good_object (mutex))
     return EINVAL;
-  if (!pthread_mutex::can_be_unlocked (mutex))
+  if (!(*mutex)->can_be_unlocked ())
     return EPERM;
 
-  if (pthread_cond::is_good_initializer (cond))
+  if (pthread_cond::is_initializer (cond))
     pthread_cond::init (cond, NULL);
   if (!pthread_cond::is_good_object (cond))
     return EINVAL;
@@ -2634,18 +2657,31 @@ pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
                        const struct timespec *abstime)
 {
   struct timeval tv;
-  long waitlength;
+  DWORD waitlength;
+
+  myfault efault;
+  if (efault.faulted ())
+    return EINVAL;
 
   pthread_testcancel ();
 
-  if (check_valid_pointer (abstime))
+  /* According to SUSv3, the abstime value must be checked for validity. */
+  if (abstime->tv_sec < 0
+      || abstime->tv_nsec < 0
+      || abstime->tv_nsec > 999999999)
     return EINVAL;
 
   gettimeofday (&tv, NULL);
-  waitlength = abstime->tv_sec * 1000 + abstime->tv_nsec / (1000 * 1000);
-  waitlength -= tv.tv_sec * 1000 + tv.tv_usec / 1000;
-  if (waitlength < 0)
+  /* Check for immediate timeout before converting to microseconds, since
+     the resulting value can easily overflow long.  This also allows to
+     evaluate microseconds directly in DWORD. */
+  if (tv.tv_sec > abstime->tv_sec
+      || (tv.tv_sec == abstime->tv_sec
+         && tv.tv_usec > abstime->tv_nsec / 1000))
     return ETIMEDOUT;
+
+  waitlength = (abstime->tv_sec - tv.tv_sec) * 1000;
+  waitlength += (abstime->tv_nsec / 1000 - tv.tv_usec) / 1000;
   return __pthread_cond_dowait (cond, mutex, waitlength);
 }
 
@@ -2706,44 +2742,10 @@ pthread_condattr_destroy (pthread_condattr_t *condattr)
   return 0;
 }
 
-/* RW locks */
-bool
-pthread_rwlock::is_good_object (pthread_rwlock_t const *rwlock)
-{
-  if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
-}
-
-bool
-pthread_rwlock::is_good_initializer (pthread_rwlock_t const *rwlock)
-{
-  if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) != VALID_STATIC_OBJECT)
-    return false;
-  return true;
-}
-
-bool
-pthread_rwlock::is_good_initializer_or_object (pthread_rwlock_t const *rwlock)
-{
-  if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) == INVALID_OBJECT)
-    return false;
-  return true;
-}
-
-bool
-pthread_rwlock::is_good_initializer_or_bad_object (pthread_rwlock_t const *rwlock)
-{
-  verifyable_object_state objectState = verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER);
-  if (objectState == VALID_OBJECT)
-       return false;
-  return true;
-}
-
 extern "C" int
 pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
 {
-  if (pthread_rwlock::is_good_initializer (rwlock))
+  if (pthread_rwlock::is_initializer (rwlock))
     return 0;
   if (!pthread_rwlock::is_good_object (rwlock))
     return EINVAL;
@@ -2761,26 +2763,32 @@ pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
 int
 pthread_rwlock::init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
 {
+  pthread_rwlock_t new_rwlock;
+
   if (attr && !pthread_rwlockattr::is_good_object (attr))
     return EINVAL;
 
   rwlock_initialization_lock.lock ();
 
-  if (!is_good_initializer_or_bad_object (rwlock))
+  new_rwlock = new pthread_rwlock (attr ? (*attr) : NULL);
+  if (!is_good_object (&new_rwlock))
     {
+      delete new_rwlock;
       rwlock_initialization_lock.unlock ();
-      return EBUSY;
+      return EAGAIN;
     }
 
-  *rwlock = new pthread_rwlock (attr ? (*attr) : NULL);
-  if (!is_good_object (rwlock))
+  myfault efault;
+  if (efault.faulted ())
     {
-      delete (*rwlock);
-      *rwlock = NULL;
+      delete new_rwlock;
       rwlock_initialization_lock.unlock ();
-      return EAGAIN;
+      return EINVAL;
     }
+
+  *rwlock = new_rwlock;
   rwlock_initialization_lock.unlock ();
+
   return 0;
 }
 
@@ -2789,7 +2797,7 @@ pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
 {
   pthread_testcancel ();
 
-  if (pthread_rwlock::is_good_initializer (rwlock))
+  if (pthread_rwlock::is_initializer (rwlock))
     pthread_rwlock::init (rwlock, NULL);
   if (!pthread_rwlock::is_good_object (rwlock))
     return EINVAL;
@@ -2800,7 +2808,7 @@ pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
 extern "C" int
 pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
 {
-  if (pthread_rwlock::is_good_initializer (rwlock))
+  if (pthread_rwlock::is_initializer (rwlock))
     pthread_rwlock::init (rwlock, NULL);
   if (!pthread_rwlock::is_good_object (rwlock))
     return EINVAL;
@@ -2813,7 +2821,7 @@ pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
 {
   pthread_testcancel ();
 
-  if (pthread_rwlock::is_good_initializer (rwlock))
+  if (pthread_rwlock::is_initializer (rwlock))
     pthread_rwlock::init (rwlock, NULL);
   if (!pthread_rwlock::is_good_object (rwlock))
     return EINVAL;
@@ -2824,7 +2832,7 @@ pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
 extern "C" int
 pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
 {
-  if (pthread_rwlock::is_good_initializer (rwlock))
+  if (pthread_rwlock::is_initializer (rwlock))
     pthread_rwlock::init (rwlock, NULL);
   if (!pthread_rwlock::is_good_object (rwlock))
     return EINVAL;
@@ -2835,7 +2843,7 @@ pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
 extern "C" int
 pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
 {
-  if (pthread_rwlock::is_good_initializer (rwlock))
+  if (pthread_rwlock::is_initializer (rwlock))
     return 0;
   if (!pthread_rwlock::is_good_object (rwlock))
     return EINVAL;
@@ -2902,12 +2910,29 @@ pthread_kill (pthread_t thread, int sig)
   if (!pthread::is_good_object (&thread))
     return EINVAL;
 
-#if 0
-  if (thread->sigs)
-    myself->setthread2signal (thread);
-#endif
-
-  int rval = raise (sig);
+  siginfo_t si = {0};
+  si.si_signo = sig;
+  si.si_code = SI_USER;
+  si.si_pid = myself->pid;
+  si.si_uid = myself->uid;
+  int rval;
+  if (!thread->valid)
+    rval = ESRCH;
+  else if (sig)
+    {
+      thread->cygtls->set_threadkill ();
+      rval = sig_send (NULL, si, thread->cygtls);
+    }
+  else
+    switch (WaitForSingleObject (thread->win32_obj_id, 0))
+      {
+      case WAIT_TIMEOUT:
+       rval = 0;
+       break;
+      default:
+       rval = ESRCH;
+       break;
+      }
 
   // unlock myself
   return rval;
@@ -2916,21 +2941,7 @@ pthread_kill (pthread_t thread, int sig)
 extern "C" int
 pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set)
 {
-#if 0
-  pthread *thread = pthread::self ();
-
-  // lock this myself, for the use of thread2signal
-  // two differt kills might clash: FIXME
-
-  if (thread->sigs)
-    myself->setthread2signal (thread);
-#endif
-
-  int rval = sigprocmask (operation, set, old_set);
-
-  // unlock this myself
-
-  return rval;
+  return handle_sigprocmask (operation, set, old_set, _my_tls.sigmask);
 }
 
 /* ID */
@@ -2943,38 +2954,48 @@ pthread_equal (pthread_t t1, pthread_t t2)
 
 /* Mutexes  */
 
-/* FIXME: there's a potential race with PTHREAD_MUTEX_INITALIZER:
-   the mutex is not actually inited until the first use.
-   So two threads trying to lock/trylock may collide.
-   Solution: we need a global mutex on mutex creation, or possibly simply
-   on all constructors that allow INITIALIZER macros.
-   the lock should be very small: only around the init routine, not
-   every test, or all mutex access will be synchronised.  */
-
 int
 pthread_mutex::init (pthread_mutex_t *mutex,
-                     const pthread_mutexattr_t *attr)
+                    const pthread_mutexattr_t *attr,
+                    const pthread_mutex_t initializer)
 {
-  if (attr && !pthread_mutexattr::is_good_object (attr) || check_valid_pointer (mutex))
+  if (attr && !pthread_mutexattr::is_good_object (attr))
     return EINVAL;
 
   mutex_initialization_lock.lock ();
-
-  if (!is_good_initializer_or_bad_object (mutex))
+  if (initializer == NULL || pthread_mutex::is_initializer (mutex))
     {
-      mutex_initialization_lock.unlock ();
-      return EBUSY;
-    }
+      pthread_mutex_t new_mutex = new pthread_mutex (attr ? (*attr) : NULL);
+      if (!is_good_object (&new_mutex))
+       {
+         delete new_mutex;
+         mutex_initialization_lock.unlock ();
+         return EAGAIN;
+       }
+
+      if (!attr && initializer)
+       {
+         if (initializer == PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
+           new_mutex->type = PTHREAD_MUTEX_RECURSIVE;
+         else if (initializer == PTHREAD_NORMAL_MUTEX_INITIALIZER_NP)
+           new_mutex->type = PTHREAD_MUTEX_NORMAL;
+         else if (initializer == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP)
+           new_mutex->type = PTHREAD_MUTEX_ERRORCHECK;
+       }
+
+      myfault efault;
+      if (efault.faulted ())
+       {
+         delete new_mutex;
+         mutex_initialization_lock.unlock ();
+         return EINVAL;
+       }
 
-  *mutex = new pthread_mutex (attr ? (*attr) : NULL);
-  if (!is_good_object (mutex))
-    {
-      delete (*mutex);
-      *mutex = NULL;
-      mutex_initialization_lock.unlock ();
-      return EAGAIN;
+      *mutex = new_mutex;
     }
   mutex_initialization_lock.unlock ();
+  pthread_printf ("*mutex %p, attr %p, initializer %p", *mutex, attr, initializer);
+
   return 0;
 }
 
@@ -2982,11 +3003,6 @@ extern "C" int
 pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
                                int *prioceiling)
 {
-  pthread_mutex_t *themutex = (pthread_mutex_t *) mutex;
-  if (pthread_mutex::is_good_initializer (mutex))
-    pthread_mutex::init ((pthread_mutex_t *) mutex, NULL);
-  if (!pthread_mutex::is_good_object (themutex))
-    return EINVAL;
   /* We don't define _POSIX_THREAD_PRIO_PROTECT because we do't currently support
      mutex priorities.
 
@@ -3000,47 +3016,28 @@ pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
 extern "C" int
 pthread_mutex_lock (pthread_mutex_t *mutex)
 {
-  pthread_mutex_t *themutex = mutex;
-  /* This could be simplified via is_good_initializer_or_object
-     and is_good_initializer, but in a performance critical call like this....
-     no.  */
-  switch (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER))
-    {
-    case INVALID_OBJECT:
-      return EINVAL;
-      break;
-    case VALID_STATIC_OBJECT:
-      if (pthread_mutex::is_good_initializer (mutex))
-       {
-         int rv = pthread_mutex::init (mutex, NULL);
-         if (rv && rv != EBUSY)
-           return rv;
-       }
-      /* No else needed. If it's been initialized while we waited,
-        we can just attempt to lock it */
-      break;
-    case VALID_OBJECT:
-      break;
-    }
-  return (*themutex)->lock ();
+  if (pthread_mutex::is_initializer (mutex))
+    pthread_mutex::init (mutex, NULL, *mutex);
+  if (!pthread_mutex::is_good_object (mutex))
+    return EINVAL;
+  return (*mutex)->lock ();
 }
 
 extern "C" int
 pthread_mutex_trylock (pthread_mutex_t *mutex)
 {
-  pthread_mutex_t *themutex = mutex;
-  if (pthread_mutex::is_good_initializer (mutex))
-    pthread_mutex::init (mutex, NULL);
-  if (!pthread_mutex::is_good_object (themutex))
+  if (pthread_mutex::is_initializer (mutex))
+    pthread_mutex::init (mutex, NULL, *mutex);
+  if (!pthread_mutex::is_good_object (mutex))
     return EINVAL;
-  return (*themutex)->trylock ();
+  return (*mutex)->trylock ();
 }
 
 extern "C" int
 pthread_mutex_unlock (pthread_mutex_t *mutex)
 {
-  if (pthread_mutex::is_good_initializer (mutex))
-    pthread_mutex::init (mutex, NULL);
+  if (pthread_mutex::is_initializer (mutex))
+    return EPERM;
   if (!pthread_mutex::is_good_object (mutex))
     return EINVAL;
   return (*mutex)->unlock ();
@@ -3051,7 +3048,7 @@ pthread_mutex_destroy (pthread_mutex_t *mutex)
 {
   int rv;
 
-  if (pthread_mutex::is_good_initializer (mutex))
+  if (pthread_mutex::is_initializer (mutex))
     return 0;
   if (!pthread_mutex::is_good_object (mutex))
     return EINVAL;
@@ -3068,14 +3065,66 @@ extern "C" int
 pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
                                int *old_ceiling)
 {
-  pthread_mutex_t *themutex = mutex;
-  if (pthread_mutex::is_good_initializer (mutex))
-    pthread_mutex::init (mutex, NULL);
-  if (!pthread_mutex::is_good_object (themutex))
-    return EINVAL;
   return ENOSYS;
 }
 
+/* Spinlocks  */
+
+int
+pthread_spinlock::init (pthread_spinlock_t *spinlock, int pshared)
+{
+  pthread_spinlock_t new_spinlock = new pthread_spinlock (pshared);
+  if (!is_good_object (&new_spinlock))
+    {
+      delete new_spinlock;
+      return EAGAIN;
+    }
+
+  myfault efault;
+  if (efault.faulted ())
+    {
+      delete new_spinlock;
+      return EINVAL;
+    }
+
+  *spinlock = new_spinlock;
+  pthread_printf ("*spinlock %p, pshared %d", *spinlock, pshared);
+
+  return 0;
+}
+
+extern "C" int
+pthread_spin_lock (pthread_spinlock_t *spinlock)
+{
+  if (!pthread_spinlock::is_good_object (spinlock))
+    return EINVAL;
+  return (*spinlock)->lock ();
+}
+
+extern "C" int
+pthread_spin_trylock (pthread_spinlock_t *spinlock)
+{
+  if (!pthread_spinlock::is_good_object (spinlock))
+    return EINVAL;
+  return (*spinlock)->trylock ();
+}
+
+extern "C" int
+pthread_spin_unlock (pthread_spinlock_t *spinlock)
+{
+  if (!pthread_spinlock::is_good_object (spinlock))
+    return EINVAL;
+  return (*spinlock)->unlock ();
+}
+
+extern "C" int
+pthread_spin_destroy (pthread_spinlock_t *spinlock)
+{
+  if (!pthread_spinlock::is_good_object (spinlock))
+    return EINVAL;
+  return (*spinlock)->destroy ();
+}
+
 /* Win32 doesn't support mutex priorities - see __pthread_mutex_getprioceiling
    for more detail */
 extern "C" int
@@ -3199,24 +3248,204 @@ pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
 
 /* Semaphores */
 
-/* static members */
-bool
-semaphore::is_good_object (sem_t const * sem)
+List<semaphore> semaphore::semaphores;
+
+semaphore::semaphore (int pshared, unsigned int value)
+: verifyable_object (SEM_MAGIC),
+  shared (pshared),
+  currentvalue (value),
+  fd (-1),
+  hash (0ULL),
+  sem (NULL)
 {
-  if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT)
-    return false;
-  return true;
+  SECURITY_ATTRIBUTES sa = (pshared != PTHREAD_PROCESS_PRIVATE)
+                          ? sec_all : sec_none_nih;
+  this->win32_obj_id = ::CreateSemaphore (&sa, value, LONG_MAX, NULL);
+  if (!this->win32_obj_id)
+    magic = 0;
+
+  semaphores.insert (this);
+}
+
+semaphore::semaphore (unsigned long long shash, LUID sluid, int sfd,
+                     sem_t *ssem, int oflag, mode_t mode, unsigned int value)
+: verifyable_object (SEM_MAGIC),
+  shared (PTHREAD_PROCESS_SHARED),
+  currentvalue (value),                /* Unused for named semaphores. */
+  fd (sfd),
+  hash (shash),
+  luid (sluid),
+  sem (ssem)
+{
+  char name[MAX_PATH];
+
+  __small_sprintf (name, "semaphore/%016X%08x%08x",
+                  hash, luid.HighPart, luid.LowPart);
+  this->win32_obj_id = ::CreateSemaphore (&sec_all, value, LONG_MAX, name);
+  if (!this->win32_obj_id)
+    magic = 0;
+  if (GetLastError () == ERROR_ALREADY_EXISTS && (oflag & O_EXCL))
+    {
+      __seterrno ();
+      CloseHandle (this->win32_obj_id);
+      magic = 0;
+    }
+
+  semaphores.insert (this);
+}
+
+semaphore::~semaphore ()
+{
+  if (win32_obj_id)
+    CloseHandle (win32_obj_id);
+
+  semaphores.remove (this);
+}
+
+void
+semaphore::_post ()
+{
+  if (ReleaseSemaphore (win32_obj_id, 1, &currentvalue))
+    currentvalue++;
+}
+
+int
+semaphore::_getvalue (int *sval)
+{
+  long val;
+
+  switch (WaitForSingleObject (win32_obj_id, 0))
+    {
+      case WAIT_OBJECT_0:
+       ReleaseSemaphore (win32_obj_id, 1, &val);
+       *sval = val + 1;
+       break;
+      case WAIT_TIMEOUT:
+       *sval = 0;
+       break;
+      default:
+       set_errno (EAGAIN);
+       return -1;
+    }
+  return 0;
+}
+
+int
+semaphore::_trywait ()
+{
+  /* FIXME: signals should be able to interrupt semaphores...
+    We probably need WaitForMultipleObjects here.  */
+  if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT)
+    {
+      set_errno (EAGAIN);
+      return -1;
+    }
+  currentvalue--;
+  return 0;
+}
+
+int
+semaphore::_timedwait (const struct timespec *abstime)
+{
+  struct timeval tv;
+  long waitlength;
+
+  myfault efault;
+  if (efault.faulted ())
+    {
+      /* According to SUSv3, abstime need not be checked for validity,
+        if the semaphore can be locked immediately. */
+      if (!_trywait ())
+       return 0;
+      set_errno (EINVAL);
+      return -1;
+    }
+
+  gettimeofday (&tv, NULL);
+  waitlength = abstime->tv_sec * 1000 + abstime->tv_nsec / (1000 * 1000);
+  waitlength -= tv.tv_sec * 1000 + tv.tv_usec / 1000;
+  if (waitlength < 0)
+    waitlength = 0;
+  switch (cancelable_wait (win32_obj_id, waitlength, cw_cancel_self, cw_sig_eintr))
+    {
+    case WAIT_OBJECT_0:
+      currentvalue--;
+      break;
+    case WAIT_SIGNALED:
+      set_errno (EINTR);
+      return -1;
+    case WAIT_TIMEOUT:
+      set_errno (ETIMEDOUT);
+      return -1;
+    default:
+      pthread_printf ("cancelable_wait failed. %E");
+      __seterrno ();
+      return -1;
+    }
+  return 0;
+}
+
+int
+semaphore::_wait ()
+{
+  switch (cancelable_wait (win32_obj_id, INFINITE, cw_cancel_self, cw_sig_eintr))
+    {
+    case WAIT_OBJECT_0:
+      currentvalue--;
+      break;
+    case WAIT_SIGNALED:
+      set_errno (EINTR);
+      return -1;
+    default:
+      pthread_printf ("cancelable_wait failed. %E");
+      break;
+    }
+  return 0;
+}
+
+void
+semaphore::_fixup_after_fork ()
+{
+  if (shared == PTHREAD_PROCESS_PRIVATE)
+    {
+      pthread_printf ("sem %x", this);
+      /* FIXME: duplicate code here and in the constructor. */
+      this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue,
+                                             LONG_MAX, NULL);
+      if (!win32_obj_id)
+       api_fatal ("failed to create new win32 semaphore, error %d");
+    }
+}
+
+void
+semaphore::_terminate ()
+{
+  int _sem_close (sem_t *, bool);
+
+  if (sem)
+    _sem_close (sem, false);
 }
 
+/* static members */
+
 int
 semaphore::init (sem_t *sem, int pshared, unsigned int value)
 {
-  /* opengroup calls this undefined */
+  /*
+     We can't tell the difference between reinitialising an
+     existing semaphore and initialising a semaphore who's
+     contents happen to be a valid pointer
+   */
   if (is_good_object (sem))
-    return EBUSY;
+    {
+      paranoid_printf ("potential attempt to reinitialise a semaphore");
+    }
 
   if (value > SEM_VALUE_MAX)
-    return EINVAL;
+    {
+      set_errno(EINVAL);
+      return -1;
+    }
 
   *sem = new semaphore (pshared, value);
 
@@ -3224,7 +3453,8 @@ semaphore::init (sem_t *sem, int pshared, unsigned int value)
     {
       delete (*sem);
       *sem = NULL;
-      return EAGAIN;
+      set_errno(EAGAIN);
+      return -1;
     }
   return 0;
 }
@@ -3233,7 +3463,17 @@ int
 semaphore::destroy (sem_t *sem)
 {
   if (!is_good_object (sem))
-    return EINVAL;
+    {
+      set_errno(EINVAL);
+      return -1;
+    }
+
+  /* It's invalid to destroy a semaphore not opened with sem_init. */
+  if ((*sem)->fd != -1)
+    {
+      set_errno(EINVAL);
+      return -1;
+    }
 
   /* FIXME - new feature - test for busy against threads... */
 
@@ -3242,8 +3482,30 @@ semaphore::destroy (sem_t *sem)
   return 0;
 }
 
+int
+semaphore::close (sem_t *sem)
+{
+  if (!is_good_object (sem))
+    {
+      set_errno(EINVAL);
+      return -1;
+    }
+
+  /* It's invalid to close a semaphore not opened with sem_open. */
+  if ((*sem)->fd == -1)
+    {
+      set_errno(EINVAL);
+      return -1;
+    }
+
+  delete (*sem);
+  delete sem;
+  return 0;
+}
+
 sem_t *
-semaphore::open (const char *name, int oflag, mode_t mode, unsigned int value)
+semaphore::open (unsigned long long hash, LUID luid, int fd, int oflag,
+                mode_t mode, unsigned int value, bool &wasopen)
 {
   if (value > SEM_VALUE_MAX)
     {
@@ -3251,6 +3513,22 @@ semaphore::open (const char *name, int oflag, mode_t mode, unsigned int value)
       return NULL;
     }
 
+  /* sem_open is supposed to return the same pointer, if the same named
+     semaphore is opened multiple times in the same process, as long as
+     the semaphore hasn't been closed or unlinked in the meantime. */
+  semaphores.mx.lock ();
+  for (semaphore *sema = semaphores.head; sema; sema = sema->next)
+    if (sema->fd >= 0 && sema->hash == hash
+       && sema->luid.HighPart == luid.HighPart
+       && sema->luid.LowPart == sema->luid.LowPart)
+      {
+       wasopen = true;
+       semaphores.mx.unlock ();
+       return sema->sem;
+      }
+  semaphores.mx.unlock ();
+
+  wasopen = false;
   sem_t *sem = new sem_t;
   if (!sem)
     {
@@ -3258,7 +3536,7 @@ semaphore::open (const char *name, int oflag, mode_t mode, unsigned int value)
       return NULL;
     }
 
-  *sem = new semaphore (name, oflag, mode, value);
+  *sem = new semaphore (hash, luid, fd, sem, oflag, mode, value);
 
   if (!is_good_object (sem))
     {
@@ -3280,8 +3558,7 @@ semaphore::wait (sem_t *sem)
       return -1;
     }
 
-  (*sem)->_wait ();
-  return 0;
+  return (*sem)->_wait ();
 }
 
 int
@@ -3324,9 +3601,8 @@ semaphore::post (sem_t *sem)
 int
 semaphore::getvalue (sem_t *sem, int *sval)
 {
-  
-  if (!is_good_object (sem)
-      || __check_null_invalid_struct (sval, sizeof (int)))
+  myfault efault;
+  if (efault.faulted () || !is_good_object (sem))
     {
       set_errno (EINVAL);
       return -1;
@@ -3335,6 +3611,28 @@ semaphore::getvalue (sem_t *sem, int *sval)
   return (*sem)->_getvalue (sval);
 }
 
+int
+semaphore::getinternal (sem_t *sem, int *sfd, unsigned long long *shash,
+                       LUID *sluid, unsigned int *sval)
+{
+  myfault efault;
+  if (efault.faulted () || !is_good_object (sem))
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+  if ((*sfd = (*sem)->fd) < 0)
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+  *shash = (*sem)->hash;
+  *sluid = (*sem)->luid;
+  /* POSIX defines the value in calls to sem_init/sem_open as unsigned, but
+     the sem_getvalue gets a pointer to int to return the value.  Go figure! */
+  return (*sem)->_getvalue ((int *)sval);
+}
+
 /* pthread_null */
 pthread *
 pthread_null::get_null_pthread ()
@@ -3355,14 +3653,16 @@ pthread_null::~pthread_null ()
 {
 }
 
-void
+bool
 pthread_null::create (void *(*)(void *), pthread_attr *, void *)
 {
+  return true;
 }
 
 void
 pthread_null::exit (void *value_ptr)
 {
+  _my_tls.remove (INFINITE);
   ExitThread (0);
 }
 
This page took 0.087496 seconds and 5 git commands to generate.