diff options
Diffstat (limited to 'lib/libthr/thread/thr_suspend_np.c')
-rw-r--r-- | lib/libthr/thread/thr_suspend_np.c | 45 |
1 files changed, 42 insertions, 3 deletions
diff --git a/lib/libthr/thread/thr_suspend_np.c b/lib/libthr/thread/thr_suspend_np.c index d5868e8..284619d 100644 --- a/lib/libthr/thread/thr_suspend_np.c +++ b/lib/libthr/thread/thr_suspend_np.c @@ -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); |