move in NFS specific call from vnode.h
[unix-history] / usr / src / sys / kern / kern_time.c
index e76adc4..4dc818c 100644 (file)
@@ -1,27 +1,18 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  *
  *
- *     @(#)kern_time.c 7.9 (Berkeley) %G%
+ *     @(#)kern_time.c 8.2 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "dir.h"               /* XXX */
-#include "user.h"
-#include "kernel.h"
-#include "proc.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>
 
 
 /* 
 
 
 /* 
  * timers when they expire.
  */
 
  * 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;
        struct timeval atv;
+       int error = 0;
 
        if (uap->tp) {
                microtime(&atv);
 
        if (uap->tp) {
                microtime(&atv);
-               u.u_error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
-                       sizeof (atv));
-               if (u.u_error)
-                       return;
+               if (error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
+                   sizeof (atv)))
+                       return (error);
        }
        if (uap->tzp)
        }
        if (uap->tzp)
-               u.u_error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
-                       sizeof (tz));
+               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;
        struct timezone atz;
-       int s;
+       int error, s;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
+       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) {
        if (uap->tv) {
-               u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
-                       sizeof (struct timeval));
-               if (u.u_error)
-                       return;
                /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
                /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
-               boottime.tv_sec += atv.tv_sec - time.tv_sec;
-               s = splhigh(); time = atv; splx(s);
+               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();
        }
                resettodr();
        }
-       if (uap->tzp == 0)
-               return;
-       u.u_error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof (atz));
-       if (u.u_error == 0)
+       if (uap->tzp)
                tz = atz;
                tz = atz;
+       return (0);
 }
 
 extern int tickadj;                    /* "standard" clock skew, us./tick */
 }
 
 extern int tickadj;                    /* "standard" clock skew, us./tick */
@@ -88,47 +101,66 @@ int        tickdelta;                      /* current clock skew, us. per tick */
 long   timedelta;                      /* unapplied time correction, us. */
 long   bigadj = 1000000;               /* use 10x skew above bigadj us. */
 
 long   timedelta;                      /* unapplied time correction, us. */
 long   bigadj = 1000000;               /* use 10x skew above bigadj us. */
 
-adjtime()
+struct adjtime_args {
+       struct timeval *delta;
+       struct timeval *olddelta;
+};
+/* ARGSUSED */
+adjtime(p, uap, retval)
+       struct proc *p;
+       register struct adjtime_args *uap;
+       int *retval;
 {
 {
-       register struct a {
-               struct timeval *delta;
-               struct timeval *olddelta;
-       } *uap = (struct a *)u.u_ap;
-       struct timeval atv, oatv;
-       register long ndelta;
-       int s;
+       struct timeval atv;
+       register long ndelta, ntickdelta, odelta;
+       int s, error;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
-       u.u_error = copyin((caddr_t)uap->delta, (caddr_t)&atv,
-               sizeof (struct timeval));
-       if (u.u_error)
-               return;
+       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;
        ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
-       if (timedelta == 0)
-               if (ndelta > bigadj)
-                       tickdelta = 10 * tickadj;
-               else
-                       tickdelta = tickadj;
-       if (ndelta % tickdelta)
-               ndelta = ndelta / tickadj * tickadj;
+       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();
        s = splclock();
-       if (uap->olddelta) {
-               oatv.tv_sec = timedelta / 1000000;
-               oatv.tv_usec = timedelta % 1000000;
-       }
+       odelta = timedelta;
        timedelta = ndelta;
        timedelta = ndelta;
+       tickdelta = ntickdelta;
        splx(s);
 
        splx(s);
 
-       if (uap->olddelta)
-               (void) copyout((caddr_t)&oatv, (caddr_t)uap->olddelta,
-                       sizeof (struct timeval));
+       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
 }
 
 /*
  * 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.
  *
  * they can be swapped out.  These are kept internally in the
  * way they are specified externally: in time until they expire.
  *
@@ -147,19 +179,21 @@ adjtime()
  * real time timers .it_interval.  Rather, we compute the next time in
  * absolute time the timer should go off.
  */
  * 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;
 
        struct itimerval aitv;
        int s;
 
-       if (uap->which > ITIMER_PROF) {
-               u.u_error = EINVAL;
-               return;
-       }
+       if (uap->which > ITIMER_PROF)
+               return (EINVAL);
        s = splclock();
        if (uap->which == ITIMER_REAL) {
                /*
        s = splclock();
        if (uap->which == ITIMER_REAL) {
                /*
@@ -168,60 +202,58 @@ getitimer()
                 * has passed return 0, else return difference between
                 * current time and time for the timer to go off.
                 */
                 * 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
                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
        } else
-               aitv = u.u_timer[uap->which];
+               aitv = p->p_stats->p_timer[uap->which];
        splx(s);
        splx(s);
-       u.u_error = copyout((caddr_t)&aitv, (caddr_t)uap->itv,
-           sizeof (struct itimerval));
+       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;
        register struct itimerval *itvp;
        struct itimerval aitv;
        register struct itimerval *itvp;
-       int s;
-       register struct proc *p = u.u_procp;
+       int s, error;
 
 
-       if (uap->which > ITIMER_PROF) {
-               u.u_error = EINVAL;
-               return;
-       }
+       if (uap->which > ITIMER_PROF)
+               return (EINVAL);
        itvp = uap->itv;
        itvp = uap->itv;
-       if (itvp && (u.u_error = copyin((caddr_t)itvp, (caddr_t)&aitv,
+       if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
            sizeof(struct itimerval))))
            sizeof(struct itimerval))))
-               return;
-       if (uap->itv = uap->oitv) {
-               getitimer();
-               if (u.u_error)
-                       return;
-       }
+               return (error);
+       if ((uap->itv = uap->oitv) && (error = getitimer(p, uap, retval)))
+               return (error);
        if (itvp == 0)
        if (itvp == 0)
-               return;
-       if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) {
-               u.u_error = EINVAL;
-               return;
-       }
+               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)) {
        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
                        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);
        splx(s);
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -232,11 +264,14 @@ setitimer()
  * This is where delay in processing this timeout causes multiple
  * SIGALRM calls to be compressed into one.
  */
  * 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;
 
        int s;
 
+       p = (struct proc *)arg;
        psignal(p, SIGALRM);
        if (!timerisset(&p->p_realtimer.it_interval)) {
                timerclear(&p->p_realtimer.it_value);
        psignal(p, SIGALRM);
        if (!timerisset(&p->p_realtimer.it_interval)) {
                timerclear(&p->p_realtimer.it_value);
@@ -279,7 +314,7 @@ itimerfix(tv)
  * 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
  * 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.
  * 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.