18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro 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
3237a6356bSDavid Xu #include "namespace.h"
33bb535300SJeff Roberson #include <errno.h>
34bb535300SJeff Roberson #include <pthread.h>
3537a6356bSDavid Xu #include <pthread_np.h>
3637a6356bSDavid Xu #include "un-namespace.h"
37a091d823SDavid Xu
38bb535300SJeff Roberson #include "thr_private.h"
39bb535300SJeff Roberson
40bc414752SDavid Xu static int suspend_common(struct pthread *, struct pthread *,
41bc414752SDavid Xu int);
42a091d823SDavid Xu
43bb535300SJeff Roberson __weak_reference(_pthread_suspend_np, pthread_suspend_np);
44*83aafcdcSKyle Evans __weak_reference(_thr_suspend_all_np, pthread_suspend_all_np);
45*83aafcdcSKyle Evans __weak_reference(_thr_suspend_all_np, _pthread_suspend_all_np);
46bb535300SJeff Roberson
47bb535300SJeff Roberson /* Suspend a thread: */
48bb535300SJeff Roberson int
_pthread_suspend_np(pthread_t thread)49bb535300SJeff Roberson _pthread_suspend_np(pthread_t thread)
50bb535300SJeff Roberson {
51a091d823SDavid Xu struct pthread *curthread = _get_curthread();
52a091d823SDavid Xu int ret;
53a091d823SDavid Xu
54a091d823SDavid Xu /* Suspending the current thread doesn't make sense. */
55a091d823SDavid Xu if (thread == _get_curthread())
56a091d823SDavid Xu ret = EDEADLK;
57a091d823SDavid Xu
58a091d823SDavid Xu /* Add a reference to the thread: */
59a091d823SDavid Xu else if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0))
60a091d823SDavid Xu == 0) {
61a091d823SDavid Xu /* Lock the threads scheduling queue: */
62a091d823SDavid Xu THR_THREAD_LOCK(curthread, thread);
63bc414752SDavid Xu suspend_common(curthread, thread, 1);
64a091d823SDavid Xu /* Unlock the threads scheduling queue: */
65a091d823SDavid Xu THR_THREAD_UNLOCK(curthread, thread);
66a091d823SDavid Xu
67a091d823SDavid Xu /* Don't forget to remove the reference: */
68a091d823SDavid Xu _thr_ref_delete(curthread, thread);
69a091d823SDavid Xu }
70a091d823SDavid Xu return (ret);
71bb535300SJeff Roberson }
72bb535300SJeff Roberson
73bb535300SJeff Roberson void
_thr_suspend_all_lock(struct pthread * curthread)74a7b84c65SDavid Xu _thr_suspend_all_lock(struct pthread *curthread)
75a7b84c65SDavid Xu {
76a7b84c65SDavid Xu int old;
77a7b84c65SDavid Xu
78a7b84c65SDavid Xu THR_LOCK_ACQUIRE(curthread, &_suspend_all_lock);
79a7b84c65SDavid Xu while (_single_thread != NULL) {
80a7b84c65SDavid Xu old = _suspend_all_cycle;
81a7b84c65SDavid Xu _suspend_all_waiters++;
82a7b84c65SDavid Xu THR_LOCK_RELEASE(curthread, &_suspend_all_lock);
83a7b84c65SDavid Xu _thr_umtx_wait_uint(&_suspend_all_cycle, old, NULL, 0);
84a7b84c65SDavid Xu THR_LOCK_ACQUIRE(curthread, &_suspend_all_lock);
85a7b84c65SDavid Xu _suspend_all_waiters--;
86a7b84c65SDavid Xu }
87a7b84c65SDavid Xu _single_thread = curthread;
88a7b84c65SDavid Xu THR_LOCK_RELEASE(curthread, &_suspend_all_lock);
89a7b84c65SDavid Xu }
90a7b84c65SDavid Xu
91a7b84c65SDavid Xu void
_thr_suspend_all_unlock(struct pthread * curthread)92a7b84c65SDavid Xu _thr_suspend_all_unlock(struct pthread *curthread)
93a7b84c65SDavid Xu {
94a7b84c65SDavid Xu
95a7b84c65SDavid Xu THR_LOCK_ACQUIRE(curthread, &_suspend_all_lock);
96a7b84c65SDavid Xu _single_thread = NULL;
97a7b84c65SDavid Xu if (_suspend_all_waiters != 0) {
98a7b84c65SDavid Xu _suspend_all_cycle++;
99a7b84c65SDavid Xu _thr_umtx_wake(&_suspend_all_cycle, INT_MAX, 0);
100a7b84c65SDavid Xu }
101a7b84c65SDavid Xu THR_LOCK_RELEASE(curthread, &_suspend_all_lock);
102a7b84c65SDavid Xu }
103a7b84c65SDavid Xu
104a7b84c65SDavid Xu void
_thr_suspend_all_np(void)105*83aafcdcSKyle Evans _thr_suspend_all_np(void)
106bb535300SJeff Roberson {
107a091d823SDavid Xu struct pthread *curthread = _get_curthread();
108a091d823SDavid Xu struct pthread *thread;
109a7b84c65SDavid Xu int old_nocancel;
110bc414752SDavid Xu int ret;
111a091d823SDavid Xu
112a7b84c65SDavid Xu old_nocancel = curthread->no_cancel;
113a7b84c65SDavid Xu curthread->no_cancel = 1;
114a7b84c65SDavid Xu _thr_suspend_all_lock(curthread);
115a9b764e2SDavid Xu THREAD_LIST_RDLOCK(curthread);
116a091d823SDavid Xu TAILQ_FOREACH(thread, &_thread_list, tle) {
117a091d823SDavid Xu if (thread != curthread) {
118a091d823SDavid Xu THR_THREAD_LOCK(curthread, thread);
1190d29c148SDavid Xu if (thread->state != PS_DEAD &&
1200d29c148SDavid Xu !(thread->flags & THR_FLAGS_SUSPENDED))
1210d29c148SDavid Xu thread->flags |= THR_FLAGS_NEED_SUSPEND;
1220d29c148SDavid Xu THR_THREAD_UNLOCK(curthread, thread);
1230d29c148SDavid Xu }
1240d29c148SDavid Xu }
1250d29c148SDavid Xu thr_kill(-1, SIGCANCEL);
1260d29c148SDavid Xu
1270d29c148SDavid Xu restart:
1280d29c148SDavid Xu TAILQ_FOREACH(thread, &_thread_list, tle) {
1290d29c148SDavid Xu if (thread != curthread) {
130bc414752SDavid Xu /* First try to suspend the thread without waiting */
1310d29c148SDavid Xu THR_THREAD_LOCK(curthread, thread);
132bc414752SDavid Xu ret = suspend_common(curthread, thread, 0);
133bc414752SDavid Xu if (ret == 0) {
134bc414752SDavid Xu THREAD_LIST_UNLOCK(curthread);
135a9b764e2SDavid Xu /* Can not suspend, try to wait */
136a9b764e2SDavid Xu THR_REF_ADD(curthread, thread);
137bc414752SDavid Xu suspend_common(curthread, thread, 1);
138a9b764e2SDavid Xu THR_REF_DEL(curthread, thread);
139a9b764e2SDavid Xu _thr_try_gc(curthread, thread);
140a9b764e2SDavid Xu /* thread lock released */
141a9b764e2SDavid Xu
142a9b764e2SDavid Xu THREAD_LIST_RDLOCK(curthread);
143bc414752SDavid Xu /*
144bc414752SDavid Xu * Because we were blocked, things may have
145bc414752SDavid Xu * been changed, we have to restart the
146bc414752SDavid Xu * process.
147bc414752SDavid Xu */
148bc414752SDavid Xu goto restart;
149bc414752SDavid Xu }
150a091d823SDavid Xu THR_THREAD_UNLOCK(curthread, thread);
151a091d823SDavid Xu }
152a091d823SDavid Xu }
153a091d823SDavid Xu THREAD_LIST_UNLOCK(curthread);
154a7b84c65SDavid Xu _thr_suspend_all_unlock(curthread);
155a7b84c65SDavid Xu curthread->no_cancel = old_nocancel;
156a7b84c65SDavid Xu _thr_testcancel(curthread);
157a091d823SDavid Xu }
158a091d823SDavid Xu
159bc414752SDavid Xu static int
suspend_common(struct pthread * curthread,struct pthread * thread,int waitok)160bc414752SDavid Xu suspend_common(struct pthread *curthread, struct pthread *thread,
161bc414752SDavid Xu int waitok)
162a091d823SDavid Xu {
163a7b84c65SDavid Xu uint32_t tmp;
164bc414752SDavid Xu
165bc414752SDavid Xu while (thread->state != PS_DEAD &&
166bc414752SDavid Xu !(thread->flags & THR_FLAGS_SUSPENDED)) {
167a091d823SDavid Xu thread->flags |= THR_FLAGS_NEED_SUSPEND;
168a7b84c65SDavid Xu /* Thread is in creation. */
169a7b84c65SDavid Xu if (thread->tid == TID_TERMINATED)
170a7b84c65SDavid Xu return (1);
171bab012a9SDavid Xu tmp = thread->cycle;
172a091d823SDavid Xu _thr_send_sig(thread, SIGCANCEL);
173a9b764e2SDavid Xu THR_THREAD_UNLOCK(curthread, thread);
174bc414752SDavid Xu if (waitok) {
1758d6a11a0SDavid Xu _thr_umtx_wait_uint(&thread->cycle, tmp, NULL, 0);
176bc414752SDavid Xu THR_THREAD_LOCK(curthread, thread);
177bc414752SDavid Xu } else {
1780d29c148SDavid Xu THR_THREAD_LOCK(curthread, thread);
179bc414752SDavid Xu return (0);
180a091d823SDavid Xu }
181bb535300SJeff Roberson }
182bc414752SDavid Xu
183bc414752SDavid Xu return (1);
184bc414752SDavid Xu }
185