BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / kern / kern_time.c
index 8419fe0..e5291f2 100644 (file)
@@ -1,12 +1,44 @@
-/*     kern_time.c     5.7     82/09/11        */
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)kern_time.c 7.15 (Berkeley) 3/17/91
+ */
 
 
-#include "../h/param.h"
-#include "../h/dir.h"          /* XXX */
-#include "../h/user.h"
-#include "../h/kernel.h"
-#include "../h/reg.h"
-#include "../h/inode.h"
-#include "../h/proc.h"
+#include "param.h"
+#include "resourcevar.h"
+#include "kernel.h"
+#include "proc.h"
+
+#include "machine/cpu.h"
 
 /* 
  * Time of day and interval timer support.
 
 /* 
  * Time of day and interval timer support.
  * timers when they expire.
  */
 
  * timers when they expire.
  */
 
-gettimeofday()
-{
-       register struct a {
+/* ARGSUSED */
+gettimeofday(p, uap, retval)
+       struct proc *p;
+       register struct args {
                struct  timeval *tp;
                struct  timezone *tzp;
                struct  timeval *tp;
                struct  timezone *tzp;
-       } *uap = (struct a *)u.u_ap;
+       } *uap;
+       int *retval;
+{
        struct timeval atv;
        struct timeval atv;
-       int s;
+       int error = 0;
 
 
-       s = spl7(); atv = time; splx(s);
-       if (copyout((caddr_t)&atv, (caddr_t)uap->tp, sizeof (atv))) {
-               u.u_error = EFAULT;
-               return;
-       }
-       if (uap->tzp == 0)
-               return;
-       /* SHOULD HAVE PER-PROCESS TIMEZONE */
-       if (copyout((caddr_t)&tz, uap->tzp, sizeof (tz))) {
-               u.u_error = EFAULT;
-               return;
+       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()
-{
-       register struct a {
+/* ARGSUSED */
+settimeofday(p, uap, retval)
+       struct proc *p;
+       struct args {
                struct  timeval *tv;
                struct  timezone *tzp;
                struct  timeval *tv;
                struct  timezone *tzp;
-       } *uap = (struct a *)u.u_ap;
+       } *uap;
+       int *retval;
+{
        struct timeval atv;
        struct timezone atz;
        struct timeval atv;
        struct timezone atz;
-
-       if (copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (struct timeval))) {
-               u.u_error = EFAULT;
-               return;
-       }
-       setthetime(&atv);
-       if (uap->tzp && suser()) {
-               if (copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof (atz))) {
-                       u.u_error = EFAULT;
-                       return;
-               }
+       int error, s;
+
+       if (error = suser(p->p_ucred, &p->p_acflag))
+               return (error);
+       if (uap->tv) {
+               if (error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
+                   sizeof (struct timeval)))
+                       return (error);
+               /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
+               boottime.tv_sec += atv.tv_sec - time.tv_sec;
+               s = splhigh(); time = atv; splx(s);
+               resettodr();
        }
        }
+       if (uap->tzp && (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz,
+           sizeof (atz))) == 0)
+               tz = atz;
+       return (error);
 }
 
 }
 
-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. */
+
+/* ARGSUSED */
+adjtime(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               struct timeval *delta;
+               struct timeval *olddelta;
+       } *uap;
+       int *retval;
 {
 {
-       register int delta;
-       int s;
+       struct timeval atv, oatv;
+       register long ndelta;
+       int s, error;
+
+       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);
+       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;
+
+       s = splclock();
+       if (uap->olddelta) {
+               oatv.tv_sec = timedelta / 1000000;
+               oatv.tv_usec = timedelta % 1000000;
+       }
+       timedelta = ndelta;
+       splx(s);
 
 
-       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);
-       clockset();
+       if (uap->olddelta)
+               (void) copyout((caddr_t)&oatv, (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.
  *
@@ -98,20 +171,21 @@ setthetime(tv)
  * 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()
-{
-       register struct a {
+/* ARGSUSED */
+getitimer(p, uap, retval)
+       struct proc *p;
+       register struct args {
                u_int   which;
                struct  itimerval *itv;
                u_int   which;
                struct  itimerval *itv;
-       } *uap = (struct a *)u.u_ap;
+       } *uap;
+       int *retval;
+{
        struct itimerval aitv;
        int s;
 
        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
        if (uap->which == ITIMER_REAL) {
                /*
                 * Convert from absoulte to relative time in .it_value
@@ -119,58 +193,56 @@ 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
                                timevalsub(&aitv.it_value, &time);
        } else
                if (timerisset(&aitv.it_value))
                        if (timercmp(&aitv.it_value, &time, <))
                                timerclear(&aitv.it_value);
                        else
                                timevalsub(&aitv.it_value, &time);
        } else
-               aitv = u.u_timer[uap->which];
-       splx(s);
-       if (copyout((caddr_t)&aitv, uap->itv, sizeof (struct itimerval)))
-               u.u_error = EFAULT;
+               aitv = p->p_stats->p_timer[uap->which];
        splx(s);
        splx(s);
+       return (copyout((caddr_t)&aitv, (caddr_t)uap->itv,
+           sizeof (struct itimerval)));
 }
 
 }
 
-setitimer()
-{
-       register struct a {
+/* ARGSUSED */
+setitimer(p, uap, retval)
+       struct proc *p;
+       register struct args {
                u_int   which;
                struct  itimerval *itv, *oitv;
                u_int   which;
                struct  itimerval *itv, *oitv;
-       } *uap = (struct a *)u.u_ap;
+       } *uap;
+       int *retval;
+{
        struct itimerval aitv;
        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;
-       }
-       if (copyin((caddr_t)uap->itv, (caddr_t)&aitv,
-           sizeof (struct itimerval))) {
-               u.u_error = EFAULT;
-               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) {
        if (uap->which == ITIMER_REAL) {
-               untimeout(realitexpire, p);
+               untimeout(realitexpire, (caddr_t)p);
                if (timerisset(&aitv.it_value)) {
                        timevaladd(&aitv.it_value, &time);
                if (timerisset(&aitv.it_value)) {
                        timevaladd(&aitv.it_value, &time);
-                       timeout(realitexpire, p, hzto(&aitv.it_value));
+                       timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
                }
                p->p_realtimer = aitv;
        } else
                }
                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);
 }
 
 /*
 }
 
 /*
@@ -192,12 +264,12 @@ realitexpire(p)
                return;
        }
        for (;;) {
                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, >)) {
                timevaladd(&p->p_realtimer.it_value,
                    &p->p_realtimer.it_interval);
                if (timercmp(&p->p_realtimer.it_value, &time, >)) {
-                       timeout(realitexpire,
-                           p, hzto(&p->p_realtimer.it_value));
+                       timeout(realitexpire, (caddr_t)p,
+                           hzto(&p->p_realtimer.it_value));
                        splx(s);
                        return;
                }
                        splx(s);
                        return;
                }
@@ -218,7 +290,7 @@ itimerfix(tv)
        if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
            tv->tv_usec < 0 || tv->tv_usec >= 1000000)
                return (EINVAL);
        if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
            tv->tv_usec < 0 || tv->tv_usec >= 1000000)
                return (EINVAL);
-       if (tv->tv_sec == 0 && tv->tv_usec < tick)
+       if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
                tv->tv_usec = tick;
        return (0);
 }
                tv->tv_usec = tick;
        return (0);
 }
@@ -303,74 +375,3 @@ timevalfix(t1)
                t1->tv_usec -= 1000000;
        }
 }
                t1->tv_usec -= 1000000;
        }
 }
-
-#ifndef NOCOMPAT
-otime()
-{
-
-       u.u_r.r_time = time.tv_sec;
-}
-
-ostime()
-{
-       register struct a {
-               int     time;
-       } *uap = (struct a *)u.u_ap;
-       struct timeval tv;
-
-       tv.tv_sec = uap->time;
-       tv.tv_usec = 0;
-       setthetime(&tv);
-}
-
-/* from old timeb.h */
-struct timeb {
-       time_t  time;
-       u_short millitm;
-       short   timezone;
-       short   dstflag;
-};
-
-oftime()
-{
-       register struct a {
-               struct  timeb   *tp;
-       } *uap;
-       struct timeb tb;
-
-       uap = (struct a *)u.u_ap;
-       (void) spl7();
-       tb.time = time.tv_sec;
-       tb.millitm = time.tv_usec / 1000;
-       (void) spl0();
-       tb.timezone = tz.tz_minuteswest;
-       tb.dstflag = tz.tz_dsttime;
-       if (copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof(t)) < 0)
-               u.u_error = EFAULT;
-}
-
-oalarm()
-{
-       register struct a {
-               int     deltat;
-       } *uap = (struct a *)u.u_ap;
-       register struct proc *p = u.u_procp;
-       struct timeval atv;
-       int s = spl7();
-
-       untimeout(realitexpire, p);
-       timerclear(&p->p_realtimer.it_interval);
-       u.u_r.r_val1 = 0;
-       if (timerisset(&p->p_realtimer.it_value) &&
-           timercmp(&p->p_realtimer.it_value, &time, >))
-               u.u_r.r_val1 = p->p_realtimer.it_value.tv_sec - time.tv_sec;
-       if (uap->deltat == 0) {
-               splx(s);
-               return;
-       }
-       p->p_realtimer.it_value = time;
-       p->p_realtimer.it_value.tv_sec += uap->deltat;
-       timeout(realitexpire, p, hzto(&p->p_realtimer.it_value));
-       splx(s);
-}
-#endif