Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Aug 2012 03:09:40 +0000 (UTC)
From:      David Xu <davidxu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r239718 - head/lib/libthr/thread
Message-ID:  <201208270309.q7R39erT029697@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201208270309.q7R39erT029697>