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"