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