Author: davidxu
Date: Mon Aug 27 03:09:39 2012
New Revision: 239718
URL: http://svn.freebsd.org/changeset/base/239718

Log:
  In suspend_common(), don't wait for a thread which is in creation, because
  pthread_suspend_all_np() may have already suspended its parent thread.
  Add locking code in pthread_suspend_all_np() to only allow one thread
  to suspend other threads, this eliminates a deadlock where two or more
  threads try to suspend each others.

Modified:
  head/lib/libthr/thread/thr_init.c
  head/lib/libthr/thread/thr_private.h
  head/lib/libthr/thread/thr_resume_np.c
  head/lib/libthr/thread/thr_sig.c
  head/lib/libthr/thread/thr_suspend_np.c

Modified: head/lib/libthr/thread/thr_init.c
==============================================================================
--- head/lib/libthr/thread/thr_init.c   Mon Aug 27 02:56:58 2012        
(r239717)
+++ head/lib/libthr/thread/thr_init.c   Mon Aug 27 03:09:39 2012        
(r239718)
@@ -120,6 +120,10 @@ struct umutex      _rwlock_static_lock = DEFA
 struct umutex  _keytable_lock = DEFAULT_UMUTEX;
 struct urwlock _thr_list_lock = DEFAULT_URWLOCK;
 struct umutex  _thr_event_lock = DEFAULT_UMUTEX;
+struct umutex  _suspend_all_lock = DEFAULT_UMUTEX;
+struct pthread *_single_thread;
+int            _suspend_all_cycle;
+int            _suspend_all_waiters;
 
 int    __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
 int    __pthread_mutex_lock(pthread_mutex_t *);
@@ -441,11 +445,14 @@ init_private(void)
        _thr_umutex_init(&_keytable_lock);
        _thr_urwlock_init(&_thr_atfork_lock);
        _thr_umutex_init(&_thr_event_lock);
+       _thr_umutex_init(&_suspend_all_lock);
        _thr_once_init();
        _thr_spinlock_init();
        _thr_list_init();
        _thr_wake_addr_init();
        _sleepq_init();
+       _single_thread = NULL;
+       _suspend_all_waiters = 0;
 
        /*
         * Avoid reinitializing some things if they don't need to be,

Modified: head/lib/libthr/thread/thr_private.h
==============================================================================
--- head/lib/libthr/thread/thr_private.h        Mon Aug 27 02:56:58 2012        
(r239717)
+++ head/lib/libthr/thread/thr_private.h        Mon Aug 27 03:09:39 2012        
(r239718)
@@ -721,6 +721,10 @@ extern struct umutex       _rwlock_static_lock
 extern struct umutex   _keytable_lock __hidden;
 extern struct urwlock  _thr_list_lock __hidden;
 extern struct umutex   _thr_event_lock __hidden;
+extern struct umutex   _suspend_all_lock __hidden;
+extern int             _suspend_all_waiters __hidden;
+extern int             _suspend_all_cycle __hidden;
+extern struct pthread  *_single_thread __hidden;
 
 /*
  * Function prototype definitions.
@@ -777,6 +781,8 @@ int _thr_setscheduler(lwpid_t, int, cons
 void   _thr_signal_prefork(void) __hidden;
 void   _thr_signal_postfork(void) __hidden;
 void   _thr_signal_postfork_child(void) __hidden;
+void   _thr_suspend_all_lock(struct pthread *) __hidden;
+void   _thr_suspend_all_unlock(struct pthread *) __hidden;
 void   _thr_try_gc(struct pthread *, struct pthread *) __hidden;
 int    _rtp_to_schedparam(const struct rtprio *rtp, int *policy,
                struct sched_param *param) __hidden;

Modified: head/lib/libthr/thread/thr_resume_np.c
==============================================================================
--- head/lib/libthr/thread/thr_resume_np.c      Mon Aug 27 02:56:58 2012        
(r239717)
+++ head/lib/libthr/thread/thr_resume_np.c      Mon Aug 27 03:09:39 2012        
(r239718)
@@ -63,7 +63,11 @@ _pthread_resume_all_np(void)
 {
        struct pthread *curthread = _get_curthread();
        struct pthread *thread;
+       int old_nocancel;
 
+       old_nocancel = curthread->no_cancel;
+       curthread->no_cancel = 1;
+       _thr_suspend_all_lock(curthread);
        /* Take the thread list lock: */
        THREAD_LIST_RDLOCK(curthread);
 
@@ -77,6 +81,9 @@ _pthread_resume_all_np(void)
 
        /* Release the thread list lock: */
        THREAD_LIST_UNLOCK(curthread);
+       _thr_suspend_all_unlock(curthread);
+       curthread->no_cancel = old_nocancel;
+       _thr_testcancel(curthread);
 }
 
 static void

Modified: head/lib/libthr/thread/thr_sig.c
==============================================================================
--- head/lib/libthr/thread/thr_sig.c    Mon Aug 27 02:56:58 2012        
(r239717)
+++ head/lib/libthr/thread/thr_sig.c    Mon Aug 27 03:09:39 2012        
(r239718)
@@ -356,7 +356,8 @@ check_suspend(struct pthread *curthread)
                (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
                != THR_FLAGS_NEED_SUSPEND))
                return;
-
+       if (curthread == _single_thread)
+               return;
        if (curthread->force_exit)
                return;
 

Modified: head/lib/libthr/thread/thr_suspend_np.c
==============================================================================
--- head/lib/libthr/thread/thr_suspend_np.c     Mon Aug 27 02:56:58 2012        
(r239717)
+++ head/lib/libthr/thread/thr_suspend_np.c     Mon Aug 27 03:09:39 2012        
(r239718)
@@ -70,14 +70,48 @@ _pthread_suspend_np(pthread_t thread)
 }
 
 void
+_thr_suspend_all_lock(struct pthread *curthread)
+{
+       int old;
+
+       THR_LOCK_ACQUIRE(curthread, &_suspend_all_lock);
+       while (_single_thread != NULL) {
+               old = _suspend_all_cycle;
+               _suspend_all_waiters++;
+               THR_LOCK_RELEASE(curthread, &_suspend_all_lock);
+               _thr_umtx_wait_uint(&_suspend_all_cycle, old, NULL, 0);
+               THR_LOCK_ACQUIRE(curthread, &_suspend_all_lock);
+               _suspend_all_waiters--;
+       }
+       _single_thread = curthread;
+       THR_LOCK_RELEASE(curthread, &_suspend_all_lock);
+}
+
+void
+_thr_suspend_all_unlock(struct pthread *curthread)
+{
+
+       THR_LOCK_ACQUIRE(curthread, &_suspend_all_lock);
+       _single_thread = NULL;
+       if (_suspend_all_waiters != 0) {
+               _suspend_all_cycle++;
+               _thr_umtx_wake(&_suspend_all_cycle, INT_MAX, 0);
+       }
+       THR_LOCK_RELEASE(curthread, &_suspend_all_lock);
+}
+
+void
 _pthread_suspend_all_np(void)
 {
        struct pthread *curthread = _get_curthread();
        struct pthread *thread;
+       int old_nocancel;
        int ret;
 
+       old_nocancel = curthread->no_cancel;
+       curthread->no_cancel = 1;
+       _thr_suspend_all_lock(curthread);
        THREAD_LIST_RDLOCK(curthread);
-
        TAILQ_FOREACH(thread, &_thread_list, tle) {
                if (thread != curthread) {
                        THR_THREAD_LOCK(curthread, thread);
@@ -115,19 +149,24 @@ restart:
                        THR_THREAD_UNLOCK(curthread, thread);
                }
        }
-
        THREAD_LIST_UNLOCK(curthread);
+       _thr_suspend_all_unlock(curthread);
+       curthread->no_cancel = old_nocancel;
+       _thr_testcancel(curthread);
 }
 
 static int
 suspend_common(struct pthread *curthread, struct pthread *thread,
        int waitok)
 {
-       long tmp;
+       uint32_t tmp;
 
        while (thread->state != PS_DEAD &&
              !(thread->flags & THR_FLAGS_SUSPENDED)) {
                thread->flags |= THR_FLAGS_NEED_SUSPEND;
+               /* Thread is in creation. */
+               if (thread->tid == TID_TERMINATED)
+                       return (1);
                tmp = thread->cycle;
                _thr_send_sig(thread, SIGCANCEL);
                THR_THREAD_UNLOCK(curthread, thread);
_______________________________________________
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