-/* kern_time.c 6.3 84/08/29 */
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ * @(#)kern_time.c 8.2 (Berkeley) %G%
+ */
-#include "../machine/reg.h"
+#include <sys/param.h>
+#include <sys/resourcevar.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
-#include "param.h"
-#include "dir.h" /* XXX */
-#include "user.h"
-#include "kernel.h"
-#include "inode.h"
-#include "proc.h"
/*
* Time of day and interval timer support.
* timers when they expire.
*/
-gettimeofday()
+struct gettimeofday_args {
+ struct timeval *tp;
+ struct timezone *tzp;
+};
+/* ARGSUSED */
+gettimeofday(p, uap, retval)
+ struct proc *p;
+ register struct gettimeofday_args *uap;
+ int *retval;
{
- register struct a {
- struct timeval *tp;
- struct timezone *tzp;
- } *uap = (struct a *)u.u_ap;
struct timeval atv;
- int s;
+ int error = 0;
- s = spl7(); atv = time; splx(s);
- u.u_error = copyout((caddr_t)&atv, (caddr_t)uap->tp, sizeof (atv));
- if (u.u_error)
- return;
- if (uap->tzp == 0)
- return;
- /* SHOULD HAVE PER-PROCESS TIMEZONE */
- u.u_error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, sizeof (tz));
+ if (uap->tp) {
+ microtime(&atv);
+ if (error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
+ sizeof (atv)))
+ return (error);
+ }
+ if (uap->tzp)
+ error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
+ sizeof (tz));
+ return (error);
}
-settimeofday()
+struct settimeofday_args {
+ struct timeval *tv;
+ struct timezone *tzp;
+};
+/* ARGSUSED */
+settimeofday(p, uap, retval)
+ struct proc *p;
+ struct settimeofday_args *uap;
+ int *retval;
{
- register struct a {
- struct timeval *tv;
- struct timezone *tzp;
- } *uap = (struct a *)u.u_ap;
- struct timeval atv;
+ struct timeval atv, delta;
struct timezone atz;
+ int error, s;
- u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
- sizeof (struct timeval));
- if (u.u_error)
- return;
- setthetime(&atv);
- if (uap->tzp && suser()) {
- u.u_error = copyin((caddr_t)uap->tzp, (caddr_t)&atz,
- sizeof (atz));
- if (u.u_error == 0)
- tz = atz;
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ /* Verify all parameters before changing time. */
+ if (uap->tv &&
+ (error = copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof(atv))))
+ return (error);
+ if (uap->tzp &&
+ (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz))))
+ return (error);
+ if (uap->tv) {
+ /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
+ s = splclock();
+ /* nb. delta.tv_usec may be < 0, but this is OK here */
+ delta.tv_sec = atv.tv_sec - time.tv_sec;
+ delta.tv_usec = atv.tv_usec - time.tv_usec;
+ time = atv;
+ (void) splsoftclock();
+ timevaladd(&boottime, &delta);
+ timevalfix(&boottime);
+ timevaladd(&runtime, &delta);
+ timevalfix(&runtime);
+# ifdef NFS
+ lease_updatetime(delta.tv_sec);
+# endif
+ splx(s);
+ resettodr();
}
+ if (uap->tzp)
+ tz = atz;
+ return (0);
}
-setthetime(tv)
- struct timeval *tv;
+extern int tickadj; /* "standard" clock skew, us./tick */
+int tickdelta; /* current clock skew, us. per tick */
+long timedelta; /* unapplied time correction, us. */
+long bigadj = 1000000; /* use 10x skew above bigadj us. */
+
+struct adjtime_args {
+ struct timeval *delta;
+ struct timeval *olddelta;
+};
+/* ARGSUSED */
+adjtime(p, uap, retval)
+ struct proc *p;
+ register struct adjtime_args *uap;
+ int *retval;
{
- int s;
+ struct timeval atv;
+ register long ndelta, ntickdelta, odelta;
+ int s, error;
- if (!suser())
- return;
-/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
- boottime.tv_sec += tv->tv_sec - time.tv_sec;
- s = spl7(); time = *tv; splx(s);
- resettodr();
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ if (error =
+ copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval)))
+ return (error);
+
+ /*
+ * Compute the total correction and the rate at which to apply it.
+ * Round the adjustment down to a whole multiple of the per-tick
+ * delta, so that after some number of incremental changes in
+ * hardclock(), tickdelta will become zero, lest the correction
+ * overshoot and start taking us away from the desired final time.
+ */
+ ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
+ if (ndelta > bigadj)
+ ntickdelta = 10 * tickadj;
+ else
+ ntickdelta = tickadj;
+ if (ndelta % ntickdelta)
+ ndelta = ndelta / ntickdelta * ntickdelta;
+
+ /*
+ * To make hardclock()'s job easier, make the per-tick delta negative
+ * if we want time to run slower; then hardclock can simply compute
+ * tick + tickdelta, and subtract tickdelta from timedelta.
+ */
+ if (ndelta < 0)
+ ntickdelta = -ntickdelta;
+ s = splclock();
+ odelta = timedelta;
+ timedelta = ndelta;
+ tickdelta = ntickdelta;
+ splx(s);
+
+ if (uap->olddelta) {
+ atv.tv_sec = odelta / 1000000;
+ atv.tv_usec = odelta % 1000000;
+ (void) copyout((caddr_t)&atv, (caddr_t)uap->olddelta,
+ sizeof(struct timeval));
+ }
+ return (0);
}
/*
* Get value of an interval timer. The process virtual and
- * profiling virtual time timers are kept in the u. area, since
+ * profiling virtual time timers are kept in the p_stats area, since
* they can be swapped out. These are kept internally in the
* way they are specified externally: in time until they expire.
*
* real time timers .it_interval. Rather, we compute the next time in
* absolute time the timer should go off.
*/
-getitimer()
+struct getitimer_args {
+ u_int which;
+ struct itimerval *itv;
+};
+/* ARGSUSED */
+getitimer(p, uap, retval)
+ struct proc *p;
+ register struct getitimer_args *uap;
+ int *retval;
{
- register struct a {
- u_int which;
- struct itimerval *itv;
- } *uap = (struct a *)u.u_ap;
struct itimerval aitv;
int s;
- if (uap->which > 2) {
- u.u_error = EINVAL;
- return;
- }
- s = spl7();
+ if (uap->which > ITIMER_PROF)
+ return (EINVAL);
+ s = splclock();
if (uap->which == ITIMER_REAL) {
/*
* Convert from absoulte to relative time in .it_value
* has passed return 0, else return difference between
* current time and time for the timer to go off.
*/
- aitv = u.u_procp->p_realtimer;
+ aitv = p->p_realtimer;
if (timerisset(&aitv.it_value))
if (timercmp(&aitv.it_value, &time, <))
timerclear(&aitv.it_value);
else
- timevalsub(&aitv.it_value, &time);
+ timevalsub(&aitv.it_value,
+ (struct timeval *)&time);
} else
- aitv = u.u_timer[uap->which];
- splx(s);
- u.u_error = copyout((caddr_t)&aitv, (caddr_t)uap->itv,
- sizeof (struct itimerval));
+ aitv = p->p_stats->p_timer[uap->which];
splx(s);
+ return (copyout((caddr_t)&aitv, (caddr_t)uap->itv,
+ sizeof (struct itimerval)));
}
-setitimer()
+struct setitimer_args {
+ u_int which;
+ struct itimerval *itv, *oitv;
+};
+/* ARGSUSED */
+setitimer(p, uap, retval)
+ struct proc *p;
+ register struct setitimer_args *uap;
+ int *retval;
{
- register struct a {
- u_int which;
- struct itimerval *itv, *oitv;
- } *uap = (struct a *)u.u_ap;
struct itimerval aitv;
- int s;
- register struct proc *p = u.u_procp;
+ register struct itimerval *itvp;
+ int s, error;
- if (uap->which > 2) {
- u.u_error = EINVAL;
- return;
- }
- u.u_error = copyin((caddr_t)uap->itv, (caddr_t)&aitv,
- sizeof (struct itimerval));
- if (u.u_error)
- return;
- if (uap->oitv) {
- uap->itv = uap->oitv;
- getitimer();
- }
- if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) {
- u.u_error = EINVAL;
- return;
- }
- s = spl7();
+ if (uap->which > ITIMER_PROF)
+ return (EINVAL);
+ itvp = uap->itv;
+ if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
+ sizeof(struct itimerval))))
+ return (error);
+ if ((uap->itv = uap->oitv) && (error = getitimer(p, uap, retval)))
+ return (error);
+ if (itvp == 0)
+ return (0);
+ if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
+ return (EINVAL);
+ s = splclock();
if (uap->which == ITIMER_REAL) {
untimeout(realitexpire, (caddr_t)p);
if (timerisset(&aitv.it_value)) {
- timevaladd(&aitv.it_value, &time);
+ timevaladd(&aitv.it_value, (struct timeval *)&time);
timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
}
p->p_realtimer = aitv;
} else
- u.u_timer[uap->which] = aitv;
+ p->p_stats->p_timer[uap->which] = aitv;
splx(s);
+ return (0);
}
/*
* This is where delay in processing this timeout causes multiple
* SIGALRM calls to be compressed into one.
*/
-realitexpire(p)
- register struct proc *p;
+void
+realitexpire(arg)
+ void *arg;
{
+ register struct proc *p;
int s;
+ p = (struct proc *)arg;
psignal(p, SIGALRM);
if (!timerisset(&p->p_realtimer.it_interval)) {
timerclear(&p->p_realtimer.it_value);
return;
}
for (;;) {
- s = spl7();
+ s = splclock();
timevaladd(&p->p_realtimer.it_value,
&p->p_realtimer.it_interval);
if (timercmp(&p->p_realtimer.it_value, &time, >)) {
* of microseconds, which must be less than a second,
* i.e. < 1000000. If the timer expires, then reload
* it. In this case, carry over (usec - old value) to
- * reducint the value reloaded into the timer so that
+ * reduce the value reloaded into the timer so that
* the timer does not drift. This routine assumes
* that it is called in a context where the timers
* on which it is operating cannot change in value.