1238510fcSJason Evans /*- 2238510fcSJason Evans * Copyright (c) 2000 Jake Burkholder <jake@freebsd.org>. 3238510fcSJason Evans * All rights reserved. 4238510fcSJason Evans * 5238510fcSJason Evans * Redistribution and use in source and binary forms, with or without 6238510fcSJason Evans * modification, are permitted provided that the following conditions 7238510fcSJason Evans * are met: 8238510fcSJason Evans * 1. Redistributions of source code must retain the above copyright 9238510fcSJason Evans * notice, this list of conditions and the following disclaimer. 10238510fcSJason Evans * 2. Redistributions in binary form must reproduce the above copyright 11238510fcSJason Evans * notice, this list of conditions and the following disclaimer in the 12238510fcSJason Evans * documentation and/or other materials provided with the distribution. 13238510fcSJason Evans * 14238510fcSJason Evans * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15238510fcSJason Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16238510fcSJason Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17238510fcSJason Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18238510fcSJason Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19238510fcSJason Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20238510fcSJason Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21238510fcSJason Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22238510fcSJason Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23238510fcSJason Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24238510fcSJason Evans * SUCH DAMAGE. 25238510fcSJason Evans * 26238510fcSJason Evans * $FreeBSD$ 27238510fcSJason Evans */ 28238510fcSJason Evans 29238510fcSJason Evans #include "opt_ktrace.h" 30238510fcSJason Evans 31238510fcSJason Evans #include <sys/param.h> 32238510fcSJason Evans #include <sys/systm.h> 33238510fcSJason Evans #include <sys/proc.h> 34238510fcSJason Evans #include <sys/kernel.h> 35238510fcSJason Evans #include <sys/ktr.h> 36238510fcSJason Evans #include <sys/condvar.h> 37238510fcSJason Evans #include <sys/mutex.h> 38238510fcSJason Evans #include <sys/signalvar.h> 39238510fcSJason Evans #include <sys/resourcevar.h> 40238510fcSJason Evans #ifdef KTRACE 41238510fcSJason Evans #include <sys/uio.h> 42238510fcSJason Evans #include <sys/ktrace.h> 43238510fcSJason Evans #endif 44238510fcSJason Evans 45238510fcSJason Evans /* 46238510fcSJason Evans * Common sanity checks for cv_wait* functions. 47238510fcSJason Evans */ 48238510fcSJason Evans #define CV_ASSERT(cvp, mp, p) do { \ 49238510fcSJason Evans KASSERT((p) != NULL, ("%s: curproc NULL", __FUNCTION__)); \ 50238510fcSJason Evans KASSERT((p)->p_stat == SRUN, ("%s: not SRUN", __FUNCTION__)); \ 51238510fcSJason Evans KASSERT((cvp) != NULL, ("%s: cvp NULL", __FUNCTION__)); \ 52238510fcSJason Evans KASSERT((mp) != NULL, ("%s: mp NULL", __FUNCTION__)); \ 53238510fcSJason Evans mtx_assert((mp), MA_OWNED | MA_NOTRECURSED); \ 54238510fcSJason Evans } while (0) 55238510fcSJason Evans 56238510fcSJason Evans #ifdef CV_DEBUG 57238510fcSJason Evans #define CV_WAIT_VALIDATE(cvp, mp) do { \ 58238510fcSJason Evans if (TAILQ_EMPTY(&(cvp)->cv_waitq)) { \ 59238510fcSJason Evans /* Only waiter. */ \ 60238510fcSJason Evans (cvp)->cv_mtx = (mp); \ 61238510fcSJason Evans } else { \ 62238510fcSJason Evans /* \ 63238510fcSJason Evans * Other waiter; assert that we're using the \ 64238510fcSJason Evans * same mutex. \ 65238510fcSJason Evans */ \ 66238510fcSJason Evans KASSERT((cvp)->cv_mtx == (mp), \ 67238510fcSJason Evans ("%s: Multiple mutexes", __FUNCTION__)); \ 68238510fcSJason Evans } \ 69238510fcSJason Evans } while (0) 70238510fcSJason Evans #define CV_SIGNAL_VALIDATE(cvp) do { \ 71238510fcSJason Evans if (!TAILQ_EMPTY(&(cvp)->cv_waitq)) { \ 72238510fcSJason Evans KASSERT(mtx_owned((cvp)->cv_mtx), \ 73238510fcSJason Evans ("%s: Mutex not owned", __FUNCTION__)); \ 74238510fcSJason Evans } \ 75238510fcSJason Evans } while (0) 76238510fcSJason Evans #else 77238510fcSJason Evans #define CV_WAIT_VALIDATE(cvp, mp) 78238510fcSJason Evans #define CV_SIGNAL_VALIDATE(cvp) 79238510fcSJason Evans #endif 80238510fcSJason Evans 81238510fcSJason Evans static void cv_timedwait_end(void *arg); 82238510fcSJason Evans 83238510fcSJason Evans /* 84238510fcSJason Evans * Initialize a condition variable. Must be called before use. 85238510fcSJason Evans */ 86238510fcSJason Evans void 87238510fcSJason Evans cv_init(struct cv *cvp, const char *desc) 88238510fcSJason Evans { 89238510fcSJason Evans 90238510fcSJason Evans TAILQ_INIT(&cvp->cv_waitq); 91238510fcSJason Evans cvp->cv_mtx = NULL; 92238510fcSJason Evans cvp->cv_description = desc; 93238510fcSJason Evans } 94238510fcSJason Evans 95238510fcSJason Evans /* 96238510fcSJason Evans * Destroy a condition variable. The condition variable must be re-initialized 97238510fcSJason Evans * in order to be re-used. 98238510fcSJason Evans */ 99238510fcSJason Evans void 100238510fcSJason Evans cv_destroy(struct cv *cvp) 101238510fcSJason Evans { 102238510fcSJason Evans 103238510fcSJason Evans KASSERT(cv_waitq_empty(cvp), ("%s: cv_waitq non-empty", __FUNCTION__)); 104238510fcSJason Evans } 105238510fcSJason Evans 106238510fcSJason Evans /* 107238510fcSJason Evans * Common code for cv_wait* functions. All require sched_lock. 108238510fcSJason Evans */ 109238510fcSJason Evans 110238510fcSJason Evans /* 111238510fcSJason Evans * Switch context. 112238510fcSJason Evans */ 113238510fcSJason Evans static __inline void 114238510fcSJason Evans cv_switch(struct proc *p) 115238510fcSJason Evans { 116238510fcSJason Evans 117238510fcSJason Evans p->p_stat = SSLEEP; 118238510fcSJason Evans p->p_stats->p_ru.ru_nvcsw++; 119238510fcSJason Evans mi_switch(); 120238510fcSJason Evans CTR3(KTR_PROC, "cv_switch: resume proc %p (pid %d, %s)", p, p->p_pid, 121238510fcSJason Evans p->p_comm); 122238510fcSJason Evans } 123238510fcSJason Evans 124238510fcSJason Evans /* 125238510fcSJason Evans * Switch context, catching signals. 126238510fcSJason Evans */ 127238510fcSJason Evans static __inline int 128238510fcSJason Evans cv_switch_catch(struct proc *p) 129238510fcSJason Evans { 130238510fcSJason Evans int sig; 131238510fcSJason Evans 132238510fcSJason Evans /* 133238510fcSJason Evans * We put ourselves on the sleep queue and start our timeout before 134238510fcSJason Evans * calling CURSIG, as we could stop there, and a wakeup or a SIGCONT (or 135238510fcSJason Evans * both) could occur while we were stopped. A SIGCONT would cause us to 136238510fcSJason Evans * be marked as SSLEEP without resuming us, thus we must be ready for 137238510fcSJason Evans * sleep when CURSIG is called. If the wakeup happens while we're 138238510fcSJason Evans * stopped, p->p_wchan will be 0 upon return from CURSIG. 139238510fcSJason Evans */ 140238510fcSJason Evans p->p_flag |= P_SINTR; 141238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 142238510fcSJason Evans /* proc_lock(p); */ 143238510fcSJason Evans sig = CURSIG(p); 144238510fcSJason Evans mtx_enter(&sched_lock, MTX_SPIN); 145238510fcSJason Evans /* proc_unlock_noswitch(p); */ 146238510fcSJason Evans if (sig != 0) { 147238510fcSJason Evans if (p->p_wchan != NULL) 148238510fcSJason Evans cv_waitq_remove(p); 149238510fcSJason Evans p->p_stat = SRUN; 150238510fcSJason Evans } else if (p->p_wchan != NULL) { 151238510fcSJason Evans cv_switch(p); 152238510fcSJason Evans } 153238510fcSJason Evans p->p_flag &= ~P_SINTR; 154238510fcSJason Evans 155238510fcSJason Evans return sig; 156238510fcSJason Evans } 157238510fcSJason Evans 158238510fcSJason Evans /* 159238510fcSJason Evans * Add a process to the wait queue of a condition variable. 160238510fcSJason Evans */ 161238510fcSJason Evans static __inline void 162238510fcSJason Evans cv_waitq_add(struct cv *cvp, struct proc *p) 163238510fcSJason Evans { 164238510fcSJason Evans 165238510fcSJason Evans /* 166238510fcSJason Evans * Process may be sitting on a slpque if asleep() was called, remove it 167238510fcSJason Evans * before re-adding. 168238510fcSJason Evans */ 169238510fcSJason Evans if (p->p_wchan != NULL) 170238510fcSJason Evans unsleep(p); 171238510fcSJason Evans 172238510fcSJason Evans p->p_flag |= P_CVWAITQ; 173238510fcSJason Evans p->p_wchan = cvp; 174238510fcSJason Evans p->p_wmesg = cvp->cv_description; 175238510fcSJason Evans p->p_slptime = 0; 176238510fcSJason Evans p->p_nativepri = p->p_priority; 177238510fcSJason Evans CTR3(KTR_PROC, "cv_waitq_add: proc %p (pid %d, %s)", p, p->p_pid, 178238510fcSJason Evans p->p_comm); 179238510fcSJason Evans TAILQ_INSERT_TAIL(&cvp->cv_waitq, p, p_slpq); 180238510fcSJason Evans } 181238510fcSJason Evans 182238510fcSJason Evans /* 183238510fcSJason Evans * Wait on a condition variable. The current process is placed on the condition 184238510fcSJason Evans * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 185238510fcSJason Evans * condition variable will resume the process. The mutex is released before 186238510fcSJason Evans * sleeping and will be held on return. It is recommended that the mutex be 187238510fcSJason Evans * held when cv_signal or cv_broadcast are called. 188238510fcSJason Evans */ 189238510fcSJason Evans void 190238510fcSJason Evans cv_wait(struct cv *cvp, struct mtx *mp) 191238510fcSJason Evans { 192238510fcSJason Evans struct proc *p; 193238510fcSJason Evans WITNESS_SAVE_DECL(mp); 194238510fcSJason Evans 195238510fcSJason Evans p = CURPROC; 196238510fcSJason Evans #ifdef KTRACE 197238510fcSJason Evans if (p && KTRPOINT(p, KTR_CSW)) 198238510fcSJason Evans ktrcsw(p->p_tracep, 1, 0); 199238510fcSJason Evans #endif 200238510fcSJason Evans CV_ASSERT(cvp, mp, p); 201238510fcSJason Evans WITNESS_SLEEP(0, mp); 202238510fcSJason Evans WITNESS_SAVE(mp, mp); 203238510fcSJason Evans 204238510fcSJason Evans mtx_enter(&sched_lock, MTX_SPIN); 205238510fcSJason Evans if (cold || panicstr) { 206238510fcSJason Evans /* 207238510fcSJason Evans * After a panic, or during autoconfiguration, just give 208238510fcSJason Evans * interrupts a chance, then just return; don't run any other 209238510fcSJason Evans * procs or panic below, in case this is the idle process and 210238510fcSJason Evans * already asleep. 211238510fcSJason Evans */ 212238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 213238510fcSJason Evans return; 214238510fcSJason Evans } 215238510fcSJason Evans CV_WAIT_VALIDATE(cvp, mp); 216238510fcSJason Evans 217238510fcSJason Evans DROP_GIANT_NOSWITCH(); 218238510fcSJason Evans mtx_exit(mp, MTX_DEF | MTX_NOSWITCH); 219238510fcSJason Evans 220238510fcSJason Evans cv_waitq_add(cvp, p); 221238510fcSJason Evans cv_switch(p); 222238510fcSJason Evans curpriority = p->p_usrpri; 223238510fcSJason Evans 224238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 225238510fcSJason Evans #ifdef KTRACE 226238510fcSJason Evans if (KTRPOINT(p, KTR_CSW)) 227238510fcSJason Evans ktrcsw(p->p_tracep, 0, 0); 228238510fcSJason Evans #endif 229238510fcSJason Evans PICKUP_GIANT(); 230238510fcSJason Evans mtx_enter(mp, MTX_DEF); 231238510fcSJason Evans WITNESS_RESTORE(mp, mp); 232238510fcSJason Evans } 233238510fcSJason Evans 234238510fcSJason Evans /* 235238510fcSJason Evans * Wait on a condition variable, allowing interruption by signals. Return 0 if 236238510fcSJason Evans * the process was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 237238510fcSJason Evans * a signal was caught. If ERESTART is returned the system call should be 238238510fcSJason Evans * restarted if possible. 239238510fcSJason Evans */ 240238510fcSJason Evans int 241238510fcSJason Evans cv_wait_sig(struct cv *cvp, struct mtx *mp) 242238510fcSJason Evans { 243238510fcSJason Evans struct proc *p; 244238510fcSJason Evans int rval; 245238510fcSJason Evans int sig; 246238510fcSJason Evans WITNESS_SAVE_DECL(mp); 247238510fcSJason Evans 248238510fcSJason Evans p = CURPROC; 249238510fcSJason Evans rval = 0; 250238510fcSJason Evans #ifdef KTRACE 251238510fcSJason Evans if (p && KTRPOINT(p, KTR_CSW)) 252238510fcSJason Evans ktrcsw(p->p_tracep, 1, 0); 253238510fcSJason Evans #endif 254238510fcSJason Evans CV_ASSERT(cvp, mp, p); 255238510fcSJason Evans WITNESS_SLEEP(0, mp); 256238510fcSJason Evans WITNESS_SAVE(mp, mp); 257238510fcSJason Evans 258238510fcSJason Evans mtx_enter(&sched_lock, MTX_SPIN); 259238510fcSJason Evans if (cold || panicstr) { 260238510fcSJason Evans /* 261238510fcSJason Evans * After a panic, or during autoconfiguration, just give 262238510fcSJason Evans * interrupts a chance, then just return; don't run any other 263238510fcSJason Evans * procs or panic below, in case this is the idle process and 264238510fcSJason Evans * already asleep. 265238510fcSJason Evans */ 266238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 267238510fcSJason Evans return 0; 268238510fcSJason Evans } 269238510fcSJason Evans CV_WAIT_VALIDATE(cvp, mp); 270238510fcSJason Evans 271238510fcSJason Evans DROP_GIANT_NOSWITCH(); 272238510fcSJason Evans mtx_exit(mp, MTX_DEF | MTX_NOSWITCH); 273238510fcSJason Evans 274238510fcSJason Evans cv_waitq_add(cvp, p); 275238510fcSJason Evans sig = cv_switch_catch(p); 276238510fcSJason Evans curpriority = p->p_usrpri; 277238510fcSJason Evans 278238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 279238510fcSJason Evans PICKUP_GIANT(); 280238510fcSJason Evans 281238510fcSJason Evans /* proc_lock(p); */ 282238510fcSJason Evans if (sig == 0) 283238510fcSJason Evans sig = CURSIG(p); 284238510fcSJason Evans if (sig != 0) { 285238510fcSJason Evans if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) 286238510fcSJason Evans rval = EINTR; 287238510fcSJason Evans else 288238510fcSJason Evans rval = ERESTART; 289238510fcSJason Evans } 290238510fcSJason Evans /* proc_unlock(p); */ 291238510fcSJason Evans 292238510fcSJason Evans #ifdef KTRACE 293238510fcSJason Evans if (KTRPOINT(p, KTR_CSW)) 294238510fcSJason Evans ktrcsw(p->p_tracep, 0, 0); 295238510fcSJason Evans #endif 296238510fcSJason Evans mtx_enter(mp, MTX_DEF); 297238510fcSJason Evans WITNESS_RESTORE(mp, mp); 298238510fcSJason Evans 299238510fcSJason Evans return (rval); 300238510fcSJason Evans } 301238510fcSJason Evans 302238510fcSJason Evans /* 303238510fcSJason Evans * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 304238510fcSJason Evans * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 305238510fcSJason Evans * expires. 306238510fcSJason Evans */ 307238510fcSJason Evans int 308238510fcSJason Evans cv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 309238510fcSJason Evans { 310238510fcSJason Evans struct proc *p; 311238510fcSJason Evans int rval; 312238510fcSJason Evans WITNESS_SAVE_DECL(mp); 313238510fcSJason Evans 314238510fcSJason Evans p = CURPROC; 315238510fcSJason Evans rval = 0; 316238510fcSJason Evans #ifdef KTRACE 317238510fcSJason Evans if (p && KTRPOINT(p, KTR_CSW)) 318238510fcSJason Evans ktrcsw(p->p_tracep, 1, 0); 319238510fcSJason Evans #endif 320238510fcSJason Evans CV_ASSERT(cvp, mp, p); 321238510fcSJason Evans WITNESS_SLEEP(0, mp); 322238510fcSJason Evans WITNESS_SAVE(mp, mp); 323238510fcSJason Evans 324238510fcSJason Evans mtx_enter(&sched_lock, MTX_SPIN); 325238510fcSJason Evans if (cold || panicstr) { 326238510fcSJason Evans /* 327238510fcSJason Evans * After a panic, or during autoconfiguration, just give 328238510fcSJason Evans * interrupts a chance, then just return; don't run any other 329238510fcSJason Evans * procs or panic below, in case this is the idle process and 330238510fcSJason Evans * already asleep. 331238510fcSJason Evans */ 332238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 333238510fcSJason Evans return 0; 334238510fcSJason Evans } 335238510fcSJason Evans CV_WAIT_VALIDATE(cvp, mp); 336238510fcSJason Evans 337238510fcSJason Evans DROP_GIANT_NOSWITCH(); 338238510fcSJason Evans mtx_exit(mp, MTX_DEF | MTX_NOSWITCH); 339238510fcSJason Evans 340238510fcSJason Evans cv_waitq_add(cvp, p); 341238510fcSJason Evans callout_reset(&p->p_slpcallout, timo, cv_timedwait_end, p); 342238510fcSJason Evans cv_switch(p); 343238510fcSJason Evans curpriority = p->p_usrpri; 344238510fcSJason Evans 345238510fcSJason Evans if (p->p_flag & P_TIMEOUT) { 346238510fcSJason Evans p->p_flag &= ~P_TIMEOUT; 347238510fcSJason Evans rval = EWOULDBLOCK; 348238510fcSJason Evans } else 349238510fcSJason Evans callout_stop(&p->p_slpcallout); 350238510fcSJason Evans 351238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 352238510fcSJason Evans #ifdef KTRACE 353238510fcSJason Evans if (KTRPOINT(p, KTR_CSW)) 354238510fcSJason Evans ktrcsw(p->p_tracep, 0, 0); 355238510fcSJason Evans #endif 356238510fcSJason Evans PICKUP_GIANT(); 357238510fcSJason Evans mtx_enter(mp, MTX_DEF); 358238510fcSJason Evans WITNESS_RESTORE(mp, mp); 359238510fcSJason Evans 360238510fcSJason Evans return (rval); 361238510fcSJason Evans } 362238510fcSJason Evans 363238510fcSJason Evans /* 364238510fcSJason Evans * Wait on a condition variable for at most timo/hz seconds, allowing 365238510fcSJason Evans * interruption by signals. Returns 0 if the process was resumed by cv_signal 366238510fcSJason Evans * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 367238510fcSJason Evans * a signal was caught. 368238510fcSJason Evans */ 369238510fcSJason Evans int 370238510fcSJason Evans cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 371238510fcSJason Evans { 372238510fcSJason Evans struct proc *p; 373238510fcSJason Evans int rval; 374238510fcSJason Evans int sig; 375238510fcSJason Evans WITNESS_SAVE_DECL(mp); 376238510fcSJason Evans 377238510fcSJason Evans p = CURPROC; 378238510fcSJason Evans rval = 0; 379238510fcSJason Evans #ifdef KTRACE 380238510fcSJason Evans if (p && KTRPOINT(p, KTR_CSW)) 381238510fcSJason Evans ktrcsw(p->p_tracep, 1, 0); 382238510fcSJason Evans #endif 383238510fcSJason Evans CV_ASSERT(cvp, mp, p); 384238510fcSJason Evans WITNESS_SLEEP(0, mp); 385238510fcSJason Evans WITNESS_SAVE(mp, mp); 386238510fcSJason Evans 387238510fcSJason Evans mtx_enter(&sched_lock, MTX_SPIN); 388238510fcSJason Evans if (cold || panicstr) { 389238510fcSJason Evans /* 390238510fcSJason Evans * After a panic, or during autoconfiguration, just give 391238510fcSJason Evans * interrupts a chance, then just return; don't run any other 392238510fcSJason Evans * procs or panic below, in case this is the idle process and 393238510fcSJason Evans * already asleep. 394238510fcSJason Evans */ 395238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 396238510fcSJason Evans return 0; 397238510fcSJason Evans } 398238510fcSJason Evans CV_WAIT_VALIDATE(cvp, mp); 399238510fcSJason Evans 400238510fcSJason Evans DROP_GIANT_NOSWITCH(); 401238510fcSJason Evans mtx_exit(mp, MTX_DEF | MTX_NOSWITCH); 402238510fcSJason Evans 403238510fcSJason Evans cv_waitq_add(cvp, p); 404238510fcSJason Evans callout_reset(&p->p_slpcallout, timo, cv_timedwait_end, p); 405238510fcSJason Evans sig = cv_switch_catch(p); 406238510fcSJason Evans curpriority = p->p_usrpri; 407238510fcSJason Evans 408238510fcSJason Evans if (p->p_flag & P_TIMEOUT) { 409238510fcSJason Evans p->p_flag &= ~P_TIMEOUT; 410238510fcSJason Evans rval = EWOULDBLOCK; 411238510fcSJason Evans } else 412238510fcSJason Evans callout_stop(&p->p_slpcallout); 413238510fcSJason Evans 414238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 415238510fcSJason Evans PICKUP_GIANT(); 416238510fcSJason Evans 417238510fcSJason Evans /* proc_lock(p); */ 418238510fcSJason Evans if (sig == 0) 419238510fcSJason Evans sig = CURSIG(p); 420238510fcSJason Evans if (sig != 0) { 421238510fcSJason Evans if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) 422238510fcSJason Evans rval = EINTR; 423238510fcSJason Evans else 424238510fcSJason Evans rval = ERESTART; 425238510fcSJason Evans } 426238510fcSJason Evans /* proc_unlock(p); */ 427238510fcSJason Evans 428238510fcSJason Evans #ifdef KTRACE 429238510fcSJason Evans if (KTRPOINT(p, KTR_CSW)) 430238510fcSJason Evans ktrcsw(p->p_tracep, 0, 0); 431238510fcSJason Evans #endif 432238510fcSJason Evans mtx_enter(mp, MTX_DEF); 433238510fcSJason Evans WITNESS_RESTORE(mp, mp); 434238510fcSJason Evans 435238510fcSJason Evans return (rval); 436238510fcSJason Evans } 437238510fcSJason Evans 438238510fcSJason Evans /* 439238510fcSJason Evans * Common code for signal and broadcast. Assumes waitq is not empty. Must be 440238510fcSJason Evans * called with sched_lock held. 441238510fcSJason Evans */ 442238510fcSJason Evans static __inline void 443238510fcSJason Evans cv_wakeup(struct cv *cvp) 444238510fcSJason Evans { 445238510fcSJason Evans struct proc *p; 446238510fcSJason Evans 447238510fcSJason Evans p = TAILQ_FIRST(&cvp->cv_waitq); 448238510fcSJason Evans KASSERT(p->p_wchan == cvp, ("%s: bogus wchan", __FUNCTION__)); 449238510fcSJason Evans KASSERT(p->p_flag & P_CVWAITQ, ("%s: not on waitq", __FUNCTION__)); 450238510fcSJason Evans TAILQ_REMOVE(&cvp->cv_waitq, p, p_slpq); 451238510fcSJason Evans p->p_flag &= ~P_CVWAITQ; 452238510fcSJason Evans p->p_wchan = 0; 453238510fcSJason Evans if (p->p_stat == SSLEEP) { 454238510fcSJason Evans /* OPTIMIZED EXPANSION OF setrunnable(p); */ 455238510fcSJason Evans CTR3(KTR_PROC, "cv_signal: proc %p (pid %d, %s)", 456238510fcSJason Evans p, p->p_pid, p->p_comm); 457238510fcSJason Evans if (p->p_slptime > 1) 458238510fcSJason Evans updatepri(p); 459238510fcSJason Evans p->p_slptime = 0; 460238510fcSJason Evans p->p_stat = SRUN; 461238510fcSJason Evans if (p->p_flag & P_INMEM) { 462238510fcSJason Evans setrunqueue(p); 463238510fcSJason Evans maybe_resched(p); 464238510fcSJason Evans } else { 465238510fcSJason Evans p->p_flag |= P_SWAPINREQ; 466238510fcSJason Evans wakeup(&proc0); 467238510fcSJason Evans } 468238510fcSJason Evans /* END INLINE EXPANSION */ 469238510fcSJason Evans } 470238510fcSJason Evans } 471238510fcSJason Evans 472238510fcSJason Evans /* 473238510fcSJason Evans * Signal a condition variable, wakes up one waiting process. Will also wakeup 474238510fcSJason Evans * the swapper if the process is not in memory, so that it can bring the 475238510fcSJason Evans * sleeping process in. Note that this may also result in additional processes 476238510fcSJason Evans * being made runnable. Should be called with the same mutex as was passed to 477238510fcSJason Evans * cv_wait held. 478238510fcSJason Evans */ 479238510fcSJason Evans void 480238510fcSJason Evans cv_signal(struct cv *cvp) 481238510fcSJason Evans { 482238510fcSJason Evans 483238510fcSJason Evans KASSERT(cvp != NULL, ("%s: cvp NULL", __FUNCTION__)); 484238510fcSJason Evans mtx_enter(&sched_lock, MTX_SPIN); 485238510fcSJason Evans if (!TAILQ_EMPTY(&cvp->cv_waitq)) { 486238510fcSJason Evans CV_SIGNAL_VALIDATE(cvp); 487238510fcSJason Evans cv_wakeup(cvp); 488238510fcSJason Evans } 489238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 490238510fcSJason Evans } 491238510fcSJason Evans 492238510fcSJason Evans /* 493238510fcSJason Evans * Broadcast a signal to a condition variable. Wakes up all waiting processes. 494238510fcSJason Evans * Should be called with the same mutex as was passed to cv_wait held. 495238510fcSJason Evans */ 496238510fcSJason Evans void 497238510fcSJason Evans cv_broadcast(struct cv *cvp) 498238510fcSJason Evans { 499238510fcSJason Evans 500238510fcSJason Evans KASSERT(cvp != NULL, ("%s: cvp NULL", __FUNCTION__)); 501238510fcSJason Evans mtx_enter(&sched_lock, MTX_SPIN); 502238510fcSJason Evans CV_SIGNAL_VALIDATE(cvp); 503238510fcSJason Evans while (!TAILQ_EMPTY(&cvp->cv_waitq)) 504238510fcSJason Evans cv_wakeup(cvp); 505238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 506238510fcSJason Evans } 507238510fcSJason Evans 508238510fcSJason Evans /* 509238510fcSJason Evans * Remove a process from the wait queue of its condition variable. This may be 510238510fcSJason Evans * called externally. 511238510fcSJason Evans */ 512238510fcSJason Evans void 513238510fcSJason Evans cv_waitq_remove(struct proc *p) 514238510fcSJason Evans { 515238510fcSJason Evans struct cv *cvp; 516238510fcSJason Evans 517238510fcSJason Evans mtx_enter(&sched_lock, MTX_SPIN); 518238510fcSJason Evans if ((cvp = p->p_wchan) != NULL && p->p_flag & P_CVWAITQ) { 519238510fcSJason Evans TAILQ_REMOVE(&cvp->cv_waitq, p, p_slpq); 520238510fcSJason Evans p->p_flag &= ~P_CVWAITQ; 521238510fcSJason Evans p->p_wchan = NULL; 522238510fcSJason Evans } 523238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 524238510fcSJason Evans } 525238510fcSJason Evans 526238510fcSJason Evans /* 527238510fcSJason Evans * Timeout function for cv_timedwait. Put the process on the runqueue and set 528238510fcSJason Evans * its timeout flag. 529238510fcSJason Evans */ 530238510fcSJason Evans static void 531238510fcSJason Evans cv_timedwait_end(void *arg) 532238510fcSJason Evans { 533238510fcSJason Evans struct proc *p; 534238510fcSJason Evans 535238510fcSJason Evans p = arg; 536238510fcSJason Evans CTR3(KTR_PROC, "cv_timedwait_end: proc %p (pid %d, %s)", p, p->p_pid, 537238510fcSJason Evans p->p_comm); 538238510fcSJason Evans mtx_enter(&sched_lock, MTX_SPIN); 539238510fcSJason Evans if (p->p_wchan != NULL) { 540238510fcSJason Evans if (p->p_stat == SSLEEP) 541238510fcSJason Evans setrunnable(p); 542238510fcSJason Evans else 543238510fcSJason Evans cv_waitq_remove(p); 544238510fcSJason Evans p->p_flag |= P_TIMEOUT; 545238510fcSJason Evans } 546238510fcSJason Evans mtx_exit(&sched_lock, MTX_SPIN); 547238510fcSJason Evans } 548