Author: davidxu
Date: Sat Aug 11 23:17:02 2012
New Revision: 239200
URL: http://svn.freebsd.org/changeset/base/239200

Log:
  MFp4:
  Further decreases unexpected context switches by defering mutex wakeup
  until internal sleep queue lock is released.

Modified:
  head/lib/libthr/thread/thr_cond.c
  head/lib/libthr/thread/thr_kern.c
  head/lib/libthr/thread/thr_mutex.c
  head/lib/libthr/thread/thr_private.h
  head/lib/libthr/thread/thr_umtx.h

Modified: head/lib/libthr/thread/thr_cond.c
==============================================================================
--- head/lib/libthr/thread/thr_cond.c   Sat Aug 11 22:39:27 2012        
(r239199)
+++ head/lib/libthr/thread/thr_cond.c   Sat Aug 11 23:17:02 2012        
(r239200)
@@ -217,6 +217,7 @@ cond_wait_user(struct pthread_cond *cvp,
        struct sleepqueue *sq;
        int     recurse;
        int     error;
+       int     defered;
 
        if (curthread->wchan != NULL)
                PANIC("thread was already on queue.");
@@ -230,13 +231,23 @@ cond_wait_user(struct pthread_cond *cvp,
         * us to check it without locking in pthread_cond_signal().
         */
        cvp->__has_user_waiters = 1; 
-       curthread->will_sleep = 1;
-       (void)_mutex_cv_unlock(mp, &recurse);
+       defered = 0;
+       (void)_mutex_cv_unlock(mp, &recurse, &defered);
        curthread->mutex_obj = mp;
        _sleepq_add(cvp, curthread);
        for(;;) {
                _thr_clear_wake(curthread);
                _sleepq_unlock(cvp);
+               if (defered) {
+                       if ((mp->m_lock.m_owner & UMUTEX_CONTESTED) == 0)
+                               (void)_umtx_op_err(&mp->m_lock, 
UMTX_OP_MUTEX_WAKE2,
+                                        mp->m_lock.m_flags, 0, 0);
+               }
+               if (curthread->nwaiter_defer > 0) {
+                       _thr_wake_all(curthread->defer_waiters,
+                               curthread->nwaiter_defer);
+                       curthread->nwaiter_defer = 0;
+               }
 
                if (cancel) {
                        _thr_cancel_enter2(curthread, 0);

Modified: head/lib/libthr/thread/thr_kern.c
==============================================================================
--- head/lib/libthr/thread/thr_kern.c   Sat Aug 11 22:39:27 2012        
(r239199)
+++ head/lib/libthr/thread/thr_kern.c   Sat Aug 11 23:17:02 2012        
(r239200)
@@ -199,13 +199,6 @@ _thr_sleep(struct pthread *curthread, in
        const struct timespec *abstime)
 {
 
-       curthread->will_sleep = 0;
-       if (curthread->nwaiter_defer > 0) {
-               _thr_wake_all(curthread->defer_waiters,
-                       curthread->nwaiter_defer);
-               curthread->nwaiter_defer = 0;
-       }
-
        if (curthread->wake_addr->value != 0)
                return (0);
 

Modified: head/lib/libthr/thread/thr_mutex.c
==============================================================================
--- head/lib/libthr/thread/thr_mutex.c  Sat Aug 11 22:39:27 2012        
(r239199)
+++ head/lib/libthr/thread/thr_mutex.c  Sat Aug 11 23:17:02 2012        
(r239200)
@@ -92,7 +92,7 @@ int   __pthread_mutex_setyieldloops_np(pth
 static int     mutex_self_trylock(pthread_mutex_t);
 static int     mutex_self_lock(pthread_mutex_t,
                                const struct timespec *abstime);
-static int     mutex_unlock_common(struct pthread_mutex *, int);
+static int     mutex_unlock_common(struct pthread_mutex *, int, int *);
 static int     mutex_lock_sleep(struct pthread *, pthread_mutex_t,
                                const struct timespec *);
 
@@ -461,7 +461,7 @@ _pthread_mutex_unlock(pthread_mutex_t *m
        struct pthread_mutex *mp;
 
        mp = *mutex;
-       return (mutex_unlock_common(mp, 0));
+       return (mutex_unlock_common(mp, 0, NULL));
 }
 
 int
@@ -476,7 +476,7 @@ _mutex_cv_lock(struct pthread_mutex *m, 
 }
 
 int
-_mutex_cv_unlock(struct pthread_mutex *m, int *count)
+_mutex_cv_unlock(struct pthread_mutex *m, int *count, int *defer)
 {
 
        /*
@@ -484,7 +484,7 @@ _mutex_cv_unlock(struct pthread_mutex *m
         */
        *count = m->m_count;
        m->m_count = 0;
-       (void)mutex_unlock_common(m, 1);
+       (void)mutex_unlock_common(m, 1, defer);
         return (0);
 }
 
@@ -629,7 +629,7 @@ mutex_self_lock(struct pthread_mutex *m,
 }
 
 static int
-mutex_unlock_common(struct pthread_mutex *m, int cv)
+mutex_unlock_common(struct pthread_mutex *m, int cv, int *mtx_defer)
 {
        struct pthread *curthread = _get_curthread();
        uint32_t id;
@@ -657,12 +657,12 @@ mutex_unlock_common(struct pthread_mutex
                        defered = 1;
                        m->m_flags &= ~PMUTEX_FLAG_DEFERED;
                } else
-                       defered = 0;
+                       defered = 0;
 
                DEQUEUE_MUTEX(curthread, m);
-               _thr_umutex_unlock(&m->m_lock, id);
+               _thr_umutex_unlock2(&m->m_lock, id, mtx_defer);
 
-               if (curthread->will_sleep == 0 && defered)  {
+               if (mtx_defer == NULL && defered)  {
                        _thr_wake_all(curthread->defer_waiters,
                                curthread->nwaiter_defer);
                        curthread->nwaiter_defer = 0;

Modified: head/lib/libthr/thread/thr_private.h
==============================================================================
--- head/lib/libthr/thread/thr_private.h        Sat Aug 11 22:39:27 2012        
(r239199)
+++ head/lib/libthr/thread/thr_private.h        Sat Aug 11 23:17:02 2012        
(r239200)
@@ -727,10 +727,10 @@ extern struct umutex      _thr_event_lock __h
  */
 __BEGIN_DECLS
 int    _thr_setthreaded(int) __hidden;
-int    _mutex_cv_lock(struct pthread_mutex *, int count) __hidden;
-int    _mutex_cv_unlock(struct pthread_mutex *, int *count) __hidden;
-int     _mutex_cv_attach(struct pthread_mutex *, int count) __hidden;
-int     _mutex_cv_detach(struct pthread_mutex *, int *count) __hidden;
+int    _mutex_cv_lock(struct pthread_mutex *, int) __hidden;
+int    _mutex_cv_unlock(struct pthread_mutex *, int *, int *) __hidden;
+int     _mutex_cv_attach(struct pthread_mutex *, int) __hidden;
+int     _mutex_cv_detach(struct pthread_mutex *, int *) __hidden;
 int     _mutex_owned(struct pthread *, const struct pthread_mutex *) __hidden;
 int    _mutex_reinit(pthread_mutex_t *) __hidden;
 void   _mutex_fork(struct pthread *curthread) __hidden;

Modified: head/lib/libthr/thread/thr_umtx.h
==============================================================================
--- head/lib/libthr/thread/thr_umtx.h   Sat Aug 11 22:39:27 2012        
(r239199)
+++ head/lib/libthr/thread/thr_umtx.h   Sat Aug 11 23:17:02 2012        
(r239200)
@@ -120,7 +120,7 @@ _thr_umutex_timedlock(struct umutex *mtx
 }
 
 static inline int
-_thr_umutex_unlock(struct umutex *mtx, uint32_t id)
+_thr_umutex_unlock2(struct umutex *mtx, uint32_t id, int *defer)
 {
        uint32_t flags = mtx->m_flags;
 
@@ -132,8 +132,12 @@ _thr_umutex_unlock(struct umutex *mtx, u
                                return (EPERM);
                } while (__predict_false(!atomic_cmpset_rel_32(&mtx->m_owner,
                                         owner, UMUTEX_UNOWNED)));
-               if ((owner & UMUTEX_CONTESTED))
-                       (void)_umtx_op_err(mtx, UMTX_OP_MUTEX_WAKE2, flags, 0, 
0);
+               if ((owner & UMUTEX_CONTESTED)) {
+                       if (defer == NULL)
+                               (void)_umtx_op_err(mtx, UMTX_OP_MUTEX_WAKE2, 
flags, 0, 0);
+                       else
+                               *defer = 1;
+               }
                return (0);
        }
        if (atomic_cmpset_rel_32(&mtx->m_owner, id, UMUTEX_UNOWNED))
@@ -142,6 +146,12 @@ _thr_umutex_unlock(struct umutex *mtx, u
 }
 
 static inline int
+_thr_umutex_unlock(struct umutex *mtx, uint32_t id)
+{
+       return _thr_umutex_unlock2(mtx, id, NULL);
+}
+
+static inline int
 _thr_rwlock_tryrdlock(struct urwlock *rwlock, int flags)
 {
        int32_t state;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to