OSDN Git Service

Merge branch 'binutils' into tmp
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / thread.cc
index 2f9695f..901155a 100644 (file)
@@ -1,7 +1,7 @@
 /* thread.cc: Locking and threading module functions
 
    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007, 2008 Red Hat, Inc.
+   2006, 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -16,16 +16,13 @@ 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.
 
    R.Collins, April 2001.  */
 
-#ifdef HAVE_CONFIG_H
-#endif
-
 #include "winsup.h"
 #include "miscfuncs.h"
 #include "path.h"
@@ -37,17 +34,46 @@ details. */
 #include "fhandler.h"
 #include "dtable.h"
 #include "cygheap.h"
+#include "ntdll.h"
+#include "miscfuncs.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, long magic,
+  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 ()
@@ -95,13 +121,11 @@ __cygwin_lock_unlock (_LOCK_T *lock)
 }
 
 static inline verifyable_object_state
-verifyable_object_isvalid (void const *objectptr, long magic, void *static_ptr1,
+verifyable_object_isvalid (void const *objectptr, thread_magic_t magic, void *static_ptr1,
                           void *static_ptr2, void *static_ptr3)
 {
   myfault efault;
-  /* Check for NULL pointer specifically since it is a cheap test and avoids the
-     overhead of setting up the fault handler.  */
-  if (!objectptr || efault.faulted ())
+  if (efault.faulted (objectptr))
     return INVALID_OBJECT;
 
   verifyable_object **object = (verifyable_object **) objectptr;
@@ -149,6 +173,14 @@ pthread_key::is_good_object (pthread_key_t const *key)
 }
 
 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;
+}
+
+inline bool
 pthread_mutex::is_good_object (pthread_mutex_t const *mutex)
 {
   if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT)
@@ -157,7 +189,7 @@ pthread_mutex::is_good_object (pthread_mutex_t const *mutex)
 }
 
 inline bool
-pthread_mutex::is_good_initializer (pthread_mutex_t const *mutex)
+pthread_mutex::is_initializer (pthread_mutex_t const *mutex)
 {
   if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC,
                                 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
@@ -168,7 +200,7 @@ pthread_mutex::is_good_initializer (pthread_mutex_t const *mutex)
 }
 
 inline bool
-pthread_mutex::is_good_initializer_or_object (pthread_mutex_t const *mutex)
+pthread_mutex::is_initializer_or_object (pthread_mutex_t const *mutex)
 {
   if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC,
                                 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
@@ -178,18 +210,17 @@ pthread_mutex::is_good_initializer_or_object (pthread_mutex_t const *mutex)
   return true;
 }
 
+/* FIXME: Accommodate PTHREAD_MUTEX_ERRORCHECK */
 inline bool
-pthread_mutex::can_be_unlocked (pthread_mutex_t const *mutex)
+pthread_mutex::can_be_unlocked ()
 {
   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.
    * Also check for the ANONYMOUS owner to cover NORMAL mutexes as well. */
-  return ((*mutex)->recursion_counter == 1
-         && ((*mutex)->owner == MUTEX_OWNER_ANONYMOUS
-             || pthread::equal ((*mutex)->owner, self)));
+  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;
 }
 
 inline bool
@@ -218,7 +249,7 @@ pthread_cond::is_good_object (pthread_cond_t const *cond)
 }
 
 inline bool
-pthread_cond::is_good_initializer (pthread_cond_t const *cond)
+pthread_cond::is_initializer (pthread_cond_t const *cond)
 {
   if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) != VALID_STATIC_OBJECT)
     return false;
@@ -226,7 +257,7 @@ pthread_cond::is_good_initializer (pthread_cond_t const *cond)
 }
 
 inline bool
-pthread_cond::is_good_initializer_or_object (pthread_cond_t const *cond)
+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;
@@ -243,7 +274,7 @@ pthread_rwlock::is_good_object (pthread_rwlock_t const *rwlock)
 }
 
 inline bool
-pthread_rwlock::is_good_initializer (pthread_rwlock_t const *rwlock)
+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;
@@ -251,7 +282,7 @@ pthread_rwlock::is_good_initializer (pthread_rwlock_t const *rwlock)
 }
 
 inline bool
-pthread_rwlock::is_good_initializer_or_object (pthread_rwlock_t const *rwlock)
+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;
@@ -302,7 +333,7 @@ MTinterface::fixup_after_fork ()
 void
 pthread::init_mainthread ()
 {
-  pthread *thread = get_tls_self_pointer ();
+  pthread *thread = _my_tls.tid;
   if (!thread)
     {
       thread = new pthread ();
@@ -325,7 +356,7 @@ pthread::init_mainthread ()
 pthread *
 pthread::self ()
 {
-  pthread *thread = get_tls_self_pointer ();
+  pthread *thread = _my_tls.tid;
   if (!thread)
     {
       thread = pthread_null::get_null_pthread ();
@@ -334,12 +365,6 @@ pthread::self ()
   return thread;
 }
 
-pthread *
-pthread::get_tls_self_pointer ()
-{
-  return _my_tls.tid;
-}
-
 void
 pthread::set_tls_self_pointer (pthread *thread)
 {
@@ -351,13 +376,13 @@ 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;
+  sigprocmask (SIG_SETMASK, NULL, &parent_sigmask);
 }
 
 pthread::~pthread ()
@@ -374,7 +399,7 @@ pthread::~pthread ()
 bool
 pthread::create_cancel_event ()
 {
-  cancel_event = ::CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
+  cancel_event = ::CreateEvent (&sec_none_nih, true, false, NULL);
   if (!cancel_event)
     {
       system_printf ("couldn't create cancel event, %E");
@@ -398,7 +423,9 @@ pthread::precreate (pthread_attr *newattr)
       attr.joinable = newattr->joinable;
       attr.contentionscope = newattr->contentionscope;
       attr.inheritsched = newattr->inheritsched;
+      attr.stackaddr = newattr->stackaddr;
       attr.stacksize = newattr->stacksize;
+      attr.guardsize = newattr->guardsize;
     }
 
   if (!pthread_mutex::is_good_object (&verifyable_mutex_obj))
@@ -409,7 +436,7 @@ pthread::precreate (pthread_attr *newattr)
       return;
     }
   /* Change the mutex type to NORMAL to speed up mutex operations */
-  mutex.type = PTHREAD_MUTEX_NORMAL;
+  mutex.set_type (PTHREAD_MUTEX_NORMAL);
   if (!create_cancel_event ())
     magic = 0;
 }
@@ -428,8 +455,9 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr,
   arg = threadarg;
 
   mutex.lock ();
-  win32_obj_id = ::CreateThread (&sec_none_nih, attr.stacksize,
-                               thread_init_wrapper, this, 0, &thread_id);
+  win32_obj_id = CygwinCreateThread (thread_init_wrapper, this,
+                                    attr.stackaddr, attr.stacksize,
+                                    attr.guardsize, 0, &thread_id);
 
   if (!win32_obj_id)
     {
@@ -440,7 +468,7 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr,
     {
       postcreate ();
       while (!cygtls)
-       low_priority_sleep (0);
+       yield ();
     }
   retval = magic;
   mutex.unlock ();
@@ -486,12 +514,17 @@ pthread::exit (void *value_ptr)
     _my_tls.local_clib.__sdidinit = 0;
   (_reclaim_reent) (_REENT);
 
-
   if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0)
     ::exit (0);
   else
     {
-      _my_tls.remove (INFINITE);
+      if (cygtls == _main_tls)
+       {
+         _cygtls *dummy = (_cygtls *) malloc (sizeof (_cygtls));
+         *dummy = *_main_tls;
+         _main_tls = dummy;
+         _main_tls->initialized = false;
+       }
       ExitThread (0);
     }
 }
@@ -515,6 +548,7 @@ pthread::cancel ()
     {
       // cancel deferred
       mutex.unlock ();
+      canceled = true;
       SetEvent (cancel_event);
       return 0;
     }
@@ -539,189 +573,339 @@ pthread::cancel ()
   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 ()
+    * 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 ()
+      psiginfo ()
+      psignal ()
+      pthread_rwlock_rdlock ()
+    o pthread_rwlock_timedrdlock ()
+    o 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 ()
 {
   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
@@ -731,13 +915,13 @@ pthread::static_cancel_self ()
 }
 
 DWORD
-cancelable_wait (HANDLE object, DWORD timeout,
+cancelable_wait (HANDLE object, PLARGE_INTEGER timeout,
                 const cw_cancel_action cancel_action,
                 const enum cw_sig_wait sig_wait)
 {
   DWORD res;
   DWORD num = 0;
-  HANDLE wait_objects[3];
+  HANDLE wait_objects[4];
   pthread_t thread = pthread::self ();
 
   /* Do not change the wait order.
@@ -748,7 +932,7 @@ cancelable_wait (HANDLE object, DWORD timeout,
   DWORD cancel_n;
   if (cancel_action == cw_no_cancel || !pthread::is_good_object (&thread) ||
       thread->cancelstate == PTHREAD_CANCEL_DISABLE)
-    cancel_n = (DWORD) -1;
+    cancel_n = WAIT_TIMEOUT + 1;
   else
     {
       cancel_n = WAIT_OBJECT_0 + num++;
@@ -756,23 +940,38 @@ cancelable_wait (HANDLE object, DWORD timeout,
     }
 
   DWORD sig_n;
-  if (sig_wait == cw_sig_nosig || &_my_tls != _main_tls)
-    sig_n = (DWORD) -1;
+  if (sig_wait == cw_sig_nosig)
+    sig_n = WAIT_TIMEOUT + 1;
   else
     {
       sig_n = WAIT_OBJECT_0 + num++;
       wait_objects[sig_n] = signal_arrived;
     }
 
+  DWORD timeout_n;
+  if (!timeout)
+    timeout_n = WAIT_TIMEOUT + 1;
+  else
+    {
+      timeout_n = WAIT_OBJECT_0 + num++;
+      if (!_my_tls.locals.cw_timer)
+       NtCreateTimer (&_my_tls.locals.cw_timer, TIMER_ALL_ACCESS, NULL,
+                      NotificationTimer);
+      NtSetTimer (_my_tls.locals.cw_timer, timeout, NULL, NULL, FALSE, 0, NULL);
+      wait_objects[timeout_n] = _my_tls.locals.cw_timer;
+    }
+
   while (1)
     {
-      res = WaitForMultipleObjects (num, wait_objects, FALSE, timeout);
+      res = WaitForMultipleObjects (num, wait_objects, FALSE, INFINITE);
       if (res == cancel_n)
        {
          if (cancel_action == cw_cancel_self)
            pthread::static_cancel_self ();
          res = WAIT_CANCELED;
        }
+      else if (res == timeout_n)
+       res = WAIT_TIMEOUT;
       else if (res != sig_n)
        /* all set */;
       else if (sig_wait == cw_sig_eintr)
@@ -784,6 +983,21 @@ cancelable_wait (HANDLE object, DWORD timeout,
        }
       break;
     }
+
+  if (timeout)
+    {
+      const size_t sizeof_tbi = sizeof (TIMER_BASIC_INFORMATION);
+      PTIMER_BASIC_INFORMATION tbi = (PTIMER_BASIC_INFORMATION) malloc (sizeof_tbi);
+
+      NtQueryTimer (_my_tls.locals.cw_timer, TimerBasicInformation, tbi,
+                   sizeof_tbi, NULL);
+      /* if timer expired, TimeRemaining is negative and represents the
+         system uptime when signalled */
+      if (timeout->QuadPart < 0LL)
+       timeout->QuadPart = tbi->SignalState ? 0LL : tbi->TimeRemaining.QuadPart;
+      NtCancelTimer (_my_tls.locals.cw_timer, NULL);
+    }
+
   return res;
 }
 
@@ -870,7 +1084,9 @@ pthread::pop_all_cleanup_handlers ()
 void
 pthread::cancel_self ()
 {
-  exit (PTHREAD_CANCELED);
+  /* Can someone explain why the pthread:: is needed here?  g++ complains
+     without it. */
+  pthread::exit (PTHREAD_CANCELED);
 }
 
 DWORD
@@ -888,6 +1104,7 @@ pthread::_fixup_after_fork ()
       magic = 0;
       valid = false;
       win32_obj_id = NULL;
+      canceled = false;
       cancel_event = NULL;
     }
 }
@@ -910,7 +1127,8 @@ pthread::resume ()
 
 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),
+guardsize ((size_t) -1)
 {
   schedparam.sched_priority = 0;
 }
@@ -920,7 +1138,8 @@ pthread_attr::~pthread_attr ()
 }
 
 pthread_condattr::pthread_condattr ():verifyable_object
-  (PTHREAD_CONDATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE)
+  (PTHREAD_CONDATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE),
+  clock_id (CLOCK_REALTIME)
 {
 }
 
@@ -945,17 +1164,21 @@ pthread_cond::init_mutex ()
 
 pthread_cond::pthread_cond (pthread_condattr *attr) :
   verifyable_object (PTHREAD_COND_MAGIC),
-  shared (0), waiting (0), pending (0), sem_wait (NULL),
-  mtx_cond(NULL), next (NULL)
+  shared (0), clock_id (CLOCK_REALTIME), waiting (0), pending (0),
+  sem_wait (NULL), mtx_cond(NULL), next (NULL)
 {
   pthread_mutex *verifyable_mutex_obj;
 
   if (attr)
-    if (attr->shared != PTHREAD_PROCESS_PRIVATE)
-      {
-       magic = 0;
-       return;
-      }
+    {
+      clock_id = attr->clock_id;
+
+      if (attr->shared != PTHREAD_PROCESS_PRIVATE)
+       {
+         magic = 0;
+         return;
+       }
+    }
 
   verifyable_mutex_obj = &mtx_in;
   if (!pthread_mutex::is_good_object (&verifyable_mutex_obj))
@@ -968,7 +1191,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))
@@ -978,12 +1201,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;
     }
@@ -1044,7 +1267,7 @@ pthread_cond::unblock (const bool all)
 }
 
 int
-pthread_cond::wait (pthread_mutex_t mutex, DWORD dwMilliseconds)
+pthread_cond::wait (pthread_mutex_t mutex, PLARGE_INTEGER timeout)
 {
   DWORD rv;
 
@@ -1065,7 +1288,7 @@ pthread_cond::wait (pthread_mutex_t mutex, DWORD dwMilliseconds)
   ++mutex->condwaits;
   mutex->unlock ();
 
-  rv = cancelable_wait (sem_wait, dwMilliseconds, cw_no_cancel_self, cw_sig_eintr);
+  rv = cancelable_wait (sem_wait, timeout, cw_no_cancel_self, cw_sig_eintr);
 
   mtx_out.lock ();
 
@@ -1182,7 +1405,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))
@@ -1224,7 +1447,7 @@ pthread_rwlock::rdlock ()
       if (reader->n < ULONG_MAX)
        ++reader->n;
       else
-       errno = EAGAIN;
+       errno = EAGAIN;
       goto DONE;
     }
 
@@ -1367,7 +1590,7 @@ pthread_rwlock::unlock ()
          goto DONE;
        }
       if (--reader->n > 0)
-       goto DONE;
+       goto DONE;
 
       remove_reader (reader);
       delete reader;
@@ -1514,28 +1737,7 @@ 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 */
 
@@ -1544,9 +1746,6 @@ 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 ()
 {
@@ -1555,56 +1754,56 @@ 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),
+  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);
+      cancelable_wait (win32_obj_id, NULL, cw_no_cancel, cw_sig_resume);
       set_owner (self);
     }
   else
@@ -1616,12 +1815,44 @@ pthread_mutex::_lock (pthread_t self)
        result = EDEADLK;
     }
 
+  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)
@@ -1635,31 +1866,9 @@ pthread_mutex::_trylock (pthread_t self)
 }
 
 int
-pthread_mutex::_unlock (pthread_t self)
+pthread_mutex::destroy ()
 {
-  if (!pthread::equal (owner, self))
-    return EPERM;
-
-  /* Don't try to unlock anything if recursion_counter == 0 initially.
-     That means that we've forked. */
-  if (recursion_counter > 0 && --recursion_counter == 0)
-    {
-      owner = NULL;
-#ifdef DEBUGGING
-      tid = 0;
-#endif
-      if (InterlockedDecrement ((long *) &lock_counter))
-       // Another thread is waiting
-       ::ReleaseSemaphore (win32_obj_id, 1, NULL);
-    }
-
-  return 0;
-}
-
-int
-pthread_mutex::_destroy (pthread_t self)
-{
-  if (condwaits || _trylock (self))
+  if (condwaits || trylock ())
     // Do not destroy a condwaited or locked mutex
     return EBUSY;
   else if (recursion_counter > 1)
@@ -1676,7 +1885,7 @@ pthread_mutex::_destroy (pthread_t self)
 void
 pthread_mutex::_fixup_after_fork ()
 {
-  debug_printf ("mutex %p in _fixup_after_fork", this);
+  pthread_printf ("mutex %p", this);
   if (pshared != PTHREAD_PROCESS_PRIVATE)
     api_fatal ("pthread_mutex::_fixup_after_fork () doesn't understand PROCESS_SHARED mutex's");
 
@@ -1687,9 +1896,9 @@ pthread_mutex::_fixup_after_fork ()
 #ifdef DEBUGGING
   tid = 0xffffffff;    /* Don't know the tid after a fork */
 #endif
-  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)
-    api_fatal ("pthread_mutex::_fixup_after_fork () failed to recreate win32 semaphore for mutex");
+    api_fatal ("pthread_mutex::_fixup_after_fork () failed to recreate win32 event for mutex");
 }
 
 pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC),
@@ -1701,14 +1910,68 @@ pthread_mutexattr::~pthread_mutexattr ()
 {
 }
 
-verifyable_object::verifyable_object (long verifyer):
-magic (verifyer)
+/* pshared spinlocks
+
+   The infrastructure is provided by the underlying pthread_mutex class.
+   The rest is a simplification implementing spin locking. */
+
+pthread_spinlock::pthread_spinlock (int pshared) :
+  pthread_mutex (NULL)
 {
+  magic = PTHREAD_SPINLOCK_MAGIC;
+  set_type (PTHREAD_MUTEX_NORMAL);
+  set_shared (pshared);
 }
 
-verifyable_object::~verifyable_object ()
+int
+pthread_spinlock::lock ()
 {
-  magic = 0;
+  pthread_t self = ::pthread_self ();
+  int result = -1;
+
+  do
+    {
+      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. */
+         LARGE_INTEGER timeout;
+         timeout.QuadPart = -10000LL;
+         cancelable_wait (win32_obj_id, &timeout, cw_no_cancel, cw_sig_resume);
+       }
+    }
+  while (result == -1);
+  pthread_printf ("spinlock %p, self %p, owner %p", this, self, owner);
+  return result;
+}
+
+int
+pthread_spinlock::unlock ()
+{
+  pthread_t self = ::pthread_self ();
+  int result = 0;
+
+  if (!pthread::equal (owner, self))
+    result = EPERM;
+  else
+    {
+      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;
 }
 
 DWORD WINAPI
@@ -1722,7 +1985,7 @@ pthread::thread_init_wrapper (void *arg)
   // 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;
+  _my_tls.sigmask = thread->parent_sigmask;
   thread->mutex.unlock ();
 
   thread_printf ("started thread %p %p %p %p %p %p", arg, &_my_tls.local_clib,
@@ -2028,10 +2291,59 @@ pthread_attr_setscope (pthread_attr_t *attr, int contentionscope)
 }
 
 extern "C" int
+pthread_attr_setstack (pthread_attr_t *attr, void *addr, size_t size)
+{
+  if (!pthread_attr::is_good_object (attr))
+    return EINVAL;
+  if (addr == NULL)
+    return EINVAL;
+  if (size < PTHREAD_STACK_MIN)
+    return EINVAL;
+  (*attr)->stackaddr = addr;
+  (*attr)->stacksize = size;
+  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_setstackaddr (pthread_attr_t *attr, void *addr)
+{
+  if (!pthread_attr::is_good_object (attr))
+    return EINVAL;
+  if (addr == NULL)
+    return EINVAL;
+  (*attr)->stackaddr = addr;
+  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;
 }
@@ -2046,6 +2358,27 @@ pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size)
 }
 
 extern "C" int
+pthread_attr_setguardsize (pthread_attr_t *attr, size_t size)
+{
+  if (!pthread_attr::is_good_object (attr))
+    return EINVAL;
+  /* We don't support a guardsize of more than 1 Meg. */
+  if (size > 1024 * 1024)
+    return EINVAL;
+  (*attr)->guardsize = size;
+  return 0;
+}
+
+extern "C" int
+pthread_attr_getguardsize (const pthread_attr_t *attr, size_t *size)
+{
+  if (!pthread_attr::is_good_object (attr))
+    return EINVAL;
+  *size = (*attr)->guardsize;
+  return 0;
+}
+
+extern "C" int
 pthread_attr_destroy (pthread_attr_t *attr)
 {
   if (!pthread_attr::is_good_object (attr))
@@ -2088,7 +2421,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, cw_no_cancel_self, cw_sig_resume))
+      switch (cancelable_wait ((*thread)->win32_obj_id, NULL, cw_no_cancel_self, cw_sig_resume))
        {
        case WAIT_OBJECT_0:
          if (return_val)
@@ -2171,6 +2504,53 @@ 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 status;
+
+  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;
+  (*attr)->guardsize = thread->attr.guardsize;
+
+  tbi = (PTHREAD_BASIC_INFORMATION) malloc (sizeof_tbi);
+  status = NtQueryInformationThread (thread->win32_obj_id,
+                                    ThreadBasicInformation,
+                                    tbi, sizeof_tbi, NULL);
+  if (NT_SUCCESS (status))
+    {
+      PNT_TIB tib = tbi->TebBaseAddress;
+      (*attr)->stackaddr = tib->StackBase;
+      /* stack grows downwards on x86 systems */
+      (*attr)->stacksize = (uintptr_t) tib->StackBase
+                          - (uintptr_t) tib->StackLimit;
+    }
+  else
+    {
+      debug_printf ("NtQueryInformationThread(ThreadBasicInformation), "
+                   "status %p", status);
+      (*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
 */
@@ -2180,6 +2560,15 @@ pthread_getconcurrency ()
   return MT_INTERFACE->concurrency;
 }
 
+extern "C" int
+pthread_getcpuclockid (pthread_t thread, clockid_t *clk_id)
+{
+  if (!pthread::is_good_object (&thread))
+    return (ESRCH);
+  *clk_id = (clockid_t) THREADID_TO_CLOCKID (thread->getsequence_np ());
+  return 0;
+}
+
 /* keep this in sync with sched.cc */
 extern "C" int
 pthread_getschedparam (pthread_t thread, int *policy,
@@ -2249,6 +2638,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)
@@ -2272,7 +2672,7 @@ pthread_getspecific (pthread_key_t key)
 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;
@@ -2322,7 +2722,7 @@ pthread_cond::init (pthread_cond_t *cond, const pthread_condattr_t *attr)
 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;
@@ -2335,7 +2735,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;
@@ -2347,14 +2747,14 @@ pthread_cond_signal (pthread_cond_t *cond)
 
 static int
 __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex,
-                      DWORD waitlength)
+                      PLARGE_INTEGER waitlength)
 {
   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;
@@ -2366,8 +2766,8 @@ extern "C" int
 pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
                        const struct timespec *abstime)
 {
-  struct timeval tv;
-  DWORD waitlength;
+  struct timespec tp;
+  LARGE_INTEGER timeout;
 
   myfault efault;
   if (efault.faulted ())
@@ -2381,18 +2781,29 @@ pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
       || abstime->tv_nsec > 999999999)
     return EINVAL;
 
-  gettimeofday (&tv, NULL);
-  /* 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))
+  clock_gettime ((*cond)->clock_id, &tp);
+
+  /* Check for immediate timeout before converting */
+  if (tp.tv_sec > abstime->tv_sec
+      || (tp.tv_sec == abstime->tv_sec
+         && tp.tv_nsec > abstime->tv_nsec))
     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);
+  timeout.QuadPart = abstime->tv_sec * NSPERSEC
+                     + (abstime->tv_nsec + 99LL) / 100LL;
+
+  switch ((*cond)->clock_id)
+    {
+    case CLOCK_REALTIME:
+      timeout.QuadPart += FACTOR;
+      break;
+    default:
+      /* other clocks must be handled as relative timeout */
+      timeout.QuadPart -= tp.tv_sec * NSPERSEC + tp.tv_nsec / 100LL;
+      timeout.QuadPart *= -1LL;
+      break;
+    }
+  return __pthread_cond_dowait (cond, mutex, &timeout);
 }
 
 extern "C" int
@@ -2400,7 +2811,7 @@ pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
   pthread_testcancel ();
 
-  return __pthread_cond_dowait (cond, mutex, INFINITE);
+  return __pthread_cond_dowait (cond, mutex, NULL);
 }
 
 extern "C" int
@@ -2443,6 +2854,32 @@ pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
 }
 
 extern "C" int
+pthread_condattr_getclock (const pthread_condattr_t *attr, clockid_t *clock_id)
+{
+  if (!pthread_condattr::is_good_object (attr))
+    return EINVAL;
+  *clock_id = (*attr)->clock_id;
+  return 0;
+}
+
+extern "C" int
+pthread_condattr_setclock (pthread_condattr_t *attr, clockid_t clock_id)
+{
+  if (!pthread_condattr::is_good_object (attr))
+    return EINVAL;
+  switch (clock_id)
+    {
+    case CLOCK_REALTIME:
+    case CLOCK_MONOTONIC:
+      break;
+    default:
+      return EINVAL;
+    }
+  (*attr)->clock_id = clock_id;
+  return 0;
+}
+
+extern "C" int
 pthread_condattr_destroy (pthread_condattr_t *condattr)
 {
   if (!pthread_condattr::is_good_object (condattr))
@@ -2455,7 +2892,7 @@ pthread_condattr_destroy (pthread_condattr_t *condattr)
 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;
@@ -2507,7 +2944,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;
@@ -2518,7 +2955,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;
@@ -2531,7 +2968,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;
@@ -2542,7 +2979,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;
@@ -2553,7 +2990,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;
@@ -2651,7 +3088,27 @@ pthread_kill (pthread_t thread, int sig)
 extern "C" int
 pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set)
 {
-  return handle_sigprocmask (operation, set, old_set, _my_tls.sigmask);
+  int res = handle_sigprocmask (operation, set, old_set, _my_tls.sigmask);
+  syscall_printf ("%d = pthread_sigmask(%d, %p, %p)", operation, set, old_set);
+  return res;
+}
+
+extern "C" int
+pthread_sigqueue (pthread_t *thread, int sig, const union sigval value)
+{
+  siginfo_t si = {0};
+
+  if (!pthread::is_good_object (thread))
+    return EINVAL;
+  if (!(*thread)->valid)
+    return ESRCH;
+
+  si.si_signo = sig;
+  si.si_code = SI_QUEUE;
+  si.si_value = value;
+  si.si_pid = myself->pid;
+  si.si_uid = myself->uid;
+  return sig_send (NULL, si, (*thread)->cygtls);
 }
 
 /* ID */
@@ -2669,41 +3126,42 @@ pthread_mutex::init (pthread_mutex_t *mutex,
                     const pthread_mutexattr_t *attr,
                     const pthread_mutex_t initializer)
 {
-  pthread_mutex_t new_mutex;
-
   if (attr && !pthread_mutexattr::is_good_object (attr))
     return EINVAL;
 
   mutex_initialization_lock.lock ();
-
-  new_mutex = new pthread_mutex (attr ? (*attr) : NULL);
-  if (!is_good_object (&new_mutex))
+  if (initializer == NULL || pthread_mutex::is_initializer (mutex))
     {
-      delete new_mutex;
-      mutex_initialization_lock.unlock ();
-      return EAGAIN;
-    }
+      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;
-    }
+      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;
-    }
+      myfault efault;
+      if (efault.faulted ())
+       {
+         delete new_mutex;
+         mutex_initialization_lock.unlock ();
+         return EINVAL;
+       }
 
-  *mutex = new_mutex;
+      *mutex = new_mutex;
+    }
   mutex_initialization_lock.unlock ();
+  pthread_printf ("*mutex %p, attr %p, initializer %p", *mutex, attr, initializer);
 
   return 0;
 }
@@ -2725,7 +3183,7 @@ pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
 extern "C" int
 pthread_mutex_lock (pthread_mutex_t *mutex)
 {
-  if (pthread_mutex::is_good_initializer (mutex))
+  if (pthread_mutex::is_initializer (mutex))
     pthread_mutex::init (mutex, NULL, *mutex);
   if (!pthread_mutex::is_good_object (mutex))
     return EINVAL;
@@ -2735,7 +3193,7 @@ pthread_mutex_lock (pthread_mutex_t *mutex)
 extern "C" int
 pthread_mutex_trylock (pthread_mutex_t *mutex)
 {
-  if (pthread_mutex::is_good_initializer (mutex))
+  if (pthread_mutex::is_initializer (mutex))
     pthread_mutex::init (mutex, NULL, *mutex);
   if (!pthread_mutex::is_good_object (mutex))
     return EINVAL;
@@ -2745,7 +3203,7 @@ pthread_mutex_trylock (pthread_mutex_t *mutex)
 extern "C" int
 pthread_mutex_unlock (pthread_mutex_t *mutex)
 {
-  if (pthread_mutex::is_good_initializer (mutex))
+  if (pthread_mutex::is_initializer (mutex))
     return EPERM;
   if (!pthread_mutex::is_good_object (mutex))
     return EINVAL;
@@ -2757,7 +3215,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;
@@ -2777,6 +3235,63 @@ pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
   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
@@ -2999,8 +3514,7 @@ semaphore::_trywait ()
 int
 semaphore::_timedwait (const struct timespec *abstime)
 {
-  struct timeval tv;
-  long waitlength;
+  LARGE_INTEGER timeout;
 
   myfault efault;
   if (efault.faulted ())
@@ -3013,12 +3527,10 @@ semaphore::_timedwait (const struct timespec *abstime)
       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))
+  timeout.QuadPart = abstime->tv_sec * NSPERSEC
+                    + (abstime->tv_nsec + 99) / 100 + FACTOR;
+
+  switch (cancelable_wait (win32_obj_id, &timeout, cw_cancel_self, cw_sig_eintr))
     {
     case WAIT_OBJECT_0:
       currentvalue--;
@@ -3030,7 +3542,7 @@ semaphore::_timedwait (const struct timespec *abstime)
       set_errno (ETIMEDOUT);
       return -1;
     default:
-      debug_printf ("cancelable_wait failed. %E");
+      pthread_printf ("cancelable_wait failed. %E");
       __seterrno ();
       return -1;
     }
@@ -3040,7 +3552,7 @@ semaphore::_timedwait (const struct timespec *abstime)
 int
 semaphore::_wait ()
 {
-  switch (cancelable_wait (win32_obj_id, INFINITE, cw_cancel_self, cw_sig_eintr))
+  switch (cancelable_wait (win32_obj_id, NULL, cw_cancel_self, cw_sig_eintr))
     {
     case WAIT_OBJECT_0:
       currentvalue--;
@@ -3049,7 +3561,7 @@ semaphore::_wait ()
       set_errno (EINTR);
       return -1;
     default:
-      debug_printf ("cancelable_wait failed. %E");
+      pthread_printf ("cancelable_wait failed. %E");
       break;
     }
   return 0;
@@ -3060,7 +3572,7 @@ semaphore::_fixup_after_fork ()
 {
   if (shared == PTHREAD_PROCESS_PRIVATE)
     {
-      debug_printf ("sem %x in _fixup_after_fork", this);
+      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);
@@ -3083,12 +3595,21 @@ semaphore::_terminate ()
 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);
 
@@ -3096,7 +3617,8 @@ semaphore::init (sem_t *sem, int pshared, unsigned int value)
     {
       delete (*sem);
       *sem = NULL;
-      return EAGAIN;
+      set_errno(EAGAIN);
+      return -1;
     }
   return 0;
 }
@@ -3105,11 +3627,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)
-    return EINVAL;
+    {
+      set_errno(EINVAL);
+      return -1;
+    }
 
   /* FIXME - new feature - test for busy against threads... */
 
@@ -3122,11 +3650,17 @@ int
 semaphore::close (sem_t *sem)
 {
   if (!is_good_object (sem))
-    return EINVAL;
+    {
+      set_errno(EINVAL);
+      return -1;
+    }
 
   /* It's invalid to close a semaphore not opened with sem_open. */
   if ((*sem)->fd == -1)
-    return EINVAL;
+    {
+      set_errno(EINVAL);
+      return -1;
+    }
 
   delete (*sem);
   delete sem;
@@ -3149,7 +3683,7 @@ semaphore::open (unsigned long long hash, LUID luid, int fd, int oflag,
   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.HighPart == luid.HighPart
        && sema->luid.LowPart == sema->luid.LowPart)
       {
        wasopen = true;