1*8a16b7a1SPedro F. Giffuni /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro F. Giffuni * 4bb535300SJeff Roberson * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. 5bb535300SJeff Roberson * All rights reserved. 6bb535300SJeff Roberson * 7bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without 8bb535300SJeff Roberson * modification, are permitted provided that the following conditions 9bb535300SJeff Roberson * are met: 10bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright 11bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer. 12bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 13bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 14bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 15fed32d75SWarner Losh * 3. Neither the name of the author nor the names of any co-contributors 16bb535300SJeff Roberson * may be used to endorse or promote products derived from this software 17bb535300SJeff Roberson * without specific prior written permission. 18bb535300SJeff Roberson * 19bb535300SJeff Roberson * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 20bb535300SJeff Roberson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21bb535300SJeff Roberson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22bb535300SJeff Roberson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23bb535300SJeff Roberson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24bb535300SJeff Roberson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25bb535300SJeff Roberson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26bb535300SJeff Roberson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27bb535300SJeff Roberson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28bb535300SJeff Roberson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29bb535300SJeff Roberson * SUCH DAMAGE. 30bb535300SJeff Roberson */ 31a091d823SDavid Xu 3232793011SKonstantin Belousov #include <sys/cdefs.h> 3332793011SKonstantin Belousov __FBSDID("$FreeBSD$"); 3432793011SKonstantin Belousov 3537a6356bSDavid Xu #include "namespace.h" 36bb535300SJeff Roberson #include <errno.h> 37bb535300SJeff Roberson #include <pthread.h> 3837a6356bSDavid Xu #include <pthread_np.h> 3937a6356bSDavid Xu #include "un-namespace.h" 40a091d823SDavid Xu 41bb535300SJeff Roberson #include "thr_private.h" 42bb535300SJeff Roberson 43bc414752SDavid Xu static int suspend_common(struct pthread *, struct pthread *, 44bc414752SDavid Xu int); 45a091d823SDavid Xu 46bb535300SJeff Roberson __weak_reference(_pthread_suspend_np, pthread_suspend_np); 47bb535300SJeff Roberson __weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np); 48bb535300SJeff Roberson 49bb535300SJeff Roberson /* Suspend a thread: */ 50bb535300SJeff Roberson int 51bb535300SJeff Roberson _pthread_suspend_np(pthread_t thread) 52bb535300SJeff Roberson { 53a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 54a091d823SDavid Xu int ret; 55a091d823SDavid Xu 56a091d823SDavid Xu /* Suspending the current thread doesn't make sense. */ 57a091d823SDavid Xu if (thread == _get_curthread()) 58a091d823SDavid Xu ret = EDEADLK; 59a091d823SDavid Xu 60a091d823SDavid Xu /* Add a reference to the thread: */ 61a091d823SDavid Xu else if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) 62a091d823SDavid Xu == 0) { 63a091d823SDavid Xu /* Lock the threads scheduling queue: */ 64a091d823SDavid Xu THR_THREAD_LOCK(curthread, thread); 65bc414752SDavid Xu suspend_common(curthread, thread, 1); 66a091d823SDavid Xu /* Unlock the threads scheduling queue: */ 67a091d823SDavid Xu THR_THREAD_UNLOCK(curthread, thread); 68a091d823SDavid Xu 69a091d823SDavid Xu /* Don't forget to remove the reference: */ 70a091d823SDavid Xu _thr_ref_delete(curthread, thread); 71a091d823SDavid Xu } 72a091d823SDavid Xu return (ret); 73bb535300SJeff Roberson } 74bb535300SJeff Roberson 75bb535300SJeff Roberson void 76a7b84c65SDavid Xu _thr_suspend_all_lock(struct pthread *curthread) 77a7b84c65SDavid Xu { 78a7b84c65SDavid Xu int old; 79a7b84c65SDavid Xu 80a7b84c65SDavid Xu THR_LOCK_ACQUIRE(curthread, &_suspend_all_lock); 81a7b84c65SDavid Xu while (_single_thread != NULL) { 82a7b84c65SDavid Xu old = _suspend_all_cycle; 83a7b84c65SDavid Xu _suspend_all_waiters++; 84a7b84c65SDavid Xu THR_LOCK_RELEASE(curthread, &_suspend_all_lock); 85a7b84c65SDavid Xu _thr_umtx_wait_uint(&_suspend_all_cycle, old, NULL, 0); 86a7b84c65SDavid Xu THR_LOCK_ACQUIRE(curthread, &_suspend_all_lock); 87a7b84c65SDavid Xu _suspend_all_waiters--; 88a7b84c65SDavid Xu } 89a7b84c65SDavid Xu _single_thread = curthread; 90a7b84c65SDavid Xu THR_LOCK_RELEASE(curthread, &_suspend_all_lock); 91a7b84c65SDavid Xu } 92a7b84c65SDavid Xu 93a7b84c65SDavid Xu void 94a7b84c65SDavid Xu _thr_suspend_all_unlock(struct pthread *curthread) 95a7b84c65SDavid Xu { 96a7b84c65SDavid Xu 97a7b84c65SDavid Xu THR_LOCK_ACQUIRE(curthread, &_suspend_all_lock); 98a7b84c65SDavid Xu _single_thread = NULL; 99a7b84c65SDavid Xu if (_suspend_all_waiters != 0) { 100a7b84c65SDavid Xu _suspend_all_cycle++; 101a7b84c65SDavid Xu _thr_umtx_wake(&_suspend_all_cycle, INT_MAX, 0); 102a7b84c65SDavid Xu } 103a7b84c65SDavid Xu THR_LOCK_RELEASE(curthread, &_suspend_all_lock); 104a7b84c65SDavid Xu } 105a7b84c65SDavid Xu 106a7b84c65SDavid Xu void 107bb535300SJeff Roberson _pthread_suspend_all_np(void) 108bb535300SJeff Roberson { 109a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 110a091d823SDavid Xu struct pthread *thread; 111a7b84c65SDavid Xu int old_nocancel; 112bc414752SDavid Xu int ret; 113a091d823SDavid Xu 114a7b84c65SDavid Xu old_nocancel = curthread->no_cancel; 115a7b84c65SDavid Xu curthread->no_cancel = 1; 116a7b84c65SDavid Xu _thr_suspend_all_lock(curthread); 117a9b764e2SDavid Xu THREAD_LIST_RDLOCK(curthread); 118a091d823SDavid Xu TAILQ_FOREACH(thread, &_thread_list, tle) { 119a091d823SDavid Xu if (thread != curthread) { 120a091d823SDavid Xu THR_THREAD_LOCK(curthread, thread); 1210d29c148SDavid Xu if (thread->state != PS_DEAD && 1220d29c148SDavid Xu !(thread->flags & THR_FLAGS_SUSPENDED)) 1230d29c148SDavid Xu thread->flags |= THR_FLAGS_NEED_SUSPEND; 1240d29c148SDavid Xu THR_THREAD_UNLOCK(curthread, thread); 1250d29c148SDavid Xu } 1260d29c148SDavid Xu } 1270d29c148SDavid Xu thr_kill(-1, SIGCANCEL); 1280d29c148SDavid Xu 1290d29c148SDavid Xu restart: 1300d29c148SDavid Xu TAILQ_FOREACH(thread, &_thread_list, tle) { 1310d29c148SDavid Xu if (thread != curthread) { 132bc414752SDavid Xu /* First try to suspend the thread without waiting */ 1330d29c148SDavid Xu THR_THREAD_LOCK(curthread, thread); 134bc414752SDavid Xu ret = suspend_common(curthread, thread, 0); 135bc414752SDavid Xu if (ret == 0) { 136bc414752SDavid Xu THREAD_LIST_UNLOCK(curthread); 137a9b764e2SDavid Xu /* Can not suspend, try to wait */ 138a9b764e2SDavid Xu THR_REF_ADD(curthread, thread); 139bc414752SDavid Xu suspend_common(curthread, thread, 1); 140a9b764e2SDavid Xu THR_REF_DEL(curthread, thread); 141a9b764e2SDavid Xu _thr_try_gc(curthread, thread); 142a9b764e2SDavid Xu /* thread lock released */ 143a9b764e2SDavid Xu 144a9b764e2SDavid Xu THREAD_LIST_RDLOCK(curthread); 145bc414752SDavid Xu /* 146bc414752SDavid Xu * Because we were blocked, things may have 147bc414752SDavid Xu * been changed, we have to restart the 148bc414752SDavid Xu * process. 149bc414752SDavid Xu */ 150bc414752SDavid Xu goto restart; 151bc414752SDavid Xu } 152a091d823SDavid Xu THR_THREAD_UNLOCK(curthread, thread); 153a091d823SDavid Xu } 154a091d823SDavid Xu } 155a091d823SDavid Xu THREAD_LIST_UNLOCK(curthread); 156a7b84c65SDavid Xu _thr_suspend_all_unlock(curthread); 157a7b84c65SDavid Xu curthread->no_cancel = old_nocancel; 158a7b84c65SDavid Xu _thr_testcancel(curthread); 159a091d823SDavid Xu } 160a091d823SDavid Xu 161bc414752SDavid Xu static int 162bc414752SDavid Xu suspend_common(struct pthread *curthread, struct pthread *thread, 163bc414752SDavid Xu int waitok) 164a091d823SDavid Xu { 165a7b84c65SDavid Xu uint32_t tmp; 166bc414752SDavid Xu 167bc414752SDavid Xu while (thread->state != PS_DEAD && 168bc414752SDavid Xu !(thread->flags & THR_FLAGS_SUSPENDED)) { 169a091d823SDavid Xu thread->flags |= THR_FLAGS_NEED_SUSPEND; 170a7b84c65SDavid Xu /* Thread is in creation. */ 171a7b84c65SDavid Xu if (thread->tid == TID_TERMINATED) 172a7b84c65SDavid Xu return (1); 173bab012a9SDavid Xu tmp = thread->cycle; 174a091d823SDavid Xu _thr_send_sig(thread, SIGCANCEL); 175a9b764e2SDavid Xu THR_THREAD_UNLOCK(curthread, thread); 176bc414752SDavid Xu if (waitok) { 1778d6a11a0SDavid Xu _thr_umtx_wait_uint(&thread->cycle, tmp, NULL, 0); 178bc414752SDavid Xu THR_THREAD_LOCK(curthread, thread); 179bc414752SDavid Xu } else { 1800d29c148SDavid Xu THR_THREAD_LOCK(curthread, thread); 181bc414752SDavid Xu return (0); 182a091d823SDavid Xu } 183bb535300SJeff Roberson } 184bc414752SDavid Xu 185bc414752SDavid Xu return (1); 186bc414752SDavid Xu } 187