diff options
Diffstat (limited to 'freebsd/sys/kern/kern_time.c')
-rw-r--r-- | freebsd/sys/kern/kern_time.c | 164 |
1 files changed, 99 insertions, 65 deletions
diff --git a/freebsd/sys/kern/kern_time.c b/freebsd/sys/kern/kern_time.c index 44bd206c..2fb4dd2e 100644 --- a/freebsd/sys/kern/kern_time.c +++ b/freebsd/sys/kern/kern_time.c @@ -34,6 +34,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include <rtems/bsd/local/opt_ktrace.h> + #include <rtems/bsd/sys/param.h> #include <sys/systm.h> #include <sys/limits.h> @@ -45,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/resourcevar.h> #include <sys/signalvar.h> #include <sys/kernel.h> +#include <sys/sleepqueue.h> #include <sys/syscallsubr.h> #include <sys/sysctl.h> #include <sys/sysent.h> @@ -55,6 +58,9 @@ __FBSDID("$FreeBSD$"); #include <sys/timers.h> #include <sys/timetc.h> #include <sys/vnode.h> +#ifdef KTRACE +#include <sys/ktrace.h> +#endif #include <vm/vm.h> #include <vm/vm_extern.h> @@ -119,9 +125,7 @@ settime(struct thread *td, struct timeval *tv) struct timeval delta, tv1, tv2; static struct timeval maxtime, laststep; struct timespec ts; - int s; - s = splclock(); microtime(&tv1); delta = *tv; timevalsub(&delta, &tv1); @@ -151,10 +155,8 @@ settime(struct thread *td, struct timeval *tv) printf("Time adjustment clamped to -1 second\n"); } } else { - if (tv1.tv_sec == laststep.tv_sec) { - splx(s); + if (tv1.tv_sec == laststep.tv_sec) return (EPERM); - } if (delta.tv_sec > 1) { tv->tv_sec = tv1.tv_sec + 1; printf("Time adjustment clamped to +1 second\n"); @@ -165,10 +167,8 @@ settime(struct thread *td, struct timeval *tv) ts.tv_sec = tv->tv_sec; ts.tv_nsec = tv->tv_usec * 1000; - mtx_lock(&Giant); tc_setclock(&ts); resettodr(); - mtx_unlock(&Giant); return (0); } @@ -280,10 +280,10 @@ get_process_cputime(struct proc *targetp, struct timespec *ats) uint64_t runtime; struct rusage ru; - PROC_SLOCK(targetp); + PROC_STATLOCK(targetp); rufetch(targetp, &ru); runtime = targetp->p_rux.rux_runtime; - PROC_SUNLOCK(targetp); + PROC_STATUNLOCK(targetp); cputick2timespec(runtime, ats); } @@ -332,17 +332,17 @@ kern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec *ats) break; case CLOCK_VIRTUAL: PROC_LOCK(p); - PROC_SLOCK(p); + PROC_STATLOCK(p); calcru(p, &user, &sys); - PROC_SUNLOCK(p); + PROC_STATUNLOCK(p); PROC_UNLOCK(p); TIMEVAL_TO_TIMESPEC(&user, ats); break; case CLOCK_PROF: PROC_LOCK(p); - PROC_SLOCK(p); + PROC_STATLOCK(p); calcru(p, &user, &sys); - PROC_SUNLOCK(p); + PROC_STATUNLOCK(p); PROC_UNLOCK(p); timevaladd(&user, &sys); TIMEVAL_TO_TIMESPEC(&user, ats); @@ -407,7 +407,8 @@ kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats) return (error); if (clock_id != CLOCK_REALTIME) return (EINVAL); - if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000) + if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000 || + ats->tv_sec < 0) return (EINVAL); /* XXX Don't convert nsec->usec and back */ TIMESPEC_TO_TIMEVAL(&atv, ats); @@ -463,7 +464,7 @@ kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts) case CLOCK_VIRTUAL: case CLOCK_PROF: /* Accurately round up here because we can do so cheaply. */ - ts->tv_nsec = (1000000000 + hz - 1) / hz; + ts->tv_nsec = howmany(1000000000, hz); break; case CLOCK_SECOND: ts->tv_sec = 1; @@ -486,43 +487,50 @@ kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts) } #endif -static int nanowait; +static uint8_t nanowait[MAXCPU]; int kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) { - struct timespec ts, ts2, ts3; - struct timeval tv; + struct timespec ts; + sbintime_t sbt, sbtt, prec, tmp; + time_t over; int error; if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) return (EINVAL); if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) return (0); - getnanouptime(&ts); - timespecadd(&ts, rqt); - TIMESPEC_TO_TIMEVAL(&tv, rqt); - for (;;) { - error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp", - tvtohz(&tv)); - getnanouptime(&ts2); - if (error != EWOULDBLOCK) { - if (error == ERESTART) - error = EINTR; - if (rmt != NULL) { - timespecsub(&ts, &ts2); - if (ts.tv_sec < 0) - timespecclear(&ts); - *rmt = ts; - } - return (error); + ts = *rqt; + if (ts.tv_sec > INT32_MAX / 2) { + over = ts.tv_sec - INT32_MAX / 2; + ts.tv_sec -= over; + } else + over = 0; + tmp = tstosbt(ts); + prec = tmp; + prec >>= tc_precexp; + if (TIMESEL(&sbt, tmp)) + sbt += tc_tick_sbt; + sbt += tmp; + error = tsleep_sbt(&nanowait[curcpu], PWAIT | PCATCH, "nanslp", + sbt, prec, C_ABSOLUTE); + if (error != EWOULDBLOCK) { + if (error == ERESTART) + error = EINTR; + TIMESEL(&sbtt, tmp); + if (rmt != NULL) { + ts = sbttots(sbt - sbtt); + ts.tv_sec += over; + if (ts.tv_sec < 0) + timespecclear(&ts); + *rmt = ts; } - if (timespeccmp(&ts2, &ts, >=)) + if (sbtt >= sbt) return (0); - ts3 = ts; - timespecsub(&ts3, &ts2); - TIMESPEC_TO_TIMEVAL(&tv, &ts3); + return (error); } + return (0); } #ifndef _SYS_SYSPROTO_H_ @@ -623,7 +631,8 @@ kern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp) return (error); /* Verify all parameters before changing time. */ if (tv) { - if (tv->tv_usec < 0 || tv->tv_usec >= 1000000) + if (tv->tv_usec < 0 || tv->tv_usec >= 1000000 || + tv->tv_sec < 0) return (EINVAL); error = settime(td, tv); } @@ -693,17 +702,21 @@ kern_getitimer(struct thread *td, u_int which, struct itimerval *aitv) *aitv = p->p_realtimer; PROC_UNLOCK(p); if (timevalisset(&aitv->it_value)) { - getmicrouptime(&ctv); + microuptime(&ctv); if (timevalcmp(&aitv->it_value, &ctv, <)) timevalclear(&aitv->it_value); else timevalsub(&aitv->it_value, &ctv); } } else { - PROC_SLOCK(p); + PROC_ITIMLOCK(p); *aitv = p->p_stats->p_timer[which]; - PROC_SUNLOCK(p); + PROC_ITIMUNLOCK(p); } +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + ktritimerval(aitv); +#endif return (0); } @@ -738,28 +751,37 @@ kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv, { struct proc *p = td->td_proc; struct timeval ctv; + sbintime_t sbt, pr; if (aitv == NULL) return (kern_getitimer(td, which, oitv)); if (which > ITIMER_PROF) return (EINVAL); - if (itimerfix(&aitv->it_value)) +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + ktritimerval(aitv); +#endif + if (itimerfix(&aitv->it_value) || + aitv->it_value.tv_sec > INT32_MAX / 2) return (EINVAL); if (!timevalisset(&aitv->it_value)) timevalclear(&aitv->it_interval); - else if (itimerfix(&aitv->it_interval)) + else if (itimerfix(&aitv->it_interval) || + aitv->it_interval.tv_sec > INT32_MAX / 2) return (EINVAL); if (which == ITIMER_REAL) { PROC_LOCK(p); if (timevalisset(&p->p_realtimer.it_value)) callout_stop(&p->p_itcallout); - getmicrouptime(&ctv); + microuptime(&ctv); if (timevalisset(&aitv->it_value)) { - callout_reset(&p->p_itcallout, tvtohz(&aitv->it_value), - realitexpire, p); + pr = tvtosbt(aitv->it_value) >> tc_precexp; timevaladd(&aitv->it_value, &ctv); + sbt = tvtosbt(aitv->it_value); + callout_reset_sbt(&p->p_itcallout, sbt, pr, + realitexpire, p, C_ABSOLUTE); } *oitv = p->p_realtimer; p->p_realtimer = *aitv; @@ -771,11 +793,23 @@ kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv, timevalsub(&oitv->it_value, &ctv); } } else { - PROC_SLOCK(p); + if (aitv->it_interval.tv_sec == 0 && + aitv->it_interval.tv_usec != 0 && + aitv->it_interval.tv_usec < tick) + aitv->it_interval.tv_usec = tick; + if (aitv->it_value.tv_sec == 0 && + aitv->it_value.tv_usec != 0 && + aitv->it_value.tv_usec < tick) + aitv->it_value.tv_usec = tick; + PROC_ITIMLOCK(p); *oitv = p->p_stats->p_timer[which]; p->p_stats->p_timer[which] = *aitv; - PROC_SUNLOCK(p); + PROC_ITIMUNLOCK(p); } +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + ktritimerval(oitv); +#endif return (0); } @@ -795,7 +829,8 @@ void realitexpire(void *arg) { struct proc *p; - struct timeval ctv, ntv; + struct timeval ctv; + sbintime_t isbt; p = (struct proc *)arg; kern_psignal(p, SIGALRM); @@ -805,19 +840,17 @@ realitexpire(void *arg) wakeup(&p->p_itcallout); return; } - for (;;) { + isbt = tvtosbt(p->p_realtimer.it_interval); + if (isbt >= sbt_timethreshold) + getmicrouptime(&ctv); + else + microuptime(&ctv); + do { timevaladd(&p->p_realtimer.it_value, &p->p_realtimer.it_interval); - getmicrouptime(&ctv); - if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) { - ntv = p->p_realtimer.it_value; - timevalsub(&ntv, &ctv); - callout_reset(&p->p_itcallout, tvtohz(&ntv) - 1, - realitexpire, p); - return; - } - } - /*NOTREACHED*/ + } while (timevalcmp(&p->p_realtimer.it_value, &ctv, <=)); + callout_reset_sbt(&p->p_itcallout, tvtosbt(p->p_realtimer.it_value), + isbt >> tc_precexp, realitexpire, p, C_ABSOLUTE); } #endif /* __rtems__ */ @@ -833,8 +866,9 @@ itimerfix(struct timeval *tv) if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) return (EINVAL); - if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) - tv->tv_usec = tick; + if (tv->tv_sec == 0 && tv->tv_usec != 0 && + tv->tv_usec < (u_int)tick / 16) + tv->tv_usec = (u_int)tick / 16; return (0); } @@ -977,7 +1011,7 @@ ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) return (maxpps != 0); } else { (*curpps)++; /* NB: ignore potential overflow */ - return (maxpps < 0 || *curpps < maxpps); + return (maxpps < 0 || *curpps <= maxpps); } } |