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.
This commit is contained in:
David Xu 2012-08-27 03:09:39 +00:00
parent 62a3930e06
commit a7b84c6512
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=239718
5 changed files with 64 additions and 4 deletions

View File

@ -120,6 +120,10 @@ struct umutex _rwlock_static_lock = DEFAULT_UMUTEX;
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,

View File

@ -721,6 +721,10 @@ extern struct umutex _rwlock_static_lock __hidden;
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, const struct sched_param *) __hidden;
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;

View File

@ -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

View File

@ -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;

View File

@ -69,15 +69,49 @@ _pthread_suspend_np(pthread_t thread)
return (ret);
}
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 @@ _pthread_suspend_all_np(void)
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);