xref: /titanic_44/usr/src/uts/common/syscall/lwpsys.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/prsystm.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/signal.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/unistd.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate kthread_t *
48*7c478bd9Sstevel@tonic-gate idtot(proc_t *p, id_t lwpid)
49*7c478bd9Sstevel@tonic-gate {
50*7c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate 	if ((ldp = lwp_hash_lookup(p, lwpid)) != NULL)
53*7c478bd9Sstevel@tonic-gate 		return (ldp->ld_entry->le_thread);
54*7c478bd9Sstevel@tonic-gate 	return (NULL);
55*7c478bd9Sstevel@tonic-gate }
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /*
58*7c478bd9Sstevel@tonic-gate  * Stop an lwp of the current process
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate int
61*7c478bd9Sstevel@tonic-gate syslwp_suspend(id_t lwpid)
62*7c478bd9Sstevel@tonic-gate {
63*7c478bd9Sstevel@tonic-gate 	kthread_t *t;
64*7c478bd9Sstevel@tonic-gate 	int error;
65*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
68*7c478bd9Sstevel@tonic-gate 	if ((t = idtot(p, lwpid)) == NULL)
69*7c478bd9Sstevel@tonic-gate 		error = ESRCH;
70*7c478bd9Sstevel@tonic-gate 	else
71*7c478bd9Sstevel@tonic-gate 		error = lwp_suspend(t);
72*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
73*7c478bd9Sstevel@tonic-gate 	if (error)
74*7c478bd9Sstevel@tonic-gate 		return (set_errno(error));
75*7c478bd9Sstevel@tonic-gate 	return (0);
76*7c478bd9Sstevel@tonic-gate }
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate int
79*7c478bd9Sstevel@tonic-gate syslwp_continue(id_t lwpid)
80*7c478bd9Sstevel@tonic-gate {
81*7c478bd9Sstevel@tonic-gate 	kthread_t *t;
82*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
85*7c478bd9Sstevel@tonic-gate 	if ((t = idtot(p, lwpid)) == NULL) {
86*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
87*7c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
88*7c478bd9Sstevel@tonic-gate 	}
89*7c478bd9Sstevel@tonic-gate 	lwp_continue(t);
90*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
91*7c478bd9Sstevel@tonic-gate 	return (0);
92*7c478bd9Sstevel@tonic-gate }
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate int
95*7c478bd9Sstevel@tonic-gate lwp_kill(id_t lwpid, int sig)
96*7c478bd9Sstevel@tonic-gate {
97*7c478bd9Sstevel@tonic-gate 	sigqueue_t *sqp;
98*7c478bd9Sstevel@tonic-gate 	kthread_t *t;
99*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	if (sig < 0 || sig >= NSIG)
102*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
103*7c478bd9Sstevel@tonic-gate 	if (sig != 0)
104*7c478bd9Sstevel@tonic-gate 		sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
105*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
106*7c478bd9Sstevel@tonic-gate 	if ((t = idtot(p, lwpid)) == NULL) {
107*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
108*7c478bd9Sstevel@tonic-gate 		if (sig != 0)
109*7c478bd9Sstevel@tonic-gate 			kmem_free(sqp, sizeof (sigqueue_t));
110*7c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
111*7c478bd9Sstevel@tonic-gate 	}
112*7c478bd9Sstevel@tonic-gate 	if (sig == 0) {
113*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
114*7c478bd9Sstevel@tonic-gate 		return (0);
115*7c478bd9Sstevel@tonic-gate 	}
116*7c478bd9Sstevel@tonic-gate 	sqp->sq_info.si_signo = sig;
117*7c478bd9Sstevel@tonic-gate 	sqp->sq_info.si_code = SI_LWP;
118*7c478bd9Sstevel@tonic-gate 	sqp->sq_info.si_pid = p->p_pid;
119*7c478bd9Sstevel@tonic-gate 	sqp->sq_info.si_ctid = PRCTID(p);
120*7c478bd9Sstevel@tonic-gate 	sqp->sq_info.si_zoneid = getzoneid();
121*7c478bd9Sstevel@tonic-gate 	sqp->sq_info.si_uid = crgetruid(CRED());
122*7c478bd9Sstevel@tonic-gate 	sigaddqa(p, t, sqp);
123*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
124*7c478bd9Sstevel@tonic-gate 	return (0);
125*7c478bd9Sstevel@tonic-gate }
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /*
128*7c478bd9Sstevel@tonic-gate  * This is the specification of lwp_wait() from the _lwp_wait(2) manual page:
129*7c478bd9Sstevel@tonic-gate  *
130*7c478bd9Sstevel@tonic-gate  * The lwp_wait() function blocks the current lwp until the lwp specified
131*7c478bd9Sstevel@tonic-gate  * by 'lwpid' terminates.  If the specified lwp terminated prior to the call
132*7c478bd9Sstevel@tonic-gate  * to lwp_wait(), then lwp_wait() returns immediately.  If 'lwpid' is zero,
133*7c478bd9Sstevel@tonic-gate  * then lwp_wait() waits for any undetached lwp in the current process.
134*7c478bd9Sstevel@tonic-gate  * If 'lwpid' is not zero, then it must specify an undetached lwp in the
135*7c478bd9Sstevel@tonic-gate  * current process.  If 'departed' is not NULL, then it points to a location
136*7c478bd9Sstevel@tonic-gate  * where the id of the exited lwp is stored.
137*7c478bd9Sstevel@tonic-gate  *
138*7c478bd9Sstevel@tonic-gate  * When an lwp exits and there are one or more lwps in the process waiting
139*7c478bd9Sstevel@tonic-gate  * for this specific lwp to exit, then one of the waiting lwps is unblocked
140*7c478bd9Sstevel@tonic-gate  * and it returns from lwp_wait() successfully.  Any other lwps waiting for
141*7c478bd9Sstevel@tonic-gate  * this same lwp to exit are also unblocked, however, they return from
142*7c478bd9Sstevel@tonic-gate  * lwp_wait() with the error ESRCH.  If there are no lwps in the process
143*7c478bd9Sstevel@tonic-gate  * waiting for this specific lwp to exit but there are one or more lwps
144*7c478bd9Sstevel@tonic-gate  * waiting for any lwp to exit, then one of the waiting lwps is unblocked
145*7c478bd9Sstevel@tonic-gate  * and it returns from lwp_wait() successfully.
146*7c478bd9Sstevel@tonic-gate  *
147*7c478bd9Sstevel@tonic-gate  * If an lwp is waiting for any lwp to exit, it blocks until an undetached
148*7c478bd9Sstevel@tonic-gate  * lwp for which no other lwp is waiting terminates, at which time it returns
149*7c478bd9Sstevel@tonic-gate  * successfully, or until all other lwps in the process are either daemon
150*7c478bd9Sstevel@tonic-gate  * lwps or lwps waiting in lwp_wait(), in which case it returns EDEADLK.
151*7c478bd9Sstevel@tonic-gate  */
152*7c478bd9Sstevel@tonic-gate int
153*7c478bd9Sstevel@tonic-gate lwp_wait(id_t lwpid, id_t *departed)
154*7c478bd9Sstevel@tonic-gate {
155*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
156*7c478bd9Sstevel@tonic-gate 	int error = 0;
157*7c478bd9Sstevel@tonic-gate 	int daemon = (curthread->t_proc_flag & TP_DAEMON)? 1 : 0;
158*7c478bd9Sstevel@tonic-gate 	lwpent_t *target_lep;
159*7c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
160*7c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	/*
163*7c478bd9Sstevel@tonic-gate 	 * lwp_wait() is not supported for the /proc agent lwp.
164*7c478bd9Sstevel@tonic-gate 	 */
165*7c478bd9Sstevel@tonic-gate 	if (curthread == p->p_agenttp)
166*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENOTSUP));
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
169*7c478bd9Sstevel@tonic-gate 	prbarrier(p);
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	curthread->t_waitfor = lwpid;
172*7c478bd9Sstevel@tonic-gate 	p->p_lwpwait++;
173*7c478bd9Sstevel@tonic-gate 	p->p_lwpdwait += daemon;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	if (lwpid != 0) {
176*7c478bd9Sstevel@tonic-gate 		if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL)
177*7c478bd9Sstevel@tonic-gate 			target_lep = NULL;
178*7c478bd9Sstevel@tonic-gate 		else {
179*7c478bd9Sstevel@tonic-gate 			target_lep = ldp->ld_entry;
180*7c478bd9Sstevel@tonic-gate 			target_lep->le_waiters++;
181*7c478bd9Sstevel@tonic-gate 			target_lep->le_dwaiters += daemon;
182*7c478bd9Sstevel@tonic-gate 		}
183*7c478bd9Sstevel@tonic-gate 	}
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	while (error == 0) {
186*7c478bd9Sstevel@tonic-gate 		kthread_t *t;
187*7c478bd9Sstevel@tonic-gate 		id_t tid;
188*7c478bd9Sstevel@tonic-gate 		int i;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 		if (lwpid != 0) {
191*7c478bd9Sstevel@tonic-gate 			/*
192*7c478bd9Sstevel@tonic-gate 			 * Look for a specific zombie lwp.
193*7c478bd9Sstevel@tonic-gate 			 */
194*7c478bd9Sstevel@tonic-gate 			if (target_lep == NULL)
195*7c478bd9Sstevel@tonic-gate 				error = ESRCH;
196*7c478bd9Sstevel@tonic-gate 			else if ((t = target_lep->le_thread) != NULL) {
197*7c478bd9Sstevel@tonic-gate 				if (!(t->t_proc_flag & TP_TWAIT))
198*7c478bd9Sstevel@tonic-gate 					error = EINVAL;
199*7c478bd9Sstevel@tonic-gate 			} else {
200*7c478bd9Sstevel@tonic-gate 				/*
201*7c478bd9Sstevel@tonic-gate 				 * We found the zombie we are waiting for.
202*7c478bd9Sstevel@tonic-gate 				 */
203*7c478bd9Sstevel@tonic-gate 				ASSERT(p->p_zombcnt > 0);
204*7c478bd9Sstevel@tonic-gate 				p->p_zombcnt--;
205*7c478bd9Sstevel@tonic-gate 				p->p_lwpwait--;
206*7c478bd9Sstevel@tonic-gate 				p->p_lwpdwait -= daemon;
207*7c478bd9Sstevel@tonic-gate 				curthread->t_waitfor = -1;
208*7c478bd9Sstevel@tonic-gate 				lwp_hash_out(p, lwpid);
209*7c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
210*7c478bd9Sstevel@tonic-gate 				if (departed != NULL &&
211*7c478bd9Sstevel@tonic-gate 				    copyout(&lwpid, departed, sizeof (id_t)))
212*7c478bd9Sstevel@tonic-gate 					return (set_errno(EFAULT));
213*7c478bd9Sstevel@tonic-gate 				return (0);
214*7c478bd9Sstevel@tonic-gate 			}
215*7c478bd9Sstevel@tonic-gate 		} else {
216*7c478bd9Sstevel@tonic-gate 			/*
217*7c478bd9Sstevel@tonic-gate 			 * Look for any zombie lwp.
218*7c478bd9Sstevel@tonic-gate 			 */
219*7c478bd9Sstevel@tonic-gate 			int some_non_daemon_will_return = 0;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 			/* for each entry in the lwp directory... */
222*7c478bd9Sstevel@tonic-gate 			ldp = p->p_lwpdir;
223*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 				if ((lep = ldp->ld_entry) == NULL ||
226*7c478bd9Sstevel@tonic-gate 				    lep->le_thread != NULL)
227*7c478bd9Sstevel@tonic-gate 					continue;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 				/*
230*7c478bd9Sstevel@tonic-gate 				 * We found a zombie lwp.  If there is some
231*7c478bd9Sstevel@tonic-gate 				 * other thread waiting specifically for the
232*7c478bd9Sstevel@tonic-gate 				 * zombie we just found, then defer to the other
233*7c478bd9Sstevel@tonic-gate 				 * waiting thread and continue searching for
234*7c478bd9Sstevel@tonic-gate 				 * another zombie.  Also check to see if there
235*7c478bd9Sstevel@tonic-gate 				 * is some non-daemon thread sleeping here in
236*7c478bd9Sstevel@tonic-gate 				 * lwp_wait() that will succeed and return when
237*7c478bd9Sstevel@tonic-gate 				 * we drop p->p_lock.  This is tested below.
238*7c478bd9Sstevel@tonic-gate 				 */
239*7c478bd9Sstevel@tonic-gate 				tid = lep->le_lwpid;
240*7c478bd9Sstevel@tonic-gate 				if (lep->le_waiters != 0) {
241*7c478bd9Sstevel@tonic-gate 					if (lep->le_waiters - lep->le_dwaiters)
242*7c478bd9Sstevel@tonic-gate 						some_non_daemon_will_return = 1;
243*7c478bd9Sstevel@tonic-gate 					continue;
244*7c478bd9Sstevel@tonic-gate 				}
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 				/*
247*7c478bd9Sstevel@tonic-gate 				 * We found a zombie that no one else
248*7c478bd9Sstevel@tonic-gate 				 * is specifically waiting for.
249*7c478bd9Sstevel@tonic-gate 				 */
250*7c478bd9Sstevel@tonic-gate 				ASSERT(p->p_zombcnt > 0);
251*7c478bd9Sstevel@tonic-gate 				p->p_zombcnt--;
252*7c478bd9Sstevel@tonic-gate 				p->p_lwpwait--;
253*7c478bd9Sstevel@tonic-gate 				p->p_lwpdwait -= daemon;
254*7c478bd9Sstevel@tonic-gate 				curthread->t_waitfor = -1;
255*7c478bd9Sstevel@tonic-gate 				lwp_hash_out(p, tid);
256*7c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
257*7c478bd9Sstevel@tonic-gate 				if (departed != NULL &&
258*7c478bd9Sstevel@tonic-gate 				    copyout(&tid, departed, sizeof (id_t)))
259*7c478bd9Sstevel@tonic-gate 					return (set_errno(EFAULT));
260*7c478bd9Sstevel@tonic-gate 				return (0);
261*7c478bd9Sstevel@tonic-gate 			}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 			/*
264*7c478bd9Sstevel@tonic-gate 			 * We are waiting for anyone.  If all non-daemon lwps
265*7c478bd9Sstevel@tonic-gate 			 * are waiting here, and if we determined above that
266*7c478bd9Sstevel@tonic-gate 			 * no non-daemon lwp will return, we have deadlock.
267*7c478bd9Sstevel@tonic-gate 			 */
268*7c478bd9Sstevel@tonic-gate 			if (!some_non_daemon_will_return &&
269*7c478bd9Sstevel@tonic-gate 			    p->p_lwpcnt == p->p_lwpdaemon +
270*7c478bd9Sstevel@tonic-gate 			    (p->p_lwpwait - p->p_lwpdwait))
271*7c478bd9Sstevel@tonic-gate 				error = EDEADLK;
272*7c478bd9Sstevel@tonic-gate 		}
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 		if (error == 0 && lwpid != 0) {
275*7c478bd9Sstevel@tonic-gate 			/*
276*7c478bd9Sstevel@tonic-gate 			 * We are waiting for a specific non-zombie lwp.
277*7c478bd9Sstevel@tonic-gate 			 * Fail if there is a deadlock loop.
278*7c478bd9Sstevel@tonic-gate 			 */
279*7c478bd9Sstevel@tonic-gate 			for (;;) {
280*7c478bd9Sstevel@tonic-gate 				if (t == curthread) {
281*7c478bd9Sstevel@tonic-gate 					error = EDEADLK;
282*7c478bd9Sstevel@tonic-gate 					break;
283*7c478bd9Sstevel@tonic-gate 				}
284*7c478bd9Sstevel@tonic-gate 				/* who is he waiting for? */
285*7c478bd9Sstevel@tonic-gate 				if ((tid = t->t_waitfor) == -1)
286*7c478bd9Sstevel@tonic-gate 					break;
287*7c478bd9Sstevel@tonic-gate 				if (tid == 0) {
288*7c478bd9Sstevel@tonic-gate 					/*
289*7c478bd9Sstevel@tonic-gate 					 * The lwp we are waiting for is
290*7c478bd9Sstevel@tonic-gate 					 * waiting for anyone (transitively).
291*7c478bd9Sstevel@tonic-gate 					 * If there are no zombies right now
292*7c478bd9Sstevel@tonic-gate 					 * and if we would have deadlock due
293*7c478bd9Sstevel@tonic-gate 					 * to all non-daemon lwps waiting here,
294*7c478bd9Sstevel@tonic-gate 					 * wake up the lwp that is waiting for
295*7c478bd9Sstevel@tonic-gate 					 * anyone so it can return EDEADLK.
296*7c478bd9Sstevel@tonic-gate 					 */
297*7c478bd9Sstevel@tonic-gate 					if (p->p_zombcnt == 0 &&
298*7c478bd9Sstevel@tonic-gate 					    p->p_lwpcnt == p->p_lwpdaemon +
299*7c478bd9Sstevel@tonic-gate 					    p->p_lwpwait - p->p_lwpdwait)
300*7c478bd9Sstevel@tonic-gate 						cv_broadcast(&p->p_lwpexit);
301*7c478bd9Sstevel@tonic-gate 					break;
302*7c478bd9Sstevel@tonic-gate 				}
303*7c478bd9Sstevel@tonic-gate 				if ((ldp = lwp_hash_lookup(p, tid)) == NULL ||
304*7c478bd9Sstevel@tonic-gate 				    (t = ldp->ld_entry->le_thread) == NULL)
305*7c478bd9Sstevel@tonic-gate 					break;
306*7c478bd9Sstevel@tonic-gate 			}
307*7c478bd9Sstevel@tonic-gate 		}
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 		if (error)
310*7c478bd9Sstevel@tonic-gate 			break;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 		/*
313*7c478bd9Sstevel@tonic-gate 		 * Wait for some lwp to terminate.
314*7c478bd9Sstevel@tonic-gate 		 */
315*7c478bd9Sstevel@tonic-gate 		if (!cv_wait_sig(&p->p_lwpexit, &p->p_lock))
316*7c478bd9Sstevel@tonic-gate 			error = EINTR;
317*7c478bd9Sstevel@tonic-gate 		prbarrier(p);
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 		if (lwpid != 0) {
320*7c478bd9Sstevel@tonic-gate 			if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL)
321*7c478bd9Sstevel@tonic-gate 				target_lep = NULL;
322*7c478bd9Sstevel@tonic-gate 			else
323*7c478bd9Sstevel@tonic-gate 				target_lep = ldp->ld_entry;
324*7c478bd9Sstevel@tonic-gate 		}
325*7c478bd9Sstevel@tonic-gate 	}
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	if (lwpid != 0 && target_lep != NULL) {
328*7c478bd9Sstevel@tonic-gate 		target_lep->le_waiters--;
329*7c478bd9Sstevel@tonic-gate 		target_lep->le_dwaiters -= daemon;
330*7c478bd9Sstevel@tonic-gate 	}
331*7c478bd9Sstevel@tonic-gate 	p->p_lwpwait--;
332*7c478bd9Sstevel@tonic-gate 	p->p_lwpdwait -= daemon;
333*7c478bd9Sstevel@tonic-gate 	curthread->t_waitfor = -1;
334*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
335*7c478bd9Sstevel@tonic-gate 	return (set_errno(error));
336*7c478bd9Sstevel@tonic-gate }
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate int
339*7c478bd9Sstevel@tonic-gate lwp_detach(id_t lwpid)
340*7c478bd9Sstevel@tonic-gate {
341*7c478bd9Sstevel@tonic-gate 	kthread_t *t;
342*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
343*7c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
344*7c478bd9Sstevel@tonic-gate 	int error = 0;
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
347*7c478bd9Sstevel@tonic-gate 	prbarrier(p);
348*7c478bd9Sstevel@tonic-gate 	if ((ldp = lwp_hash_lookup(p, lwpid)) == NULL)
349*7c478bd9Sstevel@tonic-gate 		error = ESRCH;
350*7c478bd9Sstevel@tonic-gate 	else if ((t = ldp->ld_entry->le_thread) != NULL) {
351*7c478bd9Sstevel@tonic-gate 		if (!(t->t_proc_flag & TP_TWAIT))
352*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
353*7c478bd9Sstevel@tonic-gate 		else {
354*7c478bd9Sstevel@tonic-gate 			t->t_proc_flag &= ~TP_TWAIT;
355*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&p->p_lwpexit);
356*7c478bd9Sstevel@tonic-gate 		}
357*7c478bd9Sstevel@tonic-gate 	} else {
358*7c478bd9Sstevel@tonic-gate 		ASSERT(p->p_zombcnt > 0);
359*7c478bd9Sstevel@tonic-gate 		p->p_zombcnt--;
360*7c478bd9Sstevel@tonic-gate 		lwp_hash_out(p, lwpid);
361*7c478bd9Sstevel@tonic-gate 	}
362*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	if (error)
365*7c478bd9Sstevel@tonic-gate 		return (set_errno(error));
366*7c478bd9Sstevel@tonic-gate 	return (0);
367*7c478bd9Sstevel@tonic-gate }
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate /*
370*7c478bd9Sstevel@tonic-gate  * Unpark the specified lwp.
371*7c478bd9Sstevel@tonic-gate  */
372*7c478bd9Sstevel@tonic-gate static int
373*7c478bd9Sstevel@tonic-gate lwp_unpark(id_t lwpid)
374*7c478bd9Sstevel@tonic-gate {
375*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
376*7c478bd9Sstevel@tonic-gate 	kthread_t *t;
377*7c478bd9Sstevel@tonic-gate 	int error = 0;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
380*7c478bd9Sstevel@tonic-gate 	if ((t = idtot(p, lwpid)) == NULL)
381*7c478bd9Sstevel@tonic-gate 		error = ESRCH;
382*7c478bd9Sstevel@tonic-gate 	else {
383*7c478bd9Sstevel@tonic-gate 		mutex_enter(&t->t_delay_lock);
384*7c478bd9Sstevel@tonic-gate 		t->t_unpark = 1;
385*7c478bd9Sstevel@tonic-gate 		cv_signal(&t->t_delay_cv);
386*7c478bd9Sstevel@tonic-gate 		mutex_exit(&t->t_delay_lock);
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
389*7c478bd9Sstevel@tonic-gate 	return (error);
390*7c478bd9Sstevel@tonic-gate }
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate /*
393*7c478bd9Sstevel@tonic-gate  * Sleep until we are set running by lwp_unpark() or until we are
394*7c478bd9Sstevel@tonic-gate  * interrupted by a signal or until we exhaust our timeout.
395*7c478bd9Sstevel@tonic-gate  * timeoutp is an in/out parameter.  On entry, it contains the relative
396*7c478bd9Sstevel@tonic-gate  * time until timeout.  On exit, we copyout the residual time left to it.
397*7c478bd9Sstevel@tonic-gate  */
398*7c478bd9Sstevel@tonic-gate static int
399*7c478bd9Sstevel@tonic-gate lwp_park(timespec_t *timeoutp, id_t lwpid)
400*7c478bd9Sstevel@tonic-gate {
401*7c478bd9Sstevel@tonic-gate 	timespec_t rqtime;
402*7c478bd9Sstevel@tonic-gate 	timespec_t rmtime;
403*7c478bd9Sstevel@tonic-gate 	timespec_t now;
404*7c478bd9Sstevel@tonic-gate 	timespec_t *rqtp = NULL;
405*7c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
406*7c478bd9Sstevel@tonic-gate 	int timecheck = 0;
407*7c478bd9Sstevel@tonic-gate 	int error = 0;
408*7c478bd9Sstevel@tonic-gate 	model_t datamodel = ttoproc(t)->p_model;
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	if (lwpid != 0)		/* unpark the other lwp, if any */
411*7c478bd9Sstevel@tonic-gate 		(void) lwp_unpark(lwpid);
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	if (timeoutp) {
414*7c478bd9Sstevel@tonic-gate 		timecheck = timechanged;
415*7c478bd9Sstevel@tonic-gate 		gethrestime(&now);
416*7c478bd9Sstevel@tonic-gate 		if (datamodel == DATAMODEL_NATIVE) {
417*7c478bd9Sstevel@tonic-gate 			if (copyin(timeoutp, &rqtime, sizeof (timespec_t))) {
418*7c478bd9Sstevel@tonic-gate 				error = EFAULT;
419*7c478bd9Sstevel@tonic-gate 				goto out;
420*7c478bd9Sstevel@tonic-gate 			}
421*7c478bd9Sstevel@tonic-gate 		} else {
422*7c478bd9Sstevel@tonic-gate 			timespec32_t timeout32;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 			if (copyin(timeoutp, &timeout32, sizeof (timeout32))) {
425*7c478bd9Sstevel@tonic-gate 				error = EFAULT;
426*7c478bd9Sstevel@tonic-gate 				goto out;
427*7c478bd9Sstevel@tonic-gate 			}
428*7c478bd9Sstevel@tonic-gate 			TIMESPEC32_TO_TIMESPEC(&rqtime, &timeout32)
429*7c478bd9Sstevel@tonic-gate 		}
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 		if (itimerspecfix(&rqtime)) {
432*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
433*7c478bd9Sstevel@tonic-gate 			goto out;
434*7c478bd9Sstevel@tonic-gate 		}
435*7c478bd9Sstevel@tonic-gate 		/*
436*7c478bd9Sstevel@tonic-gate 		 * Convert the timespec value into absolute time.
437*7c478bd9Sstevel@tonic-gate 		 */
438*7c478bd9Sstevel@tonic-gate 		timespecadd(&rqtime, &now);
439*7c478bd9Sstevel@tonic-gate 		rqtp = &rqtime;
440*7c478bd9Sstevel@tonic-gate 	}
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	(void) new_mstate(t, LMS_USER_LOCK);
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	mutex_enter(&t->t_delay_lock);
445*7c478bd9Sstevel@tonic-gate 	if (!schedctl_is_park())
446*7c478bd9Sstevel@tonic-gate 		error = EINTR;
447*7c478bd9Sstevel@tonic-gate 	while (error == 0 && t->t_unpark == 0) {
448*7c478bd9Sstevel@tonic-gate 		switch (cv_waituntil_sig(&t->t_delay_cv,
449*7c478bd9Sstevel@tonic-gate 		    &t->t_delay_lock, rqtp, timecheck)) {
450*7c478bd9Sstevel@tonic-gate 		case 0:
451*7c478bd9Sstevel@tonic-gate 			error = EINTR;
452*7c478bd9Sstevel@tonic-gate 			break;
453*7c478bd9Sstevel@tonic-gate 		case -1:
454*7c478bd9Sstevel@tonic-gate 			error = ETIME;
455*7c478bd9Sstevel@tonic-gate 			break;
456*7c478bd9Sstevel@tonic-gate 		}
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 	t->t_unpark = 0;
459*7c478bd9Sstevel@tonic-gate 	mutex_exit(&t->t_delay_lock);
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	if (timeoutp != NULL) {
462*7c478bd9Sstevel@tonic-gate 		rmtime.tv_sec = rmtime.tv_nsec = 0;
463*7c478bd9Sstevel@tonic-gate 		if (error != ETIME) {
464*7c478bd9Sstevel@tonic-gate 			gethrestime(&now);
465*7c478bd9Sstevel@tonic-gate 			if ((now.tv_sec < rqtime.tv_sec) ||
466*7c478bd9Sstevel@tonic-gate 			    ((now.tv_sec == rqtime.tv_sec) &&
467*7c478bd9Sstevel@tonic-gate 			    (now.tv_nsec < rqtime.tv_nsec))) {
468*7c478bd9Sstevel@tonic-gate 				rmtime = rqtime;
469*7c478bd9Sstevel@tonic-gate 				timespecsub(&rmtime, &now);
470*7c478bd9Sstevel@tonic-gate 			}
471*7c478bd9Sstevel@tonic-gate 		}
472*7c478bd9Sstevel@tonic-gate 		if (datamodel == DATAMODEL_NATIVE) {
473*7c478bd9Sstevel@tonic-gate 			if (copyout(&rmtime, timeoutp, sizeof (rmtime)))
474*7c478bd9Sstevel@tonic-gate 				error = EFAULT;
475*7c478bd9Sstevel@tonic-gate 		} else {
476*7c478bd9Sstevel@tonic-gate 			timespec32_t rmtime32;
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 			TIMESPEC_TO_TIMESPEC32(&rmtime32, &rmtime);
479*7c478bd9Sstevel@tonic-gate 			if (copyout(&rmtime32, timeoutp, sizeof (rmtime32)))
480*7c478bd9Sstevel@tonic-gate 				error = EFAULT;
481*7c478bd9Sstevel@tonic-gate 		}
482*7c478bd9Sstevel@tonic-gate 	}
483*7c478bd9Sstevel@tonic-gate out:
484*7c478bd9Sstevel@tonic-gate 	schedctl_unpark();
485*7c478bd9Sstevel@tonic-gate 	if (t->t_mstate == LMS_USER_LOCK)
486*7c478bd9Sstevel@tonic-gate 		(void) new_mstate(t, LMS_SYSTEM);
487*7c478bd9Sstevel@tonic-gate 	return (error);
488*7c478bd9Sstevel@tonic-gate }
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate #define	MAXLWPIDS	1024
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate /*
493*7c478bd9Sstevel@tonic-gate  * Unpark all of the specified lwps.
494*7c478bd9Sstevel@tonic-gate  * Do it in chunks of MAXLWPIDS to avoid allocating too much memory.
495*7c478bd9Sstevel@tonic-gate  */
496*7c478bd9Sstevel@tonic-gate static int
497*7c478bd9Sstevel@tonic-gate lwp_unpark_all(id_t *lwpidp, int nids)
498*7c478bd9Sstevel@tonic-gate {
499*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
500*7c478bd9Sstevel@tonic-gate 	kthread_t *t;
501*7c478bd9Sstevel@tonic-gate 	int error = 0;
502*7c478bd9Sstevel@tonic-gate 	id_t *lwpid;
503*7c478bd9Sstevel@tonic-gate 	size_t lwpidsz;
504*7c478bd9Sstevel@tonic-gate 	int n;
505*7c478bd9Sstevel@tonic-gate 	int i;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	if (nids <= 0)
508*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	lwpidsz = MIN(nids, MAXLWPIDS) * sizeof (id_t);
511*7c478bd9Sstevel@tonic-gate 	lwpid = kmem_alloc(lwpidsz, KM_SLEEP);
512*7c478bd9Sstevel@tonic-gate 	while (nids > 0) {
513*7c478bd9Sstevel@tonic-gate 		n = MIN(nids, MAXLWPIDS);
514*7c478bd9Sstevel@tonic-gate 		if (copyin(lwpidp, lwpid, n * sizeof (id_t))) {
515*7c478bd9Sstevel@tonic-gate 			error = EFAULT;
516*7c478bd9Sstevel@tonic-gate 			break;
517*7c478bd9Sstevel@tonic-gate 		}
518*7c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
519*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < n; i++) {
520*7c478bd9Sstevel@tonic-gate 			if ((t = idtot(p, lwpid[i])) == NULL)
521*7c478bd9Sstevel@tonic-gate 				error = ESRCH;
522*7c478bd9Sstevel@tonic-gate 			else {
523*7c478bd9Sstevel@tonic-gate 				mutex_enter(&t->t_delay_lock);
524*7c478bd9Sstevel@tonic-gate 				t->t_unpark = 1;
525*7c478bd9Sstevel@tonic-gate 				cv_signal(&t->t_delay_cv);
526*7c478bd9Sstevel@tonic-gate 				mutex_exit(&t->t_delay_lock);
527*7c478bd9Sstevel@tonic-gate 			}
528*7c478bd9Sstevel@tonic-gate 		}
529*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
530*7c478bd9Sstevel@tonic-gate 		lwpidp += n;
531*7c478bd9Sstevel@tonic-gate 		nids -= n;
532*7c478bd9Sstevel@tonic-gate 	}
533*7c478bd9Sstevel@tonic-gate 	kmem_free(lwpid, lwpidsz);
534*7c478bd9Sstevel@tonic-gate 	return (error);
535*7c478bd9Sstevel@tonic-gate }
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate /*
538*7c478bd9Sstevel@tonic-gate  * SYS_lwp_park() system call.
539*7c478bd9Sstevel@tonic-gate  */
540*7c478bd9Sstevel@tonic-gate int
541*7c478bd9Sstevel@tonic-gate syslwp_park(int which, uintptr_t arg1, uintptr_t arg2)
542*7c478bd9Sstevel@tonic-gate {
543*7c478bd9Sstevel@tonic-gate 	int error;
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	switch (which) {
546*7c478bd9Sstevel@tonic-gate 	case 0:
547*7c478bd9Sstevel@tonic-gate 		error = lwp_park((timespec_t *)arg1, (id_t)arg2);
548*7c478bd9Sstevel@tonic-gate 		break;
549*7c478bd9Sstevel@tonic-gate 	case 1:
550*7c478bd9Sstevel@tonic-gate 		error = lwp_unpark((id_t)arg1);
551*7c478bd9Sstevel@tonic-gate 		break;
552*7c478bd9Sstevel@tonic-gate 	case 2:
553*7c478bd9Sstevel@tonic-gate 		error = lwp_unpark_all((id_t *)arg1, (int)arg2);
554*7c478bd9Sstevel@tonic-gate 		break;
555*7c478bd9Sstevel@tonic-gate 	default:
556*7c478bd9Sstevel@tonic-gate 		error = EINVAL;
557*7c478bd9Sstevel@tonic-gate 		break;
558*7c478bd9Sstevel@tonic-gate 	}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	if (error)
561*7c478bd9Sstevel@tonic-gate 		return (set_errno(error));
562*7c478bd9Sstevel@tonic-gate 	return (0);
563*7c478bd9Sstevel@tonic-gate }
564