cv_timedwait can't handle sub-tick waits, which we can't do now but
when we go tickless will be handy.

It's also a pain to use in a loop with a maximum timeout -- it doesn't
tell you how many ticks passed, so you have to maintain that yourself:

        unsigned timeout = mstohz(1000);
        unsigned now, end;

        now = hardclock_ticks;
        end = now + timeout;
        while (!condition) {
                error = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock,
                    timeout);
                if (error)
                        goto fail;
                now = hardclock_ticks;
                if (end < now) {
                        error = EWOULDBLOCK;
                        goto fail;
                }
                timeout = end - now;
        }

I propose to add the following routines to address these shortcomings:

int     cv_timedwaitns(kcondvar_t *, kmutex_t *, struct timespec *);
int     cv_timedwaitns_sig(kcondvar_t *, kmutex_t *, struct timespec *);

cv_timedwaitns(cv, lock, timeout) waits a duration at most timeout for
cv.  When it returns, it stores in timeout the remaining time, so that
you can safely write loops like:

        struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 };
        int error;

        while (!condition) {
                error = cv_timedwaitns_sig(&sc->sc_cv, &sc->sc_lock,
                    &timeout);
                if (error)
                        goto fail;
        }

Objections?
int
cv_timedwaitns(kcondvar_t *cv, kmutex_t *lock, struct timespec *wait)
{
        struct timespec now, end;
        unsigned ticks;
        int error;

        getnanouptime(&now);
        timespecadd(&now, wait, &end);
        ticks = mstohz(timespec2ns(wait) / 1000000);
        error = cv_timedwait(cv, lock, ticks);
        getnanouptime(&now);
        if (timespeccmp(&now, &end, <))
                timespecsub(&end, &now, wait);
        else
                timespecclear(wait);

        return error;
}

int
cv_timedwaitns_sig(kcondvar_t *cv, kmutex_t *lock, struct timespec *wait)
{
        struct timespec now, end;
        unsigned ticks;
        int error;

        getnanouptime(&now);
        timespecadd(&now, wait, &end);
        ticks = mstohz(timespec2ns(wait) / 1000000);
        error = cv_timedwait_sig(cv, lock, ticks);
        getnanouptime(&now);
        if (timespeccmp(&now, &end, <))
                timespecsub(&end, &now, wait);
        else
                timespecclear(wait);

        return error;
}

Reply via email to