int __thr_umtx_timedlock(volatile umtx_t *mtx, const struct timespec *timeout) { struct timespec ts, ts2, ts3; int timo, ret; if ((timeout->tv_sec < 0) || (timeout->tv_sec == 0 && timeout->tv_nsec <= 0)) return (ETIMEDOUT); /* XXX there should have MONO timer! */ clock_gettime(CLOCK_REALTIME, &ts); TIMESPEC_ADD(&ts, &ts, timeout); ts2 = *timeout; for (;;) { if (ts2.tv_nsec) { timo = (int)(ts2.tv_nsec / 1000); if (timo == 0) timo = 1; } else { timo = 1000000; } ret = __thr_umtx_lock(mtx, timo); if (ret != ETIMEDOUT) break; clock_gettime(CLOCK_REALTIME, &ts3); TIMESPEC_SUB(&ts2, &ts, &ts3); if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { ret = ETIMEDOUT; break; } } return (ret); }
/* * Regular umtx wait that cannot return EINTR */ int _thr_umtx_wait(volatile umtx_t *mtx, int exp, const struct timespec *timeout, int clockid) { struct timespec ts, ts2, ts3; int timo, errval, ret = 0; cpu_ccfence(); if (*mtx != exp) return (0); if (timeout == NULL) { /* * NOTE: If no timeout, EINTR cannot be returned. Ignore * EINTR. */ while ((errval = _umtx_sleep_err(mtx, exp, 10000000)) > 0) { if (errval == EBUSY) break; #if 0 if (errval == ETIMEDOUT || errval == EWOULDBLOCK) { if (*mtx != exp) { fprintf(stderr, "thr_umtx_wait: FAULT VALUE CHANGE " "%d -> %d oncond %p\n", exp, *mtx, mtx); } } #endif if (*mtx != exp) return(0); } return (ret); } /* * Timed waits can return EINTR */ if ((timeout->tv_sec < 0) || (timeout->tv_sec == 0 && timeout->tv_nsec <= 0)) return (ETIMEDOUT); clock_gettime(clockid, &ts); TIMESPEC_ADD(&ts, &ts, timeout); ts2 = *timeout; for (;;) { if (ts2.tv_nsec) { timo = (int)(ts2.tv_nsec / 1000); if (timo == 0) timo = 1; } else { timo = 1000000; } if ((errval = _umtx_sleep_err(mtx, exp, timo)) > 0) { if (errval == EBUSY) { ret = 0; break; } if (errval == EINTR) { ret = EINTR; break; } } clock_gettime(clockid, &ts3); TIMESPEC_SUB(&ts2, &ts, &ts3); if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { ret = ETIMEDOUT; break; } } return (ret); }
int _nanosleep(const struct timespec *time_to_sleep, struct timespec *time_remaining) { struct pthread *curthread = _get_curthread(); int ret = 0; struct timespec ts, ts1; struct timespec remaining_time; struct timespec wakeup_time; /* Check if the time to sleep is legal: */ if ((time_to_sleep == NULL) || (time_to_sleep->tv_sec < 0) || (time_to_sleep->tv_nsec < 0) || (time_to_sleep->tv_nsec >= 1000000000)) { /* Return an EINVAL error : */ errno = EINVAL; ret = -1; } else { if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) return (__sys_nanosleep(time_to_sleep, time_remaining)); KSE_GET_TOD(curthread->kse, &ts); /* Calculate the time for the current thread to wake up: */ TIMESPEC_ADD(&wakeup_time, &ts, time_to_sleep); THR_LOCK_SWITCH(curthread); curthread->interrupted = 0; curthread->wakeup_time = wakeup_time; THR_SET_STATE(curthread, PS_SLEEP_WAIT); /* Reschedule the current thread to sleep: */ _thr_sched_switch_unlocked(curthread); /* Calculate the remaining time to sleep: */ KSE_GET_TOD(curthread->kse, &ts1); remaining_time.tv_sec = time_to_sleep->tv_sec + ts.tv_sec - ts1.tv_sec; remaining_time.tv_nsec = time_to_sleep->tv_nsec + ts.tv_nsec - ts1.tv_nsec; /* Check if the nanosecond field has underflowed: */ if (remaining_time.tv_nsec < 0) { /* Handle the underflow: */ remaining_time.tv_sec -= 1; remaining_time.tv_nsec += 1000000000; } /* Check if the nanosecond field has overflowed: */ else if (remaining_time.tv_nsec >= 1000000000) { /* Handle the overflow: */ remaining_time.tv_sec += 1; remaining_time.tv_nsec -= 1000000000; } /* Check if the sleep was longer than the required time: */ if (remaining_time.tv_sec < 0) { /* Reset the time left: */ remaining_time.tv_sec = 0; remaining_time.tv_nsec = 0; } /* Check if the time remaining is to be returned: */ if (time_remaining != NULL) { /* Return the actual time slept: */ time_remaining->tv_sec = remaining_time.tv_sec; time_remaining->tv_nsec = remaining_time.tv_nsec; } /* Check if the sleep was interrupted: */ if (curthread->interrupted) { /* Return an EINTR error : */ errno = EINTR; ret = -1; } } return (ret); }