17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
547eb4d1eSsl108498 * Common Development and Distribution License (the "License").
647eb4d1eSsl108498 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21*6eb30ec3SRoger A. Faulkner
227c478bd9Sstevel@tonic-gate /*
23*6eb30ec3SRoger A. Faulkner * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include <sys/param.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <sys/systm.h>
337c478bd9Sstevel@tonic-gate #include <sys/prsystm.h>
347c478bd9Sstevel@tonic-gate #include <sys/cred.h>
357c478bd9Sstevel@tonic-gate #include <sys/errno.h>
367c478bd9Sstevel@tonic-gate #include <sys/proc.h>
377c478bd9Sstevel@tonic-gate #include <sys/signal.h>
387c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
397c478bd9Sstevel@tonic-gate #include <sys/unistd.h>
407c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
417c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
427c478bd9Sstevel@tonic-gate #include <sys/debug.h>
437c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h>
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate kthread_t *
idtot(proc_t * p,id_t lwpid)467c478bd9Sstevel@tonic-gate idtot(proc_t *p, id_t lwpid)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate lwpdir_t *ldp;
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) != NULL)
517c478bd9Sstevel@tonic-gate return (ldp->ld_entry->le_thread);
527c478bd9Sstevel@tonic-gate return (NULL);
537c478bd9Sstevel@tonic-gate }
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate /*
56*6eb30ec3SRoger A. Faulkner * Same as idtot(), but acquire and return
57*6eb30ec3SRoger A. Faulkner * the tid hash table entry lock on success.
58*6eb30ec3SRoger A. Faulkner * This allows lwp_unpark() to do its job without acquiring
59*6eb30ec3SRoger A. Faulkner * p->p_lock (and thereby causing congestion problems when
60*6eb30ec3SRoger A. Faulkner * the application calls lwp_unpark() too often).
61*6eb30ec3SRoger A. Faulkner */
62*6eb30ec3SRoger A. Faulkner static kthread_t *
idtot_and_lock(proc_t * p,id_t lwpid,kmutex_t ** mpp)63*6eb30ec3SRoger A. Faulkner idtot_and_lock(proc_t *p, id_t lwpid, kmutex_t **mpp)
64*6eb30ec3SRoger A. Faulkner {
65*6eb30ec3SRoger A. Faulkner lwpdir_t *ldp;
66*6eb30ec3SRoger A. Faulkner kthread_t *t;
67*6eb30ec3SRoger A. Faulkner
68*6eb30ec3SRoger A. Faulkner if ((ldp = lwp_hash_lookup_and_lock(p, lwpid, mpp)) != NULL) {
69*6eb30ec3SRoger A. Faulkner if ((t = ldp->ld_entry->le_thread) == NULL)
70*6eb30ec3SRoger A. Faulkner mutex_exit(*mpp);
71*6eb30ec3SRoger A. Faulkner return (t);
72*6eb30ec3SRoger A. Faulkner }
73*6eb30ec3SRoger A. Faulkner return (NULL);
74*6eb30ec3SRoger A. Faulkner }
75*6eb30ec3SRoger A. Faulkner
76*6eb30ec3SRoger A. Faulkner /*
777c478bd9Sstevel@tonic-gate * Stop an lwp of the current process
787c478bd9Sstevel@tonic-gate */
797c478bd9Sstevel@tonic-gate int
syslwp_suspend(id_t lwpid)807c478bd9Sstevel@tonic-gate syslwp_suspend(id_t lwpid)
817c478bd9Sstevel@tonic-gate {
827c478bd9Sstevel@tonic-gate kthread_t *t;
837c478bd9Sstevel@tonic-gate int error;
847c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
877c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL)
887c478bd9Sstevel@tonic-gate error = ESRCH;
897c478bd9Sstevel@tonic-gate else
907c478bd9Sstevel@tonic-gate error = lwp_suspend(t);
917c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
927c478bd9Sstevel@tonic-gate if (error)
937c478bd9Sstevel@tonic-gate return (set_errno(error));
947c478bd9Sstevel@tonic-gate return (0);
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate int
syslwp_continue(id_t lwpid)987c478bd9Sstevel@tonic-gate syslwp_continue(id_t lwpid)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate kthread_t *t;
1017c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
1047c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) {
1057c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
1067c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate lwp_continue(t);
1097c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
1107c478bd9Sstevel@tonic-gate return (0);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate int
lwp_kill(id_t lwpid,int sig)1147c478bd9Sstevel@tonic-gate lwp_kill(id_t lwpid, int sig)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate sigqueue_t *sqp;
1177c478bd9Sstevel@tonic-gate kthread_t *t;
1187c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate if (sig < 0 || sig >= NSIG)
1217c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
1227c478bd9Sstevel@tonic-gate if (sig != 0)
1237c478bd9Sstevel@tonic-gate sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
1247c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
1257c478bd9Sstevel@tonic-gate if ((t = idtot(p, lwpid)) == NULL) {
1267c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
1277c478bd9Sstevel@tonic-gate if (sig != 0)
1287c478bd9Sstevel@tonic-gate kmem_free(sqp, sizeof (sigqueue_t));
1297c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate if (sig == 0) {
1327c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
1337c478bd9Sstevel@tonic-gate return (0);
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate sqp->sq_info.si_signo = sig;
1367c478bd9Sstevel@tonic-gate sqp->sq_info.si_code = SI_LWP;
1377c478bd9Sstevel@tonic-gate sqp->sq_info.si_pid = p->p_pid;
1387c478bd9Sstevel@tonic-gate sqp->sq_info.si_ctid = PRCTID(p);
1397c478bd9Sstevel@tonic-gate sqp->sq_info.si_zoneid = getzoneid();
1407c478bd9Sstevel@tonic-gate sqp->sq_info.si_uid = crgetruid(CRED());
1417c478bd9Sstevel@tonic-gate sigaddqa(p, t, sqp);
1427c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
1437c478bd9Sstevel@tonic-gate return (0);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate * This is the specification of lwp_wait() from the _lwp_wait(2) manual page:
1487c478bd9Sstevel@tonic-gate *
1497c478bd9Sstevel@tonic-gate * The lwp_wait() function blocks the current lwp until the lwp specified
1507c478bd9Sstevel@tonic-gate * by 'lwpid' terminates. If the specified lwp terminated prior to the call
1517c478bd9Sstevel@tonic-gate * to lwp_wait(), then lwp_wait() returns immediately. If 'lwpid' is zero,
1527c478bd9Sstevel@tonic-gate * then lwp_wait() waits for any undetached lwp in the current process.
1537c478bd9Sstevel@tonic-gate * If 'lwpid' is not zero, then it must specify an undetached lwp in the
1547c478bd9Sstevel@tonic-gate * current process. If 'departed' is not NULL, then it points to a location
1557c478bd9Sstevel@tonic-gate * where the id of the exited lwp is stored.
1567c478bd9Sstevel@tonic-gate *
1577c478bd9Sstevel@tonic-gate * When an lwp exits and there are one or more lwps in the process waiting
1587c478bd9Sstevel@tonic-gate * for this specific lwp to exit, then one of the waiting lwps is unblocked
1597c478bd9Sstevel@tonic-gate * and it returns from lwp_wait() successfully. Any other lwps waiting for
1607c478bd9Sstevel@tonic-gate * this same lwp to exit are also unblocked, however, they return from
1617c478bd9Sstevel@tonic-gate * lwp_wait() with the error ESRCH. If there are no lwps in the process
1627c478bd9Sstevel@tonic-gate * waiting for this specific lwp to exit but there are one or more lwps
1637c478bd9Sstevel@tonic-gate * waiting for any lwp to exit, then one of the waiting lwps is unblocked
1647c478bd9Sstevel@tonic-gate * and it returns from lwp_wait() successfully.
1657c478bd9Sstevel@tonic-gate *
1667c478bd9Sstevel@tonic-gate * If an lwp is waiting for any lwp to exit, it blocks until an undetached
1677c478bd9Sstevel@tonic-gate * lwp for which no other lwp is waiting terminates, at which time it returns
1687c478bd9Sstevel@tonic-gate * successfully, or until all other lwps in the process are either daemon
1697c478bd9Sstevel@tonic-gate * lwps or lwps waiting in lwp_wait(), in which case it returns EDEADLK.
1707c478bd9Sstevel@tonic-gate */
1717c478bd9Sstevel@tonic-gate int
lwp_wait(id_t lwpid,id_t * departed)1727c478bd9Sstevel@tonic-gate lwp_wait(id_t lwpid, id_t *departed)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
1757c478bd9Sstevel@tonic-gate int error = 0;
1767c478bd9Sstevel@tonic-gate int daemon = (curthread->t_proc_flag & TP_DAEMON)? 1 : 0;
1777c478bd9Sstevel@tonic-gate lwpent_t *target_lep;
1787c478bd9Sstevel@tonic-gate lwpdir_t *ldp;
1797c478bd9Sstevel@tonic-gate lwpent_t *lep;
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate * lwp_wait() is not supported for the /proc agent lwp.
1837c478bd9Sstevel@tonic-gate */
1847c478bd9Sstevel@tonic-gate if (curthread == p->p_agenttp)
1857c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP));
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
1887c478bd9Sstevel@tonic-gate prbarrier(p);
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate curthread->t_waitfor = lwpid;
1917c478bd9Sstevel@tonic-gate p->p_lwpwait++;
1927c478bd9Sstevel@tonic-gate p->p_lwpdwait += daemon;
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate if (lwpid != 0) {
1957c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL)
1967c478bd9Sstevel@tonic-gate target_lep = NULL;
1977c478bd9Sstevel@tonic-gate else {
1987c478bd9Sstevel@tonic-gate target_lep = ldp->ld_entry;
1997c478bd9Sstevel@tonic-gate target_lep->le_waiters++;
2007c478bd9Sstevel@tonic-gate target_lep->le_dwaiters += daemon;
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate while (error == 0) {
2057c478bd9Sstevel@tonic-gate kthread_t *t;
2067c478bd9Sstevel@tonic-gate id_t tid;
2077c478bd9Sstevel@tonic-gate int i;
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate if (lwpid != 0) {
2107c478bd9Sstevel@tonic-gate /*
2117c478bd9Sstevel@tonic-gate * Look for a specific zombie lwp.
2127c478bd9Sstevel@tonic-gate */
2137c478bd9Sstevel@tonic-gate if (target_lep == NULL)
2147c478bd9Sstevel@tonic-gate error = ESRCH;
2157c478bd9Sstevel@tonic-gate else if ((t = target_lep->le_thread) != NULL) {
2167c478bd9Sstevel@tonic-gate if (!(t->t_proc_flag & TP_TWAIT))
2177c478bd9Sstevel@tonic-gate error = EINVAL;
2187c478bd9Sstevel@tonic-gate } else {
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate * We found the zombie we are waiting for.
2217c478bd9Sstevel@tonic-gate */
2227c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0);
2237c478bd9Sstevel@tonic-gate p->p_zombcnt--;
2247c478bd9Sstevel@tonic-gate p->p_lwpwait--;
2257c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon;
2267c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1;
2277c478bd9Sstevel@tonic-gate lwp_hash_out(p, lwpid);
2287c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
2297c478bd9Sstevel@tonic-gate if (departed != NULL &&
2307c478bd9Sstevel@tonic-gate copyout(&lwpid, departed, sizeof (id_t)))
2317c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
2327c478bd9Sstevel@tonic-gate return (0);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate } else {
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate * Look for any zombie lwp.
2377c478bd9Sstevel@tonic-gate */
2387c478bd9Sstevel@tonic-gate int some_non_daemon_will_return = 0;
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate /* for each entry in the lwp directory... */
2417c478bd9Sstevel@tonic-gate ldp = p->p_lwpdir;
2427c478bd9Sstevel@tonic-gate for (i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate if ((lep = ldp->ld_entry) == NULL ||
2457c478bd9Sstevel@tonic-gate lep->le_thread != NULL)
2467c478bd9Sstevel@tonic-gate continue;
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate * We found a zombie lwp. If there is some
2507c478bd9Sstevel@tonic-gate * other thread waiting specifically for the
2517c478bd9Sstevel@tonic-gate * zombie we just found, then defer to the other
2527c478bd9Sstevel@tonic-gate * waiting thread and continue searching for
2537c478bd9Sstevel@tonic-gate * another zombie. Also check to see if there
2547c478bd9Sstevel@tonic-gate * is some non-daemon thread sleeping here in
2557c478bd9Sstevel@tonic-gate * lwp_wait() that will succeed and return when
2567c478bd9Sstevel@tonic-gate * we drop p->p_lock. This is tested below.
2577c478bd9Sstevel@tonic-gate */
2587c478bd9Sstevel@tonic-gate tid = lep->le_lwpid;
2597c478bd9Sstevel@tonic-gate if (lep->le_waiters != 0) {
2607c478bd9Sstevel@tonic-gate if (lep->le_waiters - lep->le_dwaiters)
2617c478bd9Sstevel@tonic-gate some_non_daemon_will_return = 1;
2627c478bd9Sstevel@tonic-gate continue;
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate * We found a zombie that no one else
2677c478bd9Sstevel@tonic-gate * is specifically waiting for.
2687c478bd9Sstevel@tonic-gate */
2697c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0);
2707c478bd9Sstevel@tonic-gate p->p_zombcnt--;
2717c478bd9Sstevel@tonic-gate p->p_lwpwait--;
2727c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon;
2737c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1;
2747c478bd9Sstevel@tonic-gate lwp_hash_out(p, tid);
2757c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
2767c478bd9Sstevel@tonic-gate if (departed != NULL &&
2777c478bd9Sstevel@tonic-gate copyout(&tid, departed, sizeof (id_t)))
2787c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
2797c478bd9Sstevel@tonic-gate return (0);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate * We are waiting for anyone. If all non-daemon lwps
2847c478bd9Sstevel@tonic-gate * are waiting here, and if we determined above that
2857c478bd9Sstevel@tonic-gate * no non-daemon lwp will return, we have deadlock.
2867c478bd9Sstevel@tonic-gate */
2877c478bd9Sstevel@tonic-gate if (!some_non_daemon_will_return &&
2887c478bd9Sstevel@tonic-gate p->p_lwpcnt == p->p_lwpdaemon +
2897c478bd9Sstevel@tonic-gate (p->p_lwpwait - p->p_lwpdwait))
2907c478bd9Sstevel@tonic-gate error = EDEADLK;
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate if (error == 0 && lwpid != 0) {
2947c478bd9Sstevel@tonic-gate /*
2957c478bd9Sstevel@tonic-gate * We are waiting for a specific non-zombie lwp.
2967c478bd9Sstevel@tonic-gate * Fail if there is a deadlock loop.
2977c478bd9Sstevel@tonic-gate */
2987c478bd9Sstevel@tonic-gate for (;;) {
2997c478bd9Sstevel@tonic-gate if (t == curthread) {
3007c478bd9Sstevel@tonic-gate error = EDEADLK;
3017c478bd9Sstevel@tonic-gate break;
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate /* who is he waiting for? */
3047c478bd9Sstevel@tonic-gate if ((tid = t->t_waitfor) == -1)
3057c478bd9Sstevel@tonic-gate break;
3067c478bd9Sstevel@tonic-gate if (tid == 0) {
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate * The lwp we are waiting for is
3097c478bd9Sstevel@tonic-gate * waiting for anyone (transitively).
3107c478bd9Sstevel@tonic-gate * If there are no zombies right now
3117c478bd9Sstevel@tonic-gate * and if we would have deadlock due
3127c478bd9Sstevel@tonic-gate * to all non-daemon lwps waiting here,
3137c478bd9Sstevel@tonic-gate * wake up the lwp that is waiting for
3147c478bd9Sstevel@tonic-gate * anyone so it can return EDEADLK.
3157c478bd9Sstevel@tonic-gate */
3167c478bd9Sstevel@tonic-gate if (p->p_zombcnt == 0 &&
3177c478bd9Sstevel@tonic-gate p->p_lwpcnt == p->p_lwpdaemon +
3187c478bd9Sstevel@tonic-gate p->p_lwpwait - p->p_lwpdwait)
3197c478bd9Sstevel@tonic-gate cv_broadcast(&p->p_lwpexit);
3207c478bd9Sstevel@tonic-gate break;
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, tid)) == NULL ||
3237c478bd9Sstevel@tonic-gate (t = ldp->ld_entry->le_thread) == NULL)
3247c478bd9Sstevel@tonic-gate break;
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate if (error)
3297c478bd9Sstevel@tonic-gate break;
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate * Wait for some lwp to terminate.
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate if (!cv_wait_sig(&p->p_lwpexit, &p->p_lock))
3357c478bd9Sstevel@tonic-gate error = EINTR;
3367c478bd9Sstevel@tonic-gate prbarrier(p);
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate if (lwpid != 0) {
3397c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL)
3407c478bd9Sstevel@tonic-gate target_lep = NULL;
3417c478bd9Sstevel@tonic-gate else
3427c478bd9Sstevel@tonic-gate target_lep = ldp->ld_entry;
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate if (lwpid != 0 && target_lep != NULL) {
3477c478bd9Sstevel@tonic-gate target_lep->le_waiters--;
3487c478bd9Sstevel@tonic-gate target_lep->le_dwaiters -= daemon;
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate p->p_lwpwait--;
3517c478bd9Sstevel@tonic-gate p->p_lwpdwait -= daemon;
3527c478bd9Sstevel@tonic-gate curthread->t_waitfor = -1;
3537c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
3547c478bd9Sstevel@tonic-gate return (set_errno(error));
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate int
lwp_detach(id_t lwpid)3587c478bd9Sstevel@tonic-gate lwp_detach(id_t lwpid)
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate kthread_t *t;
3617c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
3627c478bd9Sstevel@tonic-gate lwpdir_t *ldp;
3637c478bd9Sstevel@tonic-gate int error = 0;
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
3667c478bd9Sstevel@tonic-gate prbarrier(p);
3677c478bd9Sstevel@tonic-gate if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL)
3687c478bd9Sstevel@tonic-gate error = ESRCH;
3697c478bd9Sstevel@tonic-gate else if ((t = ldp->ld_entry->le_thread) != NULL) {
3707c478bd9Sstevel@tonic-gate if (!(t->t_proc_flag & TP_TWAIT))
3717c478bd9Sstevel@tonic-gate error = EINVAL;
3727c478bd9Sstevel@tonic-gate else {
3737c478bd9Sstevel@tonic-gate t->t_proc_flag &= ~TP_TWAIT;
3747c478bd9Sstevel@tonic-gate cv_broadcast(&p->p_lwpexit);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate } else {
3777c478bd9Sstevel@tonic-gate ASSERT(p->p_zombcnt > 0);
3787c478bd9Sstevel@tonic-gate p->p_zombcnt--;
3797c478bd9Sstevel@tonic-gate lwp_hash_out(p, lwpid);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate if (error)
3847c478bd9Sstevel@tonic-gate return (set_errno(error));
3857c478bd9Sstevel@tonic-gate return (0);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate * Unpark the specified lwp.
3907c478bd9Sstevel@tonic-gate */
3917c478bd9Sstevel@tonic-gate static int
lwp_unpark(id_t lwpid)3927c478bd9Sstevel@tonic-gate lwp_unpark(id_t lwpid)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
3957c478bd9Sstevel@tonic-gate kthread_t *t;
396*6eb30ec3SRoger A. Faulkner kmutex_t *mp;
3977c478bd9Sstevel@tonic-gate int error = 0;
3987c478bd9Sstevel@tonic-gate
399*6eb30ec3SRoger A. Faulkner if ((t = idtot_and_lock(p, lwpid, &mp)) == NULL) {
4007c478bd9Sstevel@tonic-gate error = ESRCH;
401*6eb30ec3SRoger A. Faulkner } else {
4027c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock);
4037c478bd9Sstevel@tonic-gate t->t_unpark = 1;
4047c478bd9Sstevel@tonic-gate cv_signal(&t->t_delay_cv);
4057c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock);
406*6eb30ec3SRoger A. Faulkner mutex_exit(mp);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate return (error);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate /*
41247eb4d1eSsl108498 * Cancel a previous unpark for the specified lwp.
41347eb4d1eSsl108498 *
41447eb4d1eSsl108498 * This interface exists ONLY to support older versions of libthread, which
41547eb4d1eSsl108498 * called lwp_unpark(self) to force calls to lwp_park(self) to return
41647eb4d1eSsl108498 * immediately. These older libthreads required a mechanism to cancel the
41747eb4d1eSsl108498 * lwp_unpark(self).
41847eb4d1eSsl108498 *
41947eb4d1eSsl108498 * libc does not call this interface. Instead, the sc_park flag in the
42047eb4d1eSsl108498 * schedctl page is cleared to force calls to lwp_park() to return
42147eb4d1eSsl108498 * immediately.
42247eb4d1eSsl108498 */
42347eb4d1eSsl108498 static int
lwp_unpark_cancel(id_t lwpid)42447eb4d1eSsl108498 lwp_unpark_cancel(id_t lwpid)
42547eb4d1eSsl108498 {
42647eb4d1eSsl108498 proc_t *p = ttoproc(curthread);
42747eb4d1eSsl108498 kthread_t *t;
428*6eb30ec3SRoger A. Faulkner kmutex_t *mp;
42947eb4d1eSsl108498 int error = 0;
43047eb4d1eSsl108498
431*6eb30ec3SRoger A. Faulkner if ((t = idtot_and_lock(p, lwpid, &mp)) == NULL) {
43247eb4d1eSsl108498 error = ESRCH;
43347eb4d1eSsl108498 } else {
43447eb4d1eSsl108498 mutex_enter(&t->t_delay_lock);
43547eb4d1eSsl108498 t->t_unpark = 0;
43647eb4d1eSsl108498 mutex_exit(&t->t_delay_lock);
437*6eb30ec3SRoger A. Faulkner mutex_exit(mp);
43847eb4d1eSsl108498 }
43947eb4d1eSsl108498 return (error);
44047eb4d1eSsl108498 }
44147eb4d1eSsl108498
44247eb4d1eSsl108498 /*
4437c478bd9Sstevel@tonic-gate * Sleep until we are set running by lwp_unpark() or until we are
4447c478bd9Sstevel@tonic-gate * interrupted by a signal or until we exhaust our timeout.
4457c478bd9Sstevel@tonic-gate * timeoutp is an in/out parameter. On entry, it contains the relative
4467c478bd9Sstevel@tonic-gate * time until timeout. On exit, we copyout the residual time left to it.
4477c478bd9Sstevel@tonic-gate */
4487c478bd9Sstevel@tonic-gate static int
lwp_park(timespec_t * timeoutp,id_t lwpid)4497c478bd9Sstevel@tonic-gate lwp_park(timespec_t *timeoutp, id_t lwpid)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate timespec_t rqtime;
4527c478bd9Sstevel@tonic-gate timespec_t rmtime;
4537c478bd9Sstevel@tonic-gate timespec_t now;
4547c478bd9Sstevel@tonic-gate timespec_t *rqtp = NULL;
4557c478bd9Sstevel@tonic-gate kthread_t *t = curthread;
4563348528fSdm120769 int timecheck = 0;
4577c478bd9Sstevel@tonic-gate int error = 0;
4587c478bd9Sstevel@tonic-gate model_t datamodel = ttoproc(t)->p_model;
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate if (lwpid != 0) /* unpark the other lwp, if any */
4617c478bd9Sstevel@tonic-gate (void) lwp_unpark(lwpid);
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate if (timeoutp) {
4643348528fSdm120769 timecheck = timechanged;
4657c478bd9Sstevel@tonic-gate gethrestime(&now);
4667c478bd9Sstevel@tonic-gate if (datamodel == DATAMODEL_NATIVE) {
4677c478bd9Sstevel@tonic-gate if (copyin(timeoutp, &rqtime, sizeof (timespec_t))) {
4687c478bd9Sstevel@tonic-gate error = EFAULT;
4697c478bd9Sstevel@tonic-gate goto out;
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate } else {
4727c478bd9Sstevel@tonic-gate timespec32_t timeout32;
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate if (copyin(timeoutp, &timeout32, sizeof (timeout32))) {
4757c478bd9Sstevel@tonic-gate error = EFAULT;
4767c478bd9Sstevel@tonic-gate goto out;
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate TIMESPEC32_TO_TIMESPEC(&rqtime, &timeout32)
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate if (itimerspecfix(&rqtime)) {
4827c478bd9Sstevel@tonic-gate error = EINVAL;
4837c478bd9Sstevel@tonic-gate goto out;
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate * Convert the timespec value into absolute time.
4877c478bd9Sstevel@tonic-gate */
4887c478bd9Sstevel@tonic-gate timespecadd(&rqtime, &now);
4897c478bd9Sstevel@tonic-gate rqtp = &rqtime;
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate (void) new_mstate(t, LMS_USER_LOCK);
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock);
4957c478bd9Sstevel@tonic-gate if (!schedctl_is_park())
4967c478bd9Sstevel@tonic-gate error = EINTR;
4977c478bd9Sstevel@tonic-gate while (error == 0 && t->t_unpark == 0) {
4987c478bd9Sstevel@tonic-gate switch (cv_waituntil_sig(&t->t_delay_cv,
4993348528fSdm120769 &t->t_delay_lock, rqtp, timecheck)) {
5007c478bd9Sstevel@tonic-gate case 0:
5017c478bd9Sstevel@tonic-gate error = EINTR;
5027c478bd9Sstevel@tonic-gate break;
5037c478bd9Sstevel@tonic-gate case -1:
5047c478bd9Sstevel@tonic-gate error = ETIME;
5057c478bd9Sstevel@tonic-gate break;
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate t->t_unpark = 0;
5097c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock);
5107c478bd9Sstevel@tonic-gate
5117c478bd9Sstevel@tonic-gate if (timeoutp != NULL) {
5127c478bd9Sstevel@tonic-gate rmtime.tv_sec = rmtime.tv_nsec = 0;
5137c478bd9Sstevel@tonic-gate if (error != ETIME) {
5147c478bd9Sstevel@tonic-gate gethrestime(&now);
5157c478bd9Sstevel@tonic-gate if ((now.tv_sec < rqtime.tv_sec) ||
5167c478bd9Sstevel@tonic-gate ((now.tv_sec == rqtime.tv_sec) &&
5177c478bd9Sstevel@tonic-gate (now.tv_nsec < rqtime.tv_nsec))) {
5187c478bd9Sstevel@tonic-gate rmtime = rqtime;
5197c478bd9Sstevel@tonic-gate timespecsub(&rmtime, &now);
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate if (datamodel == DATAMODEL_NATIVE) {
5237c478bd9Sstevel@tonic-gate if (copyout(&rmtime, timeoutp, sizeof (rmtime)))
5247c478bd9Sstevel@tonic-gate error = EFAULT;
5257c478bd9Sstevel@tonic-gate } else {
5267c478bd9Sstevel@tonic-gate timespec32_t rmtime32;
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&rmtime32, &rmtime);
5297c478bd9Sstevel@tonic-gate if (copyout(&rmtime32, timeoutp, sizeof (rmtime32)))
5307c478bd9Sstevel@tonic-gate error = EFAULT;
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate out:
5347c478bd9Sstevel@tonic-gate schedctl_unpark();
5357c478bd9Sstevel@tonic-gate if (t->t_mstate == LMS_USER_LOCK)
5367c478bd9Sstevel@tonic-gate (void) new_mstate(t, LMS_SYSTEM);
5377c478bd9Sstevel@tonic-gate return (error);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate #define MAXLWPIDS 1024
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate * Unpark all of the specified lwps.
5447c478bd9Sstevel@tonic-gate * Do it in chunks of MAXLWPIDS to avoid allocating too much memory.
5457c478bd9Sstevel@tonic-gate */
5467c478bd9Sstevel@tonic-gate static int
lwp_unpark_all(id_t * lwpidp,int nids)5477c478bd9Sstevel@tonic-gate lwp_unpark_all(id_t *lwpidp, int nids)
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
5507c478bd9Sstevel@tonic-gate kthread_t *t;
551*6eb30ec3SRoger A. Faulkner kmutex_t *mp;
5527c478bd9Sstevel@tonic-gate int error = 0;
5537c478bd9Sstevel@tonic-gate id_t *lwpid;
5547c478bd9Sstevel@tonic-gate size_t lwpidsz;
5557c478bd9Sstevel@tonic-gate int n;
5567c478bd9Sstevel@tonic-gate int i;
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate if (nids <= 0)
5597c478bd9Sstevel@tonic-gate return (EINVAL);
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate lwpidsz = MIN(nids, MAXLWPIDS) * sizeof (id_t);
5627c478bd9Sstevel@tonic-gate lwpid = kmem_alloc(lwpidsz, KM_SLEEP);
5637c478bd9Sstevel@tonic-gate while (nids > 0) {
5647c478bd9Sstevel@tonic-gate n = MIN(nids, MAXLWPIDS);
5657c478bd9Sstevel@tonic-gate if (copyin(lwpidp, lwpid, n * sizeof (id_t))) {
5667c478bd9Sstevel@tonic-gate error = EFAULT;
5677c478bd9Sstevel@tonic-gate break;
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) {
570*6eb30ec3SRoger A. Faulkner if ((t = idtot_and_lock(p, lwpid[i], &mp)) == NULL) {
5717c478bd9Sstevel@tonic-gate error = ESRCH;
572*6eb30ec3SRoger A. Faulkner } else {
5737c478bd9Sstevel@tonic-gate mutex_enter(&t->t_delay_lock);
5747c478bd9Sstevel@tonic-gate t->t_unpark = 1;
5757c478bd9Sstevel@tonic-gate cv_signal(&t->t_delay_cv);
5767c478bd9Sstevel@tonic-gate mutex_exit(&t->t_delay_lock);
577*6eb30ec3SRoger A. Faulkner mutex_exit(mp);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate lwpidp += n;
5817c478bd9Sstevel@tonic-gate nids -= n;
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate kmem_free(lwpid, lwpidsz);
5847c478bd9Sstevel@tonic-gate return (error);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate * SYS_lwp_park() system call.
5897c478bd9Sstevel@tonic-gate */
5907c478bd9Sstevel@tonic-gate int
syslwp_park(int which,uintptr_t arg1,uintptr_t arg2)5917c478bd9Sstevel@tonic-gate syslwp_park(int which, uintptr_t arg1, uintptr_t arg2)
5927c478bd9Sstevel@tonic-gate {
5937c478bd9Sstevel@tonic-gate int error;
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate switch (which) {
5967c478bd9Sstevel@tonic-gate case 0:
5977c478bd9Sstevel@tonic-gate error = lwp_park((timespec_t *)arg1, (id_t)arg2);
5987c478bd9Sstevel@tonic-gate break;
5997c478bd9Sstevel@tonic-gate case 1:
6007c478bd9Sstevel@tonic-gate error = lwp_unpark((id_t)arg1);
6017c478bd9Sstevel@tonic-gate break;
6027c478bd9Sstevel@tonic-gate case 2:
6037c478bd9Sstevel@tonic-gate error = lwp_unpark_all((id_t *)arg1, (int)arg2);
6047c478bd9Sstevel@tonic-gate break;
60547eb4d1eSsl108498 case 3:
60647eb4d1eSsl108498 /*
60747eb4d1eSsl108498 * This subcode is not used by libc. It exists ONLY to
60847eb4d1eSsl108498 * support older versions of libthread which do not use
60947eb4d1eSsl108498 * the sc_park flag in the schedctl page.
61047eb4d1eSsl108498 *
61147eb4d1eSsl108498 * These versions of libthread need to be modifed or emulated
61247eb4d1eSsl108498 * to change calls to syslwp_park(1, tid, 0) to
61347eb4d1eSsl108498 * syslwp_park(3, tid).
61447eb4d1eSsl108498 */
61547eb4d1eSsl108498 error = lwp_unpark_cancel((id_t)arg1);
61647eb4d1eSsl108498 break;
61747eb4d1eSsl108498 case 4:
61847eb4d1eSsl108498 /*
61947eb4d1eSsl108498 * This subcode is not used by libc. It exists ONLY to
62047eb4d1eSsl108498 * support older versions of libthread which do not use
62147eb4d1eSsl108498 * the sc_park flag in the schedctl page.
62247eb4d1eSsl108498 *
62347eb4d1eSsl108498 * These versions of libthread need to be modified or emulated
62447eb4d1eSsl108498 * to change calls to syslwp_park(0, ts, tid) to
62547eb4d1eSsl108498 * syslwp_park(4, ts, tid).
62647eb4d1eSsl108498 */
62747eb4d1eSsl108498 schedctl_set_park();
62847eb4d1eSsl108498 error = lwp_park((timespec_t *)arg1, (id_t)arg2);
62947eb4d1eSsl108498 break;
6307c478bd9Sstevel@tonic-gate default:
6317c478bd9Sstevel@tonic-gate error = EINVAL;
6327c478bd9Sstevel@tonic-gate break;
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate if (error)
6367c478bd9Sstevel@tonic-gate return (set_errno(error));
6377c478bd9Sstevel@tonic-gate return (0);
6387c478bd9Sstevel@tonic-gate }
639