xref: /illumos-gate/usr/src/uts/common/os/condvar.c (revision 7c478bd9)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/thread.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/sobject.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/sleepq.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/condvar.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/condvar_impl.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/sdt.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate /*
44*7c478bd9Sstevel@tonic-gate  * CV_MAX_WAITERS is the maximum number of waiters we track; once
45*7c478bd9Sstevel@tonic-gate  * the number becomes higher than that, we look at the sleepq to
46*7c478bd9Sstevel@tonic-gate  * see whether there are *really* any waiters.
47*7c478bd9Sstevel@tonic-gate  */
48*7c478bd9Sstevel@tonic-gate #define	CV_MAX_WAITERS		1024		/* must be power of 2 */
49*7c478bd9Sstevel@tonic-gate #define	CV_WAITERS_MASK		(CV_MAX_WAITERS - 1)
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * Threads don't "own" condition variables.
53*7c478bd9Sstevel@tonic-gate  */
54*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
55*7c478bd9Sstevel@tonic-gate static kthread_t *
56*7c478bd9Sstevel@tonic-gate cv_owner(void *cvp)
57*7c478bd9Sstevel@tonic-gate {
58*7c478bd9Sstevel@tonic-gate 	return (NULL);
59*7c478bd9Sstevel@tonic-gate }
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /*
62*7c478bd9Sstevel@tonic-gate  * Unsleep a thread that's blocked on a condition variable.
63*7c478bd9Sstevel@tonic-gate  */
64*7c478bd9Sstevel@tonic-gate static void
65*7c478bd9Sstevel@tonic-gate cv_unsleep(kthread_t *t)
66*7c478bd9Sstevel@tonic-gate {
67*7c478bd9Sstevel@tonic-gate 	condvar_impl_t *cvp = (condvar_impl_t *)t->t_wchan;
68*7c478bd9Sstevel@tonic-gate 	sleepq_head_t *sqh = SQHASH(cvp);
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	ASSERT(THREAD_LOCK_HELD(t));
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate 	if (cvp == NULL)
73*7c478bd9Sstevel@tonic-gate 		panic("cv_unsleep: thread %p not on sleepq %p", t, sqh);
74*7c478bd9Sstevel@tonic-gate 	sleepq_unsleep(t);
75*7c478bd9Sstevel@tonic-gate 	if (cvp->cv_waiters != CV_MAX_WAITERS)
76*7c478bd9Sstevel@tonic-gate 		cvp->cv_waiters--;
77*7c478bd9Sstevel@tonic-gate 	disp_lock_exit_high(&sqh->sq_lock);
78*7c478bd9Sstevel@tonic-gate 	CL_SETRUN(t);
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * Change the priority of a thread that's blocked on a condition variable.
83*7c478bd9Sstevel@tonic-gate  */
84*7c478bd9Sstevel@tonic-gate static void
85*7c478bd9Sstevel@tonic-gate cv_change_pri(kthread_t *t, pri_t pri, pri_t *t_prip)
86*7c478bd9Sstevel@tonic-gate {
87*7c478bd9Sstevel@tonic-gate 	condvar_impl_t *cvp = (condvar_impl_t *)t->t_wchan;
88*7c478bd9Sstevel@tonic-gate 	sleepq_t *sqp = t->t_sleepq;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	ASSERT(THREAD_LOCK_HELD(t));
91*7c478bd9Sstevel@tonic-gate 	ASSERT(&SQHASH(cvp)->sq_queue == sqp);
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	if (cvp == NULL)
94*7c478bd9Sstevel@tonic-gate 		panic("cv_change_pri: %p not on sleep queue", t);
95*7c478bd9Sstevel@tonic-gate 	sleepq_dequeue(t);
96*7c478bd9Sstevel@tonic-gate 	*t_prip = pri;
97*7c478bd9Sstevel@tonic-gate 	sleepq_insert(sqp, t);
98*7c478bd9Sstevel@tonic-gate }
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate /*
101*7c478bd9Sstevel@tonic-gate  * The sobj_ops vector exports a set of functions needed when a thread
102*7c478bd9Sstevel@tonic-gate  * is asleep on a synchronization object of this type.
103*7c478bd9Sstevel@tonic-gate  */
104*7c478bd9Sstevel@tonic-gate static sobj_ops_t cv_sobj_ops = {
105*7c478bd9Sstevel@tonic-gate 	SOBJ_CV, cv_owner, cv_unsleep, cv_change_pri
106*7c478bd9Sstevel@tonic-gate };
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
109*7c478bd9Sstevel@tonic-gate void
110*7c478bd9Sstevel@tonic-gate cv_init(kcondvar_t *cvp, char *name, kcv_type_t type, void *arg)
111*7c478bd9Sstevel@tonic-gate {
112*7c478bd9Sstevel@tonic-gate 	((condvar_impl_t *)cvp)->cv_waiters = 0;
113*7c478bd9Sstevel@tonic-gate }
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate /*
116*7c478bd9Sstevel@tonic-gate  * cv_destroy is not currently needed, but is part of the DDI.
117*7c478bd9Sstevel@tonic-gate  * This is in case cv_init ever needs to allocate something for a cv.
118*7c478bd9Sstevel@tonic-gate  */
119*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
120*7c478bd9Sstevel@tonic-gate void
121*7c478bd9Sstevel@tonic-gate cv_destroy(kcondvar_t *cvp)
122*7c478bd9Sstevel@tonic-gate {
123*7c478bd9Sstevel@tonic-gate 	ASSERT((((condvar_impl_t *)cvp)->cv_waiters & CV_WAITERS_MASK) == 0);
124*7c478bd9Sstevel@tonic-gate }
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate /*
127*7c478bd9Sstevel@tonic-gate  * The cv_block() function blocks a thread on a condition variable
128*7c478bd9Sstevel@tonic-gate  * by putting it in a hashed sleep queue associated with the
129*7c478bd9Sstevel@tonic-gate  * synchronization object.
130*7c478bd9Sstevel@tonic-gate  *
131*7c478bd9Sstevel@tonic-gate  * Threads are taken off the hashed sleep queues via calls to
132*7c478bd9Sstevel@tonic-gate  * cv_signal(), cv_broadcast(), or cv_unsleep().
133*7c478bd9Sstevel@tonic-gate  */
134*7c478bd9Sstevel@tonic-gate static void
135*7c478bd9Sstevel@tonic-gate cv_block(condvar_impl_t *cvp)
136*7c478bd9Sstevel@tonic-gate {
137*7c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
138*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
139*7c478bd9Sstevel@tonic-gate 	sleepq_head_t *sqh;
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	ASSERT(THREAD_LOCK_HELD(t));
142*7c478bd9Sstevel@tonic-gate 	ASSERT(t != CPU->cpu_idle_thread);
143*7c478bd9Sstevel@tonic-gate 	ASSERT(CPU_ON_INTR(CPU) == 0);
144*7c478bd9Sstevel@tonic-gate 	ASSERT(t->t_wchan0 == NULL && t->t_wchan == NULL);
145*7c478bd9Sstevel@tonic-gate 	ASSERT(t->t_state == TS_ONPROC);
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	t->t_schedflag &= ~TS_SIGNALLED;
148*7c478bd9Sstevel@tonic-gate 	CL_SLEEP(t);			/* assign kernel priority */
149*7c478bd9Sstevel@tonic-gate 	t->t_wchan = (caddr_t)cvp;
150*7c478bd9Sstevel@tonic-gate 	t->t_sobj_ops = &cv_sobj_ops;
151*7c478bd9Sstevel@tonic-gate 	DTRACE_SCHED(sleep);
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 	/*
154*7c478bd9Sstevel@tonic-gate 	 * The check for t_intr is to avoid doing the
155*7c478bd9Sstevel@tonic-gate 	 * account for an interrupt thread on the still-pinned
156*7c478bd9Sstevel@tonic-gate 	 * lwp's statistics.
157*7c478bd9Sstevel@tonic-gate 	 */
158*7c478bd9Sstevel@tonic-gate 	if (lwp != NULL && t->t_intr == NULL) {
159*7c478bd9Sstevel@tonic-gate 		lwp->lwp_ru.nvcsw++;
160*7c478bd9Sstevel@tonic-gate 		(void) new_mstate(t, LMS_SLEEP);
161*7c478bd9Sstevel@tonic-gate 	}
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	sqh = SQHASH(cvp);
164*7c478bd9Sstevel@tonic-gate 	disp_lock_enter_high(&sqh->sq_lock);
165*7c478bd9Sstevel@tonic-gate 	if (cvp->cv_waiters < CV_MAX_WAITERS)
166*7c478bd9Sstevel@tonic-gate 		cvp->cv_waiters++;
167*7c478bd9Sstevel@tonic-gate 	ASSERT(cvp->cv_waiters <= CV_MAX_WAITERS);
168*7c478bd9Sstevel@tonic-gate 	THREAD_SLEEP(t, &sqh->sq_lock);
169*7c478bd9Sstevel@tonic-gate 	sleepq_insert(&sqh->sq_queue, t);
170*7c478bd9Sstevel@tonic-gate 	/*
171*7c478bd9Sstevel@tonic-gate 	 * THREAD_SLEEP() moves curthread->t_lockp to point to the
172*7c478bd9Sstevel@tonic-gate 	 * lock sqh->sq_lock. This lock is later released by the caller
173*7c478bd9Sstevel@tonic-gate 	 * when it calls thread_unlock() on curthread.
174*7c478bd9Sstevel@tonic-gate 	 */
175*7c478bd9Sstevel@tonic-gate }
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate #define	cv_block_sig(t, cvp)	\
178*7c478bd9Sstevel@tonic-gate 	{ (t)->t_flag |= T_WAKEABLE; cv_block(cvp); }
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate /*
181*7c478bd9Sstevel@tonic-gate  * Block on the indicated condition variable and release the
182*7c478bd9Sstevel@tonic-gate  * associated kmutex while blocked.
183*7c478bd9Sstevel@tonic-gate  */
184*7c478bd9Sstevel@tonic-gate void
185*7c478bd9Sstevel@tonic-gate cv_wait(kcondvar_t *cvp, kmutex_t *mp)
186*7c478bd9Sstevel@tonic-gate {
187*7c478bd9Sstevel@tonic-gate 	if (panicstr)
188*7c478bd9Sstevel@tonic-gate 		return;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
191*7c478bd9Sstevel@tonic-gate 	thread_lock(curthread);			/* lock the thread */
192*7c478bd9Sstevel@tonic-gate 	cv_block((condvar_impl_t *)cvp);
193*7c478bd9Sstevel@tonic-gate 	thread_unlock_nopreempt(curthread);	/* unlock the waiters field */
194*7c478bd9Sstevel@tonic-gate 	mutex_exit(mp);
195*7c478bd9Sstevel@tonic-gate 	swtch();
196*7c478bd9Sstevel@tonic-gate 	mutex_enter(mp);
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate /*
200*7c478bd9Sstevel@tonic-gate  * Same as cv_wait except the thread will unblock at 'tim'
201*7c478bd9Sstevel@tonic-gate  * (an absolute time) if it hasn't already unblocked.
202*7c478bd9Sstevel@tonic-gate  *
203*7c478bd9Sstevel@tonic-gate  * Returns the amount of time left from the original 'tim' value
204*7c478bd9Sstevel@tonic-gate  * when it was unblocked.
205*7c478bd9Sstevel@tonic-gate  */
206*7c478bd9Sstevel@tonic-gate clock_t
207*7c478bd9Sstevel@tonic-gate cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t tim)
208*7c478bd9Sstevel@tonic-gate {
209*7c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
210*7c478bd9Sstevel@tonic-gate 	timeout_id_t id;
211*7c478bd9Sstevel@tonic-gate 	clock_t timeleft;
212*7c478bd9Sstevel@tonic-gate 	int signalled;
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	if (panicstr)
215*7c478bd9Sstevel@tonic-gate 		return (-1);
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	timeleft = tim - lbolt;
218*7c478bd9Sstevel@tonic-gate 	if (timeleft <= 0)
219*7c478bd9Sstevel@tonic-gate 		return (-1);
220*7c478bd9Sstevel@tonic-gate 	id = realtime_timeout((void (*)(void *))setrun, t, timeleft);
221*7c478bd9Sstevel@tonic-gate 	thread_lock(t);		/* lock the thread */
222*7c478bd9Sstevel@tonic-gate 	cv_block((condvar_impl_t *)cvp);
223*7c478bd9Sstevel@tonic-gate 	thread_unlock_nopreempt(t);
224*7c478bd9Sstevel@tonic-gate 	mutex_exit(mp);
225*7c478bd9Sstevel@tonic-gate 	if ((tim - lbolt) <= 0)		/* allow for wrap */
226*7c478bd9Sstevel@tonic-gate 		setrun(t);
227*7c478bd9Sstevel@tonic-gate 	swtch();
228*7c478bd9Sstevel@tonic-gate 	signalled = (t->t_schedflag & TS_SIGNALLED);
229*7c478bd9Sstevel@tonic-gate 	/*
230*7c478bd9Sstevel@tonic-gate 	 * Get the time left. untimeout() returns -1 if the timeout has
231*7c478bd9Sstevel@tonic-gate 	 * occured or the time remaining.  If the time remaining is zero,
232*7c478bd9Sstevel@tonic-gate 	 * the timeout has occured between when we were awoken and
233*7c478bd9Sstevel@tonic-gate 	 * we called untimeout.  We will treat this as if the timeout
234*7c478bd9Sstevel@tonic-gate 	 * has occured and set timeleft to -1.
235*7c478bd9Sstevel@tonic-gate 	 */
236*7c478bd9Sstevel@tonic-gate 	timeleft = untimeout(id);
237*7c478bd9Sstevel@tonic-gate 	mutex_enter(mp);
238*7c478bd9Sstevel@tonic-gate 	if (timeleft <= 0) {
239*7c478bd9Sstevel@tonic-gate 		timeleft = -1;
240*7c478bd9Sstevel@tonic-gate 		if (signalled)	/* avoid consuming the cv_signal() */
241*7c478bd9Sstevel@tonic-gate 			cv_signal(cvp);
242*7c478bd9Sstevel@tonic-gate 	}
243*7c478bd9Sstevel@tonic-gate 	return (timeleft);
244*7c478bd9Sstevel@tonic-gate }
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate int
247*7c478bd9Sstevel@tonic-gate cv_wait_sig(kcondvar_t *cvp, kmutex_t *mp)
248*7c478bd9Sstevel@tonic-gate {
249*7c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
250*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
251*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
252*7c478bd9Sstevel@tonic-gate 	int rval = 1;
253*7c478bd9Sstevel@tonic-gate 	int signalled = 0;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	if (panicstr)
256*7c478bd9Sstevel@tonic-gate 		return (rval);
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	/*
259*7c478bd9Sstevel@tonic-gate 	 * The check for t_intr is to catch an interrupt thread
260*7c478bd9Sstevel@tonic-gate 	 * that has not yet unpinned the thread underneath.
261*7c478bd9Sstevel@tonic-gate 	 */
262*7c478bd9Sstevel@tonic-gate 	if (lwp == NULL || t->t_intr) {
263*7c478bd9Sstevel@tonic-gate 		cv_wait(cvp, mp);
264*7c478bd9Sstevel@tonic-gate 		return (rval);
265*7c478bd9Sstevel@tonic-gate 	}
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
268*7c478bd9Sstevel@tonic-gate 	lwp->lwp_asleep = 1;
269*7c478bd9Sstevel@tonic-gate 	lwp->lwp_sysabort = 0;
270*7c478bd9Sstevel@tonic-gate 	thread_lock(t);
271*7c478bd9Sstevel@tonic-gate 	cv_block_sig(t, (condvar_impl_t *)cvp);
272*7c478bd9Sstevel@tonic-gate 	thread_unlock_nopreempt(t);
273*7c478bd9Sstevel@tonic-gate 	mutex_exit(mp);
274*7c478bd9Sstevel@tonic-gate 	if (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t))
275*7c478bd9Sstevel@tonic-gate 		setrun(t);
276*7c478bd9Sstevel@tonic-gate 	/* ASSERT(no locks are held) */
277*7c478bd9Sstevel@tonic-gate 	swtch();
278*7c478bd9Sstevel@tonic-gate 	signalled = (t->t_schedflag & TS_SIGNALLED);
279*7c478bd9Sstevel@tonic-gate 	t->t_flag &= ~T_WAKEABLE;
280*7c478bd9Sstevel@tonic-gate 	mutex_enter(mp);
281*7c478bd9Sstevel@tonic-gate 	if (ISSIG_PENDING(t, lwp, p)) {
282*7c478bd9Sstevel@tonic-gate 		mutex_exit(mp);
283*7c478bd9Sstevel@tonic-gate 		if (issig(FORREAL))
284*7c478bd9Sstevel@tonic-gate 			rval = 0;
285*7c478bd9Sstevel@tonic-gate 		mutex_enter(mp);
286*7c478bd9Sstevel@tonic-gate 	}
287*7c478bd9Sstevel@tonic-gate 	if (lwp->lwp_sysabort || MUSTRETURN(p, t))
288*7c478bd9Sstevel@tonic-gate 		rval = 0;
289*7c478bd9Sstevel@tonic-gate 	lwp->lwp_asleep = 0;
290*7c478bd9Sstevel@tonic-gate 	lwp->lwp_sysabort = 0;
291*7c478bd9Sstevel@tonic-gate 	if (rval == 0 && signalled)	/* avoid consuming the cv_signal() */
292*7c478bd9Sstevel@tonic-gate 		cv_signal(cvp);
293*7c478bd9Sstevel@tonic-gate 	return (rval);
294*7c478bd9Sstevel@tonic-gate }
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate /*
297*7c478bd9Sstevel@tonic-gate  * Returns:
298*7c478bd9Sstevel@tonic-gate  * 	Function result in order of presidence:
299*7c478bd9Sstevel@tonic-gate  *		 0 if a signal was received
300*7c478bd9Sstevel@tonic-gate  *		-1 if timeout occured
301*7c478bd9Sstevel@tonic-gate  *		>0 if awakened via cv_signal() or cv_broadcast().
302*7c478bd9Sstevel@tonic-gate  *		   (returns time remaining)
303*7c478bd9Sstevel@tonic-gate  *
304*7c478bd9Sstevel@tonic-gate  * cv_timedwait_sig() is now part of the DDI.
305*7c478bd9Sstevel@tonic-gate  */
306*7c478bd9Sstevel@tonic-gate clock_t
307*7c478bd9Sstevel@tonic-gate cv_timedwait_sig(kcondvar_t *cvp, kmutex_t *mp, clock_t tim)
308*7c478bd9Sstevel@tonic-gate {
309*7c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
310*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
311*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
312*7c478bd9Sstevel@tonic-gate 	timeout_id_t id;
313*7c478bd9Sstevel@tonic-gate 	clock_t rval = 1;
314*7c478bd9Sstevel@tonic-gate 	clock_t timeleft;
315*7c478bd9Sstevel@tonic-gate 	int signalled = 0;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	if (panicstr)
318*7c478bd9Sstevel@tonic-gate 		return (rval);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	/*
321*7c478bd9Sstevel@tonic-gate 	 * If there is no lwp, then we don't need to wait for a signal.
322*7c478bd9Sstevel@tonic-gate 	 * The check for t_intr is to catch an interrupt thread
323*7c478bd9Sstevel@tonic-gate 	 * that has not yet unpinned the thread underneath.
324*7c478bd9Sstevel@tonic-gate 	 */
325*7c478bd9Sstevel@tonic-gate 	if (lwp == NULL || t->t_intr)
326*7c478bd9Sstevel@tonic-gate 		return (cv_timedwait(cvp, mp, tim));
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	/*
329*7c478bd9Sstevel@tonic-gate 	 * If tim is less than or equal to lbolt, then the timeout
330*7c478bd9Sstevel@tonic-gate 	 * has already occured.  So just check to see if there is a signal
331*7c478bd9Sstevel@tonic-gate 	 * pending.  If so return 0 indicating that there is a signal pending.
332*7c478bd9Sstevel@tonic-gate 	 * Else return -1 indicating that the timeout occured. No need to
333*7c478bd9Sstevel@tonic-gate 	 * wait on anything.
334*7c478bd9Sstevel@tonic-gate 	 */
335*7c478bd9Sstevel@tonic-gate 	timeleft = tim - lbolt;
336*7c478bd9Sstevel@tonic-gate 	if (timeleft <= 0) {
337*7c478bd9Sstevel@tonic-gate 		lwp->lwp_asleep = 1;
338*7c478bd9Sstevel@tonic-gate 		lwp->lwp_sysabort = 0;
339*7c478bd9Sstevel@tonic-gate 		rval = -1;
340*7c478bd9Sstevel@tonic-gate 		goto out;
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	/*
344*7c478bd9Sstevel@tonic-gate 	 * Set the timeout and wait.
345*7c478bd9Sstevel@tonic-gate 	 */
346*7c478bd9Sstevel@tonic-gate 	id = realtime_timeout((void (*)(void *))setrun, t, timeleft);
347*7c478bd9Sstevel@tonic-gate 	lwp->lwp_asleep = 1;
348*7c478bd9Sstevel@tonic-gate 	lwp->lwp_sysabort = 0;
349*7c478bd9Sstevel@tonic-gate 	thread_lock(t);
350*7c478bd9Sstevel@tonic-gate 	cv_block_sig(t, (condvar_impl_t *)cvp);
351*7c478bd9Sstevel@tonic-gate 	thread_unlock_nopreempt(t);
352*7c478bd9Sstevel@tonic-gate 	mutex_exit(mp);
353*7c478bd9Sstevel@tonic-gate 	if (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t) || (tim - lbolt <= 0))
354*7c478bd9Sstevel@tonic-gate 		setrun(t);
355*7c478bd9Sstevel@tonic-gate 	/* ASSERT(no locks are held) */
356*7c478bd9Sstevel@tonic-gate 	swtch();
357*7c478bd9Sstevel@tonic-gate 	signalled = (t->t_schedflag & TS_SIGNALLED);
358*7c478bd9Sstevel@tonic-gate 	t->t_flag &= ~T_WAKEABLE;
359*7c478bd9Sstevel@tonic-gate 	mutex_enter(mp);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	/*
362*7c478bd9Sstevel@tonic-gate 	 * Untimeout the thread.  untimeout() returns -1 if the timeout has
363*7c478bd9Sstevel@tonic-gate 	 * occured or the time remaining.  If the time remaining is zero,
364*7c478bd9Sstevel@tonic-gate 	 * the timeout has occured between when we were awoken and
365*7c478bd9Sstevel@tonic-gate 	 * we called untimeout.  We will treat this as if the timeout
366*7c478bd9Sstevel@tonic-gate 	 * has occured and set rval to -1.
367*7c478bd9Sstevel@tonic-gate 	 */
368*7c478bd9Sstevel@tonic-gate 	rval = untimeout(id);
369*7c478bd9Sstevel@tonic-gate 	if (rval <= 0)
370*7c478bd9Sstevel@tonic-gate 		rval = -1;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	/*
373*7c478bd9Sstevel@tonic-gate 	 * Check to see if a signal is pending.  If so, regardless of whether
374*7c478bd9Sstevel@tonic-gate 	 * or not we were awoken due to the signal, the signal is now pending
375*7c478bd9Sstevel@tonic-gate 	 * and a return of 0 has the highest priority.
376*7c478bd9Sstevel@tonic-gate 	 */
377*7c478bd9Sstevel@tonic-gate out:
378*7c478bd9Sstevel@tonic-gate 	if (ISSIG_PENDING(t, lwp, p)) {
379*7c478bd9Sstevel@tonic-gate 		mutex_exit(mp);
380*7c478bd9Sstevel@tonic-gate 		if (issig(FORREAL))
381*7c478bd9Sstevel@tonic-gate 			rval = 0;
382*7c478bd9Sstevel@tonic-gate 		mutex_enter(mp);
383*7c478bd9Sstevel@tonic-gate 	}
384*7c478bd9Sstevel@tonic-gate 	if (lwp->lwp_sysabort || MUSTRETURN(p, t))
385*7c478bd9Sstevel@tonic-gate 		rval = 0;
386*7c478bd9Sstevel@tonic-gate 	lwp->lwp_asleep = 0;
387*7c478bd9Sstevel@tonic-gate 	lwp->lwp_sysabort = 0;
388*7c478bd9Sstevel@tonic-gate 	if (rval <= 0 && signalled)	/* avoid consuming the cv_signal() */
389*7c478bd9Sstevel@tonic-gate 		cv_signal(cvp);
390*7c478bd9Sstevel@tonic-gate 	return (rval);
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate /*
394*7c478bd9Sstevel@tonic-gate  * Like cv_wait_sig_swap but allows the caller to indicate (with a
395*7c478bd9Sstevel@tonic-gate  * non-NULL sigret) that they will take care of signalling the cv
396*7c478bd9Sstevel@tonic-gate  * after wakeup, if necessary.  This is a vile hack that should only
397*7c478bd9Sstevel@tonic-gate  * be used when no other option is available; almost all callers
398*7c478bd9Sstevel@tonic-gate  * should just use cv_wait_sig_swap (which takes care of the cv_signal
399*7c478bd9Sstevel@tonic-gate  * stuff automatically) instead.
400*7c478bd9Sstevel@tonic-gate  */
401*7c478bd9Sstevel@tonic-gate int
402*7c478bd9Sstevel@tonic-gate cv_wait_sig_swap_core(kcondvar_t *cvp, kmutex_t *mp, int *sigret)
403*7c478bd9Sstevel@tonic-gate {
404*7c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
405*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
406*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
407*7c478bd9Sstevel@tonic-gate 	int rval = 1;
408*7c478bd9Sstevel@tonic-gate 	int signalled = 0;
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	if (panicstr)
411*7c478bd9Sstevel@tonic-gate 		return (rval);
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	/*
414*7c478bd9Sstevel@tonic-gate 	 * The check for t_intr is to catch an interrupt thread
415*7c478bd9Sstevel@tonic-gate 	 * that has not yet unpinned the thread underneath.
416*7c478bd9Sstevel@tonic-gate 	 */
417*7c478bd9Sstevel@tonic-gate 	if (lwp == NULL || t->t_intr) {
418*7c478bd9Sstevel@tonic-gate 		cv_wait(cvp, mp);
419*7c478bd9Sstevel@tonic-gate 		return (rval);
420*7c478bd9Sstevel@tonic-gate 	}
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	lwp->lwp_asleep = 1;
423*7c478bd9Sstevel@tonic-gate 	lwp->lwp_sysabort = 0;
424*7c478bd9Sstevel@tonic-gate 	thread_lock(t);
425*7c478bd9Sstevel@tonic-gate 	t->t_kpri_req = 0;	/* don't need kernel priority */
426*7c478bd9Sstevel@tonic-gate 	cv_block_sig(t, (condvar_impl_t *)cvp);
427*7c478bd9Sstevel@tonic-gate 	/* I can be swapped now */
428*7c478bd9Sstevel@tonic-gate 	curthread->t_schedflag &= ~TS_DONT_SWAP;
429*7c478bd9Sstevel@tonic-gate 	thread_unlock_nopreempt(t);
430*7c478bd9Sstevel@tonic-gate 	mutex_exit(mp);
431*7c478bd9Sstevel@tonic-gate 	if (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t))
432*7c478bd9Sstevel@tonic-gate 		setrun(t);
433*7c478bd9Sstevel@tonic-gate 	/* ASSERT(no locks are held) */
434*7c478bd9Sstevel@tonic-gate 	swtch();
435*7c478bd9Sstevel@tonic-gate 	signalled = (t->t_schedflag & TS_SIGNALLED);
436*7c478bd9Sstevel@tonic-gate 	t->t_flag &= ~T_WAKEABLE;
437*7c478bd9Sstevel@tonic-gate 	/* TS_DONT_SWAP set by disp() */
438*7c478bd9Sstevel@tonic-gate 	ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
439*7c478bd9Sstevel@tonic-gate 	mutex_enter(mp);
440*7c478bd9Sstevel@tonic-gate 	if (ISSIG_PENDING(t, lwp, p)) {
441*7c478bd9Sstevel@tonic-gate 		mutex_exit(mp);
442*7c478bd9Sstevel@tonic-gate 		if (issig(FORREAL))
443*7c478bd9Sstevel@tonic-gate 			rval = 0;
444*7c478bd9Sstevel@tonic-gate 		mutex_enter(mp);
445*7c478bd9Sstevel@tonic-gate 	}
446*7c478bd9Sstevel@tonic-gate 	if (lwp->lwp_sysabort || MUSTRETURN(p, t))
447*7c478bd9Sstevel@tonic-gate 		rval = 0;
448*7c478bd9Sstevel@tonic-gate 	lwp->lwp_asleep = 0;
449*7c478bd9Sstevel@tonic-gate 	lwp->lwp_sysabort = 0;
450*7c478bd9Sstevel@tonic-gate 	if (rval == 0) {
451*7c478bd9Sstevel@tonic-gate 		if (sigret != NULL)
452*7c478bd9Sstevel@tonic-gate 			*sigret = signalled;	/* just tell the caller */
453*7c478bd9Sstevel@tonic-gate 		else if (signalled)
454*7c478bd9Sstevel@tonic-gate 			cv_signal(cvp);	/* avoid consuming the cv_signal() */
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate 	return (rval);
457*7c478bd9Sstevel@tonic-gate }
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate /*
460*7c478bd9Sstevel@tonic-gate  * Same as cv_wait_sig but the thread can be swapped out while waiting.
461*7c478bd9Sstevel@tonic-gate  * This should only be used when we know we aren't holding any locks.
462*7c478bd9Sstevel@tonic-gate  */
463*7c478bd9Sstevel@tonic-gate int
464*7c478bd9Sstevel@tonic-gate cv_wait_sig_swap(kcondvar_t *cvp, kmutex_t *mp)
465*7c478bd9Sstevel@tonic-gate {
466*7c478bd9Sstevel@tonic-gate 	return (cv_wait_sig_swap_core(cvp, mp, NULL));
467*7c478bd9Sstevel@tonic-gate }
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate void
470*7c478bd9Sstevel@tonic-gate cv_signal(kcondvar_t *cvp)
471*7c478bd9Sstevel@tonic-gate {
472*7c478bd9Sstevel@tonic-gate 	condvar_impl_t *cp = (condvar_impl_t *)cvp;
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	/* make sure the cv_waiters field looks sane */
475*7c478bd9Sstevel@tonic-gate 	ASSERT(cp->cv_waiters <= CV_MAX_WAITERS);
476*7c478bd9Sstevel@tonic-gate 	if (cp->cv_waiters > 0) {
477*7c478bd9Sstevel@tonic-gate 		sleepq_head_t *sqh = SQHASH(cp);
478*7c478bd9Sstevel@tonic-gate 		disp_lock_enter(&sqh->sq_lock);
479*7c478bd9Sstevel@tonic-gate 		ASSERT(CPU_ON_INTR(CPU) == 0);
480*7c478bd9Sstevel@tonic-gate 		if (cp->cv_waiters & CV_WAITERS_MASK) {
481*7c478bd9Sstevel@tonic-gate 			kthread_t *t;
482*7c478bd9Sstevel@tonic-gate 			cp->cv_waiters--;
483*7c478bd9Sstevel@tonic-gate 			t = sleepq_wakeone_chan(&sqh->sq_queue, cp);
484*7c478bd9Sstevel@tonic-gate 			/*
485*7c478bd9Sstevel@tonic-gate 			 * If cv_waiters is non-zero (and less than
486*7c478bd9Sstevel@tonic-gate 			 * CV_MAX_WAITERS) there should be a thread
487*7c478bd9Sstevel@tonic-gate 			 * in the queue.
488*7c478bd9Sstevel@tonic-gate 			 */
489*7c478bd9Sstevel@tonic-gate 			ASSERT(t != NULL);
490*7c478bd9Sstevel@tonic-gate 		} else if (sleepq_wakeone_chan(&sqh->sq_queue, cp) == NULL) {
491*7c478bd9Sstevel@tonic-gate 			cp->cv_waiters = 0;
492*7c478bd9Sstevel@tonic-gate 		}
493*7c478bd9Sstevel@tonic-gate 		disp_lock_exit(&sqh->sq_lock);
494*7c478bd9Sstevel@tonic-gate 	}
495*7c478bd9Sstevel@tonic-gate }
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate void
498*7c478bd9Sstevel@tonic-gate cv_broadcast(kcondvar_t *cvp)
499*7c478bd9Sstevel@tonic-gate {
500*7c478bd9Sstevel@tonic-gate 	condvar_impl_t *cp = (condvar_impl_t *)cvp;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	/* make sure the cv_waiters field looks sane */
503*7c478bd9Sstevel@tonic-gate 	ASSERT(cp->cv_waiters <= CV_MAX_WAITERS);
504*7c478bd9Sstevel@tonic-gate 	if (cp->cv_waiters > 0) {
505*7c478bd9Sstevel@tonic-gate 		sleepq_head_t *sqh = SQHASH(cp);
506*7c478bd9Sstevel@tonic-gate 		disp_lock_enter(&sqh->sq_lock);
507*7c478bd9Sstevel@tonic-gate 		ASSERT(CPU_ON_INTR(CPU) == 0);
508*7c478bd9Sstevel@tonic-gate 		sleepq_wakeall_chan(&sqh->sq_queue, cp);
509*7c478bd9Sstevel@tonic-gate 		cp->cv_waiters = 0;
510*7c478bd9Sstevel@tonic-gate 		disp_lock_exit(&sqh->sq_lock);
511*7c478bd9Sstevel@tonic-gate 	}
512*7c478bd9Sstevel@tonic-gate }
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate /*
515*7c478bd9Sstevel@tonic-gate  * Same as cv_wait(), but wakes up (after wakeup_time milliseconds) to check
516*7c478bd9Sstevel@tonic-gate  * for requests to stop, like cv_wait_sig() but without dealing with signals.
517*7c478bd9Sstevel@tonic-gate  * This is a horrible kludge.  It is evil.  It is vile.  It is swill.
518*7c478bd9Sstevel@tonic-gate  * If your code has to call this function then your code is the same.
519*7c478bd9Sstevel@tonic-gate  */
520*7c478bd9Sstevel@tonic-gate void
521*7c478bd9Sstevel@tonic-gate cv_wait_stop(kcondvar_t *cvp, kmutex_t *mp, int wakeup_time)
522*7c478bd9Sstevel@tonic-gate {
523*7c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
524*7c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
525*7c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(t);
526*7c478bd9Sstevel@tonic-gate 	timeout_id_t id;
527*7c478bd9Sstevel@tonic-gate 	clock_t tim;
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	if (panicstr)
530*7c478bd9Sstevel@tonic-gate 		return;
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	/*
533*7c478bd9Sstevel@tonic-gate 	 * If there is no lwp, then we don't need to eventually stop it
534*7c478bd9Sstevel@tonic-gate 	 * The check for t_intr is to catch an interrupt thread
535*7c478bd9Sstevel@tonic-gate 	 * that has not yet unpinned the thread underneath.
536*7c478bd9Sstevel@tonic-gate 	 */
537*7c478bd9Sstevel@tonic-gate 	if (lwp == NULL || t->t_intr) {
538*7c478bd9Sstevel@tonic-gate 		cv_wait(cvp, mp);
539*7c478bd9Sstevel@tonic-gate 		return;
540*7c478bd9Sstevel@tonic-gate 	}
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	/*
543*7c478bd9Sstevel@tonic-gate 	 * Wakeup in wakeup_time milliseconds, i.e., human time.
544*7c478bd9Sstevel@tonic-gate 	 */
545*7c478bd9Sstevel@tonic-gate 	tim = lbolt + MSEC_TO_TICK(wakeup_time);
546*7c478bd9Sstevel@tonic-gate 	id = realtime_timeout((void (*)(void *))setrun, t, tim - lbolt);
547*7c478bd9Sstevel@tonic-gate 	thread_lock(t);			/* lock the thread */
548*7c478bd9Sstevel@tonic-gate 	cv_block((condvar_impl_t *)cvp);
549*7c478bd9Sstevel@tonic-gate 	thread_unlock_nopreempt(t);
550*7c478bd9Sstevel@tonic-gate 	mutex_exit(mp);
551*7c478bd9Sstevel@tonic-gate 	/* ASSERT(no locks are held); */
552*7c478bd9Sstevel@tonic-gate 	if ((tim - lbolt) <= 0)		/* allow for wrap */
553*7c478bd9Sstevel@tonic-gate 		setrun(t);
554*7c478bd9Sstevel@tonic-gate 	swtch();
555*7c478bd9Sstevel@tonic-gate 	(void) untimeout(id);
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	/*
558*7c478bd9Sstevel@tonic-gate 	 * Check for reasons to stop, if lwp_nostop is not true.
559*7c478bd9Sstevel@tonic-gate 	 * See issig_forreal() for explanations of the various stops.
560*7c478bd9Sstevel@tonic-gate 	 */
561*7c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
562*7c478bd9Sstevel@tonic-gate 	while (lwp->lwp_nostop == 0 && !(p->p_flag & SEXITLWPS)) {
563*7c478bd9Sstevel@tonic-gate 		/*
564*7c478bd9Sstevel@tonic-gate 		 * Hold the lwp here for watchpoint manipulation.
565*7c478bd9Sstevel@tonic-gate 		 */
566*7c478bd9Sstevel@tonic-gate 		if (t->t_proc_flag & TP_PAUSE) {
567*7c478bd9Sstevel@tonic-gate 			stop(PR_SUSPENDED, SUSPEND_PAUSE);
568*7c478bd9Sstevel@tonic-gate 			continue;
569*7c478bd9Sstevel@tonic-gate 		}
570*7c478bd9Sstevel@tonic-gate 		/*
571*7c478bd9Sstevel@tonic-gate 		 * System checkpoint.
572*7c478bd9Sstevel@tonic-gate 		 */
573*7c478bd9Sstevel@tonic-gate 		if (t->t_proc_flag & TP_CHKPT) {
574*7c478bd9Sstevel@tonic-gate 			stop(PR_CHECKPOINT, 0);
575*7c478bd9Sstevel@tonic-gate 			continue;
576*7c478bd9Sstevel@tonic-gate 		}
577*7c478bd9Sstevel@tonic-gate 		/*
578*7c478bd9Sstevel@tonic-gate 		 * Honor fork1(), watchpoint activity (remapping a page),
579*7c478bd9Sstevel@tonic-gate 		 * and lwp_suspend() requests.
580*7c478bd9Sstevel@tonic-gate 		 */
581*7c478bd9Sstevel@tonic-gate 		if ((p->p_flag & (SHOLDFORK1|SHOLDWATCH)) ||
582*7c478bd9Sstevel@tonic-gate 		    (t->t_proc_flag & TP_HOLDLWP)) {
583*7c478bd9Sstevel@tonic-gate 			stop(PR_SUSPENDED, SUSPEND_NORMAL);
584*7c478bd9Sstevel@tonic-gate 			continue;
585*7c478bd9Sstevel@tonic-gate 		}
586*7c478bd9Sstevel@tonic-gate 		/*
587*7c478bd9Sstevel@tonic-gate 		 * Honor /proc requested stop.
588*7c478bd9Sstevel@tonic-gate 		 */
589*7c478bd9Sstevel@tonic-gate 		if (t->t_proc_flag & TP_PRSTOP) {
590*7c478bd9Sstevel@tonic-gate 			stop(PR_REQUESTED, 0);
591*7c478bd9Sstevel@tonic-gate 		}
592*7c478bd9Sstevel@tonic-gate 		/*
593*7c478bd9Sstevel@tonic-gate 		 * If some lwp in the process has already stopped
594*7c478bd9Sstevel@tonic-gate 		 * showing PR_JOBCONTROL, stop in sympathy with it.
595*7c478bd9Sstevel@tonic-gate 		 */
596*7c478bd9Sstevel@tonic-gate 		if (p->p_stopsig && t != p->p_agenttp) {
597*7c478bd9Sstevel@tonic-gate 			stop(PR_JOBCONTROL, p->p_stopsig);
598*7c478bd9Sstevel@tonic-gate 			continue;
599*7c478bd9Sstevel@tonic-gate 		}
600*7c478bd9Sstevel@tonic-gate 		break;
601*7c478bd9Sstevel@tonic-gate 	}
602*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
603*7c478bd9Sstevel@tonic-gate 	mutex_enter(mp);
604*7c478bd9Sstevel@tonic-gate }
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate /*
607*7c478bd9Sstevel@tonic-gate  * Like cv_timedwait_sig(), but takes an absolute hires future time
608*7c478bd9Sstevel@tonic-gate  * rather than a future time in clock ticks.  Will not return showing
609*7c478bd9Sstevel@tonic-gate  * that a timeout occurred until the future time is passed.
610*7c478bd9Sstevel@tonic-gate  * If 'when' is a NULL pointer, no timeout will occur.
611*7c478bd9Sstevel@tonic-gate  * Returns:
612*7c478bd9Sstevel@tonic-gate  * 	Function result in order of presidence:
613*7c478bd9Sstevel@tonic-gate  *		 0 if a signal was received
614*7c478bd9Sstevel@tonic-gate  *		-1 if timeout occured
615*7c478bd9Sstevel@tonic-gate  *	        >0 if awakened via cv_signal() or cv_broadcast()
616*7c478bd9Sstevel@tonic-gate  *		   or by a spurious wakeup.
617*7c478bd9Sstevel@tonic-gate  *		   (might return time remaining)
618*7c478bd9Sstevel@tonic-gate  * As a special test, if someone abruptly resets the system time
619*7c478bd9Sstevel@tonic-gate  * (but not through adjtime(2); drifting of the clock is allowed and
620*7c478bd9Sstevel@tonic-gate  * expected [see timespectohz_adj()]), then we force a return of -1
621*7c478bd9Sstevel@tonic-gate  * so the caller can return a premature timeout to the calling process
622*7c478bd9Sstevel@tonic-gate  * so it can reevaluate the situation in light of the new system time.
623*7c478bd9Sstevel@tonic-gate  * (The system clock has been reset if timecheck != timechanged.)
624*7c478bd9Sstevel@tonic-gate  */
625*7c478bd9Sstevel@tonic-gate int
626*7c478bd9Sstevel@tonic-gate cv_waituntil_sig(kcondvar_t *cvp, kmutex_t *mp,
627*7c478bd9Sstevel@tonic-gate 	timestruc_t *when, int timecheck)
628*7c478bd9Sstevel@tonic-gate {
629*7c478bd9Sstevel@tonic-gate 	timestruc_t now;
630*7c478bd9Sstevel@tonic-gate 	int rval;
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	if (when == NULL)
633*7c478bd9Sstevel@tonic-gate 		return (cv_wait_sig_swap(cvp, mp));
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	gethrestime(&now);
636*7c478bd9Sstevel@tonic-gate 	if (when->tv_sec < now.tv_sec ||
637*7c478bd9Sstevel@tonic-gate 	    (when->tv_sec == now.tv_sec &&
638*7c478bd9Sstevel@tonic-gate 	    when->tv_nsec <= now.tv_nsec)) {
639*7c478bd9Sstevel@tonic-gate 		/*
640*7c478bd9Sstevel@tonic-gate 		 * We have already reached the absolute future time.
641*7c478bd9Sstevel@tonic-gate 		 * Call cv_timedwait_sig() just to check for signals.
642*7c478bd9Sstevel@tonic-gate 		 * We will return immediately with either 0 or -1.
643*7c478bd9Sstevel@tonic-gate 		 */
644*7c478bd9Sstevel@tonic-gate 		rval = cv_timedwait_sig(cvp, mp, lbolt);
645*7c478bd9Sstevel@tonic-gate 	} else {
646*7c478bd9Sstevel@tonic-gate 		if (timecheck == timechanged) {
647*7c478bd9Sstevel@tonic-gate 			rval = cv_timedwait_sig(cvp, mp,
648*7c478bd9Sstevel@tonic-gate 				lbolt + timespectohz_adj(when, now));
649*7c478bd9Sstevel@tonic-gate 		} else {
650*7c478bd9Sstevel@tonic-gate 			/*
651*7c478bd9Sstevel@tonic-gate 			 * Someone reset the system time;
652*7c478bd9Sstevel@tonic-gate 			 * just force an immediate timeout.
653*7c478bd9Sstevel@tonic-gate 			 */
654*7c478bd9Sstevel@tonic-gate 			rval = -1;
655*7c478bd9Sstevel@tonic-gate 		}
656*7c478bd9Sstevel@tonic-gate 		if (rval == -1 && timecheck == timechanged) {
657*7c478bd9Sstevel@tonic-gate 			/*
658*7c478bd9Sstevel@tonic-gate 			 * Even though cv_timedwait_sig() returned showing a
659*7c478bd9Sstevel@tonic-gate 			 * timeout, the future time may not have passed yet.
660*7c478bd9Sstevel@tonic-gate 			 * If not, change rval to indicate a normal wakeup.
661*7c478bd9Sstevel@tonic-gate 			 */
662*7c478bd9Sstevel@tonic-gate 			gethrestime(&now);
663*7c478bd9Sstevel@tonic-gate 			if (when->tv_sec > now.tv_sec ||
664*7c478bd9Sstevel@tonic-gate 			    (when->tv_sec == now.tv_sec &&
665*7c478bd9Sstevel@tonic-gate 			    when->tv_nsec > now.tv_nsec))
666*7c478bd9Sstevel@tonic-gate 				rval = 1;
667*7c478bd9Sstevel@tonic-gate 		}
668*7c478bd9Sstevel@tonic-gate 	}
669*7c478bd9Sstevel@tonic-gate 	return (rval);
670*7c478bd9Sstevel@tonic-gate }
671