diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index d202ca74f..164641d63 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,31 @@
+Sun Apr 22 00:22:00 2001  Robert Collins <rbtcollins@hotmail.com>
+
+	* passwd.cc (getpwuid): Check for thread cancellation.
+	(getpwuid_r): Ditto.
+	(getpwname): Ditto.
+	(getpwnam_r): Ditto.
+	* thread.h (pthread_mutex): New constructors for pshared operation.
+	(MTinterface): Associative array for pshared mutex's.
+	* thread.cc (MTinterface::Init): Initailize pshared mutex array.
+	(pthread_cond::BroadCast): Implementation notes.
+	(pthread_cond::TimedWait): Remove use of SignalObjectAndWait on non-NT systems.
+	(pthread_mutex::pthread_mutex(unsigned short)): New function.
+	(pthread_mutex::pthread_mutex (pthread_mutex_t *, pthread_mutexattr *)):New function.
+	(pthread_mutex::pthread_mutex(pthread_mutexattr *)): Fail on pshared mutex's.
+	(__pthread_mutex_getpshared): New function.
+	(__pthread_join): Check for thread cancellation.
+	(__pthread_cond_timedwait): Support pshared mutex's.
+	(__pthread_cond_wait): Ditto.
+	(__pthread_condattr_setpshared): Error on PROCESS_SHARED requests.
+	(__pthread_mutex_init): Support pshared mutex's.
+	(__pthread_mutex_getprioceiling): Ditto.
+	(__pthread_mutex_lock): Ditto.
+	(__pthread_mutex_trylock): Ditto.
+	(__pthread_mutex_unlock): Ditto.
+	(__pthread_mutex_destroy): Ditto.
+	(__pthread_mutex_setprioceiling): Ditto.
+	(__pthread_mutexattr_setpshared): Support PTHREAD_PROCESS_PSHARED requests. 
+
 Fri Apr 20 19:38:29 2001  Christopher Faylor <cgf@cygnus.com>
 
 	* cygwin.din: Add *scanf and *scan_r functions.
diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc
index 6164b0930..319ebbbcd 100644
--- a/winsup/cygwin/passwd.cc
+++ b/winsup/cygwin/passwd.cc
@@ -205,6 +205,8 @@ getpwuid (uid_t uid)
 {
   if (passwd_state  <= initializing)
     read_etc_passwd ();
+  
+  pthread_testcancel();
 
   return search_for (uid, 0);
 }
@@ -220,6 +222,8 @@ getpwuid_r (uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct
   if (passwd_state  <= initializing)
     read_etc_passwd ();
 
+  pthread_testcancel();
+
   struct passwd *temppw = search_for (uid, 0);
 
   if (!temppw)
@@ -248,6 +252,8 @@ getpwnam (const char *name)
 {
   if (passwd_state  <= initializing)
     read_etc_passwd ();
+  
+  pthread_testcancel();
 
   return search_for (0, name);
 }
@@ -268,6 +274,8 @@ getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, s
   if (passwd_state  <= initializing)
     read_etc_passwd ();
 
+  pthread_testcancel();
+
   struct passwd *temppw = search_for (0, nam);
 
   if (!temppw)
diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc
index e179a1bb2..c19c0c142 100644
--- a/winsup/cygwin/thread.cc
+++ b/winsup/cygwin/thread.cc
@@ -43,6 +43,7 @@ details. */
 #include "perprocess.h"
 #include "security.h"
 #include <semaphore.h>
+#include <stdio.h>
 
 extern int threadsafe;
 
@@ -296,11 +297,17 @@ MTinterface::Init (int forked)
   if (forked)
     return;
 
+  /* shm areas a inherited when forking */
+  shm_head = NULL;
+  /* possible the atfork lists should be inited here as well */
 
   mainthread.win32_obj_id = myself->hProcess;
   mainthread.setThreadIdtoCurrent ();
   /* store the main thread's self pointer */
   TlsSetValue (thread_self_dwTlsIndex, &mainthread);
+  
+  for (int i =0;i<256;i++)pshared_mutexs[i]=NULL;
+
 #if 0
   item->function = NULL;
 
@@ -401,6 +408,8 @@ pthread_cond::~pthread_cond ()
 void
 pthread_cond::BroadCast ()
 {
+  // This potentially has an unfairness bug. We should
+  // consider preventing the wakeups from resuming until we finish signalling.
   if (!verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC))
     return;
   PulseEvent (win32_obj_id);
@@ -420,8 +429,16 @@ pthread_cond::Signal ()
 int
 pthread_cond::TimedWait (DWORD dwMilliseconds)
 {
-  DWORD rv =
-    SignalObjectAndWait (mutex->win32_obj_id, win32_obj_id, dwMilliseconds,
+  DWORD rv;
+  if (os_being_run != winNT)
+    {
+      // FIXME: race condition (potentially drop events
+      // Possible solution (single process only) - place this in a critical section.
+      ReleaseMutex(mutex->win32_obj_id);
+      rv = WaitForSingleObject(win32_obj_id, dwMilliseconds);
+    }
+  else
+    rv = SignalObjectAndWait (mutex->win32_obj_id, win32_obj_id, dwMilliseconds,
 			 false);
   switch (rv)
     {
@@ -450,11 +467,6 @@ pthread_key::pthread_key (void (*destructor) (void *)):verifyable_object (PTHREA
 
 pthread_key::~pthread_key ()
 {
-/* FIXME: New feature completeness.
- * bracketed code is to called when the thread exists, not when delete is called
- * if (destructor && TlsGetValue(dwTlsIndex))
- *   destructor (TlsGetValue(dwTlsIndex));
- */
   if (pthread_key_destructor * dest = MT_INTERFACE->destructors.Remove (this))
     delete dest;
   TlsFree (dwTlsIndex);
@@ -475,18 +487,126 @@ pthread_key::get ()
   return TlsGetValue (dwTlsIndex);
 }
 
+#define SYS_BASE (unsigned char) 0xC0
+// Note: the order is important. This is an overloaded pthread_mutex_t from 
+// userland
+typedef struct _pshared_mutex {
+ unsigned char id;
+ unsigned char reserved;
+ unsigned char reserved2;
+ unsigned char flags;
+} pshared_mutex;
+
+/* pshared mutexs:
+ * 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.
+ */
+
+pthread_mutex::pthread_mutex (unsigned short id):verifyable_object (PTHREAD_MUTEX_MAGIC)
+{
+  //FIXME: set an appropriate security mask - probably everyone.
+  if (MT_INTERFACE->pshared_mutexs[id])
+    return;
+  char stringbuf[29];
+  snprintf(stringbuf, 29, "CYGWINMUTEX0x%0x", id & 0x000f);
+  system_printf("name of mutex to transparently open %s\n",stringbuf);
+  this->win32_obj_id =::CreateMutex (&sec_none_nih, false, stringbuf);
+  if (win32_obj_id==0 || (win32_obj_id && GetLastError() != ERROR_ALREADY_EXISTS))
+    {
+      // the mutex has been deleted or we couldn't get access. 
+	// the error_already_exists test is because we are only opening an
+	// existint mutex here
+      system_printf("couldn't get pshared mutex %x, %d\n",win32_obj_id, GetLastError());
+      CloseHandle(win32_obj_id);
+      magic=0;
+      win32_obj_id=NULL;
+      return;
+    }
+  pshared = PTHREAD_PROCESS_SHARED;
+
+  MT_INTERFACE->pshared_mutexs[id]=this;
+}
+
+pthread_mutex::pthread_mutex (pthread_mutex_t *mutex, pthread_mutexattr * attr):verifyable_object (PTHREAD_MUTEX_MAGIC)
+{
+  /* attr checked in the C call */
+  if (attr && attr->pshared==PTHREAD_PROCESS_SHARED)
+    {
+      //FIXME: set an appropriate security mask - probably everyone.
+      // This does open a D.O.S. - the name is guessable (if you are willing to run
+      // thru all possible address values :]
+      char stringbuf[29];
+      unsigned short id=1;
+      while (id < 256)
+        {
+          snprintf(stringbuf, 29, "CYGWINMUTEX0x%0x", id & 0x000f);
+          system_printf("name of mutex to create %s\n",stringbuf);
+          this->win32_obj_id =::CreateMutex (&sec_none_nih, false, stringbuf);
+          if (this->win32_obj_id && GetLastError() != ERROR_ALREADY_EXISTS)
+            {
+              MT_INTERFACE->pshared_mutexs[id]=this;
+	      pshared_mutex *pmutex=(pshared_mutex *)(mutex);
+	      pmutex->id=id;
+              pmutex->flags=SYS_BASE;
+	      pshared=PTHREAD_PROCESS_SHARED;
+	      condwaits = 0;
+	      return;
+	    }
+	  id++;
+	  CloseHandle(win32_obj_id);
+        }
+      magic=0;
+      win32_obj_id=NULL;
+    }
+  else
+    {
+      this->win32_obj_id =::CreateMutex (&sec_none_nih, false, NULL);
+
+      if (!win32_obj_id)
+        magic = 0;
+      condwaits = 0;
+      pshared = PTHREAD_PROCESS_PRIVATE;
+    }
+}
+
 pthread_mutex::pthread_mutex (pthread_mutexattr * attr):verifyable_object (PTHREAD_MUTEX_MAGIC)
 {
+  /* attr checked in the C call */
+  if (attr && attr->pshared==PTHREAD_PROCESS_SHARED)
+    {
+      /* for pshared mutex's we need the mutex address */
+      magic = 0;
+      return;
+    }
+
   this->win32_obj_id =::CreateMutex (&sec_none_nih, false, NULL);
-  if (!this->win32_obj_id)
+    
+  if (!win32_obj_id)
     magic = 0;
   condwaits = 0;
+  pshared = PTHREAD_PROCESS_PRIVATE;
 }
 
 pthread_mutex::~pthread_mutex ()
 {
   if (win32_obj_id)
     CloseHandle (win32_obj_id);
+  win32_obj_id=NULL;
 }
 
 int
@@ -507,6 +627,26 @@ pthread_mutex::UnLock ()
   return ReleaseMutex (win32_obj_id);
 }
 
+pthread_mutex **
+__pthread_mutex_getpshared(pthread_mutex_t *mutex)
+{
+  if ((((pshared_mutex *)(mutex))->flags & SYS_BASE) != SYS_BASE )
+    return (pthread_mutex **)mutex;
+  pshared_mutex *pmutex=(pshared_mutex *)(mutex);
+  if ((MT_INTERFACE->pshared_mutexs[pmutex->id]) != NULL )
+    return &(MT_INTERFACE->pshared_mutexs[pmutex->id]);
+  /* attempt to get the existing mutex */
+  pthread_mutex * newmutex;
+  newmutex = new pthread_mutex (pmutex->id);
+  if (!verifyable_object_isvalid (newmutex, PTHREAD_MUTEX_MAGIC))
+  {
+    delete (newmutex);
+    MT_INTERFACE->pshared_mutexs[pmutex->id]=NULL;
+    return &(MT_INTERFACE->pshared_mutexs[0]);
+  }    
+  return &(MT_INTERFACE->pshared_mutexs[pmutex->id]);
+}
+
 pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC),
 pshared (PTHREAD_PROCESS_PRIVATE), mutextype (PTHREAD_MUTEX_DEFAULT)
 {
@@ -730,10 +870,10 @@ __pthread_cancel (pthread_t thread)
   we return ESRCH until all the required functions call testcancel();
   this will give applications predictable behaviour.
 
-  the required function list is:
+  the required function list is: * indicates done, X indicates not present in cygwin.
 aio_suspend()
-close()
-creat()
+*close()
+*creat()
 fcntl()
 fsync()
 getmsg()
@@ -751,7 +891,7 @@ poll()
 pread()
 pthread_cond_timedwait()
 pthread_cond_wait()
-pthread_join()
+*pthread_join()
 pthread_testcancel()
 putmsg()
 putpmsg()
@@ -765,10 +905,10 @@ sigsuspend()
 sigtimedwait()
 sigwait()
 sigwaitinfo()
-sleep()
+*sleep()
 system()
 tcdrain()
-usleep()
+*usleep()
 wait()
 wait3()
 waitid()
@@ -834,10 +974,10 @@ getgrnam_r()
 getlogin()
 getlogin_r()
 getpwent()
-getpwnam()
-getpwnam_r()
-getpwuid()
-getpwuid_r()
+* getpwnam()
+* getpwnam_r()
+* getpwuid()
+* getpwuid_r() 
 gets()
 getutxent()
 getutxid()
@@ -1227,6 +1367,7 @@ __pthread_exit (void *value_ptr)
 int
 __pthread_join (pthread_t * thread, void **return_val)
 {
+  /* FIXME: wait on the thread cancellation event as well - we are a cancellation point*/
   if (!verifyable_object_isvalid (*thread, PTHREAD_MAGIC))
     return ESRCH;
 
@@ -1242,7 +1383,9 @@ __pthread_join (pthread_t * thread, void **return_val)
       WaitForSingleObject ((*thread)->win32_obj_id, INFINITE);
       if (return_val)
 	*return_val = (*thread)->return_ptr;
-    }				/* End if */
+    }	/* End if */
+
+  pthread_testcancel();
 
   return 0;
 }
@@ -1466,6 +1609,8 @@ __pthread_cond_signal (pthread_cond_t * cond)
   return 0;
 }
 
+// FIXME: pshared mutexs have the cond count in the shared memory area.
+// We need to accomodate that.
 int
 __pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex,
 			  const struct timespec *abstime)
@@ -1473,25 +1618,30 @@ __pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex,
   int rv;
   if (!abstime)
     return EINVAL;
+  pthread_mutex **themutex=NULL;
   if (*mutex == PTHREAD_MUTEX_INITIALIZER)
     __pthread_mutex_init (mutex, NULL);
-  if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
+  if (( ((pshared_mutex *)(mutex))->flags & SYS_BASE == SYS_BASE ))
+    // a pshared mutex
+    themutex = __pthread_mutex_getpshared(mutex);
+
+  if (!verifyable_object_isvalid (*themutex, PTHREAD_MUTEX_MAGIC))
     return EINVAL;
   if (!verifyable_object_isvalid (*cond, PTHREAD_COND_MAGIC))
     return EINVAL;
 
   if ((*cond)->waiting)
-    if ((*cond)->mutex && ((*cond)->mutex != (*mutex)))
+    if ((*cond)->mutex && ((*cond)->mutex != (*themutex)))
       return EINVAL;
   InterlockedIncrement (&((*cond)->waiting));
 
-  (*cond)->mutex = (*mutex);
-  InterlockedIncrement (&((*mutex)->condwaits));
+  (*cond)->mutex = (*themutex);
+  InterlockedIncrement (&((*themutex)->condwaits));
   rv = (*cond)->TimedWait (abstime->tv_sec * 1000);
   (*cond)->mutex->Lock ();
   if (InterlockedDecrement (&((*cond)->waiting)) == 0)
     (*cond)->mutex = NULL;
-  InterlockedDecrement (&((*mutex)->condwaits));
+  InterlockedDecrement (&((*themutex)->condwaits));
 
   return rv;
 }
@@ -1500,25 +1650,29 @@ int
 __pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex)
 {
   int rv;
+  pthread_mutex_t *themutex=mutex;
   if (*mutex == PTHREAD_MUTEX_INITIALIZER)
     __pthread_mutex_init (mutex, NULL);
-  if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
+  if (( ((pshared_mutex *)(mutex))->flags & SYS_BASE == SYS_BASE ))
+    // a pshared mutex
+    themutex = __pthread_mutex_getpshared(mutex);
+  if (!verifyable_object_isvalid (*themutex, PTHREAD_MUTEX_MAGIC))
     return EINVAL;
   if (!verifyable_object_isvalid (*cond, PTHREAD_COND_MAGIC))
     return EINVAL;
 
   if ((*cond)->waiting)
-    if ((*cond)->mutex && ((*cond)->mutex != (*mutex)))
+    if ((*cond)->mutex && ((*cond)->mutex != (*themutex)))
       return EINVAL;
   InterlockedIncrement (&((*cond)->waiting));
 
-  (*cond)->mutex = (*mutex);
-  InterlockedIncrement (&((*mutex)->condwaits));
+  (*cond)->mutex = (*themutex);
+  InterlockedIncrement (&((*themutex)->condwaits));
   rv = (*cond)->TimedWait (INFINITE);
   (*cond)->mutex->Lock ();
   if (InterlockedDecrement (&((*cond)->waiting)) == 0)
     (*cond)->mutex = NULL;
-  InterlockedDecrement (&((*mutex)->condwaits));
+  InterlockedDecrement (&((*themutex)->condwaits));
 
   return rv;
 }
@@ -1552,6 +1706,9 @@ __pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared)
     return EINVAL;
   if ((pshared < 0) || (pshared > 1))
     return EINVAL;
+  /* shared cond vars not currently supported */
+  if (pshared != PTHREAD_PROCESS_PRIVATE)
+    return EINVAL;
   (*attr)->shared = pshared;
   return 0;
 }
@@ -1631,12 +1788,28 @@ int
 __pthread_mutex_init (pthread_mutex_t * mutex,
 		      const pthread_mutexattr_t * attr)
 {
+  if (( ((pshared_mutex *)(mutex))->flags & SYS_BASE == SYS_BASE ))
+    // a pshared mutex
+    return EBUSY;
   if (attr && !verifyable_object_isvalid (*attr, PTHREAD_MUTEXATTR_MAGIC))
     return EINVAL;
 
   if (verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
     return EBUSY;
 
+  if (attr && (*attr)->pshared == PTHREAD_PROCESS_SHARED)
+    {
+      pthread_mutex_t throwaway = new pthread_mutex (mutex, (*attr));
+      mutex = __pthread_mutex_getpshared((pthread_mutex_t *)mutex);
+	
+      if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
+        {
+          delete throwaway;
+          *mutex = NULL;
+          return EAGAIN;
+        }
+      return 0;
+    }
   *mutex = new pthread_mutex (attr ? (*attr) : NULL);
   if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
     {
@@ -1651,9 +1824,13 @@ int
 __pthread_mutex_getprioceiling (const pthread_mutex_t * mutex,
 				int *prioceiling)
 {
+  pthread_mutex_t *themutex=(pthread_mutex_t *)mutex;
   if (*mutex == PTHREAD_MUTEX_INITIALIZER)
     __pthread_mutex_init ((pthread_mutex_t *) mutex, NULL);
-  if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
+  if (( ((pshared_mutex *)(mutex))->flags & SYS_BASE == SYS_BASE ))
+    // a pshared mutex
+    themutex = __pthread_mutex_getpshared((pthread_mutex_t *)mutex);
+  if (!verifyable_object_isvalid (*themutex, PTHREAD_MUTEX_MAGIC))
     return EINVAL;
   /* We don't define _POSIX_THREAD_PRIO_PROTECT because we do't currently support
    * mutex priorities.
@@ -1669,22 +1846,30 @@ __pthread_mutex_getprioceiling (const pthread_mutex_t * mutex,
 int
 __pthread_mutex_lock (pthread_mutex_t * mutex)
 {
+  pthread_mutex_t *themutex=mutex;
   if (*mutex == PTHREAD_MUTEX_INITIALIZER)
     __pthread_mutex_init (mutex, NULL);
-  if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
+  if (( ((pshared_mutex *)(mutex))->flags & SYS_BASE) == SYS_BASE )
+    // a pshared mutex
+    themutex = __pthread_mutex_getpshared(mutex);
+  if (!verifyable_object_isvalid (*themutex, PTHREAD_MUTEX_MAGIC))
     return EINVAL;
-  (*mutex)->Lock ();
+  (*themutex)->Lock ();
   return 0;
 }
 
 int
 __pthread_mutex_trylock (pthread_mutex_t * mutex)
 {
+  pthread_mutex_t *themutex=mutex;
   if (*mutex == PTHREAD_MUTEX_INITIALIZER)
     __pthread_mutex_init (mutex, NULL);
-  if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
+  if (( ((pshared_mutex *)(mutex))->flags & SYS_BASE) == SYS_BASE )
+    // a pshared mutex
+    themutex = __pthread_mutex_getpshared(mutex);
+  if (!verifyable_object_isvalid (*themutex, PTHREAD_MUTEX_MAGIC))
     return EINVAL;
-  if ((*mutex)->TryLock () == WAIT_TIMEOUT)
+  if ((*themutex)->TryLock () == WAIT_TIMEOUT)
     return EBUSY;
   return 0;
 }
@@ -1694,6 +1879,9 @@ __pthread_mutex_unlock (pthread_mutex_t * mutex)
 {
   if (*mutex == PTHREAD_MUTEX_INITIALIZER)
     __pthread_mutex_init (mutex, NULL);
+  if (( ((pshared_mutex *)(mutex))->flags & SYS_BASE) == SYS_BASE )
+    // a pshared mutex
+    mutex = __pthread_mutex_getpshared(mutex);
   if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
     return EINVAL;
   (*mutex)->UnLock ();
@@ -1705,6 +1893,9 @@ __pthread_mutex_destroy (pthread_mutex_t * mutex)
 {
   if (*mutex == PTHREAD_MUTEX_INITIALIZER)
     return 0;
+  if (( ((pshared_mutex *)(mutex))->flags & SYS_BASE) == SYS_BASE )
+    // a pshared mutex
+    mutex = __pthread_mutex_getpshared(mutex);
   if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
     return EINVAL;
 
@@ -1721,9 +1912,13 @@ int
 __pthread_mutex_setprioceiling (pthread_mutex_t * mutex, int prioceiling,
 				int *old_ceiling)
 {
+  pthread_mutex_t *themutex=mutex;
   if (*mutex == PTHREAD_MUTEX_INITIALIZER)
     __pthread_mutex_init (mutex, NULL);
-  if (!verifyable_object_isvalid (*mutex, PTHREAD_MUTEX_MAGIC))
+  if (( ((pshared_mutex *)(mutex))->flags & SYS_BASE == SYS_BASE ))
+    // a pshared mutex
+    themutex = __pthread_mutex_getpshared(mutex);
+  if (!verifyable_object_isvalid (*themutex, PTHREAD_MUTEX_MAGIC))
     return EINVAL;
   return ENOSYS;
 }
@@ -1830,7 +2025,7 @@ __pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, int pshared)
   /* we don't use pshared for anything as yet. We need to test PROCESS_SHARED 
    * functionality 
    */
-  if (pshared != PTHREAD_PROCESS_PRIVATE)
+  if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
     return EINVAL;
   (*attr)->pshared = pshared;
   return 0;
diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h
index 6065f9d9c..39f0f58a4 100644
--- a/winsup/cygwin/thread.h
+++ b/winsup/cygwin/thread.h
@@ -263,12 +263,15 @@ class pthread_mutex:public verifyable_object
 public:
   HANDLE win32_obj_id;
   LONG condwaits;
+  int pshared;
 
   int Lock ();
   int TryLock ();
   int UnLock ();
-
+ 
+    pthread_mutex (unsigned short);
     pthread_mutex (pthread_mutexattr *);
+    pthread_mutex (pthread_mutex_t *, pthread_mutexattr *);
    ~pthread_mutex ();
 };
 
@@ -345,6 +348,11 @@ public:
   callback *pthread_child;
   callback *pthread_parent;
 
+  /* this is an associative array for the _exclusive_ use of pshared mutex's
+   * normal mutex's don't go here to reduce overhead and prevent serialisation.
+   */
+  class pthread_mutex * pshared_mutexs[256];
+
   void Init (int);
 
     MTinterface ():reent_index (0), indexallocated (0), threadcount (1)