int lwp_park(struct timespec *ts, const void *hint) { struct timespec tsx; sleepq_t *sq; kmutex_t *mp; wchan_t wchan; int timo, error; lwp_t *l; /* Fix up the given timeout value. */ if (ts != NULL) { getnanotime(&tsx); timespecsub(ts, &tsx, &tsx); if (tsx.tv_sec < 0 || (tsx.tv_sec == 0 && tsx.tv_nsec <= 0)) return ETIMEDOUT; if ((error = itimespecfix(&tsx)) != 0) return error; timo = tstohz(&tsx); KASSERT(timo != 0); } else timo = 0; /* Find and lock the sleep queue. */ l = curlwp; wchan = lwp_park_wchan(l->l_proc, hint); sq = sleeptab_lookup(&lwp_park_tab, wchan, &mp); /* * Before going the full route and blocking, check to see if an * unpark op is pending. */ lwp_lock(l); if ((l->l_flag & (LW_CANCELLED | LW_UNPARKED)) != 0) { l->l_flag &= ~(LW_CANCELLED | LW_UNPARKED); lwp_unlock(l); mutex_spin_exit(mp); return EALREADY; } lwp_unlock_to(l, mp); l->l_biglocks = 0; sleepq_enqueue(sq, wchan, "parked", &lwp_park_sobj); error = sleepq_block(timo, true); switch (error) { case EWOULDBLOCK: error = ETIMEDOUT; break; case ERESTART: error = EINTR; break; default: /* nothing */ break; } return error; }
int nanosleep1(struct lwp *l, clockid_t clock_id, int flags, struct timespec *rqt, struct timespec *rmt) { struct timespec rmtstart; int error, timo; if ((error = ts2timo(clock_id, flags, rqt, &timo, &rmtstart)) != 0) { if (error == ETIMEDOUT) { error = 0; if (rmt != NULL) rmt->tv_sec = rmt->tv_nsec = 0; } return error; } /* * Avoid inadvertently sleeping forever */ if (timo == 0) timo = 1; again: error = kpause("nanoslp", true, timo, NULL); if (rmt != NULL || error == 0) { struct timespec rmtend; struct timespec t0; struct timespec *t; (void)clock_gettime1(clock_id, &rmtend); t = (rmt != NULL) ? rmt : &t0; if (flags & TIMER_ABSTIME) { timespecsub(rqt, &rmtend, t); } else { timespecsub(&rmtend, &rmtstart, t); timespecsub(rqt, t, t); } if (t->tv_sec < 0) timespecclear(t); if (error == 0) { timo = tstohz(t); if (timo > 0) goto again; } } if (error == ERESTART) error = EINTR; if (error == EWOULDBLOCK) error = 0; return error; }
static int jzsmb_transfer_write(device_t dev, struct iic_msg *msg, int stop_hold) { struct jzsmb_softc *sc; struct timespec start, diff; uint16_t con, resid; int timeo; sc = device_get_softc(dev); timeo = JZSMB_TIMEOUT * msg->len; SMB_ASSERT_LOCKED(sc); con = SMB_READ(sc, SMBCON); con |= SMBCON_STPHLD; SMB_WRITE(sc, SMBCON, con); getnanouptime(&start); for (resid = msg->len; resid > 0; resid--) { for (;;) { getnanouptime(&diff); timespecsub(&diff, &start); if ((SMB_READ(sc, SMBST) & SMBST_TFNF) != 0) { SMB_WRITE(sc, SMBDC, msg->buf[msg->len - resid]); break; } else DELAY((1000 * hz) / JZSMB_TIMEOUT); if (tstohz(&diff) >= timeo) { device_printf(dev, "write timeout (status=0x%02x)\n", SMB_READ(sc, SMBST)); return (EIO); } } } if (!stop_hold) { con = SMB_READ(sc, SMBCON); con &= ~SMBCON_STPHLD; SMB_WRITE(sc, SMBCON, con); } return (0); }
static int jzsmb_transfer_read(device_t dev, struct iic_msg *msg) { struct jzsmb_softc *sc; struct timespec start, diff; uint16_t con, resid; int timeo; sc = device_get_softc(dev); timeo = JZSMB_TIMEOUT * msg->len; SMB_ASSERT_LOCKED(sc); con = SMB_READ(sc, SMBCON); con |= SMBCON_STPHLD; SMB_WRITE(sc, SMBCON, con); getnanouptime(&start); for (resid = msg->len; resid > 0; resid--) { for (int i = 0; i < min(resid, 8); i++) SMB_WRITE(sc, SMBDC, SMBDC_CMD); for (;;) { getnanouptime(&diff); timespecsub(&diff, &start); if ((SMB_READ(sc, SMBST) & SMBST_RFNE) != 0) { msg->buf[msg->len - resid] = SMB_READ(sc, SMBDC) & SMBDC_DAT; break; } else DELAY(1000); if (tstohz(&diff) >= timeo) { device_printf(dev, "read timeout (status=0x%02x)\n", SMB_READ(sc, SMBST)); return (EIO); } } } con = SMB_READ(sc, SMBCON); con &= ~SMBCON_STPHLD; SMB_WRITE(sc, SMBCON, con); return (0); }
int sigtimedwait1(struct lwp *l, const struct sys_____sigtimedwait50_args *uap, register_t *retval, copyin_t fetchss, copyout_t storeinf, copyin_t fetchts, copyout_t storets) { /* { syscallarg(const sigset_t *) set; syscallarg(siginfo_t *) info; syscallarg(struct timespec *) timeout; } */ struct proc *p = l->l_proc; int error, signum, timo; struct timespec ts, tsstart, tsnow; ksiginfo_t ksi; /* * Calculate timeout, if it was specified. * * NULL pointer means an infinite timeout. * {.tv_sec = 0, .tv_nsec = 0} means do not block. */ if (SCARG(uap, timeout)) { error = (*fetchts)(SCARG(uap, timeout), &ts, sizeof(ts)); if (error) return error; if ((error = itimespecfix(&ts)) != 0) return error; timo = tstohz(&ts); if (timo == 0) { if (ts.tv_sec == 0 && ts.tv_nsec == 0) timo = -1; /* do not block */ else timo = 1; /* the shortest possible timeout */ } /* * Remember current uptime, it would be used in * ECANCELED/ERESTART case. */ getnanouptime(&tsstart); } else { memset(&tsstart, 0, sizeof(tsstart)); /* XXXgcc */ timo = 0; /* infinite timeout */ } error = (*fetchss)(SCARG(uap, set), &l->l_sigwaitset, sizeof(l->l_sigwaitset)); if (error) return error; /* * Silently ignore SA_CANTMASK signals. psignal1() would ignore * SA_CANTMASK signals in waitset, we do this only for the below * siglist check. */ sigminusset(&sigcantmask, &l->l_sigwaitset); mutex_enter(p->p_lock); /* Check for pending signals in the process, if no - then in LWP. */ if ((signum = sigget(&p->p_sigpend, &ksi, 0, &l->l_sigwaitset)) == 0) signum = sigget(&l->l_sigpend, &ksi, 0, &l->l_sigwaitset); if (signum != 0) { /* If found a pending signal, just copy it out to the user. */ mutex_exit(p->p_lock); goto out; } if (timo < 0) { /* If not allowed to block, return an error */ mutex_exit(p->p_lock); return EAGAIN; } /* * Set up the sigwait list and wait for signal to arrive. * We can either be woken up or time out. */ l->l_sigwaited = &ksi; LIST_INSERT_HEAD(&p->p_sigwaiters, l, l_sigwaiter); error = cv_timedwait_sig(&l->l_sigcv, p->p_lock, timo); /* * Need to find out if we woke as a result of _lwp_wakeup() or a * signal outside our wait set. */ if (l->l_sigwaited != NULL) { if (error == EINTR) { /* Wakeup via _lwp_wakeup(). */ error = ECANCELED; } else if (!error) { /* Spurious wakeup - arrange for syscall restart. */ error = ERESTART; } l->l_sigwaited = NULL; LIST_REMOVE(l, l_sigwaiter); } mutex_exit(p->p_lock); /* * If the sleep was interrupted (either by signal or wakeup), update * the timeout and copyout new value back. It would be used when * the syscall would be restarted or called again. */ if (timo && (error == ERESTART || error == ECANCELED)) { getnanouptime(&tsnow); /* Compute how much time has passed since start. */ timespecsub(&tsnow, &tsstart, &tsnow); /* Substract passed time from timeout. */ timespecsub(&ts, &tsnow, &ts); if (ts.tv_sec < 0) error = EAGAIN; else { /* Copy updated timeout to userland. */ error = (*storets)(&ts, SCARG(uap, timeout), sizeof(ts)); } } out: /* * If a signal from the wait set arrived, copy it to userland. * Copy only the used part of siginfo, the padding part is * left unchanged (userland is not supposed to touch it anyway). */ if (error == 0 && SCARG(uap, info)) { error = (*storeinf)(&ksi.ksi_info, SCARG(uap, info), sizeof(ksi.ksi_info)); } if (error == 0) *retval = ksi.ksi_info._signo; return error; }