about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--linuxthreads/ChangeLog29
-rw-r--r--linuxthreads/Examples/ex10.c105
-rw-r--r--linuxthreads/Makefile5
-rw-r--r--linuxthreads/Versions4
-rw-r--r--linuxthreads/condvar.c8
-rw-r--r--linuxthreads/mutex.c65
-rw-r--r--linuxthreads/rwlock.c121
-rw-r--r--linuxthreads/spinlock.c258
-rw-r--r--linuxthreads/spinlock.h32
-rw-r--r--linuxthreads/sysdeps/pthread/pthread.h32
10 files changed, 622 insertions, 37 deletions
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index ceb350f613..7cb6477c62 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,32 @@
+2000-06-25  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile (tests): Add ex10.  Add rules to build it.
+	* Versions [GLIBC_2.2] (libpthread): Add pthread_mutex_timedlock,
+	pthread_rwlock_timedrdlock, and pthread_rwlock_timedwrlock.
+	* condvar.c (pthread_cond_wait): Allow mutex of kind
+	PTHREAD_MUTEX_TIMED_NP.
+	(pthread_cond_timedwait_relative): Likewise.
+	* mutex.c (__pthread_mutex_init): Default is PTHREAD_MUTEX_TIMED_NP.
+	(__pthread_mutex_trylock): Use __pthread_alt_trylock for
+	PTHREAD_MUTEX_ERRORCHECK_NP.  Handle PTHREAD_MUTEX_TIMED_NP.
+	(__pthread_mutex_lock): Use __pthread_alt_lock for
+	PTHREAD_MUTEX_ERRORCHECK_NP.  Handle PTHREAD_MUTEX_TIMED_NP.
+	(__pthread_mutex_timedlock): New function.
+	(__pthread_mutex_unlock): Use __pthread_alt_unlock for
+	PTHREAD_MUTEX_ERRORCHECK_NP.  Handle PTHREAD_MUTEX_TIMED_NP.
+	(__pthread_mutexattr_init): Use PTHREAD_MUTEX_TIMED_NP.
+	(__pthread_mutexattr_settype): Allow PTHREAD_MUTEX_TIMED_NP.
+	* spinlock.c: Implement alternate fastlocks.
+	* spinlock.h: Add prototypes.
+	* Examples/ex10.c: New file.
+	* sysdeps/pthread/pthread.h: Add prototypes for new functions.
+	Patch by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+	* rwlock.c (__pthread_rwlock_rdlock): Optimize loop a bit.
+	(__pthread_rwlock_timedrdlock): New function.
+	(__pthread_rwlock_timedwrlock): New function.
+	Use laternate fastlock function everywhere.
+
 2000-06-21  Andreas Jaeger  <aj@suse.de>
 
 	* sysdeps/pthread/timer_routines.c: Include <string.h> for memset
diff --git a/linuxthreads/Examples/ex10.c b/linuxthreads/Examples/ex10.c
new file mode 100644
index 0000000000..d89f4f469d
--- /dev/null
+++ b/linuxthreads/Examples/ex10.c
@@ -0,0 +1,105 @@
+/* Tests for pthread_mutex_timedlock function.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+
+#define NUM_THREADS 10
+#define NUM_ITERS   50
+#define TIMEOUT_NS  100000000L
+
+static void *thread (void *);
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int
+main (void)
+{
+  pthread_t th;
+  int i;
+
+  for (i = 0; i < NUM_THREADS; i++)
+    {
+      if (pthread_create (&th, NULL, thread, NULL) != 0)
+	error (EXIT_FAILURE, 0, "cannot create thread");
+    }
+
+  (void) thread (NULL);
+  /* notreached */
+  return 0;
+}
+
+
+static void *
+thread (void *arg)
+{
+  int i;
+  pthread_t self = pthread_self ();
+  static int linecount; /* protected by flockfile(stdout) */
+
+  for (i = 0; i < NUM_ITERS; i++)
+    {
+      struct timespec ts;
+
+      for (;;)
+	{
+
+	  clock_gettime (CLOCK_REALTIME, &ts);
+
+	  ts.tv_nsec += TIMEOUT_NS;
+
+	  if (ts.tv_nsec > 1000000000L) {
+	     ts.tv_sec++;
+	     ts.tv_nsec -= 1000000000L;
+	  }
+
+	  switch (pthread_mutex_timedlock (&mutex, &ts))
+	    {
+	    case 0:
+	      flockfile (stdout);
+	      printf ("%04d: thread %lu got mutex\n", ++linecount,
+		      (unsigned long) self);
+	      funlockfile (stdout);
+	      break;
+	    case ETIMEDOUT:
+	      flockfile (stdout);
+	      printf ("%04d: thread %lu timed out on mutex\n", ++linecount,
+		      (unsigned long) self);
+	      funlockfile (stdout);
+	      continue;
+	    }
+	  break;
+	}
+
+      ts.tv_sec = 0;
+      ts.tv_nsec = TIMEOUT_NS;
+      nanosleep (&ts, NULL);
+
+      flockfile (stdout);
+      printf ("%04d: thread %lu releasing mutex\n", ++linecount,
+	      (unsigned long) self);
+      funlockfile (stdout);
+      pthread_mutex_unlock (&mutex);
+    }
+
+  pthread_exit (NULL);
+}
diff --git a/linuxthreads/Makefile b/linuxthreads/Makefile
index 1b4ecc0012..5c36bd22eb 100644
--- a/linuxthreads/Makefile
+++ b/linuxthreads/Makefile
@@ -38,7 +38,7 @@ libpthread-routines := attr cancel condvar join manager mutex ptfork \
 		       oldsemaphore events getcpuclockid pspinlock barrier
 
 vpath %.c Examples
-tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 joinrace
+tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 joinrace
 
 include ../Rules
 
@@ -56,8 +56,10 @@ $(objpfx)libpthread.so: $(common-objpfx)libc.so
 # Make sure we link with the thread library.
 ifeq ($(build-shared),yes)
 libpthread = $(objpfx)libpthread.so
+librt = $(common-objpfx)rt/librt.so
 else
 libpthread = $(objpfx)libpthread.a
+librt = $(common-objpfx)rt/librt.a
 endif
 
 $(objpfx)ex1: $(libpthread)
@@ -69,4 +71,5 @@ $(objpfx)ex6: $(libpthread)
 $(objpfx)ex7: $(libpthread)
 $(objpfx)ex8: $(libpthread)
 $(objpfx)ex9: $(libpthread)
+$(objpfx)ex10: $(libpthread) $(librt)
 $(objpfx)joinrace: $(libpthread)
diff --git a/linuxthreads/Versions b/linuxthreads/Versions
index 48f62ae0dd..85a58e112b 100644
--- a/linuxthreads/Versions
+++ b/linuxthreads/Versions
@@ -136,8 +136,10 @@ libpthread {
     pthread_spin_trylock; pthread_spin_unlock;
     pthread_getcpuclockid;
     pthread_barrier_destroy; pthread_barrier_init; pthread_barrier_wait;
-    pthread_barrierattr_destroy; pthread_barrierattr_init; 
+    pthread_barrierattr_destroy; pthread_barrierattr_init;
     pthread_barrierattr_getpshared; pthread_barrierattr_setpshared;
+    pthread_mutex_timedlock;
+    pthread_rwlock_timedrdlock; pthread_rwlock_timedwrlock;
 
     # Extensions.
     pthread_yield;
diff --git a/linuxthreads/condvar.c b/linuxthreads/condvar.c
index 536d88ed05..3bc672e909 100644
--- a/linuxthreads/condvar.c
+++ b/linuxthreads/condvar.c
@@ -62,7 +62,9 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
   int already_canceled = 0;
 
   /* Check whether the mutex is locked and owned by this thread.  */
-  if (mutex->__m_kind != PTHREAD_MUTEX_FAST_NP && mutex->__m_owner != self)
+  if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP  
+      && mutex->__m_kind != PTHREAD_MUTEX_FAST_NP
+      && mutex->__m_owner != self)
     return EINVAL;
 
   /* Set up extrication interface */
@@ -121,7 +123,9 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
   pthread_extricate_if extr;
 
   /* Check whether the mutex is locked and owned by this thread.  */
-  if (mutex->__m_kind != PTHREAD_MUTEX_FAST_NP && mutex->__m_owner != self)
+  if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP  
+      && mutex->__m_kind != PTHREAD_MUTEX_FAST_NP
+      && mutex->__m_owner != self)
     return EINVAL;
 
   /* Set up extrication interface */
diff --git a/linuxthreads/mutex.c b/linuxthreads/mutex.c
index 6494323006..8b137043b2 100644
--- a/linuxthreads/mutex.c
+++ b/linuxthreads/mutex.c
@@ -29,7 +29,7 @@ int __pthread_mutex_init(pthread_mutex_t * mutex,
 {
   __pthread_init_lock(&mutex->__m_lock);
   mutex->__m_kind =
-    mutex_attr == NULL ? PTHREAD_MUTEX_FAST_NP : mutex_attr->__mutexkind;
+    mutex_attr == NULL ? PTHREAD_MUTEX_TIMED_NP : mutex_attr->__mutexkind;
   mutex->__m_count = 0;
   mutex->__m_owner = NULL;
   return 0;
@@ -65,11 +65,14 @@ int __pthread_mutex_trylock(pthread_mutex_t * mutex)
     }
     return retcode;
   case PTHREAD_MUTEX_ERRORCHECK_NP:
-    retcode = __pthread_trylock(&mutex->__m_lock);
+    retcode = __pthread_alt_trylock(&mutex->__m_lock);
     if (retcode == 0) {
       mutex->__m_owner = thread_self();
     }
     return retcode;
+  case PTHREAD_MUTEX_TIMED_NP:
+    retcode = __pthread_alt_trylock(&mutex->__m_lock);
+    return retcode;
   default:
     return EINVAL;
   }
@@ -97,15 +100,61 @@ int __pthread_mutex_lock(pthread_mutex_t * mutex)
   case PTHREAD_MUTEX_ERRORCHECK_NP:
     self = thread_self();
     if (mutex->__m_owner == self) return EDEADLK;
-    __pthread_lock(&mutex->__m_lock, self);
+    __pthread_alt_lock(&mutex->__m_lock, self);
     mutex->__m_owner = self;
     return 0;
+  case PTHREAD_MUTEX_TIMED_NP:
+    __pthread_alt_lock(&mutex->__m_lock, NULL);
+    return 0;
   default:
     return EINVAL;
   }
 }
 strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
 
+int __pthread_mutex_timedlock (pthread_mutex_t *mutex,
+			       const struct timespec *abstime)
+{
+  pthread_descr self;
+  int res;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  switch(mutex->__m_kind) {
+  case PTHREAD_MUTEX_FAST_NP:
+    __pthread_lock(&mutex->__m_lock, NULL);
+    return 0;
+  case PTHREAD_MUTEX_RECURSIVE_NP:
+    self = thread_self();
+    if (mutex->__m_owner == self) {
+      mutex->__m_count++;
+      return 0;
+    }
+    __pthread_lock(&mutex->__m_lock, self);
+    mutex->__m_owner = self;
+    mutex->__m_count = 0;
+    return 0;
+  case PTHREAD_MUTEX_ERRORCHECK_NP:
+    self = thread_self();
+    if (mutex->__m_owner == self) return EDEADLK;
+    res = __pthread_alt_timedlock(&mutex->__m_lock, self, abstime);
+    if (res != 0)
+      {
+	mutex->__m_owner = self;
+	return 0;
+      }
+    return ETIMEDOUT;
+  case PTHREAD_MUTEX_TIMED_NP:
+    /* Only this type supports timed out lock. */
+    return (__pthread_alt_timedlock(&mutex->__m_lock, NULL, abstime)
+	    ? 0 : ETIMEDOUT);
+  default:
+    return EINVAL;
+  }
+}
+strong_alias (__pthread_mutex_timedlock, pthread_mutex_timedlock)
+
 int __pthread_mutex_unlock(pthread_mutex_t * mutex)
 {
   switch (mutex->__m_kind) {
@@ -124,7 +173,10 @@ int __pthread_mutex_unlock(pthread_mutex_t * mutex)
     if (mutex->__m_owner != thread_self() || mutex->__m_lock.__status == 0)
       return EPERM;
     mutex->__m_owner = NULL;
-    __pthread_unlock(&mutex->__m_lock);
+    __pthread_alt_unlock(&mutex->__m_lock);
+    return 0;
+  case PTHREAD_MUTEX_TIMED_NP:
+    __pthread_alt_unlock(&mutex->__m_lock);
     return 0;
   default:
     return EINVAL;
@@ -134,7 +186,7 @@ strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
 
 int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
 {
-  attr->__mutexkind = PTHREAD_MUTEX_FAST_NP;
+  attr->__mutexkind = PTHREAD_MUTEX_TIMED_NP;
   return 0;
 }
 strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init)
@@ -149,7 +201,8 @@ int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
 {
   if (kind != PTHREAD_MUTEX_FAST_NP
       && kind != PTHREAD_MUTEX_RECURSIVE_NP
-      && kind != PTHREAD_MUTEX_ERRORCHECK_NP)
+      && kind != PTHREAD_MUTEX_ERRORCHECK_NP
+      && kind != PTHREAD_MUTEX_TIMED_NP)
     return EINVAL;
   attr->__mutexkind = kind;
   return 0;
diff --git a/linuxthreads/rwlock.c b/linuxthreads/rwlock.c
index 9da87d25d1..6ee5b62247 100644
--- a/linuxthreads/rwlock.c
+++ b/linuxthreads/rwlock.c
@@ -184,7 +184,7 @@ rwlock_have_already(pthread_descr *pself, pthread_rwlock_t *rwlock,
 
 int
 __pthread_rwlock_init (pthread_rwlock_t *rwlock,
-		     const pthread_rwlockattr_t *attr)
+		       const pthread_rwlockattr_t *attr)
 {
   __pthread_init_lock(&rwlock->__rw_lock);
   rwlock->__rw_readers = 0;
@@ -214,10 +214,10 @@ __pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
   int readers;
   _pthread_descr writer;
 
-  __pthread_lock (&rwlock->__rw_lock, NULL);
+  __pthread_alt_lock (&rwlock->__rw_lock, NULL);
   readers = rwlock->__rw_readers;
   writer = rwlock->__rw_writer;
-  __pthread_unlock (&rwlock->__rw_lock);
+  __pthread_alt_unlock (&rwlock->__rw_lock);
 
   if (readers > 0 || writer != NULL)
     return EBUSY;
@@ -236,23 +236,23 @@ __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
   have_lock_already = rwlock_have_already(&self, rwlock,
 					  &existing, &out_of_mem);
 
+  if (self == NULL)
+    self = thread_self ();
+
   for (;;)
     {
-      if (self == NULL)
-	self = thread_self ();
-
-      __pthread_lock (&rwlock->__rw_lock, self);
+      __pthread_alt_lock (&rwlock->__rw_lock, self);
 
       if (rwlock_can_rdlock(rwlock, have_lock_already))
 	break;
 
       enqueue (&rwlock->__rw_read_waiting, self);
-      __pthread_unlock (&rwlock->__rw_lock);
+      __pthread_alt_unlock (&rwlock->__rw_lock);
       suspend (self); /* This is not a cancellation point */
     }
 
   ++rwlock->__rw_readers;
-  __pthread_unlock (&rwlock->__rw_lock);
+  __pthread_alt_unlock (&rwlock->__rw_lock);
 
   if (have_lock_already || out_of_mem)
     {
@@ -267,6 +267,51 @@ __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
 strong_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock)
 
 int
+__pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
+			      const struct timespec *abstime)
+{
+  pthread_descr self = NULL;
+  pthread_readlock_info *existing;
+  int out_of_mem, have_lock_already;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  have_lock_already = rwlock_have_already(&self, rwlock,
+					  &existing, &out_of_mem);
+
+  if (self == NULL)
+    self = thread_self ();
+
+  for (;;)
+    {
+      if (__pthread_alt_timedlock (&rwlock->__rw_lock, self, abstime) == 0)
+	return ETIMEDOUT;
+
+      if (rwlock_can_rdlock(rwlock, have_lock_already))
+	break;
+
+      enqueue (&rwlock->__rw_read_waiting, self);
+      __pthread_alt_unlock (&rwlock->__rw_lock);
+      suspend (self); /* This is not a cancellation point */
+    }
+
+  ++rwlock->__rw_readers;
+  __pthread_alt_unlock (&rwlock->__rw_lock);
+
+  if (have_lock_already || out_of_mem)
+    {
+      if (existing != NULL)
+	existing->pr_lock_count++;
+      else
+	self->p_untracked_readlock_count++;
+    }
+
+  return 0;
+}
+strong_alias (__pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock)
+
+int
 __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
 {
   pthread_descr self = thread_self();
@@ -277,7 +322,7 @@ __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
   have_lock_already = rwlock_have_already(&self, rwlock,
       &existing, &out_of_mem);
 
-  __pthread_lock (&rwlock->__rw_lock, self);
+  __pthread_alt_lock (&rwlock->__rw_lock, self);
 
   /* 0 is passed to here instead of have_lock_already.
      This is to meet Single Unix Spec requirements:
@@ -291,7 +336,7 @@ __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
       retval = 0;
     }
 
-  __pthread_unlock (&rwlock->__rw_lock);
+  __pthread_alt_unlock (&rwlock->__rw_lock);
 
   if (retval == 0)
     {
@@ -316,17 +361,17 @@ __pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
 
   while(1)
     {
-      __pthread_lock (&rwlock->__rw_lock, self);
+      __pthread_alt_lock (&rwlock->__rw_lock, self);
       if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
 	{
 	  rwlock->__rw_writer = self;
-	  __pthread_unlock (&rwlock->__rw_lock);
+	  __pthread_alt_unlock (&rwlock->__rw_lock);
 	  return 0;
 	}
 
       /* Suspend ourselves, then try again */
       enqueue (&rwlock->__rw_write_waiting, self);
-      __pthread_unlock (&rwlock->__rw_lock);
+      __pthread_alt_unlock (&rwlock->__rw_lock);
       suspend (self); /* This is not a cancellation point */
     }
 }
@@ -334,17 +379,49 @@ strong_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock)
 
 
 int
+__pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
+			      const struct timespec *abstime)
+{
+  pthread_descr self;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  self = thread_self ();
+
+  while(1)
+    {
+      if (__pthread_alt_timedlock (&rwlock->__rw_lock, self, abstime) == 0)
+	return ETIMEDOUT;
+
+      if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
+	{
+	  rwlock->__rw_writer = self;
+	  __pthread_alt_unlock (&rwlock->__rw_lock);
+	  return 0;
+	}
+
+      /* Suspend ourselves, then try again */
+      enqueue (&rwlock->__rw_write_waiting, self);
+      __pthread_alt_unlock (&rwlock->__rw_lock);
+      suspend (self); /* This is not a cancellation point */
+    }
+}
+strong_alias (__pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock)
+
+
+int
 __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
 {
   int result = EBUSY;
 
-  __pthread_lock (&rwlock->__rw_lock, NULL);
+  __pthread_alt_lock (&rwlock->__rw_lock, NULL);
   if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
     {
       rwlock->__rw_writer = thread_self ();
       result = 0;
     }
-  __pthread_unlock (&rwlock->__rw_lock);
+  __pthread_alt_unlock (&rwlock->__rw_lock);
 
   return result;
 }
@@ -357,13 +434,13 @@ __pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
   pthread_descr torestart;
   pthread_descr th;
 
-  __pthread_lock (&rwlock->__rw_lock, NULL);
+  __pthread_alt_lock (&rwlock->__rw_lock, NULL);
   if (rwlock->__rw_writer != NULL)
     {
       /* Unlocking a write lock.  */
       if (rwlock->__rw_writer != thread_self ())
 	{
-	  __pthread_unlock (&rwlock->__rw_lock);
+	  __pthread_alt_unlock (&rwlock->__rw_lock);
 	  return EPERM;
 	}
       rwlock->__rw_writer = NULL;
@@ -375,14 +452,14 @@ __pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
 	  /* Restart all waiting readers.  */
 	  torestart = rwlock->__rw_read_waiting;
 	  rwlock->__rw_read_waiting = NULL;
-	  __pthread_unlock (&rwlock->__rw_lock);
+	  __pthread_alt_unlock (&rwlock->__rw_lock);
 	  while ((th = dequeue (&torestart)) != NULL)
 	    restart (th);
 	}
       else
 	{
 	  /* Restart one waiting writer.  */
-	  __pthread_unlock (&rwlock->__rw_lock);
+	  __pthread_alt_unlock (&rwlock->__rw_lock);
 	  restart (th);
 	}
     }
@@ -391,7 +468,7 @@ __pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
       /* Unlocking a read lock.  */
       if (rwlock->__rw_readers == 0)
 	{
-	  __pthread_unlock (&rwlock->__rw_lock);
+	  __pthread_alt_unlock (&rwlock->__rw_lock);
 	  return EPERM;
 	}
 
@@ -402,7 +479,7 @@ __pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
       else
 	th = NULL;
 
-      __pthread_unlock (&rwlock->__rw_lock);
+      __pthread_alt_unlock (&rwlock->__rw_lock);
       if (th != NULL)
 	restart (th);
 
diff --git a/linuxthreads/spinlock.c b/linuxthreads/spinlock.c
index 60d056aada..5cd772602c 100644
--- a/linuxthreads/spinlock.c
+++ b/linuxthreads/spinlock.c
@@ -17,6 +17,8 @@
 #include <errno.h>
 #include <sched.h>
 #include <time.h>
+#include <stdlib.h>
+#include <limits.h>
 #include "pthread.h"
 #include "internals.h"
 #include "spinlock.h"
@@ -147,6 +149,262 @@ again:
   return 0;
 }
 
+/* 
+ * Alternate fastlocks do not queue threads directly. Instead, they queue
+ * these wait queue node structures. When a timed wait wakes up due to
+ * a timeout, it can leave its wait node in the queue (because there
+ * is no safe way to remove from the quue). Some other thread will
+ * deallocate the abandoned node.
+ */
+
+
+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;
+static int wait_node_free_list_spinlock;
+
+/* Allocate a new node from the head of the free list using an atomic
+   operation, or else using malloc if that list is empty.  A fundamental
+   assumption here is that we can safely access wait_node_free_list->next.
+   That's because we never free nodes once we allocate them, so a pointer to a
+   node remains valid indefinitely. */
+
+static struct wait_node *wait_node_alloc(void)
+{
+  long oldvalue, newvalue;
+
+  do {
+    oldvalue = wait_node_free_list;
+
+    if (oldvalue == 0)
+      return malloc(sizeof *wait_node_alloc());
+
+    newvalue = (long) ((struct wait_node *) oldvalue)->next;
+    WRITE_MEMORY_BARRIER();
+  } while (! compare_and_swap(&wait_node_free_list, oldvalue, newvalue,
+                              &wait_node_free_list_spinlock));
+
+  return (struct wait_node *) oldvalue;
+}
+
+/* Return a node to the head of the free list using an atomic 
+   operation. */
+
+static void wait_node_free(struct wait_node *wn)
+{
+  long oldvalue, newvalue;
+
+  do {
+    oldvalue = wait_node_free_list;
+    wn->next = (struct wait_node *) oldvalue;
+    newvalue = (long) wn;
+    WRITE_MEMORY_BARRIER();
+  } while (! compare_and_swap(&wait_node_free_list, oldvalue, newvalue,
+                              &wait_node_free_list_spinlock));
+}
+
+/* Remove a wait node from the specified queue.  It is assumed
+   that the removal takes place concurrently with only atomic insertions at the
+   head of the queue. */
+    
+static void wait_node_dequeue(struct wait_node **pp_head,
+			      struct wait_node **pp_node,
+			      struct wait_node *p_node,
+			      int *spinlock)
+{
+  long oldvalue, newvalue;
+
+  /* If the node is being deleted from the head of the
+     list, it must be deleted using atomic compare-and-swap.
+     Otherwise it can be deleted in the straightforward way. */
+
+  if (pp_node == pp_head) {
+    oldvalue = (long) p_node;
+    newvalue = (long) p_node->next;
+
+    if (compare_and_swap((long *) pp_node, oldvalue, newvalue, spinlock))
+      return;
+
+    /* Oops! Compare and swap failed, which means the node is
+       no longer first. We delete it using the ordinary method.  But we don't
+       know the identity of the node which now holds the pointer to the node
+       being deleted, so we must search from the beginning. */
+
+    for (pp_node = pp_head; *pp_node != p_node; pp_node = &(*pp_node)->next)
+      ; /* null body */
+  }
+
+  *pp_node = p_node->next;
+  return;
+}
+
+void __pthread_alt_lock(struct _pthread_fastlock * lock,
+		        pthread_descr self)
+{
+  struct wait_node wait_node;
+  long oldstatus, newstatus;
+
+  do {
+    oldstatus = lock->__status;
+    if (oldstatus == 0) {
+      newstatus = 1;
+    } else {
+      if (self == NULL)
+	wait_node.thr = self = thread_self();
+      newstatus = (long) &wait_node;
+    }
+    wait_node.abandoned = 0;
+    wait_node.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,
+                             &lock->__spinlock));
+
+  /* Suspend. Note that unlike in __pthread_lock, we don't worry
+     here about spurious wakeup. That's because this lock is not
+     used in situations where that can happen; the restart can
+     only come from the previous lock owner. */
+
+  if (oldstatus != 0)
+    suspend(self);
+}
+
+/* Timed-out lock operation; returns 0 to indicate timeout. */
+
+int __pthread_alt_timedlock(struct _pthread_fastlock * lock,
+			    pthread_descr self, const struct timespec *abstime)
+{
+  struct wait_node *p_wait_node = wait_node_alloc();
+  long oldstatus, newstatus;
+ 
+  /* Out of memory, just give up and do ordinary lock. */
+  if (p_wait_node == 0) {
+    __pthread_alt_lock(lock, self);
+    return 1;
+  }
+
+  do {
+    oldstatus = lock->__status;
+    if (oldstatus == 0) {
+      newstatus = 1;
+    } else {
+      if (self == NULL)
+	p_wait_node->thr = self = thread_self();
+      newstatus = (long) p_wait_node;
+    }
+    p_wait_node->abandoned = 0;
+    p_wait_node->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,
+                             &lock->__spinlock));
+
+  /* If we did not get the lock, do a timed suspend. If we wake up due
+     to a timeout, then there is a race; the old lock owner may try
+     to remove us from the queue. This race is resolved by us and the owner
+     doing an atomic testandset() to change the state of the wait node from 0
+     to 1. If we succeed, then it's a timeout and we abandon the node in the
+     queue. If we fail, it means the owner gave us the lock. */
+
+  if (oldstatus != 0) {
+    if (timedsuspend(self, abstime) == 0) {
+      if (!testandset(&p_wait_node->abandoned))
+	return 0; /* Timeout! */
+
+      /* Eat oustanding resume from owner, otherwise wait_node_free() below
+	 will race with owner's wait_node_dequeue(). */
+      suspend(self);
+    }
+  }
+
+  wait_node_free(p_wait_node);
+
+  return 1; /* Got the lock! */
+}
+
+void __pthread_alt_unlock(struct _pthread_fastlock *lock)
+{
+  long oldstatus;
+  struct wait_node *p_node, **pp_node, *p_max_prio, **pp_max_prio;
+  struct wait_node ** const pp_head = (struct wait_node **) &lock->__status;
+  int maxprio;
+
+  while (1) {
+
+  /* If no threads are waiting for this lock, try to just
+     atomically release it. */
+
+    oldstatus = lock->__status;
+    if (oldstatus == 0 || oldstatus == 1) {
+      if (compare_and_swap_with_release_semantics (&lock->__status,
+	  oldstatus, 0, &lock->__spinlock))
+	return;
+      else
+	continue;
+    }
+  
+    /* Process the entire queue of wait nodes. Remove all abandoned
+       wait nodes and put them into the global free queue, and
+       remember the one unabandoned node which refers to the thread
+       having the highest priority. */
+
+    pp_max_prio = pp_node = pp_head;
+    p_max_prio = p_node = *pp_head;
+    maxprio = INT_MIN;
+
+    while (p_node != (struct wait_node *) 1) {
+      int prio;
+
+      if (p_node->abandoned) {
+	/* Remove abandoned node. */
+	wait_node_dequeue(pp_head, pp_node, p_node, &lock->__spinlock);
+	wait_node_free(p_node);
+	READ_MEMORY_BARRIER();
+	p_node = *pp_node;
+	continue;
+      } else if ((prio = p_node->thr->p_priority) >= maxprio) {
+	/* Otherwise remember it if its thread has a higher or equal priority
+	   compared to that of any node seen thus far. */
+	maxprio = prio;
+	pp_max_prio = pp_node;
+	p_max_prio = p_node;
+      }
+
+      pp_node = &p_node->next;
+      READ_MEMORY_BARRIER();
+      p_node = *pp_node;
+    }
+
+    READ_MEMORY_BARRIER();
+
+    /* If all threads abandoned, go back to top */
+    if (maxprio == INT_MIN)
+      continue;
+
+    ASSERT (p_max_prio != (struct wait_node *) 1);
+
+    /* Now we want to to remove the max priority thread's wait node from
+       the list. Before we can do this, we must atomically try to change the
+       node's abandon state from zero to nonzero. If we succeed, that means we
+       have the node that we will wake up. If we failed, then it means the
+       thread timed out and abandoned the node in which case we repeat the
+       whole unlock operation. */
+
+    if (!testandset(&p_max_prio->abandoned)) {
+      wait_node_dequeue(pp_head, pp_max_prio, p_max_prio, &lock->__spinlock);
+      WRITE_MEMORY_BARRIER();
+      restart(p_max_prio->thr);
+      return;
+    }
+  }
+}
+
 
 /* Compare-and-swap emulation with a spinlock */
 
diff --git a/linuxthreads/spinlock.h b/linuxthreads/spinlock.h
index d1da3c1094..1145c72636 100644
--- a/linuxthreads/spinlock.h
+++ b/linuxthreads/spinlock.h
@@ -106,7 +106,39 @@ static inline int __pthread_trylock (struct _pthread_fastlock * lock)
   return 0;
 }
 
+/* Variation of internal lock used for pthread_mutex_t, supporting 
+   timed-out waits.  Warning: do not mix these operations with the above ones
+   over the same lock object! */
+
+extern void __pthread_alt_lock(struct _pthread_fastlock * lock,
+			       pthread_descr self);
+
+extern int __pthread_alt_timedlock(struct _pthread_fastlock * lock,
+			       pthread_descr self, const struct timespec *abstime);
+
+extern void __pthread_alt_unlock(struct _pthread_fastlock *lock);
+
+static inline void __pthread_alt_init_lock(struct _pthread_fastlock * lock)
+{
+  lock->__status = 0;
+  lock->__spinlock = 0;
+}
+
+static inline int __pthread_alt_trylock (struct _pthread_fastlock * lock)
+{
+  long oldstatus;
+
+  do {
+    oldstatus = lock->__status;
+    if (oldstatus != 0) return EBUSY;
+  } while(! compare_and_swap(&lock->__status, 0, 1, &lock->__spinlock));
+  return 0;
+}
+
+/* Initializers for both lock variants */
+
 #define LOCK_INITIALIZER {0, 0}
+#define ALT_LOCK_INITIALIZER {0, 0}
 
 /* Operations on pthread_atomic, which is defined in internals.h */
 
diff --git a/linuxthreads/sysdeps/pthread/pthread.h b/linuxthreads/sysdeps/pthread/pthread.h
index da39e7a923..0e1cbe891f 100644
--- a/linuxthreads/sysdeps/pthread/pthread.h
+++ b/linuxthreads/sysdeps/pthread/pthread.h
@@ -30,7 +30,7 @@ __BEGIN_DECLS
 /* Initializers.  */
 
 #define PTHREAD_MUTEX_INITIALIZER \
-  {0, 0, 0, PTHREAD_MUTEX_FAST_NP, {0, 0}}
+  {0, 0, 0, PTHREAD_MUTEX_TIMED_NP, {0, 0}}
 #ifdef __USE_GNU
 # define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
   {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, {0, 0}}
@@ -79,10 +79,11 @@ enum
 {
   PTHREAD_MUTEX_FAST_NP,
   PTHREAD_MUTEX_RECURSIVE_NP,
-  PTHREAD_MUTEX_ERRORCHECK_NP
+  PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_TIMED_NP
 #ifdef __USE_UNIX98
   ,
-  PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
+  PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
   PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
   PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
   PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
@@ -304,6 +305,13 @@ extern int pthread_mutex_trylock (pthread_mutex_t *__mutex) __THROW;
 /* Wait until lock for MUTEX becomes available and lock it.  */
 extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROW;
 
+#ifdef __USE_XOPEN2K
+/* Wait until lock becomes available, or specified time passes. */
+extern int pthread_mutex_timedlock (pthread_mutex_t *__mutex,
+				    __const struct timespec *__abstime)
+     __THROW;
+#endif
+
 /* Unlock MUTEX.  */
 extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW;
 
@@ -311,7 +319,7 @@ extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW;
 /* Functions for handling mutex attributes.  */
 
 /* Initialize mutex attribute object ATTR with default attributes
-   (kind is PTHREAD_MUTEX_FAST_NP).  */
+   (kind is PTHREAD_MUTEX_TIMED_NP).  */
 extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) __THROW;
 
 /* Destroy mutex attribute object ATTR.  */
@@ -385,12 +393,26 @@ extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW;
 /* Try to acquire read lock for RWLOCK.  */
 extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW;
 
+#ifdef __USE_XOPEN2K
+/* Try to acquire read lock for RWLOCK or return after specfied time.  */
+extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__rwlock,
+				       __const struct timespec *__abstime)
+     __THROW;
+#endif
+
 /* Acquire write lock for RWLOCK.  */
 extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW;
 
-/* Try to acquire writelock for RWLOCK.  */
+/* Try to acquire write lock for RWLOCK.  */
 extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW;
 
+#ifdef __USE_XOPEN2K
+/* Try to acquire write lock for RWLOCK or return after specfied time.  */
+extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__rwlock,
+				       __const struct timespec *__abstime)
+     __THROW;
+#endif
+
 /* Unlock RWLOCK.  */
 extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW;