summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/kern_time.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/kern/kern_time.c')
-rw-r--r--freebsd/sys/kern/kern_time.c164
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);
}
}