svn commit: r239718 - head/lib/libthr/thread
David Xu
davidxu at FreeBSD.org
Mon Aug 27 03:09:40 UTC 2012
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);
More information about the svn-src-head
mailing list