1*34eef8ebSroot /* kern_time.c 5.7 82/09/11 */ 28c362ab9Sroot 38c362ab9Sroot #include "../h/param.h" 4ef678427Sroot #include "../h/dir.h" /* XXX */ 58c362ab9Sroot #include "../h/user.h" 6ef678427Sroot #include "../h/kernel.h" 78c362ab9Sroot #include "../h/reg.h" 88c362ab9Sroot #include "../h/inode.h" 98c362ab9Sroot #include "../h/proc.h" 10ef678427Sroot 1172762883Sroot /* 1272762883Sroot * Time of day and interval timer support. 13*34eef8ebSroot * 14*34eef8ebSroot * These routines provide the kernel entry points to get and set 15*34eef8ebSroot * the time-of-day and per-process interval timers. Subroutines 16*34eef8ebSroot * here provide support for adding and subtracting timeval structures 17*34eef8ebSroot * and decrementing interval timers, optionally reloading the interval 18*34eef8ebSroot * timers when they expire. 1972762883Sroot */ 2072762883Sroot 21ef678427Sroot gettimeofday() 22ef678427Sroot { 23ef678427Sroot register struct a { 24ef678427Sroot struct timeval *tp; 25ef678427Sroot struct timezone *tzp; 26ef678427Sroot } *uap = (struct a *)u.u_ap; 27ef678427Sroot struct timeval atv; 2872762883Sroot int s; 29ef678427Sroot 3072762883Sroot s = spl7(); atv = time; splx(s); 31ef678427Sroot if (copyout((caddr_t)&atv, (caddr_t)uap->tp, sizeof (atv))) { 32ef678427Sroot u.u_error = EFAULT; 33ef678427Sroot return; 34ef678427Sroot } 35ef678427Sroot if (uap->tzp == 0) 36ef678427Sroot return; 3772762883Sroot /* SHOULD HAVE PER-PROCESS TIMEZONE */ 38ef678427Sroot if (copyout((caddr_t)&tz, uap->tzp, sizeof (tz))) { 39ef678427Sroot u.u_error = EFAULT; 40ef678427Sroot return; 41ef678427Sroot } 42ef678427Sroot } 43ef678427Sroot 44ef678427Sroot settimeofday() 45ef678427Sroot { 46ef678427Sroot register struct a { 47ef678427Sroot struct timeval *tv; 48ef678427Sroot struct timezone *tzp; 49ef678427Sroot } *uap = (struct a *)u.u_ap; 50ef678427Sroot struct timeval atv; 51ef678427Sroot struct timezone atz; 52ef678427Sroot 53ef678427Sroot if (copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (struct timeval))) { 54ef678427Sroot u.u_error = EFAULT; 55ef678427Sroot return; 56ef678427Sroot } 5772762883Sroot setthetime(&atv); 5872762883Sroot if (uap->tzp && suser()) { 59ef678427Sroot if (copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof (atz))) { 60ef678427Sroot u.u_error = EFAULT; 61ef678427Sroot return; 62ef678427Sroot } 63ef678427Sroot } 64ef678427Sroot } 65ef678427Sroot 6672762883Sroot setthetime(tv) 6772762883Sroot struct timeval *tv; 6872762883Sroot { 6972762883Sroot register int delta; 7072762883Sroot int s; 7172762883Sroot 7272762883Sroot if (!suser()) 7372762883Sroot return; 74*34eef8ebSroot /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ 7572762883Sroot boottime.tv_sec += tv->tv_sec - time.tv_sec; 7672762883Sroot s = spl7(); time = *tv; splx(s); 7772762883Sroot clockset(); 7872762883Sroot } 7972762883Sroot 80*34eef8ebSroot /* 81*34eef8ebSroot * Get value of an interval timer. The process virtual and 82*34eef8ebSroot * profiling virtual time timers are kept in the u. area, since 83*34eef8ebSroot * they can be swapped out. These are kept internally in the 84*34eef8ebSroot * way they are specified externally: in time until they expire. 85*34eef8ebSroot * 86*34eef8ebSroot * The real time interval timer is kept in the process table slot 87*34eef8ebSroot * for the process, and its value (it_value) is kept as an 88*34eef8ebSroot * absolute time rather than as a delta, so that it is easy to keep 89*34eef8ebSroot * periodic real-time signals from drifting. 90*34eef8ebSroot * 91*34eef8ebSroot * Virtual time timers are processed in the hardclock() routine of 92*34eef8ebSroot * kern_clock.c. The real time timer is processed by a timeout 93*34eef8ebSroot * routine, called from the softclock() routine. Since a callout 94*34eef8ebSroot * may be delayed in real time due to interrupt processing in the system, 95*34eef8ebSroot * it is possible for the real time timeout routine (realitexpire, given below), 96*34eef8ebSroot * to be delayed in real time past when it is supposed to occur. It 97*34eef8ebSroot * does not suffice, therefore, to reload the real timer .it_value from the 98*34eef8ebSroot * real time timers .it_interval. Rather, we compute the next time in 99*34eef8ebSroot * absolute time the timer should go off. 100*34eef8ebSroot */ 101ef678427Sroot getitimer() 102ef678427Sroot { 103ef678427Sroot register struct a { 104ef678427Sroot u_int which; 105ef678427Sroot struct itimerval *itv; 106ef678427Sroot } *uap = (struct a *)u.u_ap; 1070ed3b3c8Sroot struct itimerval aitv; 108ef678427Sroot int s; 109ef678427Sroot 110ef678427Sroot if (uap->which > 2) { 111ef678427Sroot u.u_error = EINVAL; 112ef678427Sroot return; 113ef678427Sroot } 114ef678427Sroot s = spl7(); 1150ed3b3c8Sroot if (uap->which == ITIMER_REAL) { 116*34eef8ebSroot /* 117*34eef8ebSroot * Convert from absoulte to relative time in .it_value 118*34eef8ebSroot * part of real time timer. If time for real time timer 119*34eef8ebSroot * has passed return 0, else return difference between 120*34eef8ebSroot * current time and time for the timer to go off. 121*34eef8ebSroot */ 1220ed3b3c8Sroot aitv = u.u_procp->p_realtimer; 1230ed3b3c8Sroot if (timerisset(&aitv.it_value)) 1240ed3b3c8Sroot if (timercmp(&aitv.it_value, &time, <)) 1250ed3b3c8Sroot timerclear(&aitv.it_value); 1260ed3b3c8Sroot else 1270ed3b3c8Sroot timevalsub(&aitv.it_value, &time); 1280ed3b3c8Sroot } else 1290ed3b3c8Sroot aitv = u.u_timer[uap->which]; 1300ed3b3c8Sroot splx(s); 1310ed3b3c8Sroot if (copyout((caddr_t)&aitv, uap->itv, sizeof (struct itimerval))) 132ef678427Sroot u.u_error = EFAULT; 133ef678427Sroot splx(s); 134ef678427Sroot } 135ef678427Sroot 136ef678427Sroot setitimer() 137ef678427Sroot { 138ef678427Sroot register struct a { 139ef678427Sroot u_int which; 14072762883Sroot struct itimerval *itv, *oitv; 141ef678427Sroot } *uap = (struct a *)u.u_ap; 142ef678427Sroot struct itimerval aitv; 143ef678427Sroot int s; 1440ed3b3c8Sroot register struct proc *p = u.u_procp; 145ef678427Sroot 146ef678427Sroot if (uap->which > 2) { 147ef678427Sroot u.u_error = EINVAL; 14872762883Sroot return; 149ef678427Sroot } 150ef678427Sroot if (copyin((caddr_t)uap->itv, (caddr_t)&aitv, 151ef678427Sroot sizeof (struct itimerval))) { 152ef678427Sroot u.u_error = EFAULT; 153ef678427Sroot return; 154ef678427Sroot } 15572762883Sroot if (uap->oitv) { 15672762883Sroot uap->itv = uap->oitv; 157ef678427Sroot getitimer(); 158ef678427Sroot } 15972762883Sroot if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) { 16072762883Sroot u.u_error = EINVAL; 16172762883Sroot return; 16272762883Sroot } 16372762883Sroot s = spl7(); 1640ed3b3c8Sroot if (uap->which == ITIMER_REAL) { 165*34eef8ebSroot untimeout(realitexpire, p); 1660ed3b3c8Sroot if (timerisset(&aitv.it_value)) { 1670ed3b3c8Sroot timevaladd(&aitv.it_value, &time); 168*34eef8ebSroot timeout(realitexpire, p, hzto(&aitv.it_value)); 1690ed3b3c8Sroot } 1700ed3b3c8Sroot p->p_realtimer = aitv; 1710ed3b3c8Sroot } else 17272762883Sroot u.u_timer[uap->which] = aitv; 173ef678427Sroot splx(s); 174ef678427Sroot } 175ef678427Sroot 176*34eef8ebSroot /* 177*34eef8ebSroot * Real interval timer expired: 178*34eef8ebSroot * send process whose timer expired an alarm signal. 179*34eef8ebSroot * If time is not set up to reload, then just return. 180*34eef8ebSroot * Else compute next time timer should go off which is > current time. 181*34eef8ebSroot * This is where delay in processing this timeout causes multiple 182*34eef8ebSroot * SIGALRM calls to be compressed into one. 183*34eef8ebSroot */ 184*34eef8ebSroot realitexpire(p) 1850ed3b3c8Sroot register struct proc *p; 1860ed3b3c8Sroot { 1870ed3b3c8Sroot int s; 1880ed3b3c8Sroot 1890ed3b3c8Sroot psignal(p, SIGALRM); 1900ed3b3c8Sroot if (!timerisset(&p->p_realtimer.it_interval)) { 1910ed3b3c8Sroot timerclear(&p->p_realtimer.it_value); 1920ed3b3c8Sroot return; 1930ed3b3c8Sroot } 1940ed3b3c8Sroot for (;;) { 1950ed3b3c8Sroot s = spl7(); 1960ed3b3c8Sroot timevaladd(&p->p_realtimer.it_value, 1970ed3b3c8Sroot &p->p_realtimer.it_interval); 1980ed3b3c8Sroot if (timercmp(&p->p_realtimer.it_value, &time, >)) { 199*34eef8ebSroot timeout(realitexpire, 200*34eef8ebSroot p, hzto(&p->p_realtimer.it_value)); 2010ed3b3c8Sroot splx(s); 2020ed3b3c8Sroot return; 2030ed3b3c8Sroot } 2040ed3b3c8Sroot splx(s); 2050ed3b3c8Sroot } 2060ed3b3c8Sroot } 2070ed3b3c8Sroot 208*34eef8ebSroot /* 209*34eef8ebSroot * Check that a proposed value to load into the .it_value or 210*34eef8ebSroot * .it_interval part of an interval timer is acceptable, and 211*34eef8ebSroot * fix it to have at least minimal value (i.e. if it is less 212*34eef8ebSroot * than the resolution of the clock, round it up.) 213*34eef8ebSroot */ 21472762883Sroot itimerfix(tv) 21572762883Sroot struct timeval *tv; 21672762883Sroot { 21772762883Sroot 2180ed3b3c8Sroot if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 2190ed3b3c8Sroot tv->tv_usec < 0 || tv->tv_usec >= 1000000) 22072762883Sroot return (EINVAL); 22172762883Sroot if (tv->tv_sec == 0 && tv->tv_usec < tick) 22272762883Sroot tv->tv_usec = tick; 22372762883Sroot return (0); 22472762883Sroot } 22572762883Sroot 226*34eef8ebSroot /* 227*34eef8ebSroot * Decrement an interval timer by a specified number 228*34eef8ebSroot * of microseconds, which must be less than a second, 229*34eef8ebSroot * i.e. < 1000000. If the timer expires, then reload 230*34eef8ebSroot * it. In this case, carry over (usec - old value) to 231*34eef8ebSroot * reducint the value reloaded into the timer so that 232*34eef8ebSroot * the timer does not drift. This routine assumes 233*34eef8ebSroot * that it is called in a context where the timers 234*34eef8ebSroot * on which it is operating cannot change in value. 235*34eef8ebSroot */ 236ef678427Sroot itimerdecr(itp, usec) 237ef678427Sroot register struct itimerval *itp; 238ef678427Sroot int usec; 239ef678427Sroot { 240ef678427Sroot 24172762883Sroot if (itp->it_value.tv_usec < usec) { 24272762883Sroot if (itp->it_value.tv_sec == 0) { 243*34eef8ebSroot /* expired, and already in next interval */ 24472762883Sroot usec -= itp->it_value.tv_usec; 245ef678427Sroot goto expire; 246ef678427Sroot } 24772762883Sroot itp->it_value.tv_usec += 1000000; 24872762883Sroot itp->it_value.tv_sec--; 24972762883Sroot } 25072762883Sroot itp->it_value.tv_usec -= usec; 25172762883Sroot usec = 0; 25272762883Sroot if (timerisset(&itp->it_value)) 253ef678427Sroot return (1); 254*34eef8ebSroot /* expired, exactly at end of interval */ 255ef678427Sroot expire: 25672762883Sroot if (timerisset(&itp->it_interval)) { 25772762883Sroot itp->it_value = itp->it_interval; 25872762883Sroot itp->it_value.tv_usec -= usec; 25972762883Sroot if (itp->it_value.tv_usec < 0) { 26072762883Sroot itp->it_value.tv_usec += 1000000; 26172762883Sroot itp->it_value.tv_sec--; 26272762883Sroot } 26372762883Sroot } else 264*34eef8ebSroot itp->it_value.tv_usec = 0; /* sec is already 0 */ 265ef678427Sroot return (0); 266ef678427Sroot } 267ef678427Sroot 268*34eef8ebSroot /* 269*34eef8ebSroot * Add and subtract routines for timevals. 270*34eef8ebSroot * N.B.: subtract routine doesn't deal with 271*34eef8ebSroot * results which are before the beginning, 272*34eef8ebSroot * it just gets very confused in this case. 273*34eef8ebSroot * Caveat emptor. 274*34eef8ebSroot */ 275*34eef8ebSroot timevaladd(t1, t2) 276*34eef8ebSroot struct timeval *t1, *t2; 277*34eef8ebSroot { 278*34eef8ebSroot 279*34eef8ebSroot t1->tv_sec += t2->tv_sec; 280*34eef8ebSroot t1->tv_usec += t2->tv_usec; 281*34eef8ebSroot timevalfix(t1); 282*34eef8ebSroot } 283*34eef8ebSroot 284*34eef8ebSroot timevalsub(t1, t2) 285*34eef8ebSroot struct timeval *t1, *t2; 286*34eef8ebSroot { 287*34eef8ebSroot 288*34eef8ebSroot t1->tv_sec -= t2->tv_sec; 289*34eef8ebSroot t1->tv_usec -= t2->tv_usec; 290*34eef8ebSroot timevalfix(t1); 291*34eef8ebSroot } 292*34eef8ebSroot 293*34eef8ebSroot timevalfix(t1) 294*34eef8ebSroot struct timeval *t1; 295*34eef8ebSroot { 296*34eef8ebSroot 297*34eef8ebSroot if (t1->tv_usec < 0) { 298*34eef8ebSroot t1->tv_sec--; 299*34eef8ebSroot t1->tv_usec += 1000000; 300*34eef8ebSroot } 301*34eef8ebSroot if (t1->tv_usec >= 1000000) { 302*34eef8ebSroot t1->tv_sec++; 303*34eef8ebSroot t1->tv_usec -= 1000000; 304*34eef8ebSroot } 305*34eef8ebSroot } 306*34eef8ebSroot 307ef678427Sroot #ifndef NOCOMPAT 308ef678427Sroot otime() 309ef678427Sroot { 310ef678427Sroot 311ef678427Sroot u.u_r.r_time = time.tv_sec; 312ef678427Sroot } 313ef678427Sroot 31472762883Sroot ostime() 31572762883Sroot { 31672762883Sroot register struct a { 31772762883Sroot int time; 31872762883Sroot } *uap = (struct a *)u.u_ap; 31972762883Sroot struct timeval tv; 32072762883Sroot 32172762883Sroot tv.tv_sec = uap->time; 32272762883Sroot tv.tv_usec = 0; 32372762883Sroot setthetime(&tv); 32472762883Sroot } 32572762883Sroot 326*34eef8ebSroot /* from old timeb.h */ 327*34eef8ebSroot struct timeb { 328*34eef8ebSroot time_t time; 329*34eef8ebSroot u_short millitm; 330*34eef8ebSroot short timezone; 331*34eef8ebSroot short dstflag; 332*34eef8ebSroot }; 3338c362ab9Sroot 334828d9165Sroot oftime() 3358c362ab9Sroot { 3368c362ab9Sroot register struct a { 3378c362ab9Sroot struct timeb *tp; 3388c362ab9Sroot } *uap; 339*34eef8ebSroot struct timeb tb; 3408c362ab9Sroot 3418c362ab9Sroot uap = (struct a *)u.u_ap; 3428c362ab9Sroot (void) spl7(); 343*34eef8ebSroot tb.time = time.tv_sec; 344*34eef8ebSroot tb.millitm = time.tv_usec / 1000; 3458c362ab9Sroot (void) spl0(); 346*34eef8ebSroot tb.timezone = tz.tz_minuteswest; 347*34eef8ebSroot tb.dstflag = tz.tz_dsttime; 348*34eef8ebSroot if (copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof(t)) < 0) 3498c362ab9Sroot u.u_error = EFAULT; 3508c362ab9Sroot } 351*34eef8ebSroot 35217b48886Sroot oalarm() 35317b48886Sroot { 35417b48886Sroot register struct a { 35517b48886Sroot int deltat; 35617b48886Sroot } *uap = (struct a *)u.u_ap; 35717b48886Sroot register struct proc *p = u.u_procp; 35817b48886Sroot struct timeval atv; 35917b48886Sroot int s = spl7(); 36017b48886Sroot 361*34eef8ebSroot untimeout(realitexpire, p); 36217b48886Sroot timerclear(&p->p_realtimer.it_interval); 36317b48886Sroot u.u_r.r_val1 = 0; 36417b48886Sroot if (timerisset(&p->p_realtimer.it_value) && 36517b48886Sroot timercmp(&p->p_realtimer.it_value, &time, >)) 36617b48886Sroot u.u_r.r_val1 = p->p_realtimer.it_value.tv_sec - time.tv_sec; 36717b48886Sroot if (uap->deltat == 0) { 36817b48886Sroot splx(s); 36917b48886Sroot return; 37017b48886Sroot } 37117b48886Sroot p->p_realtimer.it_value = time; 37217b48886Sroot p->p_realtimer.it_value.tv_sec += uap->deltat; 373*34eef8ebSroot timeout(realitexpire, p, hzto(&p->p_realtimer.it_value)); 37417b48886Sroot splx(s); 37517b48886Sroot } 376*34eef8ebSroot #endif 377