diff -ru ../../work.nc/linuxthreads-2.2.3_19/condvar.c ./condvar.c
--- ../../work.nc/linuxthreads-2.2.3_19/condvar.c	Thu Apr 12 23:02:02 2001
+++ ./condvar.c	Tue Jan 10 18:14:20 2006
@@ -55,6 +55,11 @@
   return did_remove;
 }
 
+extern int __pthread_mutex_condwait_completelock(pthread_mutex_t *mutex);
+
+#define CVA_AVAIL 1
+#define CVA_EXTRA_RESTART 2
+
 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
   volatile pthread_descr self = thread_self();
@@ -74,6 +79,7 @@
 
   /* Register extrication interface */
   THREAD_SETMEM(self, p_condvar_avail, 0);
+  THREAD_SETMEM(self, p_condwait_mutex, mutex);
   __pthread_set_own_extricate_if(self, &extr);
 
   /* Atomically enqueue thread for waiting, but only if it is not
@@ -102,10 +108,15 @@
   while (1)
     {
       suspend(self);
-      if (THREAD_GETMEM(self, p_condvar_avail) == 0
+      if ((THREAD_GETMEM(self, p_condvar_avail) & CVA_AVAIL) == 0
 	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
 	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
 	{
+	  if ((THREAD_GETMEM(self, p_condvar_avail) &
+	       CVA_EXTRA_RESTART) == 0 &&
+	      !__compare_and_swap(&self->p_condvar_avail,
+				  0, CVA_EXTRA_RESTART))
+	    break;		/* CVA_AVAIL set by other thread */
 	  /* Count resumes that don't belong to us. */
 	  spurious_wakeup_count++;
 	  continue;
@@ -121,15 +132,35 @@
   if (THREAD_GETMEM(self, p_woken_by_cancel)
       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
     THREAD_SETMEM(self, p_woken_by_cancel, 0);
-    pthread_mutex_lock(mutex);
+    if (THREAD_GETMEM(self, p_condwait_mutex) == NULL) {
+      if ((THREAD_GETMEM(self, p_condvar_avail) & CVA_EXTRA_RESTART) != 0) {
+	if (spurious_wakeup_count > 0)
+	  spurious_wakeup_count--;
+	else
+	  suspend(self);
+      }
+      __pthread_mutex_condwait_completelock(mutex);
+    } else
+      pthread_mutex_lock(mutex);
     __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
   }
 
+  if (THREAD_GETMEM(self, p_condwait_mutex) == NULL &&
+      (THREAD_GETMEM(self, p_condvar_avail) & CVA_EXTRA_RESTART) != 0) {
+    if (spurious_wakeup_count > 0)
+      spurious_wakeup_count--;
+    else
+      suspend(self);
+  }
+
   /* Put back any resumes we caught that don't belong to us. */
   while (spurious_wakeup_count--)
     restart(self);
 
-  pthread_mutex_lock(mutex);
+  if (THREAD_GETMEM(self, p_condwait_mutex) == NULL)
+    __pthread_mutex_condwait_completelock(mutex);
+  else
+    pthread_mutex_lock(mutex);
   return 0;
 }
 
@@ -155,6 +186,7 @@
 
   /* Register extrication interface */
   THREAD_SETMEM(self, p_condvar_avail, 0);
+  THREAD_SETMEM(self, p_condwait_mutex, mutex);
   __pthread_set_own_extricate_if(self, &extr);
 
   /* Enqueue to wait on the condition and check for cancellation. */
@@ -196,10 +228,15 @@
 	suspend(self);
       }
 
-      if (THREAD_GETMEM(self, p_condvar_avail) == 0
+      if ((THREAD_GETMEM(self, p_condvar_avail) & CVA_AVAIL) == 0
 	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
 	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
 	{
+	  if ((THREAD_GETMEM(self, p_condvar_avail) &
+	       CVA_EXTRA_RESTART) == 0 &&
+	      !__compare_and_swap(&self->p_condvar_avail,
+				0, CVA_EXTRA_RESTART))
+	    break;		/* CVA_AVAIL set by other thread */
 	  /* Count resumes that don't belong to us. */
 	  spurious_wakeup_count++;
 	  continue;
@@ -215,15 +252,35 @@
   if (THREAD_GETMEM(self, p_woken_by_cancel)
       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
     THREAD_SETMEM(self, p_woken_by_cancel, 0);
-    pthread_mutex_lock(mutex);
+    if (THREAD_GETMEM(self, p_condwait_mutex) == NULL) {
+      if ((THREAD_GETMEM(self, p_condvar_avail) & CVA_EXTRA_RESTART) != 0) {
+	if (spurious_wakeup_count > 0)
+	  spurious_wakeup_count--;
+	else
+	  suspend(self);
+      }
+      __pthread_mutex_condwait_completelock(mutex);
+    } else
+      pthread_mutex_lock(mutex);
     __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
   }
 
+  if (THREAD_GETMEM(self, p_condwait_mutex) == NULL &&
+      (THREAD_GETMEM(self, p_condvar_avail) & CVA_EXTRA_RESTART) != 0) {
+    if (spurious_wakeup_count > 0)
+      spurious_wakeup_count--;
+    else
+      suspend(self);
+  }
+
   /* Put back any resumes we caught that don't belong to us. */
   while (spurious_wakeup_count--)
     restart(self);
 
-  pthread_mutex_lock(mutex);
+  if (THREAD_GETMEM(self, p_condwait_mutex) == NULL)
+    __pthread_mutex_condwait_completelock(mutex);
+  else
+    pthread_mutex_lock(mutex);
   return 0;
 }
 
@@ -237,14 +294,34 @@
 int pthread_cond_signal(pthread_cond_t *cond)
 {
   pthread_descr th;
+  long oldcva;
 
   __pthread_lock(&cond->__c_lock, NULL);
   th = dequeue(&cond->__c_waiting);
   __pthread_unlock(&cond->__c_lock);
   if (th != NULL) {
-    th->p_condvar_avail = 1;
-    WRITE_MEMORY_BARRIER();
-    restart(th);
+    pthread_mutex_t *mutex = th->p_condwait_mutex;
+    if ((th->p_condvar_avail & CVA_AVAIL) == 0 &&
+	mutex != NULL &&
+	(mutex->__m_kind == PTHREAD_MUTEX_ERRORCHECK_NP ||
+	 mutex->__m_kind == PTHREAD_MUTEX_TIMED_NP) &&
+	__pthread_alt_condwait_queuelock(&mutex->__m_lock, th) == 0) {
+      th->p_condwait_mutex = NULL;
+      WRITE_MEMORY_BARRIER();
+      do {
+	READ_MEMORY_BARRIER();
+	oldcva = th->p_condvar_avail;
+      } while (!__compare_and_swap(&th->p_condvar_avail,
+				   oldcva,
+				   oldcva | CVA_AVAIL));
+      WRITE_MEMORY_BARRIER();
+      if ((oldcva & CVA_EXTRA_RESTART) != 0)
+	restart(th);
+    } else {
+      th->p_condvar_avail = CVA_AVAIL;
+      WRITE_MEMORY_BARRIER();
+      restart(th);
+    }
   }
   return 0;
 }
@@ -252,6 +329,7 @@
 int pthread_cond_broadcast(pthread_cond_t *cond)
 {
   pthread_descr tosignal, th;
+  long oldcva;
 
   __pthread_lock(&cond->__c_lock, NULL);
   /* Copy the current state of the waiting queue and empty it */
@@ -260,9 +338,28 @@
   __pthread_unlock(&cond->__c_lock);
   /* Now signal each process in the queue */
   while ((th = dequeue(&tosignal)) != NULL) {
-    th->p_condvar_avail = 1;
-    WRITE_MEMORY_BARRIER();
-    restart(th);
+    pthread_mutex_t *mutex = th->p_condwait_mutex;
+    if ((th->p_condvar_avail & CVA_AVAIL) == 0 &&
+	mutex != NULL &&
+	(mutex->__m_kind == PTHREAD_MUTEX_ERRORCHECK_NP ||
+	 mutex->__m_kind == PTHREAD_MUTEX_TIMED_NP) &&
+	__pthread_alt_condwait_queuelock(&mutex->__m_lock, th) == 0) {
+      th->p_condwait_mutex = NULL;
+      WRITE_MEMORY_BARRIER();
+      do {
+	READ_MEMORY_BARRIER();
+	oldcva = th->p_condvar_avail;
+      } while (!__compare_and_swap(&th->p_condvar_avail,
+				   oldcva,
+				   oldcva | CVA_AVAIL));
+      WRITE_MEMORY_BARRIER();
+      if ((oldcva & CVA_EXTRA_RESTART) != 0)
+	restart(th);
+    } else {
+      th->p_condvar_avail = CVA_AVAIL;
+      WRITE_MEMORY_BARRIER();
+      restart(th);
+    }
   }
   return 0;
 }
Only in .: condvar.c~
diff -ru ../../work.nc/linuxthreads-2.2.3_19/internals.h ./internals.h
--- ../../work.nc/linuxthreads-2.2.3_19/internals.h	Tue Jan 10 17:13:14 2006
+++ ./internals.h	Tue Jan 10 17:33:30 2006
@@ -125,6 +125,13 @@
   int pr_lock_count;
 } pthread_readlock_info;
 
+
+struct wait_node {
+  struct wait_node *next;	/* Next node in null terminated linked list */
+  pthread_descr thr;		/* The thread waiting with this node */
+  int abandoned;		/* Atomic flag */
+};
+
 struct _pthread_descr_struct {
   union {
     struct {
@@ -176,7 +183,7 @@
   struct pthread_atomic p_resume_count; /* number of times restart() was
 					   called on thread */
   char p_woken_by_cancel;       /* cancellation performed wakeup */
-  char p_condvar_avail;		/* flag if conditional variable became avail */
+  long p_condvar_avail;		/* flag if conditional variable became avail */
   char p_sem_avail;             /* flag if semaphore became available */
   pthread_extricate_if *p_extricate; /* See above */
   pthread_readlock_info *p_readlock_list;  /* List of readlock info structs */
@@ -189,6 +196,8 @@
   hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread.  */
 #endif
   /* New elements must be added at the end.  */
+  pthread_mutex_t *p_condwait_mutex;
+  struct wait_node p_condwait_waitnode;
 } __attribute__ ((aligned(32))); /* We need to align the structure so that
 				    doubles are aligned properly.  This is 8
 				    bytes on MIPS and 16 bytes on MIPS64.
Only in .: internals.h~
diff -ru ../../work.nc/linuxthreads-2.2.3_19/mutex.c ./mutex.c
--- ../../work.nc/linuxthreads-2.2.3_19/mutex.c	Sun Jan  7 05:35:20 2001
+++ ./mutex.c	Tue Jan 10 17:13:46 2006
@@ -92,6 +92,24 @@
 }
 strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
 
+int __pthread_mutex_condwait_completelock(pthread_mutex_t *mutex)
+{
+  pthread_descr self;
+
+  switch(mutex->__m_kind) {
+  case PTHREAD_MUTEX_ERRORCHECK_NP:
+    self = thread_self();
+    if (mutex->__m_owner == self) return EDEADLK;
+    mutex->__m_owner = self;
+    return 0;
+  case PTHREAD_MUTEX_TIMED_NP:
+    return 0;
+  default:
+    return EINVAL;
+  }
+}
+
+
 int __pthread_mutex_lock(pthread_mutex_t * mutex)
 {
   pthread_descr self;
diff -ru ../../work.nc/linuxthreads-2.2.3_19/spinlock.c ./spinlock.c
--- ../../work.nc/linuxthreads-2.2.3_19/spinlock.c	Tue Jan 10 17:13:14 2006
+++ ./spinlock.c	Tue Jan 10 17:13:46 2006
@@ -231,12 +231,6 @@
  */
 
 
-struct wait_node {
-  struct wait_node *next;	/* Next node in null terminated linked list */
-  pthread_descr thr;		/* The thread waiting with this node */
-  int abandoned;		/* Atomic flag */
-};
-
 static long wait_node_free_list;
 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
 static int wait_node_free_list_spinlock;
@@ -359,6 +353,55 @@
 }
 
 #endif
+
+int __pthread_alt_condwait_queuelock(struct _pthread_fastlock * lock,
+				     pthread_descr th)
+{
+#if defined HAS_COMPARE_AND_SWAP
+  long oldstatus, newstatus;
+#endif
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    __pthread_acquire(&lock->__spinlock);
+
+    if (lock->__status == 0) {
+	    WRITE_MEMORY_BARRIER();
+	    lock->__spinlock = __LT_SPINLOCK_INIT;
+	    return 1;
+    }
+    th->p_condwait_waitnode.abandoned = 0;
+    th->p_condwait_waitnode.next = (struct wait_node *) lock->__status;
+    th->p_condwait_waitnode.thr = th;
+    lock->__status = (long) &th->p_condwait_waitnode;
+
+    WRITE_MEMORY_BARRIER();
+    lock->__spinlock = __LT_SPINLOCK_INIT;
+    return 0;
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
+  do {
+    oldstatus = lock->__status;
+    if (oldstatus == 0) {
+      return 1;
+    }
+    th->p_condwait_waitnode.thr = th;
+    newstatus = (long) &th->p_condwait_waitnode;
+    th->p_condwait_waitnode.abandoned = 0;
+    th->p_condwait_waitnode.next = (struct wait_node *) oldstatus;
+    /* Make sure the store in wait_node.next completes before performing
+       the compare-and-swap */
+    MEMORY_BARRIER();
+  } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus));
+  return 0;
+#endif
+}
+
 
 void __pthread_alt_lock(struct _pthread_fastlock * lock,
 		        pthread_descr self)
diff -ru ../../work.nc/linuxthreads-2.2.3_19/spinlock.h ./spinlock.h
--- ../../work.nc/linuxthreads-2.2.3_19/spinlock.h	Tue Jan 10 17:13:14 2006
+++ ./spinlock.h	Tue Jan 10 17:13:46 2006
@@ -130,6 +130,9 @@
    timed-out waits.  Warning: do not mix these operations with the above ones
    over the same lock object! */
 
+extern int __pthread_alt_condwait_queuelock(struct _pthread_fastlock * lock,
+					    pthread_descr th);
+
 extern void __pthread_alt_lock(struct _pthread_fastlock * lock,
 			       pthread_descr self);