Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-6]: src/lib/libpthread Pull up the following revisions(s) (reques...



details:   https://anonhg.NetBSD.org/src/rev/9a2384f4fbc9
branches:  netbsd-6
changeset: 776575:9a2384f4fbc9
user:      sborrill <sborrill%NetBSD.org@localhost>
date:      Thu Feb 20 13:00:40 2014 +0000

description:
Pull up the following revisions(s) (requested by prlw1 in ticket #1029):
        lib/libpthread/pthread_cond.c:  revision 1.62
        lib/libpthread/pthread_mutex.c: revision 1.57,1.59

Partial fix for thread deadlock commonly observed with named.
Also address PR/44756.

diffstat:

 lib/libpthread/pthread_cond.c  |   14 +++--
 lib/libpthread/pthread_mutex.c |  100 ++++++++++++++++++++++------------------
 2 files changed, 64 insertions(+), 50 deletions(-)

diffs (182 lines):

diff -r efa16f58031e -r 9a2384f4fbc9 lib/libpthread/pthread_cond.c
--- a/lib/libpthread/pthread_cond.c     Fri Feb 14 23:27:34 2014 +0000
+++ b/lib/libpthread/pthread_cond.c     Thu Feb 20 13:00:40 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_cond.c,v 1.56.8.3 2013/04/29 01:50:18 riz Exp $        */
+/*     $NetBSD: pthread_cond.c,v 1.56.8.4 2014/02/20 13:00:40 sborrill Exp $   */
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread_cond.c,v 1.56.8.3 2013/04/29 01:50:18 riz Exp $");
+__RCSID("$NetBSD: pthread_cond.c,v 1.56.8.4 2014/02/20 13:00:40 sborrill Exp $");
 
 #include <errno.h>
 #include <sys/time.h>
@@ -181,10 +181,12 @@
                pthread_mutex_unlock(mutex);
                self->pt_willpark = 0;
                self->pt_blocking++;
-               retval = _lwp_park(abstime, self->pt_unpark,
-                   __UNVOLATILE(&mutex->ptm_waiters),
-                   __UNVOLATILE(&mutex->ptm_waiters));
-               self->pt_unpark = 0;
+               do {
+                       retval = _lwp_park(abstime, self->pt_unpark,
+                           __UNVOLATILE(&mutex->ptm_waiters),
+                           __UNVOLATILE(&mutex->ptm_waiters));
+                       self->pt_unpark = 0;
+               } while (retval == -1 && errno == ESRCH);
                self->pt_blocking--;
                membar_sync();
                pthread_mutex_lock(mutex);
diff -r efa16f58031e -r 9a2384f4fbc9 lib/libpthread/pthread_mutex.c
--- a/lib/libpthread/pthread_mutex.c    Fri Feb 14 23:27:34 2014 +0000
+++ b/lib/libpthread/pthread_mutex.c    Thu Feb 20 13:00:40 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_mutex.c,v 1.51.22.1 2013/04/29 01:50:18 riz Exp $      */
+/*     $NetBSD: pthread_mutex.c,v 1.51.22.2 2014/02/20 13:00:40 sborrill Exp $ */
 
 /*-
  * Copyright (c) 2001, 2003, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -47,7 +47,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread_mutex.c,v 1.51.22.1 2013/04/29 01:50:18 riz Exp $");
+__RCSID("$NetBSD: pthread_mutex.c,v 1.51.22.2 2014/02/20 13:00:40 sborrill Exp $");
 
 #include <sys/types.h>
 #include <sys/lwpctl.h>
@@ -211,11 +211,61 @@
        return owner;
 }
 
+NOINLINE static void
+pthread__mutex_setwaiters(pthread_t self, pthread_mutex_t *ptm)
+{
+       void *new, *owner;
+
+       /*
+        * Note that the mutex can become unlocked before we set
+        * the waiters bit.  If that happens it's not safe to sleep
+        * as we may never be awoken: we must remove the current
+        * thread from the waiters list and try again.
+        *
+        * Because we are doing this atomically, we can't remove
+        * one waiter: we must remove all waiters and awken them,
+        * then sleep in _lwp_park() until we have been awoken. 
+        *
+        * Issue a memory barrier to ensure that we are reading
+        * the value of ptm_owner/pt_mutexwait after we have entered
+        * the waiters list (the CAS itself must be atomic).
+        */
+again:
+       membar_consumer();
+       owner = ptm->ptm_owner;
+
+       if (MUTEX_OWNER(owner) == 0) {
+               pthread__mutex_wakeup(self, ptm);
+               return;
+       }
+       if (!MUTEX_HAS_WAITERS(owner)) {
+               new = (void *)((uintptr_t)owner | MUTEX_WAITERS_BIT);
+               if (atomic_cas_ptr(&ptm->ptm_owner, owner, new) != owner) {
+                       goto again;
+               }
+       }
+
+       /*
+        * Note that pthread_mutex_unlock() can do a non-interlocked CAS.
+        * We cannot know if the presence of the waiters bit is stable
+        * while the holding thread is running.  There are many assumptions;
+        * see sys/kern/kern_mutex.c for details.  In short, we must spin if
+        * we see that the holder is running again.
+        */
+       membar_sync();
+       pthread__mutex_spin(ptm, owner);
+
+       if (membar_consumer(), !MUTEX_HAS_WAITERS(ptm->ptm_owner)) {
+               goto again;
+       }
+}
+
 NOINLINE static int
 pthread__mutex_lock_slow(pthread_mutex_t *ptm)
 {
        void *waiters, *new, *owner, *next;
        pthread_t self;
+       int serrno;
 
        pthread__error(EINVAL, "Invalid mutex",
            ptm->ptm_magic == _PT_MUTEX_MAGIC);
@@ -235,6 +285,7 @@
                        return EDEADLK;
        }
 
+       serrno = errno;
        for (;; owner = ptm->ptm_owner) {
                /* Spin while the owner is running. */
                owner = pthread__mutex_spin(ptm, owner);
@@ -247,6 +298,7 @@
                                next = atomic_cas_ptr(&ptm->ptm_owner, owner,
                                    new);
                                if (next == owner) {
+                                       errno = serrno;
 #ifndef PTHREAD__ATOMIC_IS_MEMBAR
                                        membar_enter();
 #endif
@@ -277,48 +329,8 @@
                                break;
                }
 
-               /*
-                * Set the waiters bit and block.
-                *
-                * Note that the mutex can become unlocked before we set
-                * the waiters bit.  If that happens it's not safe to sleep
-                * as we may never be awoken: we must remove the current
-                * thread from the waiters list and try again.
-                *
-                * Because we are doing this atomically, we can't remove
-                * one waiter: we must remove all waiters and awken them,
-                * then sleep in _lwp_park() until we have been awoken. 
-                *
-                * Issue a memory barrier to ensure that we are reading
-                * the value of ptm_owner/pt_mutexwait after we have entered
-                * the waiters list (the CAS itself must be atomic).
-                */
-               membar_consumer();
-               for (owner = ptm->ptm_owner;; owner = next) {
-                       if (MUTEX_HAS_WAITERS(owner))
-                               break;
-                       if (MUTEX_OWNER(owner) == 0) {
-                               pthread__mutex_wakeup(self, ptm);
-                               break;
-                       }
-                       new = (void *)((uintptr_t)owner | MUTEX_WAITERS_BIT);
-                       next = atomic_cas_ptr(&ptm->ptm_owner, owner, new);
-                       if (next == owner) {
-                               /*
-                                * pthread_mutex_unlock() can do a
-                                * non-interlocked CAS.  We cannot
-                                * know if our attempt to set the
-                                * waiters bit has succeeded while
-                                * the holding thread is running.
-                                * There are many assumptions; see
-                                * sys/kern/kern_mutex.c for details.
-                                * In short, we must spin if we see
-                                * that the holder is running again.
-                                */
-                               membar_sync();
-                               next = pthread__mutex_spin(ptm, owner);
-                       }
-               }
+               /* Set the waiters bit and block. */
+               pthread__mutex_setwaiters(self, ptm);
 
                /*
                 * We may have been awoken by the current thread above,



Home | Main Index | Thread Index | Old Index