summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makeconfig5
-rw-r--r--libc.map3
-rw-r--r--linuxthreads/ChangeLog29
-rw-r--r--linuxthreads/attr.c8
-rw-r--r--linuxthreads/cancel.c6
-rw-r--r--linuxthreads/condvar.c79
-rw-r--r--linuxthreads/internals.h28
-rw-r--r--linuxthreads/join.c28
-rw-r--r--linuxthreads/manager.c79
-rw-r--r--linuxthreads/mutex.c122
-rw-r--r--linuxthreads/pthread.c89
-rw-r--r--linuxthreads/ptlongjmp.c2
-rw-r--r--linuxthreads/queue.h57
-rw-r--r--linuxthreads/rwlock.c47
-rw-r--r--linuxthreads/semaphore.c236
-rw-r--r--linuxthreads/semaphore.h7
-rw-r--r--linuxthreads/signals.c89
-rw-r--r--linuxthreads/spinlock.c123
-rw-r--r--linuxthreads/spinlock.h53
-rw-r--r--linuxthreads/sysdeps/i386/pt-machine.h6
-rw-r--r--linuxthreads/sysdeps/pthread/pthread.h38
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h8
-rw-r--r--sysdeps/unix/sysv/linux/bits/sched.h7
23 files changed, 635 insertions, 514 deletions
diff --git a/Makeconfig b/Makeconfig
index d70c4795ef..1ef0cc571d 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -564,8 +564,9 @@ endif	# $(+cflags) == ""
 libio-include = -I$(..)libio
 
 # These are the variables that the implicit compilation rules use.
-CPPFLAGS = $(+includes) $(defines) -include $(..)include/libc-symbols.h \
-	   $(sysdep-CPPFLAGS) $(CPPFLAGS-$(suffix $@)) $(CPPFLAGS-$(<F)) \
+CPPFLAGS = $($(subdir)-CPPFLAGS) $(+includes) $(defines) \
+	   -include $(..)include/libc-symbols.h $(sysdep-CPPFLAGS) \
+	   $($(subdir)-CPPFLAGS) $(CPPFLAGS-$(suffix $@)) $(CPPFLAGS-$(<F)) \
 	   $(CPPFLAGS-$(@F))
 override CFLAGS	= $(filter-out %frame-pointer,$(+cflags)) $(sysdep-CFLAGS) \
 		  $(CFLAGS-$(suffix $@)) $(CFLAGS-$(<F)) $(CFLAGS-$(@F))
diff --git a/libc.map b/libc.map
index 309310929d..3024bbd4af 100644
--- a/libc.map
+++ b/libc.map
@@ -87,7 +87,8 @@ GLIBC_2.0 {
     __ffs;
     __close; __connect; __fcntl; __lseek; __open; __read; __send; __wait;
     __ieee_get_fp_control; __ieee_set_fp_control;
-    __dgettext;
+    __dgettext; __sigaction;
+
     # libio
     _IO_adjust_column; _IO_clearerr; _IO_default_doallocate;
     _IO_default_finish; _IO_default_pbackfail; _IO_default_uflow;
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 69426bfb7c..882aa41d45 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,32 @@
+1998-06-25 19:27  Ulrich Drepper  <drepper@cygnus.com>
+
+	* attr.c: Finish user stack support.  Change locking code to be safe
+	in situations with different priorities.
+	* cancel.c: Likewise.
+	* condvar.c: Likewise.
+	* internals.h: Likewise.
+	* join.c: Likewise.
+	* manager.c: Likewise.
+	* mutex.c: Likewise.
+	* pthread.c: Likewise.
+	* ptlongjmp.c: Likewise.
+	* queue.h: Likewise.
+	* rwlock.c: Likewise.
+	* semaphore.c: Likewise.
+	* semaphore.h: Likewise.
+	* signals.c: Likewise.
+	* spinlock.c: Likewise.
+	* spinlock.h: Likewise.
+	Patches by Xavier leroy.
+
+1998-06-25  Ulrich Drepper  <drepper@cygnus.com>
+
+	* sysdeps/pthread/pthread.h: Make [sg]et_stacksize and
+	[sg]et_stackaddr prototypes always available.
+
+	* sysdeps/unix/sysv/linux/bits/posix_opt.h: Define
+	_POSIX_THREAD_ATTR_STACKSIZE and _POSIX_THREAD_ATTR_STACKADDR.
+
 1998-06-24  Ulrich Drepper  <drepper@cygnus.com>
 
 	* manager.c (pthread_free): Undo patch from 980430.
diff --git a/linuxthreads/attr.c b/linuxthreads/attr.c
index 027f69c997..d1f605810f 100644
--- a/linuxthreads/attr.c
+++ b/linuxthreads/attr.c
@@ -19,7 +19,6 @@
 #include "pthread.h"
 #include "internals.h"
 
-
 int __pthread_attr_init_2_1(pthread_attr_t *attr)
 {
   size_t ps = __getpagesize ();
@@ -185,11 +184,8 @@ weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
 
 int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
 {
-  size_t ps = __getpagesize ();
-
-  /* We don't accept value smaller than PTHREAD_STACK_MIN or bigger than
-     2MB - pagesize.  */
-  if (stacksize < PTHREAD_STACK_MIN || stacksize > STACK_SIZE - ps)
+  /* We don't accept value smaller than PTHREAD_STACK_MIN.  */
+  if (stacksize < PTHREAD_STACK_MIN)
     return EINVAL;
 
   attr->stacksize = stacksize;
diff --git a/linuxthreads/cancel.c b/linuxthreads/cancel.c
index a6a0ecaa5a..cd2bbace12 100644
--- a/linuxthreads/cancel.c
+++ b/linuxthreads/cancel.c
@@ -53,14 +53,14 @@ int pthread_cancel(pthread_t thread)
   pthread_handle handle = thread_handle(thread);
   int pid;
 
-  acquire(&handle->h_spinlock);
+  __pthread_lock(&handle->h_lock);
   if (invalid_handle(handle, thread)) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return ESRCH;
   }
   handle->h_descr->p_canceled = 1;
   pid = handle->h_descr->p_pid;
-  release(&handle->h_spinlock);
+  __pthread_unlock(&handle->h_lock);
   kill(pid, PTHREAD_SIG_CANCEL);
   return 0;
 }
diff --git a/linuxthreads/condvar.c b/linuxthreads/condvar.c
index 6807522edc..91067d2d17 100644
--- a/linuxthreads/condvar.c
+++ b/linuxthreads/condvar.c
@@ -25,42 +25,36 @@
 #include "queue.h"
 #include "restart.h"
 
-static void remove_from_queue(pthread_queue * q, pthread_descr th);
-
 int pthread_cond_init(pthread_cond_t *cond,
                       const pthread_condattr_t *cond_attr)
 {
-  cond->c_spinlock = 0;
-  queue_init(&cond->c_waiting);
+  __pthread_init_lock(&cond->c_lock);
+  cond->c_waiting = NULL;
   return 0;
 }
 
 int pthread_cond_destroy(pthread_cond_t *cond)
 {
-  pthread_descr head;
-
-  acquire(&cond->c_spinlock);
-  head = cond->c_waiting.head;
-  release(&cond->c_spinlock);
-  if (head != NULL) return EBUSY;
+  if (cond->c_waiting != NULL) return EBUSY;
   return 0;
 }
 
 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
   volatile pthread_descr self = thread_self();
-  acquire(&cond->c_spinlock);
+
+  __pthread_lock(&cond->c_lock);
   enqueue(&cond->c_waiting, self);
-  release(&cond->c_spinlock);
+  __pthread_unlock(&cond->c_lock);
   pthread_mutex_unlock(mutex);
   suspend_with_cancellation(self);
   pthread_mutex_lock(mutex);
   /* This is a cancellation point */
   if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
     /* Remove ourselves from the waiting queue if we're still on it */
-    acquire(&cond->c_spinlock);
+    __pthread_lock(&cond->c_lock);
     remove_from_queue(&cond->c_waiting, self);
-    release(&cond->c_spinlock);
+    __pthread_unlock(&cond->c_lock);
     pthread_exit(PTHREAD_CANCELED);
   }
   return 0;
@@ -77,15 +71,14 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
   sigjmp_buf jmpbuf;
 
   /* Wait on the condition */
-  acquire(&cond->c_spinlock);
+  __pthread_lock(&cond->c_lock);
   enqueue(&cond->c_waiting, self);
-  release(&cond->c_spinlock);
+  __pthread_unlock(&cond->c_lock);
   pthread_mutex_unlock(mutex);
-  /* Set up a longjmp handler for the restart signal */
-  /* No need to save the signal mask, since PTHREAD_SIG_RESTART will be
-     blocked when doing the siglongjmp, and we'll just leave it blocked. */
-  if (sigsetjmp(jmpbuf, 0) == 0) {
+  /* Set up a longjmp handler for the restart and cancel signals */
+  if (sigsetjmp(jmpbuf, 1) == 0) {
     self->p_signal_jmp = &jmpbuf;
+    self->p_cancel_jmp = &jmpbuf;
     self->p_signal = 0;
     /* Check for cancellation */
     if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
@@ -104,28 +97,28 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
     retsleep = -1;
   }
   self->p_signal_jmp = NULL;
+  self->p_cancel_jmp = NULL;
   /* Here, either the condition was signaled (self->p_signal != 0)
                    or we got canceled (self->p_canceled != 0)
                    or the timeout occurred (retsleep == 0)
                    or another interrupt occurred (retsleep == -1) */
-  /* Re-acquire the spinlock */
-  acquire(&cond->c_spinlock);
   /* This is a cancellation point */
   if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
+    __pthread_lock(&cond->c_lock);
     remove_from_queue(&cond->c_waiting, self);
-    release(&cond->c_spinlock);
+    __pthread_unlock(&cond->c_lock);
     pthread_mutex_lock(mutex);
     pthread_exit(PTHREAD_CANCELED);
   }
   /* If not signaled: also remove ourselves and return an error code */
   if (self->p_signal == 0) {
+    __pthread_lock(&cond->c_lock);
     remove_from_queue(&cond->c_waiting, self);
-    release(&cond->c_spinlock);
+    __pthread_unlock(&cond->c_lock);
     pthread_mutex_lock(mutex);
     return retsleep == 0 ? ETIMEDOUT : EINTR;
   }
   /* Otherwise, return normally */
-  release(&cond->c_spinlock);
   pthread_mutex_lock(mutex);
   return 0;
 }
@@ -151,23 +144,22 @@ int pthread_cond_signal(pthread_cond_t *cond)
 {
   pthread_descr th;
 
-  acquire(&cond->c_spinlock);
+  __pthread_lock(&cond->c_lock);
   th = dequeue(&cond->c_waiting);
-  release(&cond->c_spinlock);
+  __pthread_unlock(&cond->c_lock);
   if (th != NULL) restart(th);
   return 0;
 }
 
 int pthread_cond_broadcast(pthread_cond_t *cond)
 {
-  pthread_queue tosignal;
-  pthread_descr th;
+  pthread_descr tosignal, th;
 
-  acquire(&cond->c_spinlock);
+  __pthread_lock(&cond->c_lock);
   /* Copy the current state of the waiting queue and empty it */
   tosignal = cond->c_waiting;
-  queue_init(&cond->c_waiting);
-  release(&cond->c_spinlock);
+  cond->c_waiting = NULL;
+  __pthread_unlock(&cond->c_lock);
   /* Now signal each process in the queue */
   while ((th = dequeue(&tosignal)) != NULL) restart(th);
   return 0;
@@ -182,26 +174,3 @@ int pthread_condattr_destroy(pthread_condattr_t *attr)
 {
   return 0;
 }
-
-/* Auxiliary function on queues */
-
-static void remove_from_queue(pthread_queue * q, pthread_descr th)
-{
-  pthread_descr t;
-
-  if (q->head == NULL) return;
-  if (q->head == th) {
-    q->head = th->p_nextwaiting;
-    if (q->head == NULL) q->tail = NULL;
-    th->p_nextwaiting = NULL;
-    return;
-  }
-  for (t = q->head; t->p_nextwaiting != NULL; t = t->p_nextwaiting) {
-    if (t->p_nextwaiting == th) {
-      t->p_nextwaiting = th->p_nextwaiting;
-      if (th->p_nextwaiting == NULL) q->tail = t;
-      th->p_nextwaiting = NULL;
-      return;
-    }
-  }
-}
diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h
index ab6b66a857..0a01b61ede 100644
--- a/linuxthreads/internals.h
+++ b/linuxthreads/internals.h
@@ -63,7 +63,7 @@ struct _pthread_descr_struct {
   pthread_t p_tid;              /* Thread identifier */
   int p_pid;                    /* PID of Unix process */
   int p_priority;               /* Thread priority (== 0 if not realtime) */
-  int * p_spinlock;             /* Spinlock for synchronized accesses */
+  struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
   int p_signal;                 /* last signal received */
   sigjmp_buf * p_signal_jmp;    /* where to siglongjmp on a signal or NULL */
   sigjmp_buf * p_cancel_jmp;    /* where to siglongjmp on a cancel or NULL */
@@ -81,6 +81,8 @@ struct _pthread_descr_struct {
   int p_errno;                  /* error returned by last system call */
   int * p_h_errnop;             /* pointer to used h_errno variable */
   int p_h_errno;                /* error returned by last netdb function */
+  char * p_in_sighandler;       /* stack address of sighandler, or NULL */
+  char p_sigwaiting;            /* true if a sigwait() is in progress */
   struct pthread_start_args p_start_args; /* arguments for thread creation */
   void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
   void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
@@ -94,8 +96,9 @@ struct _pthread_descr_struct {
 typedef struct pthread_handle_struct * pthread_handle;
 
 struct pthread_handle_struct {
-  int h_spinlock;               /* Spinlock for sychronized access */
+  struct _pthread_fastlock h_lock; /* Fast lock for sychronized access */
   pthread_descr h_descr;        /* Thread descriptor or NULL if invalid */
+  char * h_bottom;              /* Lowest address in the stack thread */
 };
 
 /* The type of messages sent to the thread manager thread */
@@ -103,7 +106,8 @@ struct pthread_handle_struct {
 struct pthread_request {
   pthread_descr req_thread;     /* Thread doing the request */
   enum {                        /* Request kind */
-    REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT
+    REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT,
+    REQ_POST, REQ_DEBUG
   } req_kind;
   union {                       /* Arguments for request */
     struct {                    /* For REQ_CREATE: */
@@ -118,6 +122,7 @@ struct pthread_request {
     struct {                    /* For REQ_PROCESS_EXIT: */
       int code;                 /*   exit status */
     } exit;
+    void * post;                /* For REQ_POST: the semaphore */
   } req_args;
 };
 
@@ -160,6 +165,11 @@ extern pthread_descr __pthread_main_thread;
 
 extern char *__pthread_initial_thread_bos;
 
+/* Indicate whether at least one thread has a user-defined stack (if 1),
+   or all threads have stacks supplied by LinuxThreads (if 0). */
+
+extern int __pthread_nonstandard_stacks;
+
 /* File descriptor for sending requests to the thread manager.
    Initially -1, meaning that pthread_initialize must be called. */
 
@@ -178,6 +188,10 @@ extern char *__pthread_manager_thread_tos;
 
 extern int __pthread_exit_requested, __pthread_exit_code;
 
+/* Set to 1 by gdb if we're debugging */
+
+extern volatile int __pthread_threads_debug;
+
 /* Return the handle corresponding to a thread id */
 
 static inline pthread_handle thread_handle(pthread_t id)
@@ -233,6 +247,8 @@ static inline int invalid_handle(pthread_handle h, pthread_t id)
 
 /* Recover thread descriptor for the current thread */
 
+extern pthread_descr __pthread_find_self (void) __attribute__ ((const));
+
 static inline pthread_descr thread_self (void) __attribute__ ((const));
 static inline pthread_descr thread_self (void)
 {
@@ -245,6 +261,8 @@ static inline pthread_descr thread_self (void)
   else if (sp >= __pthread_manager_thread_bos
 	   && sp < __pthread_manager_thread_tos)
     return &__pthread_manager_thread;
+  else if (__pthread_nonstandard_stacks)
+    return __pthread_find_self();
   else
     return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1;
 #endif
@@ -282,8 +300,8 @@ static inline pthread_descr thread_self (void)
 
 void __pthread_destroy_specifics(void);
 void __pthread_perform_cleanup(void);
-void __pthread_sighandler(int sig);
-void __pthread_message(char * fmt, long arg, ...);
+int __pthread_initialize_manager(void);
+void __pthread_message(char * fmt, ...);
 int __pthread_manager(void *reqfd);
 void __pthread_manager_sighandler(int sig);
 void __pthread_reset_main_thread(void);
diff --git a/linuxthreads/join.c b/linuxthreads/join.c
index 2bdc189631..c59de6985a 100644
--- a/linuxthreads/join.c
+++ b/linuxthreads/join.c
@@ -35,13 +35,13 @@ void pthread_exit(void * retval)
   __pthread_perform_cleanup();
   __pthread_destroy_specifics();
   /* Store return value */
-  acquire(self->p_spinlock);
+  __pthread_lock(self->p_lock);
   self->p_retval = retval;
   /* Say that we've terminated */
   self->p_terminated = 1;
   /* See if someone is joining on us */
   joining = self->p_joining;
-  release(self->p_spinlock);
+  __pthread_unlock(self->p_lock);
   /* Restart joining thread if any */
   if (joining != NULL) restart(joining);
   /* If this is the initial thread, block until all threads have terminated.
@@ -65,36 +65,36 @@ int pthread_join(pthread_t thread_id, void ** thread_return)
   pthread_handle handle = thread_handle(thread_id);
   pthread_descr th;
 
-  acquire(&handle->h_spinlock);
+  __pthread_lock(&handle->h_lock);
   if (invalid_handle(handle, thread_id)) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return ESRCH;
   }
   th = handle->h_descr;
   if (th == self) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return EDEADLK;
   }
   /* If detached or already joined, error */
   if (th->p_detached || th->p_joining != NULL) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return EINVAL;
   }
   /* If not terminated yet, suspend ourselves. */
   if (! th->p_terminated) {
     th->p_joining = self;
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     suspend_with_cancellation(self);
     /* This is a cancellation point */
     if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
       th->p_joining = NULL;
       pthread_exit(PTHREAD_CANCELED);
     }
-    acquire(&handle->h_spinlock);
+    __pthread_lock(&handle->h_lock);
   }
   /* Get return value */
   if (thread_return != NULL) *thread_return = th->p_retval;
-  release(&handle->h_spinlock);
+  __pthread_unlock(&handle->h_lock);
   /* Send notification to thread manager */
   if (__pthread_manager_request >= 0) {
     request.req_thread = self;
@@ -113,26 +113,26 @@ int pthread_detach(pthread_t thread_id)
   pthread_handle handle = thread_handle(thread_id);
   pthread_descr th;
 
-  acquire(&handle->h_spinlock);
+  __pthread_lock(&handle->h_lock);
   if (invalid_handle(handle, thread_id)) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return ESRCH;
   }
   th = handle->h_descr;
   /* If already detached, error */
   if (th->p_detached) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return EINVAL;
   }
   /* If already joining, don't do anything. */
   if (th->p_joining != NULL) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return 0;
   }
   /* Mark as detached */
   th->p_detached = 1;
   terminated = th->p_terminated;
-  release(&handle->h_spinlock);
+  __pthread_unlock(&handle->h_lock);
   /* If already terminated, notify thread manager to reclaim resources */
   if (terminated && __pthread_manager_request >= 0) {
     request.req_thread = thread_self();
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c
index ac78d6e4ce..36c592197e 100644
--- a/linuxthreads/manager.c
+++ b/linuxthreads/manager.c
@@ -31,15 +31,22 @@
 #include "internals.h"
 #include "spinlock.h"
 #include "restart.h"
+#include "semaphore.h"
 
 /* Array of active threads. Entry 0 is reserved for the initial thread. */
-
 struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
-{ { 0, &__pthread_initial_thread, 0}, /* All NULLs */ };
+{ { LOCK_INITIALIZER, &__pthread_initial_thread, 0}, /* All NULLs */ };
 
 /* Indicate whether at least one thread has a user-defined stack (if 1),
    or if all threads have stacks supplied by LinuxThreads (if 0). */
-int __pthread_nonstandard_stacks;
+int __pthread_nonstandard_stacks = 0;
+
+/* Number of active entries in __pthread_handles (used by gdb) */
+volatile int __pthread_handles_num = 1;
+
+/* Whether to use debugger additional actions for thread creation
+   (set to 1 by gdb) */
+volatile int __pthread_threads_debug = 0;
 
 /* Mapping from stack segment to thread descriptor. */
 /* Stack segment numbers are also indices into the __pthread_handles array. */
@@ -93,12 +100,18 @@ int __pthread_manager(void *arg)
   /* Set the error variable.  */
   __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno;
   __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno;
-  /* Block all signals except PTHREAD_SIG_RESTART */
+  /* Block all signals except PTHREAD_SIG_RESTART, PTHREAD_SIG_CANCEL
+     and SIGTRAP */
   sigfillset(&mask);
   sigdelset(&mask, PTHREAD_SIG_RESTART);
+  sigdelset(&mask, PTHREAD_SIG_CANCEL); /* for debugging new threads */
+  sigdelset(&mask, SIGTRAP);            /* for debugging purposes */
   sigprocmask(SIG_SETMASK, &mask, NULL);
   /* Raise our priority to match that of main thread */
   __pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
+  /* Synchronize debugging of the thread manager */
+  n = __libc_read(reqfd, (char *)&request, sizeof(request));
+  ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG);
   /* Enter server loop */
   while(1) {
     FD_ZERO(&readfds);
@@ -146,6 +159,14 @@ int __pthread_manager(void *arg)
           return 0;
         }
         break;
+      case REQ_POST:
+        sem_post(request.req_args.post);
+        break;
+      case REQ_DEBUG:
+        /* Make gdb aware of new thread */
+        if (__pthread_threads_debug) raise(PTHREAD_SIG_CANCEL);
+        restart(request.req_thread);
+        break;
       }
     }
   }
@@ -156,6 +177,7 @@ int __pthread_manager(void *arg)
 static int pthread_start_thread(void *arg)
 {
   pthread_descr self = (pthread_descr) arg;
+  struct pthread_request request;
   void * outcome;
   /* Initialize special thread_self processing, if any.  */
 #ifdef INIT_THREAD_SELF
@@ -171,6 +193,14 @@ static int pthread_start_thread(void *arg)
   if (self->p_start_args.schedpolicy >= 0)
     __sched_setscheduler(self->p_pid, self->p_start_args.schedpolicy,
                          &self->p_start_args.schedparam);
+  /* Make gdb aware of new thread */
+  if (__pthread_threads_debug) {
+    request.req_thread = self;
+    request.req_kind = REQ_DEBUG;
+    __libc_write(__pthread_manager_request,
+                 (char *) &request, sizeof(request));
+    suspend(self);
+  }
   /* Run the thread code */
   outcome = self->p_start_args.start_routine(self->p_start_args.arg);
   /* Exit with the given return value */
@@ -188,6 +218,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   char * new_thread_bottom;
   pthread_t new_thread_id;
   void *guardaddr = NULL;
+  size_t guardsize = 0;
 
   /* Find a free stack segment for the current stack */
   for (sseg = 1; ; sseg++)
@@ -211,13 +242,16 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
 		 and allocate it if necessary.  */
 	      if (attr == NULL || attr->guardsize != 0)
 		{
+		  guardsize = attr ? attr->guardsize : __getpagesize ();
 		  guardaddr = mmap ((caddr_t)((char *)(new_thread+1)
 					      - STACK_SIZE),
-				    attr ? attr->guardsize : __getpagesize (),
-				    0, MAP_FIXED, -1, 0);
+				    guardsize, 0, MAP_FIXED, -1, 0);
 		  if (guardaddr == MAP_FAILED)
-		    /* We don't make this an error.  */
-		    guardaddr = NULL;
+		    {
+		      /* We don't make this an error.  */
+		      guardaddr = NULL;
+		      guardsize = 0;
+		    }
 		}
 	      break;
 	    }
@@ -238,7 +272,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   new_thread->p_nextwaiting = NULL;
   new_thread->p_tid = new_thread_id;
   new_thread->p_priority = 0;
-  new_thread->p_spinlock = &(__pthread_handles[sseg].h_spinlock);
+  new_thread->p_lock = &(__pthread_handles[sseg].h_lock);
   new_thread->p_signal = 0;
   new_thread->p_signal_jmp = NULL;
   new_thread->p_cancel_jmp = NULL;
@@ -255,16 +289,15 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   new_thread->p_errno = 0;
   new_thread->p_h_errnop = &new_thread->p_h_errno;
   new_thread->p_h_errno = 0;
+  new_thread->p_in_sighandler = NULL;
+  new_thread->p_sigwaiting = 0;
   new_thread->p_guardaddr = guardaddr;
-  new_thread->p_guardsize = (guardaddr == NULL
-			     ? 0
-			     : (attr == NULL
-				? __getpagesize () : attr->guardsize));
+  new_thread->p_guardsize = guardsize;
   new_thread->p_userstack = attr != NULL && attr->stackaddr_set;
   memset (new_thread->p_specific, '\0',
 	  PTHREAD_KEY_1STLEVEL_SIZE * sizeof (new_thread->p_specific[0]));
   /* Initialize the thread handle */
-  __pthread_handles[sseg].h_spinlock = 0; /* should already be 0 */
+  __pthread_init_lock(&__pthread_handles[sseg].h_lock);
   __pthread_handles[sseg].h_descr = new_thread;
   __pthread_handles[sseg].h_bottom = new_thread_bottom;
   /* Determine scheduling parameters for the thread */
@@ -305,6 +338,8 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
 	  munmap(new_thread->p_guardaddr, new_thread->p_guardsize);
       }
     __pthread_handles[sseg].h_descr = NULL;
+    __pthread_handles[sseg].h_bottom = NULL;
+    __pthread_handles_num--;
     return errno;
   }
   /* Insert new thread in doubly linked list of active threads */
@@ -330,10 +365,12 @@ static void pthread_free(pthread_descr th)
   ASSERT(th->p_exited);
   /* Make the handle invalid */
   handle =  thread_handle(th->p_tid);
-  acquire(&handle->h_spinlock);
+  __pthread_lock(&handle->h_lock);
   handle->h_descr = NULL;
   handle->h_bottom = (char *)(-1L);
-  release(&handle->h_spinlock);
+  __pthread_unlock(&handle->h_lock);
+  /* One fewer threads in __pthread_handles */
+  __pthread_handles_num--;
   /* If initial thread, nothing to free */
   if (th == &__pthread_initial_thread) return;
   if (!th->p_userstack)
@@ -360,10 +397,10 @@ static void pthread_exited(pid_t pid)
       th->p_nextlive->p_prevlive = th->p_prevlive;
       th->p_prevlive->p_nextlive = th->p_nextlive;
       /* Mark thread as exited, and if detached, free its resources */
-      acquire(th->p_spinlock);
+      __pthread_lock(th->p_lock);
       th->p_exited = 1;
       detached = th->p_detached;
-      release(th->p_spinlock);
+      __pthread_unlock(th->p_lock);
       if (detached) pthread_free(th);
       break;
     }
@@ -409,16 +446,16 @@ static void pthread_handle_free(pthread_descr th)
   } while (t != __pthread_main_thread);
   if (t != th) return;
 
-  acquire(th->p_spinlock);
+  __pthread_lock(th->p_lock);
   if (th->p_exited) {
-    release(th->p_spinlock);
+    __pthread_unlock(th->p_lock);
     pthread_free(th);
   } else {
     /* The Unix process of the thread is still running.
        Mark the thread as detached so that the thread manager will
        deallocate its resources when the Unix process exits. */
     th->p_detached = 1;
-    release(th->p_spinlock);
+    __pthread_unlock(th->p_lock);
   }
 }
 
diff --git a/linuxthreads/mutex.c b/linuxthreads/mutex.c
index 3b40ac04c5..54504bfbc3 100644
--- a/linuxthreads/mutex.c
+++ b/linuxthreads/mutex.c
@@ -26,23 +26,18 @@
 int __pthread_mutex_init(pthread_mutex_t * mutex,
                        const pthread_mutexattr_t * mutex_attr)
 {
-  mutex->m_spinlock = 0;
-  mutex->m_count = 0;
-  mutex->m_owner = NULL;
+  __pthread_init_lock(&mutex->m_lock);
   mutex->m_kind =
     mutex_attr == NULL ? PTHREAD_MUTEX_FAST_NP : mutex_attr->mutexkind;
-  queue_init(&mutex->m_waiting);
+  mutex->m_count = 0;
+  mutex->m_owner = NULL;
   return 0;
 }
 weak_alias (__pthread_mutex_init, pthread_mutex_init)
 
 int __pthread_mutex_destroy(pthread_mutex_t * mutex)
 {
-  int count;
-  acquire(&mutex->m_spinlock);
-  count = mutex->m_count;
-  release(&mutex->m_spinlock);
-  if (count > 0) return EBUSY;
+  if (mutex->m_lock.status != 0) return EBUSY;
   return 0;
 }
 weak_alias (__pthread_mutex_destroy, pthread_mutex_destroy)
@@ -50,40 +45,33 @@ weak_alias (__pthread_mutex_destroy, pthread_mutex_destroy)
 int __pthread_mutex_trylock(pthread_mutex_t * mutex)
 {
   pthread_descr self;
+  int retcode;
 
-  acquire(&mutex->m_spinlock);
   switch(mutex->m_kind) {
   case PTHREAD_MUTEX_FAST_NP:
-    if (mutex->m_count == 0) {
-      mutex->m_count = 1;
-      release(&mutex->m_spinlock);
-      return 0;
-    }
-    break;
+    retcode = __pthread_trylock(&mutex->m_lock);
+    return retcode;
   case PTHREAD_MUTEX_RECURSIVE_NP:
     self = thread_self();
-    if (mutex->m_count == 0 || mutex->m_owner == self) {
+    if (mutex->m_owner == self) {
       mutex->m_count++;
-      mutex->m_owner = self;
-      release(&mutex->m_spinlock);
       return 0;
     }
-    break;
-  case PTHREAD_MUTEX_ERRORCHECK_NP:
-    self = thread_self();
-    if (mutex->m_count == 0) {
-      mutex->m_count = 1;
+    retcode = __pthread_trylock(&mutex->m_lock);
+    if (retcode == 0) {
       mutex->m_owner = self;
-      release(&mutex->m_spinlock);
-      return 0;
+      mutex->m_count = 0;
+    }
+    return retcode;
+  case PTHREAD_MUTEX_ERRORCHECK_NP:
+    retcode = __pthread_trylock(&mutex->m_lock);
+    if (retcode == 0) {
+      mutex->m_owner = thread_self();
     }
-    break;
+    return retcode;
   default:
-    release(&mutex->m_spinlock);
     return EINVAL;
   }
-  release(&mutex->m_spinlock);
-  return EBUSY;
 }
 weak_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
 
@@ -91,87 +79,55 @@ int __pthread_mutex_lock(pthread_mutex_t * mutex)
 {
   pthread_descr self;
 
-  acquire(&mutex->m_spinlock);
   switch(mutex->m_kind) {
   case PTHREAD_MUTEX_FAST_NP:
-    if (mutex->m_count == 0) {
-      mutex->m_count = 1;
-      release(&mutex->m_spinlock);
-      return 0;
-    }
-    self = thread_self();
-    break;
+    __pthread_lock(&mutex->m_lock);
+    return 0;
   case PTHREAD_MUTEX_RECURSIVE_NP:
     self = thread_self();
-    if (mutex->m_count == 0 || mutex->m_owner == self) {
+    if (mutex->m_owner == self) {
       mutex->m_count++;
-      mutex->m_owner = self;
-      release(&mutex->m_spinlock);
       return 0;
     }
-    break;
+    __pthread_lock(&mutex->m_lock);
+    mutex->m_owner = self;
+    mutex->m_count = 0;
+    return 0;
   case PTHREAD_MUTEX_ERRORCHECK_NP:
     self = thread_self();
-    if (mutex->m_count == 0) {
-      mutex->m_count = 1;
-      mutex->m_owner = self;
-      release(&mutex->m_spinlock);
-      return 0;
-    } else if (mutex->m_owner == self) {
-      release(&mutex->m_spinlock);
-      return EDEADLK;
-    }
-    break;
+    if (mutex->m_owner == self) return EDEADLK;
+    __pthread_lock(&mutex->m_lock);
+    mutex->m_owner = self;
+    return 0;
   default:
-    release(&mutex->m_spinlock);
     return EINVAL;
   }
-  /* Suspend ourselves */
-  enqueue(&mutex->m_waiting, self);
-  release(&mutex->m_spinlock);
-  suspend(self); /* This is not a cancellation point */
-  /* Now we own the mutex */
-  ASSERT(mutex->m_count == 1);
-  mutex->m_owner = self;        /* for recursive and errorcheck mutexes */
-  return 0;
 }
 weak_alias (__pthread_mutex_lock, pthread_mutex_lock)
 
 int __pthread_mutex_unlock(pthread_mutex_t * mutex)
 {
-  pthread_descr th;
-
-  acquire(&mutex->m_spinlock);
   switch (mutex->m_kind) {
   case PTHREAD_MUTEX_FAST_NP:
-    break;
+    __pthread_unlock(&mutex->m_lock);
+    return 0;
   case PTHREAD_MUTEX_RECURSIVE_NP:
-    if (mutex->m_count >= 2) {
+    if (mutex->m_count > 0) {
       mutex->m_count--;
-      release(&mutex->m_spinlock);
       return 0;
     }
-    break;
+    mutex->m_owner = NULL;
+    __pthread_unlock(&mutex->m_lock);
+    return 0;
   case PTHREAD_MUTEX_ERRORCHECK_NP:
-    if (mutex->m_count == 0 || mutex->m_owner != thread_self()) {
-      release(&mutex->m_spinlock);
+    if (mutex->m_owner != thread_self() || mutex->m_lock.status == 0)
       return EPERM;
-    }
-    break;
+    mutex->m_owner = NULL;
+    __pthread_unlock(&mutex->m_lock);
+    return 0;
   default:
-    release(&mutex->m_spinlock);
     return EINVAL;
   }
-  th = dequeue(&mutex->m_waiting);
-  /* If no waiters, unlock the mutex */
-  if (th == NULL) mutex->m_count = 0;
-  release(&mutex->m_spinlock);
-  /* If there is a waiter, restart it with the mutex still locked */
-  if (th != NULL) {
-    mutex->m_owner = NULL;      /* we no longer own the mutex */
-    restart(th);
-  }
-  return 0;
 }
 weak_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
 
diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c
index 83d160622d..e95b352b72 100644
--- a/linuxthreads/pthread.c
+++ b/linuxthreads/pthread.c
@@ -35,7 +35,7 @@ struct _pthread_descr_struct __pthread_initial_thread = {
   PTHREAD_THREADS_MAX,        /* pthread_t p_tid */
   0,                          /* int p_pid */
   0,                          /* int p_priority */
-  &__pthread_handles[0].h_spinlock, /* int * p_spinlock */
+  &__pthread_handles[0].h_lock, /* struct _pthread_fastlock * p_lock */
   0,                          /* int p_signal */
   NULL,                       /* sigjmp_buf * p_signal_buf */
   NULL,                       /* sigjmp_buf * p_cancel_buf */
@@ -53,6 +53,8 @@ struct _pthread_descr_struct __pthread_initial_thread = {
   0,                          /* int p_errno */
   NULL,                       /* int *p_h_errnop */
   0,                          /* int p_h_errno */
+  NULL,                       /* char * p_in_sighandler */
+  0,                          /* char p_sigwaiting */
   PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */
   {NULL}                      /* void * p_specific[PTHREAD_KEYS_MAX] */
 };
@@ -68,7 +70,7 @@ struct _pthread_descr_struct __pthread_manager_thread = {
   0,                          /* int p_tid */
   0,                          /* int p_pid */
   0,                          /* int p_priority */
-  NULL,                       /* int * p_spinlock */
+  NULL,                       /* struct _pthread_fastlock * p_lock */
   0,                          /* int p_signal */
   NULL,                       /* sigjmp_buf * p_signal_buf */
   NULL,                       /* sigjmp_buf * p_cancel_buf */
@@ -86,6 +88,8 @@ struct _pthread_descr_struct __pthread_manager_thread = {
   0,                          /* int p_errno */
   NULL,                       /* int *p_h_errnop */
   0,                          /* int p_h_errno */
+  NULL,                       /* char * p_in_sighandler */
+  0,                          /* char p_sigwaiting */
   PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */
   {NULL}                      /* void * p_specific[PTHREAD_KEYS_MAX] */
 };
@@ -119,6 +123,15 @@ char *__pthread_manager_thread_tos = NULL;
 int __pthread_exit_requested = 0;
 int __pthread_exit_code = 0;
 
+/* Communicate relevant LinuxThreads constants to gdb */
+
+const int __pthread_threads_max = PTHREAD_THREADS_MAX;
+const int __pthread_sizeof_handle = sizeof(struct pthread_handle_struct);
+const int __pthread_offsetof_descr = offsetof(struct pthread_handle_struct,
+                                              h_descr);
+const int __pthread_offsetof_pid = offsetof(struct _pthread_descr_struct,
+                                            p_pid);
+
 /* Signal numbers used for the communication.  */
 int __pthread_sig_restart;
 int __pthread_sig_cancel;
@@ -131,6 +144,7 @@ extern int _h_errno;
 
 static void pthread_exit_process(int retcode, void *arg);
 static void pthread_handle_sigcancel(int sig);
+static void pthread_handle_sigrestart(int sig);
 
 /* Initialize the pthread library.
    Initialization is split in two functions:
@@ -148,6 +162,10 @@ static void pthread_initialize(void)
 
   /* If already done (e.g. by a constructor called earlier!), bail out */
   if (__pthread_initial_thread_bos != NULL) return;
+#ifdef TEST_FOR_COMPARE_AND_SWAP
+  /* Test if compare-and-swap is available */
+  __pthread_has_cas = compare_and_swap_is_available();
+#endif
   /* For the initial stack, reserve at least STACK_SIZE bytes of stack
      below the current stack address, and align that on a
      STACK_SIZE boundary. */
@@ -178,14 +196,14 @@ static void pthread_initialize(void)
   /* Setup signal handlers for the initial thread.
      Since signal handlers are shared between threads, these settings
      will be inherited by all other threads. */
-  sa.sa_handler = __pthread_sighandler;
+  sa.sa_handler = pthread_handle_sigrestart;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = SA_RESTART; /* does not matter for regular threads, but
                                better for the thread manager */
-  sigaction(PTHREAD_SIG_RESTART, &sa, NULL);
+  __sigaction(PTHREAD_SIG_RESTART, &sa, NULL);
   sa.sa_handler = pthread_handle_sigcancel;
   sa.sa_flags = 0;
-  sigaction(PTHREAD_SIG_CANCEL, &sa, NULL);
+  __sigaction(PTHREAD_SIG_CANCEL, &sa, NULL);
 
   /* Initially, block PTHREAD_SIG_RESTART. Will be unblocked on demand. */
   sigemptyset(&mask);
@@ -197,10 +215,11 @@ static void pthread_initialize(void)
   __on_exit(pthread_exit_process, NULL);
 }
 
-static int pthread_initialize_manager(void)
+int __pthread_initialize_manager(void)
 {
   int manager_pipe[2];
   int pid;
+  struct pthread_request request;
 
   /* If basic initialization not done yet (e.g. we're called from a
      constructor run before our constructor), do it now */
@@ -228,6 +247,11 @@ static int pthread_initialize_manager(void)
   __pthread_manager_request = manager_pipe[1]; /* writing end */
   __pthread_manager_reader = manager_pipe[0]; /* reading end */
   __pthread_manager_thread.p_pid = pid;
+  /* Make gdb aware of new thread manager */
+  if (__pthread_threads_debug) raise(PTHREAD_SIG_CANCEL);
+  /* Synchronize debugging of the thread manager */
+  request.req_kind = REQ_DEBUG;
+  __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
   return 0;
 }
 
@@ -239,7 +263,7 @@ int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr,
   pthread_descr self = thread_self();
   struct pthread_request request;
   if (__pthread_manager_request < 0) {
-    if (pthread_initialize_manager() < 0) return EAGAIN;
+    if (__pthread_initialize_manager() < 0) return EAGAIN;
   }
   request.req_thread = self;
   request.req_kind = REQ_CREATE;
@@ -296,6 +320,24 @@ int pthread_equal(pthread_t thread1, pthread_t thread2)
   return thread1 == thread2;
 }
 
+/* Helper function for thread_self in the case of user-provided stacks */
+
+#ifndef THREAD_SELF
+
+pthread_descr __pthread_find_self()
+{
+  char * sp = CURRENT_STACK_FRAME;
+  pthread_handle h;
+
+  /* __pthread_handles[0] is the initial thread, handled specially in
+     thread_self(), so start at 1 */
+  h = __pthread_handles + 1;
+  while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++;
+  return h->h_descr;
+}
+
+#endif
+
 /* Thread scheduling */
 
 int pthread_setschedparam(pthread_t thread, int policy,
@@ -304,18 +346,18 @@ int pthread_setschedparam(pthread_t thread, int policy,
   pthread_handle handle = thread_handle(thread);
   pthread_descr th;
 
-  acquire(&handle->h_spinlock);
+  __pthread_lock(&handle->h_lock);
   if (invalid_handle(handle, thread)) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return ESRCH;
   }
   th = handle->h_descr;
   if (__sched_setscheduler(th->p_pid, policy, param) == -1) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return errno;
   }
   th->p_priority = policy == SCHED_OTHER ? 0 : param->sched_priority;
-  release(&handle->h_spinlock);
+  __pthread_unlock(&handle->h_lock);
   if (__pthread_manager_request >= 0)
     __pthread_manager_adjust_prio(th->p_priority);
   return 0;
@@ -327,13 +369,13 @@ int pthread_getschedparam(pthread_t thread, int *policy,
   pthread_handle handle = thread_handle(thread);
   int pid, pol;
 
-  acquire(&handle->h_spinlock);
+  __pthread_lock(&handle->h_lock);
   if (invalid_handle(handle, thread)) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return ESRCH;
   }
   pid = handle->h_descr->p_pid;
-  release(&handle->h_spinlock);
+  __pthread_unlock(&handle->h_lock);
   pol = __sched_getscheduler(pid);
   if (pol == -1) return errno;
   if (__sched_getparam(pid, param) == -1) return errno;
@@ -364,11 +406,11 @@ static void pthread_exit_process(int retcode, void *arg)
 
 /* The handler for the RESTART signal just records the signal received
    in the thread descriptor, and optionally performs a siglongjmp
-   (for pthread_cond_timedwait). Also used in sigwait.
+   (for pthread_cond_timedwait).
    For the thread manager thread, redirect the signal to
    __pthread_manager_sighandler. */
 
-void __pthread_sighandler(int sig)
+static void pthread_handle_sigrestart(int sig)
 {
   pthread_descr self = thread_self();
   if (self == &__pthread_manager_thread) {
@@ -380,13 +422,24 @@ void __pthread_sighandler(int sig)
 }
 
 /* The handler for the CANCEL signal checks for cancellation
-   (in asynchronous mode) and for process-wide exit and exec requests. */
+   (in asynchronous mode), for process-wide exit and exec requests.
+   For the thread manager thread, we ignore the signal.
+   The debugging strategy is as follows:
+   On reception of a REQ_DEBUG request (sent by new threads created to
+   the thread manager under debugging mode), the thread manager throws
+   PTHREAD_SIG_CANCEL to itself. The debugger (if active) intercepts
+   this signal, takes into account new threads and continue execution
+   of the thread manager by propagating the signal because it doesn't
+   know what it is specifically done for. In the current implementation,
+   the thread manager simply discards it. */
 
 static void pthread_handle_sigcancel(int sig)
 {
   pthread_descr self = thread_self();
   sigjmp_buf * jmpbuf;
 
+  if (self == &__pthread_manager_thread)
+    return;
   if (__pthread_exit_requested) {
     /* Main thread should accumulate times for thread manager and its
        children, so that timings for main thread account for all threads. */
@@ -469,7 +522,7 @@ weak_alias (__pthread_getconcurrency, pthread_getconcurrency)
 #ifdef DEBUG
 #include <stdarg.h>
 
-void __pthread_message(char * fmt, long arg)
+void __pthread_message(char * fmt, ...)
 {
   char buffer[1024];
   va_list args;
diff --git a/linuxthreads/ptlongjmp.c b/linuxthreads/ptlongjmp.c
index c5704f9e9a..580ae93f88 100644
--- a/linuxthreads/ptlongjmp.c
+++ b/linuxthreads/ptlongjmp.c
@@ -37,6 +37,8 @@ static void pthread_cleanup_upto(__jmp_buf target)
        c = c->prev)
     c->routine(c->arg);
   self->p_cleanup = c;
+  if (self->p_in_sighandler && _JMPBUF_UNWINDS(target, self->p_in_sighandler))
+    self->p_in_sighandler = NULL;
 }
 
 void siglongjmp(sigjmp_buf env, int val)
diff --git a/linuxthreads/queue.h b/linuxthreads/queue.h
index 60039cce6e..fa8c5d861d 100644
--- a/linuxthreads/queue.h
+++ b/linuxthreads/queue.h
@@ -14,49 +14,42 @@
 
 /* Waiting queues */
 
-typedef struct _pthread_queue pthread_queue;
+/* Waiting queues are represented by lists of thread descriptors
+   linked through their p_nextwaiting field.  The lists are kept
+   sorted by decreasing priority, and then decreasing waiting time. */
 
-static inline void queue_init(pthread_queue * q)
+static inline void enqueue(pthread_descr * q, pthread_descr th)
 {
-  q->head = q->tail = NULL;
-}
-
-static inline void enqueue(pthread_queue * q, pthread_descr th)
-{
-  int prio;
-  pthread_descr * elt;
-
+  int prio = th->p_priority;
   ASSERT(th->p_nextwaiting == NULL);
-  if (q->tail == NULL) {
-    q->head = th;
-    q->tail = th;
-    return;
-  }
-  prio = th->p_priority;
-  if (prio > 0) {
-    /* Insert in queue according to priority order */
-    for (elt = &(q->head); *elt != NULL; elt = &((*elt)->p_nextwaiting)) {
-      if (prio > (*elt)->p_priority) {
-        th->p_nextwaiting = *elt;
-        *elt = th;
-        return;
-      }
+  for (; *q != NULL; q = &((*q)->p_nextwaiting)) {
+    if (prio > (*q)->p_priority) {
+      th->p_nextwaiting = *q;
+      *q = th;
+      return;
     }
   }
-  /* Priority is no greater than any thread in the queue.
-     Insert at end of queue */
-  q->tail->p_nextwaiting = th;
-  q->tail = th;
+  *q = th;
 }
 
-static inline pthread_descr dequeue(pthread_queue * q)
+static inline pthread_descr dequeue(pthread_descr * q)
 {
   pthread_descr th;
-  th = q->head;
+  th = *q;
   if (th != NULL) {
-    q->head = th->p_nextwaiting;
-    if (q->head == NULL) q->tail = NULL;
+    *q = th->p_nextwaiting;
     th->p_nextwaiting = NULL;
   }
   return th;
 }
+
+static inline void remove_from_queue(pthread_descr * q, pthread_descr th)
+{
+  for (; *q != NULL; q = &((*q)->p_nextwaiting)) {
+    if (*q == th) {
+      *q = th->p_nextwaiting;
+      th->p_nextwaiting = NULL;
+      return;
+    }
+  }
+}
diff --git a/linuxthreads/rwlock.c b/linuxthreads/rwlock.c
index c6b281551a..99209f75da 100644
--- a/linuxthreads/rwlock.c
+++ b/linuxthreads/rwlock.c
@@ -30,12 +30,11 @@ int
 pthread_rwlock_init (pthread_rwlock_t *rwlock,
 		     const pthread_rwlockattr_t *attr)
 {
-  rwlock->rw_spinlock = 0;
+  __pthread_init_lock(&rwlock->rw_lock);
   rwlock->rw_readers = 0;
   rwlock->rw_writer = NULL;
-
-  queue_init(&rwlock->rw_read_waiting);
-  queue_init(&rwlock->rw_write_waiting);
+  rwlock->rw_read_waiting = NULL;
+  rwlock->rw_write_waiting = NULL;
 
   if (attr == NULL)
     {
@@ -58,10 +57,10 @@ pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
   int readers;
   _pthread_descr writer;
 
-  acquire (&rwlock->rw_spinlock);
+  __pthread_lock (&rwlock->rw_lock);
   readers = rwlock->rw_readers;
   writer = rwlock->rw_writer;
-  release (&rwlock->rw_spinlock);
+  __pthread_unlock (&rwlock->rw_lock);
 
   if (readers > 0 || writer != NULL)
     return EBUSY;
@@ -77,7 +76,7 @@ pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
 
   while (1)
     {
-      acquire (&rwlock->rw_spinlock);
+      __pthread_lock (&rwlock->rw_lock);
       if (rwlock->rw_writer == NULL
 	  || (rwlock->rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
 	      && rwlock->rw_readers != 0))
@@ -87,12 +86,12 @@ pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
       /* Suspend ourselves, then try again */
       self = thread_self ();
       enqueue (&rwlock->rw_read_waiting, self);
-      release (&rwlock->rw_spinlock);
+      __pthread_unlock (&rwlock->rw_lock);
       suspend (self); /* This is not a cancellation point */
     }
 
   ++rwlock->rw_readers;
-  release (&rwlock->rw_spinlock);
+  __pthread_unlock (&rwlock->rw_lock);
 
   return 0;
 }
@@ -103,7 +102,7 @@ pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
 {
   int result = EBUSY;
 
-  acquire (&rwlock->rw_spinlock);
+  __pthread_lock (&rwlock->rw_lock);
   if (rwlock->rw_writer == NULL
       || (rwlock->rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
 	  && rwlock->rw_readers != 0))
@@ -111,7 +110,7 @@ pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
       ++rwlock->rw_readers;
       result = 0;
     }
-  release (&rwlock->rw_spinlock);
+  __pthread_unlock (&rwlock->rw_lock);
 
   return result;
 }
@@ -124,17 +123,17 @@ pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
 
   while(1)
     {
-      acquire (&rwlock->rw_spinlock);
+      __pthread_lock (&rwlock->rw_lock);
       if (rwlock->rw_readers == 0 && rwlock->rw_writer == NULL)
 	{
 	  rwlock->rw_writer = self;
-	  release (&rwlock->rw_spinlock);
+	  __pthread_unlock (&rwlock->rw_lock);
 	  return 0;
 	}
 
       /* Suspend ourselves, then try again */
       enqueue (&rwlock->rw_write_waiting, self);
-      release (&rwlock->rw_spinlock);
+      __pthread_unlock (&rwlock->rw_lock);
       suspend (self); /* This is not a cancellation point */
     }
 }
@@ -145,13 +144,13 @@ pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
 {
   int result = EBUSY;
 
-  acquire (&rwlock->rw_spinlock);
+  __pthread_lock (&rwlock->rw_lock);
   if (rwlock->rw_readers == 0 && rwlock->rw_writer == NULL)
     {
       rwlock->rw_writer = thread_self ();
       result = 0;
     }
-  release (&rwlock->rw_spinlock);
+  __pthread_unlock (&rwlock->rw_lock);
 
   return result;
 }
@@ -160,16 +159,16 @@ pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
 int
 pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
 {
-  struct _pthread_queue torestart;
+  pthread_descr torestart;
   pthread_descr th;
 
-  acquire (&rwlock->rw_spinlock);
+  __pthread_lock (&rwlock->rw_lock);
   if (rwlock->rw_writer != NULL)
     {
       /* Unlocking a write lock.  */
       if (rwlock->rw_writer != thread_self ())
 	{
-	  release (&rwlock->rw_spinlock);
+	  __pthread_unlock (&rwlock->rw_lock);
 	  return EPERM;
 	}
       rwlock->rw_writer = NULL;
@@ -179,15 +178,15 @@ pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
 	{
 	  /* Restart all waiting readers.  */
 	  torestart = rwlock->rw_read_waiting;
-	  queue_init (&rwlock->rw_read_waiting);
-	  release (&rwlock->rw_spinlock);
+	  rwlock->rw_read_waiting = NULL;
+	  __pthread_unlock (&rwlock->rw_lock);
 	  while ((th = dequeue (&torestart)) != NULL)
 	    restart (th);
 	}
       else
 	{
 	  /* Restart one waiting writer.  */
-	  release (&rwlock->rw_spinlock);
+	  __pthread_unlock (&rwlock->rw_lock);
 	  restart (th);
 	}
     }
@@ -196,7 +195,7 @@ pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
       /* Unlocking a read lock.  */
       if (rwlock->rw_readers == 0)
 	{
-	  release (&rwlock->rw_spinlock);
+	  __pthread_unlock (&rwlock->rw_lock);
 	  return EPERM;
 	}
 
@@ -207,7 +206,7 @@ pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
       else
 	th = NULL;
 
-      release (&rwlock->rw_spinlock);
+      __pthread_unlock (&rwlock->rw_lock);
       if (th != NULL)
 	restart (th);
     }
diff --git a/linuxthreads/semaphore.c b/linuxthreads/semaphore.c
index bd07439cde..7ca609f6b2 100644
--- a/linuxthreads/semaphore.c
+++ b/linuxthreads/semaphore.c
@@ -17,69 +17,13 @@
 #include "pthread.h"
 #include "semaphore.h"
 #include "internals.h"
-#include "restart.h"
-
-
-#if !defined HAS_COMPARE_AND_SWAP && !defined TEST_FOR_COMPARE_AND_SWAP
-/* If we have no atomic compare and swap, fake it using an extra spinlock.  */
-
-#include "spinlock.h"
-static inline int sem_compare_and_swap(sem_t *sem, long oldval, long newval)
-{
-  int ret;
-  acquire(&sem->sem_spinlock);
-  ret = (sem->sem_status == oldval);
-  if (ret) sem->sem_status = newval;
-  release(&sem->sem_spinlock);
-  return ret;
-}
-
-#elif defined TEST_FOR_COMPARE_AND_SWAP
-
 #include "spinlock.h"
-static int has_compare_and_swap = -1; /* to be determined at run-time */
-
-static inline int sem_compare_and_swap(sem_t *sem, long oldval, long newval)
-{
-  int ret;
-
-  if (has_compare_and_swap == 1)
-    return __compare_and_swap(&sem->sem_status, oldval, newval);
-
-  acquire(&sem->sem_spinlock);
-  ret = (sem->sem_status == oldval);
-  if (ret) sem->sem_status = newval;
-  release(&sem->sem_spinlock);
-  return ret;
-}
-
-#else
-/* But if we do have an atomic compare and swap, use it!  */
-
-static inline int sem_compare_and_swap(sem_t *sem, long oldval, long newval)
-{
-  return __compare_and_swap(&sem->sem_status, oldval, newval);
-}
-
-#endif
-
-
-/* The state of a semaphore is represented by a long int encoding
-   either the semaphore count if >= 0 and no thread is waiting on it,
-   or the head of the list of threads waiting for the semaphore.
-   To distinguish the two cases, we encode the semaphore count N
-   as 2N+1, so that it has the lowest bit set.
-
-   A sequence of sem_wait operations on a semaphore initialized to N
-   result in the following successive states:
-     2N+1, 2N-1, ..., 3, 1, &first_waiting_thread, &second_waiting_thread, ...
-*/
-
-static void sem_restart_list(pthread_descr waiting);
+#include "restart.h"
+#include "queue.h"
 
 int sem_init(sem_t *sem, int pshared, unsigned int value)
 {
-  if ((long)value > SEM_VALUE_MAX) {
+  if (value > SEM_VALUE_MAX) {
     errno = EINVAL;
     return -1;
   }
@@ -87,150 +31,104 @@ int sem_init(sem_t *sem, int pshared, unsigned int value)
     errno = ENOSYS;
     return -1;
   }
-#ifdef TEST_FOR_COMPARE_AND_SWAP
-  if (has_compare_and_swap == -1) {
-    has_compare_and_swap = compare_and_swap_is_available();
-  }
-#endif
-#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
-  sem->sem_spinlock = 0;
-#endif
-  sem->sem_status = ((long)value << 1) + 1;
+  __pthread_init_lock((struct _pthread_fastlock *) &sem->sem_lock);
+  sem->sem_value = value;
+  sem->sem_waiting = NULL;
   return 0;
 }
 
 int sem_wait(sem_t * sem)
 {
-  long oldstatus, newstatus;
-  volatile pthread_descr self = thread_self();
-  pthread_descr * th;
+  volatile pthread_descr self;
 
-  while (1) {
-    do {
-      oldstatus = sem->sem_status;
-      if ((oldstatus & 1) && (oldstatus != 1))
-        newstatus = oldstatus - 2;
-      else {
-        newstatus = (long) self;
-        self->p_nextwaiting = (pthread_descr) oldstatus;
-      }
-    }
-    while (! sem_compare_and_swap(sem, oldstatus, newstatus));
-    if (newstatus & 1)
-      /* We got the semaphore. */
-      return 0;
-    /* Wait for sem_post or cancellation */
-    suspend_with_cancellation(self);
-    /* This is a cancellation point */
-    if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
-      /* Remove ourselves from the waiting list if we're still on it */
-      /* First check if we're at the head of the list. */
-      do {
-        oldstatus = sem->sem_status;
-        if (oldstatus != (long) self) break;
-        newstatus = (long) self->p_nextwaiting;
-      }
-      while (! sem_compare_and_swap(sem, oldstatus, newstatus));
-      /* Now, check if we're somewhere in the list.
-         There's a race condition with sem_post here, but it does not matter:
-         the net result is that at the time pthread_exit is called,
-         self is no longer reachable from sem->sem_status. */
-      if (oldstatus != (long) self && (oldstatus & 1) == 0) {
-	for (th = &(((pthread_descr) oldstatus)->p_nextwaiting);
-	     *th != NULL && *th != (pthread_descr) 1;
-	     th = &((*th)->p_nextwaiting)) {
-          if (*th == self) {
-            *th = self->p_nextwaiting;
-            break;
-          }
-        }
-      }
-      pthread_exit(PTHREAD_CANCELED);
-    }
+  __pthread_lock((struct _pthread_fastlock *) &sem->sem_lock);
+  if (sem->sem_value > 0) {
+    sem->sem_value--;
+    __pthread_unlock((struct _pthread_fastlock *) &sem->sem_lock);
+    return 0;
+  }
+  self = thread_self();
+  enqueue(&sem->sem_waiting, self);
+  /* Wait for sem_post or cancellation */
+  __pthread_unlock((struct _pthread_fastlock *) &sem->sem_lock);
+  suspend_with_cancellation(self);
+  /* This is a cancellation point */
+  if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
+    /* Remove ourselves from the waiting list if we're still on it */
+    __pthread_lock((struct _pthread_fastlock *) &sem->sem_lock);
+    remove_from_queue(&sem->sem_waiting, self);
+    __pthread_unlock((struct _pthread_fastlock *) &sem->sem_lock);
+    pthread_exit(PTHREAD_CANCELED);
   }
+  /* We got the semaphore */
+  return 0;
 }
 
 int sem_trywait(sem_t * sem)
 {
-  long oldstatus, newstatus;
-
-  do {
-    oldstatus = sem->sem_status;
-    if ((oldstatus & 1) == 0 || (oldstatus == 1)) {
-      errno = EAGAIN;
-      return -1;
-    }
-    newstatus = oldstatus - 2;
+  int retval;
+
+  __pthread_lock((struct _pthread_fastlock *) &sem->sem_lock);
+  if (sem->sem_value == 0) {
+    errno = EAGAIN;
+    retval = -1;
+  } else {
+    sem->sem_value--;
+    retval = 0;
   }
-  while (! sem_compare_and_swap(sem, oldstatus, newstatus));
-  return 0;
+  return retval;
 }
 
 int sem_post(sem_t * sem)
 {
-  long oldstatus, newstatus;
-
-  do {
-    oldstatus = sem->sem_status;
-    if ((oldstatus & 1) == 0)
-      newstatus = 3;
-    else {
-      if (oldstatus >= SEM_VALUE_MAX) {
+  pthread_descr self = thread_self();
+  pthread_descr th;
+  struct pthread_request request;
+
+  if (self->p_in_sighandler == NULL) {
+    __pthread_lock((struct _pthread_fastlock *) &sem->sem_lock);
+    if (sem->sem_waiting == NULL) {
+      if (sem->sem_value >= SEM_VALUE_MAX) {
         /* Overflow */
         errno = ERANGE;
+        __pthread_unlock((struct _pthread_fastlock *) &sem->sem_lock);
+        return -1;
+      }
+      sem->sem_value++;
+      __pthread_unlock((struct _pthread_fastlock *) &sem->sem_lock);
+    } else {
+      th = dequeue(&sem->sem_waiting);
+      __pthread_unlock((struct _pthread_fastlock *) &sem->sem_lock);
+      restart(th);
+    }
+  } else {
+    /* If we're in signal handler, delegate post operation to
+       the thread manager. */
+    if (__pthread_manager_request < 0) {
+      if (__pthread_initialize_manager() < 0) {
+        errno = EAGAIN;
         return -1;
       }
-      newstatus = oldstatus + 2;
     }
+    request.req_kind = REQ_POST;
+    request.req_args.post = sem;
+    __libc_write(__pthread_manager_request,
+                 (char *) &request, sizeof(request));
   }
-  while (! sem_compare_and_swap(sem, oldstatus, newstatus));
-  if ((oldstatus & 1) == 0)
-    sem_restart_list((pthread_descr) oldstatus);
   return 0;
 }
 
 int sem_getvalue(sem_t * sem, int * sval)
 {
-  long status = sem->sem_status;
-  if (status & 1)
-    *sval = (int)((unsigned long) status >> 1);
-  else
-    *sval = 0;
+  *sval = sem->sem_value;
   return 0;
 }
 
 int sem_destroy(sem_t * sem)
 {
-  if ((sem->sem_status & 1) == 0) {
+  if (sem->sem_waiting != NULL) {
     errno = EBUSY;
     return -1;
   }
   return 0;
 }
-
-/* Auxiliary function for restarting all threads on a waiting list,
-   in priority order. */
-
-static void sem_restart_list(pthread_descr waiting)
-{
-  pthread_descr th, towake, *p;
-
-  /* Sort list of waiting threads by decreasing priority (insertion sort) */
-  towake = NULL;
-  while (waiting != (pthread_descr) 1) {
-    th = waiting;
-    waiting = waiting->p_nextwaiting;
-    p = &towake;
-    while (*p != NULL && th->p_priority < (*p)->p_priority)
-      p = &((*p)->p_nextwaiting);
-    th->p_nextwaiting = *p;
-    *p = th;
-  }
-  /* Wake up threads in priority order */
-  while (towake != NULL) {
-    th = towake;
-    towake = towake->p_nextwaiting;
-    th->p_nextwaiting = NULL;
-    restart(th);
-  }
-}
diff --git a/linuxthreads/semaphore.h b/linuxthreads/semaphore.h
index 9f01a7f4fa..0740962902 100644
--- a/linuxthreads/semaphore.h
+++ b/linuxthreads/semaphore.h
@@ -21,8 +21,11 @@
 
 #define SEM_VALUE_MAX INT_MAX
 
-/* Get the semaphore structure definition.  */
-#include <bits/semaphore.h>
+typedef struct {
+  struct { long status; int spinlock; } sem_lock;
+  int sem_value;
+  _pthread_descr sem_waiting;
+} sem_t;
 
 __BEGIN_DECLS
 
diff --git a/linuxthreads/signals.c b/linuxthreads/signals.c
index 905e11e5fe..4a83b14d83 100644
--- a/linuxthreads/signals.c
+++ b/linuxthreads/signals.c
@@ -53,83 +53,88 @@ int pthread_kill(pthread_t thread, int signo)
   pthread_handle handle = thread_handle(thread);
   int pid;
 
-  acquire(&handle->h_spinlock);
+  __pthread_lock(&handle->h_lock);
   if (invalid_handle(handle, thread)) {
-    release(&handle->h_spinlock);
+    __pthread_unlock(&handle->h_lock);
     return ESRCH;
   }
   pid = handle->h_descr->p_pid;
-  release(&handle->h_spinlock);
+  __pthread_unlock(&handle->h_lock);
   if (kill(pid, signo) == -1)
     return errno;
   else
     return 0;
 }
 
-/* The set of signals on which some thread is doing a sigwait */
-static sigset_t sigwaited;
-static pthread_mutex_t sigwaited_mut = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t sigwaited_changed = PTHREAD_COND_INITIALIZER;
+/* User-provided signal handlers */
+static __sighandler_t sighandler[NSIG];
+
+/* The wrapper around user-provided signal handlers */
+static void pthread_sighandler(int signo)
+{
+  pthread_descr self = thread_self();
+  char * in_sighandler;
+  /* If we're in a sigwait operation, just record the signal received
+     and return without calling the user's handler */
+  if (self->p_sigwaiting) {
+    self->p_sigwaiting = 0;
+    self->p_signal = signo;
+    return;
+  }
+  /* Record that we're in a signal handler and call the user's
+     handler function */
+  in_sighandler = self->p_in_sighandler;
+  if (in_sighandler == NULL) self->p_in_sighandler = CURRENT_STACK_FRAME;
+  sighandler[signo](signo);
+  if (in_sighandler == NULL) self->p_in_sighandler = NULL;
+}
+
+int sigaction(int sig, const struct sigaction * act,
+              struct sigaction * oact)
+{
+  struct sigaction newact;
+
+  if (sig == PTHREAD_SIG_RESTART || sig == PTHREAD_SIG_CANCEL)
+    return EINVAL;
+  newact = *act;
+  if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL)
+    newact.sa_handler = pthread_sighandler;
+  if (__sigaction(sig, &newact, oact) == -1)
+    return -1;
+  if (oact != NULL) oact->sa_handler = sighandler[sig];
+  sighandler[sig] = act->sa_handler;
+  return 0;
+}
 
 int sigwait(const sigset_t * set, int * sig)
 {
   volatile pthread_descr self = thread_self();
   sigset_t mask;
   int s;
-  struct sigaction action, saved_signals[NSIG];
   sigjmp_buf jmpbuf;
 
-  pthread_mutex_lock(&sigwaited_mut);
-  /* Make sure no other thread is waiting on our signals */
-test_again:
-  for (s = 1; s < NSIG; s++) {
-    if (sigismember(set, s) && sigismember(&sigwaited, s)) {
-      pthread_cond_wait(&sigwaited_changed, &sigwaited_mut);
-      goto test_again;
-    }
-  }
   /* Get ready to block all signals except those in set
      and the cancellation signal */
   sigfillset(&mask);
   sigdelset(&mask, PTHREAD_SIG_CANCEL);
-  /* Signals in set are assumed blocked on entrance */
-  /* Install our signal handler on all signals in set,
-     and unblock them in mask.
-     Also mark those signals as being sigwaited on */
-  for (s = 1; s < NSIG; s++) {
-    if (sigismember(set, s) && s != PTHREAD_SIG_CANCEL) {
+  for (s = 1; s <= NSIG; s++) {
+    if (sigismember(set, s) && s != PTHREAD_SIG_CANCEL)
       sigdelset(&mask, s);
-      action.sa_handler = __pthread_sighandler;
-      sigemptyset(&action.sa_mask);
-      action.sa_flags = 0;
-      sigaction(s, &action, &(saved_signals[s]));
-      sigaddset(&sigwaited, s);
-    }
   }
-  pthread_mutex_unlock(&sigwaited_mut);
-
   /* Test for cancellation */
   if (sigsetjmp(jmpbuf, 1) == 0) {
     self->p_cancel_jmp = &jmpbuf;
     if (! (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE)) {
       /* Reset the signal count */
       self->p_signal = 0;
+      /* Say we're in sigwait */
+      self->p_sigwaiting = 1;
       /* Unblock the signals and wait for them */
       sigsuspend(&mask);
     }
   }
   self->p_cancel_jmp = NULL;
-  /* The signals are now reblocked. Restore the sighandlers. */
-  pthread_mutex_lock(&sigwaited_mut);
-  for (s = 1; s < NSIG; s++) {
-    if (sigismember(set, s) && s != PTHREAD_SIG_CANCEL) {
-      sigaction(s, &(saved_signals[s]), NULL);
-      sigdelset(&sigwaited, s);
-    }
-  }
-  pthread_cond_broadcast(&sigwaited_changed);
-  pthread_mutex_unlock(&sigwaited_mut);
-  /* Check for cancellation */
+  /* The signals are now reblocked.  Check for cancellation */
   pthread_testcancel();
   /* We should have self->p_signal != 0 and equal to the signal received */
   *sig = self->p_signal;
diff --git a/linuxthreads/spinlock.c b/linuxthreads/spinlock.c
index 170d9ae8d0..dba5d38fd2 100644
--- a/linuxthreads/spinlock.c
+++ b/linuxthreads/spinlock.c
@@ -12,15 +12,130 @@
 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
 /* GNU Library General Public License for more details.                 */
 
-/* Spin locks */
+/* Internal locks */
 
 #include <sched.h>
 #include <time.h>
 #include "pthread.h"
 #include "internals.h"
 #include "spinlock.h"
+#include "restart.h"
 
-/* This function is called if the inlined test-and-set in acquire() failed */
+/* The status field of a fastlock has the following meaning:
+     0: fastlock is free
+     1: fastlock is taken, no thread is waiting on it
+  ADDR: fastlock is taken, ADDR is address of thread descriptor for
+        first waiting thread, other waiting threads are linked via
+        their p_nextwaiting field.
+   The waiting list is not sorted by priority order.
+   Actually, we always insert at top of list (sole insertion mode
+   that can be performed without locking).
+   For __pthread_unlock, we perform a linear search in the list
+   to find the highest-priority, oldest waiting thread.
+   This is safe because there are no concurrent __pthread_unlock
+   operations -- only the thread that locked the mutex can unlock it. */
+
+void __pthread_lock(struct _pthread_fastlock * lock)
+{
+  long oldstatus, newstatus;
+  pthread_descr self = NULL;
+
+  do {
+    oldstatus = lock->status;
+    if (oldstatus == 0) {
+      newstatus = 1;
+    } else {
+      self = thread_self();
+      self->p_nextwaiting = (pthread_descr) oldstatus;
+      newstatus = (long) self;
+    }
+  } while(! compare_and_swap(&lock->status, oldstatus, newstatus,
+                             &lock->spinlock));
+  if (oldstatus != 0) suspend(self);
+}
+
+int __pthread_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;
+}
+
+void __pthread_unlock(struct _pthread_fastlock * lock)
+{
+  long oldstatus;
+  pthread_descr thr, * ptr, * maxptr;
+  int maxprio;
+
+again:
+  oldstatus = lock->status;
+  if (oldstatus == 1) {
+    /* No threads are waiting for this lock */
+    if (! compare_and_swap(&lock->status, 1, 0, &lock->spinlock)) goto again;
+    return;
+  }
+  /* Find thread in waiting queue with maximal priority */
+  ptr = (pthread_descr *) &lock->status;
+  thr = (pthread_descr) oldstatus;
+  maxprio = 0;
+  maxptr = ptr;
+  while (thr != (pthread_descr) 1) {
+    if (thr->p_priority >= maxprio) {
+      maxptr = ptr;
+      maxprio = thr->p_priority;
+    }
+    ptr = &(thr->p_nextwaiting);
+    thr = *ptr;
+  }
+  /* Remove max prio thread from waiting list. */
+  if (maxptr == (pthread_descr *) &lock->status) {
+    /* If max prio thread is at head, remove it with compare-and-swap
+       to guard against concurrent lock operation */
+    thr = (pthread_descr) oldstatus;
+    if (! compare_and_swap(&lock->status,
+                           oldstatus, (long)(thr->p_nextwaiting),
+                           &lock->spinlock))
+      goto again;
+  } else {
+    /* No risk of concurrent access, remove max prio thread normally */
+    thr = *maxptr;
+    *maxptr = thr->p_nextwaiting;
+  }
+  /* Wake up the selected waiting thread */
+  thr->p_nextwaiting = NULL;
+  restart(thr);
+}
+
+/* Compare-and-swap emulation with a spinlock */
+
+#ifdef TEST_FOR_COMPARE_AND_SWAP
+int __pthread_has_cas = 0;
+#endif
+
+#ifndef HAS_COMPARE_AND_SWAP
+
+static void __pthread_acquire(int * spinlock);
+
+int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
+                               int * spinlock)
+{
+  int res;
+  if (testandset(spinlock)) __pthread_acquire(spinlock);
+  if (*ptr == oldval) {
+    *ptr = newval; res = 1;
+  } else {
+    res = 0;
+  }
+  *spinlock = 0;
+  return res;
+}
+
+/* This function is called if the inlined test-and-set
+   in __pthread_compare_and_swap() failed */
 
 /* The retry strategy is as follows:
    - We test and set the spinlock MAX_SPIN_COUNT times, calling
@@ -40,7 +155,7 @@
    - When nanosleep() returns, we try again, doing MAX_SPIN_COUNT
      sched_yield(), then sleeping again if needed. */
 
-void __pthread_acquire(int * spinlock)
+static void __pthread_acquire(int * spinlock)
 {
   int cnt = 0;
   struct timespec tm;
@@ -57,3 +172,5 @@ void __pthread_acquire(int * spinlock)
     }
   }
 }
+
+#endif
diff --git a/linuxthreads/spinlock.h b/linuxthreads/spinlock.h
index 1707d3e42a..d21a967202 100644
--- a/linuxthreads/spinlock.h
+++ b/linuxthreads/spinlock.h
@@ -1,7 +1,6 @@
 /* Linuxthreads - a simple clone()-based implementation of Posix        */
 /* threads for Linux.                                                   */
-/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) and          */
-/* Richard Henderson (rth@tamu.edu)                                     */
+/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr)              */
 /*                                                                      */
 /* This program is free software; you can redistribute it and/or        */
 /* modify it under the terms of the GNU Library General Public License  */
@@ -13,20 +12,52 @@
 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
 /* GNU Library General Public License for more details.                 */
 
-/* Spin locks */
+/* Internal locks */
 
-extern void __pthread_acquire(int * spinlock);
+extern void __pthread_lock(struct _pthread_fastlock * lock);
+extern int __pthread_trylock(struct _pthread_fastlock * lock);
+extern void __pthread_unlock(struct _pthread_fastlock * lock);
 
-static inline void acquire(int * spinlock)
+static inline void __pthread_init_lock(struct _pthread_fastlock * lock)
 {
-  if (testandset(spinlock)) __pthread_acquire(spinlock);
+  lock->status = 0;
+  lock->spinlock = 0;
 }
 
-static inline void release(int * spinlock)
+#define LOCK_INITIALIZER {0, 0}
+
+#if defined(TEST_FOR_COMPARE_AND_SWAP)
+
+extern int __pthread_has_cas;
+extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
+                                      int * spinlock);
+
+static inline int compare_and_swap(long * ptr, long oldval, long newval,
+                                   int * spinlock)
+{
+  if (__pthread_has_cas)
+    return __compare_and_swap(ptr, oldval, newval);
+  else
+    return __pthread_compare_and_swap(ptr, oldval, newval, spinlock);
+}
+
+#elif defined(HAS_COMPARE_AND_SWAP)
+
+static inline int compare_and_swap(long * ptr, long oldval, long newval,
+                                   int * spinlock)
 {
-#ifndef RELEASE
-  *spinlock = 0;
+  return __compare_and_swap(ptr, oldval, newval);
+}
+
 #else
-  RELEASE(spinlock);
-#endif
+
+extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
+                                      int * spinlock);
+
+static inline int compare_and_swap(long * ptr, long oldval, long newval,
+                                   int * spinlock)
+{
+  return __pthread_compare_and_swap(ptr, oldval, newval, spinlock);
 }
+
+#endif
diff --git a/linuxthreads/sysdeps/i386/pt-machine.h b/linuxthreads/sysdeps/i386/pt-machine.h
index ef4df2a1a3..c2a7d0883f 100644
--- a/linuxthreads/sysdeps/i386/pt-machine.h
+++ b/linuxthreads/sysdeps/i386/pt-machine.h
@@ -1,6 +1,6 @@
 /* Machine-dependent pthreads configuration and inline functions.
    i386 version.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Richard Henderson <rth@tamu.edu>.
 
@@ -45,7 +45,9 @@ register char * stack_pointer __asm__ ("%esp");
    We test dynamically whether it's available or not. */
 
 #define HAS_COMPARE_AND_SWAP
-#define TEST_FOR_COMPARE_AND_SWAP
+#ifndef __i686__
+# define TEST_FOR_COMPARE_AND_SWAP
+#endif
 
 extern inline int
 __compare_and_swap (long int *p, long int oldval, long int newval)
diff --git a/linuxthreads/sysdeps/pthread/pthread.h b/linuxthreads/sysdeps/pthread/pthread.h
index 9f5e9deef2..127e15deef 100644
--- a/linuxthreads/sysdeps/pthread/pthread.h
+++ b/linuxthreads/sysdeps/pthread/pthread.h
@@ -43,21 +43,24 @@ typedef unsigned long int pthread_t;
 /* Thread descriptors */
 typedef struct _pthread_descr_struct *_pthread_descr;
 
-/* Waiting queues (not abstract because mutexes and conditions aren't).  */
-struct _pthread_queue
+/* Fast locks (not abstract because mutexes and conditions aren't abstract). */
+struct _pthread_fastlock
 {
-  _pthread_descr head;		/* First element, or NULL if queue empty.  */
-  _pthread_descr tail;		/* Last element, or NULL if queue empty.  */
+  long status;                  /* "Free" or "taken" or head of waiting list */
+  int spinlock;                 /* For compare-and-swap emulation */
 };
 
 /* Mutexes (not abstract because of PTHREAD_MUTEX_INITIALIZER).  */
+/* (The layout is unnatural to maintain binary compatibility
+    with earlier releases of LinuxThreads.) */
+
 typedef struct
 {
-  int m_spinlock;		/* Spin lock to guarantee mutual exclusion.  */
-  int m_count;			/* 0 if free, > 0 if taken.  */
-  _pthread_descr m_owner;	/* Owner of mutex (for recursive mutexes) */
-  int m_kind;			/* Kind of mutex */
-  struct _pthread_queue m_waiting; /* Threads waiting on this mutex.  */
+  int m_reserved;               /* Reserved for future use */
+  int m_count;                  /* Depth of recursive locking */
+  _pthread_descr m_owner;       /* Owner thread (if recursive or errcheck) */
+  int m_kind;                   /* Mutex kind: fast, recursive or errcheck */
+  struct _pthread_fastlock m_lock; /* Underlying fast lock */
 } pthread_mutex_t;
 
 #define PTHREAD_MUTEX_INITIALIZER \
@@ -68,21 +71,21 @@ typedef struct
 /* Conditions (not abstract because of PTHREAD_COND_INITIALIZER */
 typedef struct
 {
-  int c_spinlock;                  /* Spin lock to protect the queue.  */
-  struct _pthread_queue c_waiting; /* Threads waiting on this condition.  */
+  struct _pthread_fastlock c_lock; /* Protect against concurrent access */
+  _pthread_descr c_waiting;        /* Threads waiting on this condition */
 } pthread_cond_t;
 
-#define PTHREAD_COND_INITIALIZER {0, {0, 0}}
+#define PTHREAD_COND_INITIALIZER {{0, 0}, 0}
 
 #ifdef __USE_UNIX98
 /* Read-write locks.  */
 typedef struct
 {
-  int rw_spinlock;              /* Spin lock to guarantee mutual exclusion */
+  struct _pthread_fastlock rw_lock; /* Lock to guarantee mutual exclusion */
   int rw_readers;               /* Number of readers */
   _pthread_descr rw_writer;     /* Identity of writer, or NULL if none */
-  struct _pthread_queue rw_read_waiting; /* Threads waiting for reading */
-  struct _pthread_queue rw_write_waiting; /* Threads waiting for writing */
+  _pthread_descr rw_read_waiting; /* Threads waiting for reading */
+  _pthread_descr rw_write_waiting; /* Threads waiting for writing */
   int rw_kind;                  /* Reader/Writer preference selection */
   int rw_pshared;               /* Shared between processes or not */
 } pthread_rwlock_t;
@@ -231,7 +234,8 @@ extern int pthread_detach __P ((pthread_t __th));
 /* Functions for handling attributes.  */
 
 /* Initialize thread attribute *ATTR with default attributes
-   (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER).  */
+   (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER,
+    no user-provided stack).  */
 extern int pthread_attr_init __P ((pthread_attr_t *__attr));
 
 /* Destroy thread attribute *ATTR.  */
@@ -288,6 +292,7 @@ extern int __pthread_attr_getguardsize __P ((__const pthread_attr_t *__attr,
 					     size_t *__guardsize));
 extern int pthread_attr_getguardsize __P ((__const pthread_attr_t *__attr,
 					   size_t *__guardsize));
+#endif
 
 /* Set the starting address of the stack of the thread to be created.
    Depending on whether the stack grows up or doen the value must either
@@ -317,7 +322,6 @@ extern int __pthread_attr_getstacksize __P ((__const pthread_attr_t *__attr,
 					     size_t *__stacksize));
 extern int pthread_attr_getstacksize __P ((__const pthread_attr_t *__attr,
 					   size_t *__stacksize));
-#endif
 
 /* Functions for scheduling control. */
 
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h b/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h
index feb4e10c6e..fe68ab7183 100644
--- a/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h
+++ b/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h
@@ -1,5 +1,5 @@
 /* Define POSIX options for Linux.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -82,6 +82,12 @@
 /* We provide priority scheduling for threads.  */
 #define	_POSIX_THREAD_PRIORITY_SCHEDULING	1
 
+/* We support user-defined stack sizes.  */
+#define _POSIX_THREAD_ATTR_STACKSIZE	1
+
+/* We support user-defined stacks.  */
+#define _POSIX_THREAD_ATTR_STACKADDR	1
+
 /* We support POSIX.1b semaphores, but only the non-shared form for now.  */
 /*#define _POSIX_SEMAPHORES	1	XXX We are not quite there now.  */
 
diff --git a/sysdeps/unix/sysv/linux/bits/sched.h b/sysdeps/unix/sysv/linux/bits/sched.h
index 0ac5409172..187039b2dc 100644
--- a/sysdeps/unix/sysv/linux/bits/sched.h
+++ b/sysdeps/unix/sysv/linux/bits/sched.h
@@ -1,6 +1,6 @@
 /* Definitions of constants and data structure for POSIX 1003.1b-1993
    scheduling interface.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -38,10 +38,11 @@ struct sched_param
 /* Cloning flags.  */
 # define CSIGNAL       0x000000ff /* Signal mask to be sent at exit.  */
 # define CLONE_VM      0x00000100 /* Set if VM shared between processes.  */
-# define CLONE_FS      0x00000200 /* Set if fs info shared between processes.*/
-# define CLONE_FILES   0x00000400 /* Set if open files shared between processes*/
+# define CLONE_FS      0x00000200 /* Set if fs info shared between processes.  */
+# define CLONE_FILES   0x00000400 /* Set if open files shared between processes.  */
 # define CLONE_SIGHAND 0x00000800 /* Set if signal handlers shared.  */
 # define CLONE_PID     0x00001000 /* Set if pid shared.  */
+# define CLONE_PTRACE  0x00002000 /* Set if tracing continues on the child.  */
 #endif