/* * callout_halt: * * Cancel a pending callout. If in-flight, block until it completes. * May not be called from a hard interrupt handler. If the callout * can take locks, the caller of callout_halt() must not hold any of * those locks, otherwise the two could deadlock. If 'interlock' is * non-NULL and we must wait for the callout to complete, it will be * released and re-acquired before returning. */ bool callout_halt(callout_t *cs, void *interlock) { callout_impl_t *c = (callout_impl_t *)cs; struct callout_cpu *cc; struct lwp *l; kmutex_t *lock, *relock; bool expired; KASSERT(c->c_magic == CALLOUT_MAGIC); KASSERT(!cpu_intr_p()); lock = callout_lock(c); relock = NULL; expired = ((c->c_flags & CALLOUT_FIRED) != 0); if ((c->c_flags & CALLOUT_PENDING) != 0) CIRCQ_REMOVE(&c->c_list); c->c_flags &= ~(CALLOUT_PENDING|CALLOUT_FIRED); l = curlwp; for (;;) { cc = c->c_cpu; if (__predict_true(cc->cc_active != c || cc->cc_lwp == l)) break; if (interlock != NULL) { /* * Avoid potential scheduler lock order problems by * dropping the interlock without the callout lock * held. */ mutex_spin_exit(lock); mutex_exit(interlock); relock = interlock; interlock = NULL; } else { /* XXX Better to do priority inheritance. */ KASSERT(l->l_wchan == NULL); cc->cc_nwait++; cc->cc_ev_block.ev_count++; l->l_kpriority = true; sleepq_enter(&cc->cc_sleepq, l, cc->cc_lock); sleepq_enqueue(&cc->cc_sleepq, cc, "callout", &sleep_syncobj); sleepq_block(0, false); } lock = callout_lock(c); } mutex_spin_exit(lock); if (__predict_false(relock != NULL)) mutex_enter(relock); return expired; }
int kcgetc_wait(char *chp) { char ch; int error; for (;;) { CONSOLE_LOCK(kernel_input); error = kernel_input->c_getc(kernel_input->c_softc, &ch); switch (error) { case ERROR_AGAIN: sleepq_enter(&kernel_input_sleepq); /* sleepq_enter drops console lock. */ continue; default: CONSOLE_UNLOCK(kernel_input); if (error != 0) return (error); *chp = ch; return (0); } } }