Annotation of sys/kern/kern_clock.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: kern_clock.c,v 1.64 2007/05/16 17:27:30 art Exp $ */
! 2: /* $NetBSD: kern_clock.c,v 1.34 1996/06/09 04:51:03 briggs Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1982, 1986, 1991, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: * (c) UNIX System Laboratories, Inc.
! 8: * All or some portions of this file are derived from material licensed
! 9: * to the University of California by American Telephone and Telegraph
! 10: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
! 11: * the permission of UNIX System Laboratories, Inc.
! 12: *
! 13: * Redistribution and use in source and binary forms, with or without
! 14: * modification, are permitted provided that the following conditions
! 15: * are met:
! 16: * 1. Redistributions of source code must retain the above copyright
! 17: * notice, this list of conditions and the following disclaimer.
! 18: * 2. Redistributions in binary form must reproduce the above copyright
! 19: * notice, this list of conditions and the following disclaimer in the
! 20: * documentation and/or other materials provided with the distribution.
! 21: * 3. Neither the name of the University nor the names of its contributors
! 22: * may be used to endorse or promote products derived from this software
! 23: * without specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 35: * SUCH DAMAGE.
! 36: *
! 37: * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/dkstat.h>
! 43: #include <sys/timeout.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/limits.h>
! 46: #include <sys/proc.h>
! 47: #include <sys/user.h>
! 48: #include <sys/resourcevar.h>
! 49: #include <sys/signalvar.h>
! 50: #include <uvm/uvm_extern.h>
! 51: #include <sys/sysctl.h>
! 52: #include <sys/sched.h>
! 53: #ifdef __HAVE_TIMECOUNTER
! 54: #include <sys/timetc.h>
! 55: #endif
! 56:
! 57: #include <machine/cpu.h>
! 58:
! 59: #ifdef GPROF
! 60: #include <sys/gmon.h>
! 61: #endif
! 62:
! 63: /*
! 64: * Clock handling routines.
! 65: *
! 66: * This code is written to operate with two timers that run independently of
! 67: * each other. The main clock, running hz times per second, is used to keep
! 68: * track of real time. The second timer handles kernel and user profiling,
! 69: * and does resource use estimation. If the second timer is programmable,
! 70: * it is randomized to avoid aliasing between the two clocks. For example,
! 71: * the randomization prevents an adversary from always giving up the cpu
! 72: * just before its quantum expires. Otherwise, it would never accumulate
! 73: * cpu ticks. The mean frequency of the second timer is stathz.
! 74: *
! 75: * If no second timer exists, stathz will be zero; in this case we drive
! 76: * profiling and statistics off the main clock. This WILL NOT be accurate;
! 77: * do not do it unless absolutely necessary.
! 78: *
! 79: * The statistics clock may (or may not) be run at a higher rate while
! 80: * profiling. This profile clock runs at profhz. We require that profhz
! 81: * be an integral multiple of stathz.
! 82: *
! 83: * If the statistics clock is running fast, it must be divided by the ratio
! 84: * profhz/stathz for statistics. (For profiling, every tick counts.)
! 85: */
! 86:
! 87: /*
! 88: * Bump a timeval by a small number of usec's.
! 89: */
! 90: #define BUMPTIME(t, usec) { \
! 91: volatile struct timeval *tp = (t); \
! 92: long us; \
! 93: \
! 94: tp->tv_usec = us = tp->tv_usec + (usec); \
! 95: if (us >= 1000000) { \
! 96: tp->tv_usec = us - 1000000; \
! 97: tp->tv_sec++; \
! 98: } \
! 99: }
! 100:
! 101: int stathz;
! 102: int schedhz;
! 103: int profhz;
! 104: int profprocs;
! 105: int ticks;
! 106: static int psdiv, pscnt; /* prof => stat divider */
! 107: int psratio; /* ratio: prof / stat */
! 108:
! 109: long cp_time[CPUSTATES];
! 110:
! 111: #ifndef __HAVE_TIMECOUNTER
! 112: int tickfix, tickfixinterval; /* used if tick not really integral */
! 113: static int tickfixcnt; /* accumulated fractional error */
! 114:
! 115: volatile time_t time_second;
! 116: volatile time_t time_uptime;
! 117:
! 118: volatile struct timeval time
! 119: __attribute__((__aligned__(__alignof__(quad_t))));
! 120: volatile struct timeval mono_time;
! 121: #endif
! 122:
! 123: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 124: void *softclock_si;
! 125: void generic_softclock(void *);
! 126:
! 127: void
! 128: generic_softclock(void *ignore)
! 129: {
! 130: /*
! 131: * XXX - don't commit, just a dummy wrapper until we learn everyone
! 132: * deal with a changed proto for softclock().
! 133: */
! 134: softclock();
! 135: }
! 136: #endif
! 137:
! 138: /*
! 139: * Initialize clock frequencies and start both clocks running.
! 140: */
! 141: void
! 142: initclocks(void)
! 143: {
! 144: int i;
! 145: #ifdef __HAVE_TIMECOUNTER
! 146: extern void inittimecounter(void);
! 147: #endif
! 148:
! 149: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 150: softclock_si = softintr_establish(IPL_SOFTCLOCK, generic_softclock, NULL);
! 151: if (softclock_si == NULL)
! 152: panic("initclocks: unable to register softclock intr");
! 153: #endif
! 154:
! 155: /*
! 156: * Set divisors to 1 (normal case) and let the machine-specific
! 157: * code do its bit.
! 158: */
! 159: psdiv = pscnt = 1;
! 160: cpu_initclocks();
! 161:
! 162: /*
! 163: * Compute profhz/stathz, and fix profhz if needed.
! 164: */
! 165: i = stathz ? stathz : hz;
! 166: if (profhz == 0)
! 167: profhz = i;
! 168: psratio = profhz / i;
! 169: #ifdef __HAVE_TIMECOUNTER
! 170: inittimecounter();
! 171: #endif
! 172: }
! 173:
! 174: /*
! 175: * hardclock does the accounting needed for ITIMER_PROF and ITIMER_VIRTUAL.
! 176: * We don't want to send signals with psignal from hardclock because it makes
! 177: * MULTIPROCESSOR locking very complicated. Instead we use a small trick
! 178: * to send the signals safely and without blocking too many interrupts
! 179: * while doing that (signal handling can be heavy).
! 180: *
! 181: * hardclock detects that the itimer has expired, and schedules a timeout
! 182: * to deliver the signal. This works because of the following reasons:
! 183: * - The timeout structures can be in struct pstats because the timers
! 184: * can be only activated on curproc (never swapped). Swapout can
! 185: * only happen from a kernel thread and softclock runs before threads
! 186: * are scheduled.
! 187: * - The timeout can be scheduled with a 1 tick time because we're
! 188: * doing it before the timeout processing in hardclock. So it will
! 189: * be scheduled to run as soon as possible.
! 190: * - The timeout will be run in softclock which will run before we
! 191: * return to userland and process pending signals.
! 192: * - If the system is so busy that several VIRTUAL/PROF ticks are
! 193: * sent before softclock processing, we'll send only one signal.
! 194: * But if we'd send the signal from hardclock only one signal would
! 195: * be delivered to the user process. So userland will only see one
! 196: * signal anyway.
! 197: */
! 198:
! 199: void
! 200: virttimer_trampoline(void *v)
! 201: {
! 202: struct proc *p = v;
! 203:
! 204: psignal(p, SIGVTALRM);
! 205: }
! 206:
! 207: void
! 208: proftimer_trampoline(void *v)
! 209: {
! 210: struct proc *p = v;
! 211:
! 212: psignal(p, SIGPROF);
! 213: }
! 214:
! 215: /*
! 216: * The real-time timer, interrupting hz times per second.
! 217: */
! 218: void
! 219: hardclock(struct clockframe *frame)
! 220: {
! 221: struct proc *p;
! 222: #ifndef __HAVE_TIMECOUNTER
! 223: int delta;
! 224: extern int tickdelta;
! 225: extern long timedelta;
! 226: extern int64_t ntp_tick_permanent;
! 227: extern int64_t ntp_tick_acc;
! 228: #endif
! 229: struct cpu_info *ci = curcpu();
! 230:
! 231: p = curproc;
! 232: if (p && ((p->p_flag & (P_SYSTEM | P_WEXIT)) == 0)) {
! 233: struct pstats *pstats;
! 234:
! 235: /*
! 236: * Run current process's virtual and profile time, as needed.
! 237: */
! 238: pstats = p->p_stats;
! 239: if (CLKF_USERMODE(frame) &&
! 240: timerisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) &&
! 241: itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0)
! 242: timeout_add(&pstats->p_virt_to, 1);
! 243: if (timerisset(&pstats->p_timer[ITIMER_PROF].it_value) &&
! 244: itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0)
! 245: timeout_add(&pstats->p_prof_to, 1);
! 246: }
! 247:
! 248: /*
! 249: * If no separate statistics clock is available, run it from here.
! 250: */
! 251: if (stathz == 0)
! 252: statclock(frame);
! 253:
! 254: if (--ci->ci_schedstate.spc_rrticks <= 0)
! 255: roundrobin(ci);
! 256:
! 257: /*
! 258: * If we are not the primary CPU, we're not allowed to do
! 259: * any more work.
! 260: */
! 261: if (CPU_IS_PRIMARY(ci) == 0)
! 262: return;
! 263:
! 264: #ifndef __HAVE_TIMECOUNTER
! 265: /*
! 266: * Increment the time-of-day. The increment is normally just
! 267: * ``tick''. If the machine is one which has a clock frequency
! 268: * such that ``hz'' would not divide the second evenly into
! 269: * milliseconds, a periodic adjustment must be applied. Finally,
! 270: * if we are still adjusting the time (see adjtime()),
! 271: * ``tickdelta'' may also be added in.
! 272: */
! 273:
! 274: delta = tick;
! 275:
! 276: if (tickfix) {
! 277: tickfixcnt += tickfix;
! 278: if (tickfixcnt >= tickfixinterval) {
! 279: delta++;
! 280: tickfixcnt -= tickfixinterval;
! 281: }
! 282: }
! 283: /* Imprecise 4bsd adjtime() handling */
! 284: if (timedelta != 0) {
! 285: delta += tickdelta;
! 286: timedelta -= tickdelta;
! 287: }
! 288:
! 289: /*
! 290: * ntp_tick_permanent accumulates the clock correction each
! 291: * tick. The unit is ns per tick shifted left 32 bits. If we have
! 292: * accumulated more than 1us, we bump delta in the right
! 293: * direction. Use a loop to avoid long long div; typicallly
! 294: * the loops will be executed 0 or 1 iteration.
! 295: */
! 296: if (ntp_tick_permanent != 0) {
! 297: ntp_tick_acc += ntp_tick_permanent;
! 298: while (ntp_tick_acc >= (1000LL << 32)) {
! 299: delta++;
! 300: ntp_tick_acc -= (1000LL << 32);
! 301: }
! 302: while (ntp_tick_acc <= -(1000LL << 32)) {
! 303: delta--;
! 304: ntp_tick_acc += (1000LL << 32);
! 305: }
! 306: }
! 307:
! 308: BUMPTIME(&time, delta);
! 309: BUMPTIME(&mono_time, delta);
! 310: time_second = time.tv_sec;
! 311: time_uptime = mono_time.tv_sec;
! 312: #else
! 313: tc_ticktock();
! 314: #endif
! 315:
! 316: /*
! 317: * Update real-time timeout queue.
! 318: * Process callouts at a very low cpu priority, so we don't keep the
! 319: * relatively high clock interrupt priority any longer than necessary.
! 320: */
! 321: if (timeout_hardclock_update()) {
! 322: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 323: softintr_schedule(softclock_si);
! 324: #else
! 325: setsoftclock();
! 326: #endif
! 327: }
! 328: }
! 329:
! 330: /*
! 331: * Compute number of hz until specified time. Used to
! 332: * compute the second argument to timeout_add() from an absolute time.
! 333: */
! 334: int
! 335: hzto(struct timeval *tv)
! 336: {
! 337: struct timeval now;
! 338: unsigned long ticks;
! 339: long sec, usec;
! 340:
! 341: /*
! 342: * If the number of usecs in the whole seconds part of the time
! 343: * difference fits in a long, then the total number of usecs will
! 344: * fit in an unsigned long. Compute the total and convert it to
! 345: * ticks, rounding up and adding 1 to allow for the current tick
! 346: * to expire. Rounding also depends on unsigned long arithmetic
! 347: * to avoid overflow.
! 348: *
! 349: * Otherwise, if the number of ticks in the whole seconds part of
! 350: * the time difference fits in a long, then convert the parts to
! 351: * ticks separately and add, using similar rounding methods and
! 352: * overflow avoidance. This method would work in the previous
! 353: * case but it is slightly slower and assumes that hz is integral.
! 354: *
! 355: * Otherwise, round the time difference down to the maximum
! 356: * representable value.
! 357: *
! 358: * If ints have 32 bits, then the maximum value for any timeout in
! 359: * 10ms ticks is 248 days.
! 360: */
! 361: getmicrotime(&now);
! 362: sec = tv->tv_sec - now.tv_sec;
! 363: usec = tv->tv_usec - now.tv_usec;
! 364: if (usec < 0) {
! 365: sec--;
! 366: usec += 1000000;
! 367: }
! 368: if (sec < 0 || (sec == 0 && usec <= 0)) {
! 369: ticks = 0;
! 370: } else if (sec <= LONG_MAX / 1000000)
! 371: ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))
! 372: / tick + 1;
! 373: else if (sec <= LONG_MAX / hz)
! 374: ticks = sec * hz
! 375: + ((unsigned long)usec + (tick - 1)) / tick + 1;
! 376: else
! 377: ticks = LONG_MAX;
! 378: if (ticks > INT_MAX)
! 379: ticks = INT_MAX;
! 380: return ((int)ticks);
! 381: }
! 382:
! 383: /*
! 384: * Compute number of hz in the specified amount of time.
! 385: */
! 386: int
! 387: tvtohz(struct timeval *tv)
! 388: {
! 389: unsigned long ticks;
! 390: long sec, usec;
! 391:
! 392: /*
! 393: * If the number of usecs in the whole seconds part of the time
! 394: * fits in a long, then the total number of usecs will
! 395: * fit in an unsigned long. Compute the total and convert it to
! 396: * ticks, rounding up and adding 1 to allow for the current tick
! 397: * to expire. Rounding also depends on unsigned long arithmetic
! 398: * to avoid overflow.
! 399: *
! 400: * Otherwise, if the number of ticks in the whole seconds part of
! 401: * the time fits in a long, then convert the parts to
! 402: * ticks separately and add, using similar rounding methods and
! 403: * overflow avoidance. This method would work in the previous
! 404: * case but it is slightly slower and assumes that hz is integral.
! 405: *
! 406: * Otherwise, round the time down to the maximum
! 407: * representable value.
! 408: *
! 409: * If ints have 32 bits, then the maximum value for any timeout in
! 410: * 10ms ticks is 248 days.
! 411: */
! 412: sec = tv->tv_sec;
! 413: usec = tv->tv_usec;
! 414: if (sec < 0 || (sec == 0 && usec <= 0))
! 415: ticks = 0;
! 416: else if (sec <= LONG_MAX / 1000000)
! 417: ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))
! 418: / tick + 1;
! 419: else if (sec <= LONG_MAX / hz)
! 420: ticks = sec * hz
! 421: + ((unsigned long)usec + (tick - 1)) / tick + 1;
! 422: else
! 423: ticks = LONG_MAX;
! 424: if (ticks > INT_MAX)
! 425: ticks = INT_MAX;
! 426: return ((int)ticks);
! 427: }
! 428:
! 429: /*
! 430: * Start profiling on a process.
! 431: *
! 432: * Kernel profiling passes proc0 which never exits and hence
! 433: * keeps the profile clock running constantly.
! 434: */
! 435: void
! 436: startprofclock(struct proc *p)
! 437: {
! 438: int s;
! 439:
! 440: if ((p->p_flag & P_PROFIL) == 0) {
! 441: atomic_setbits_int(&p->p_flag, P_PROFIL);
! 442: if (++profprocs == 1 && stathz != 0) {
! 443: s = splstatclock();
! 444: psdiv = pscnt = psratio;
! 445: setstatclockrate(profhz);
! 446: splx(s);
! 447: }
! 448: }
! 449: }
! 450:
! 451: /*
! 452: * Stop profiling on a process.
! 453: */
! 454: void
! 455: stopprofclock(struct proc *p)
! 456: {
! 457: int s;
! 458:
! 459: if (p->p_flag & P_PROFIL) {
! 460: atomic_clearbits_int(&p->p_flag, P_PROFIL);
! 461: if (--profprocs == 0 && stathz != 0) {
! 462: s = splstatclock();
! 463: psdiv = pscnt = 1;
! 464: setstatclockrate(stathz);
! 465: splx(s);
! 466: }
! 467: }
! 468: }
! 469:
! 470: /*
! 471: * Statistics clock. Grab profile sample, and if divider reaches 0,
! 472: * do process and kernel statistics.
! 473: */
! 474: void
! 475: statclock(struct clockframe *frame)
! 476: {
! 477: #ifdef GPROF
! 478: struct gmonparam *g;
! 479: int i;
! 480: #endif
! 481: struct cpu_info *ci = curcpu();
! 482: struct schedstate_percpu *spc = &ci->ci_schedstate;
! 483: struct proc *p = curproc;
! 484:
! 485: /*
! 486: * Notice changes in divisor frequency, and adjust clock
! 487: * frequency accordingly.
! 488: */
! 489: if (spc->spc_psdiv != psdiv) {
! 490: spc->spc_psdiv = psdiv;
! 491: spc->spc_pscnt = psdiv;
! 492: if (psdiv == 1) {
! 493: setstatclockrate(stathz);
! 494: } else {
! 495: setstatclockrate(profhz);
! 496: }
! 497: }
! 498:
! 499: if (CLKF_USERMODE(frame)) {
! 500: if (p->p_flag & P_PROFIL)
! 501: addupc_intr(p, CLKF_PC(frame));
! 502: if (--spc->spc_pscnt > 0)
! 503: return;
! 504: /*
! 505: * Came from user mode; CPU was in user state.
! 506: * If this process is being profiled record the tick.
! 507: */
! 508: p->p_uticks++;
! 509: if (p->p_nice > NZERO)
! 510: spc->spc_cp_time[CP_NICE]++;
! 511: else
! 512: spc->spc_cp_time[CP_USER]++;
! 513: } else {
! 514: #ifdef GPROF
! 515: /*
! 516: * Kernel statistics are just like addupc_intr, only easier.
! 517: */
! 518: g = &_gmonparam;
! 519: if (g->state == GMON_PROF_ON) {
! 520: i = CLKF_PC(frame) - g->lowpc;
! 521: if (i < g->textsize) {
! 522: i /= HISTFRACTION * sizeof(*g->kcount);
! 523: g->kcount[i]++;
! 524: }
! 525: }
! 526: #endif
! 527: #if defined(PROC_PC)
! 528: if (p != NULL && p->p_flag & P_PROFIL)
! 529: addupc_intr(p, PROC_PC(p));
! 530: #endif
! 531: if (--spc->spc_pscnt > 0)
! 532: return;
! 533: /*
! 534: * Came from kernel mode, so we were:
! 535: * - handling an interrupt,
! 536: * - doing syscall or trap work on behalf of the current
! 537: * user process, or
! 538: * - spinning in the idle loop.
! 539: * Whichever it is, charge the time as appropriate.
! 540: * Note that we charge interrupts to the current process,
! 541: * regardless of whether they are ``for'' that process,
! 542: * so that we know how much of its real time was spent
! 543: * in ``non-process'' (i.e., interrupt) work.
! 544: */
! 545: if (CLKF_INTR(frame)) {
! 546: if (p != NULL)
! 547: p->p_iticks++;
! 548: spc->spc_cp_time[CP_INTR]++;
! 549: } else if (p != NULL) {
! 550: p->p_sticks++;
! 551: spc->spc_cp_time[CP_SYS]++;
! 552: } else
! 553: spc->spc_cp_time[CP_IDLE]++;
! 554: }
! 555: spc->spc_pscnt = psdiv;
! 556:
! 557: if (p != NULL) {
! 558: p->p_cpticks++;
! 559: /*
! 560: * If no schedclock is provided, call it here at ~~12-25 Hz;
! 561: * ~~16 Hz is best
! 562: */
! 563: if (schedhz == 0) {
! 564: if ((++curcpu()->ci_schedstate.spc_schedticks & 3) ==
! 565: 0)
! 566: schedclock(p);
! 567: }
! 568: }
! 569: }
! 570:
! 571: /*
! 572: * Return information about system clocks.
! 573: */
! 574: int
! 575: sysctl_clockrate(char *where, size_t *sizep)
! 576: {
! 577: struct clockinfo clkinfo;
! 578:
! 579: /*
! 580: * Construct clockinfo structure.
! 581: */
! 582: clkinfo.tick = tick;
! 583: clkinfo.tickadj = tickadj;
! 584: clkinfo.hz = hz;
! 585: clkinfo.profhz = profhz;
! 586: clkinfo.stathz = stathz ? stathz : hz;
! 587: return (sysctl_rdstruct(where, sizep, NULL, &clkinfo, sizeof(clkinfo)));
! 588: }
! 589:
! 590: #ifndef __HAVE_TIMECOUNTER
! 591: /*
! 592: * Placeholders until everyone uses the timecounters code.
! 593: * Won't improve anything except maybe removing a bunch of bugs in fixed code.
! 594: */
! 595:
! 596: void
! 597: getmicrotime(struct timeval *tvp)
! 598: {
! 599: int s;
! 600:
! 601: s = splhigh();
! 602: *tvp = time;
! 603: splx(s);
! 604: }
! 605:
! 606: void
! 607: nanotime(struct timespec *tsp)
! 608: {
! 609: struct timeval tv;
! 610:
! 611: microtime(&tv);
! 612: TIMEVAL_TO_TIMESPEC(&tv, tsp);
! 613: }
! 614:
! 615: void
! 616: getnanotime(struct timespec *tsp)
! 617: {
! 618: struct timeval tv;
! 619:
! 620: getmicrotime(&tv);
! 621: TIMEVAL_TO_TIMESPEC(&tv, tsp);
! 622: }
! 623:
! 624: void
! 625: nanouptime(struct timespec *tsp)
! 626: {
! 627: struct timeval tv;
! 628:
! 629: microuptime(&tv);
! 630: TIMEVAL_TO_TIMESPEC(&tv, tsp);
! 631: }
! 632:
! 633:
! 634: void
! 635: getnanouptime(struct timespec *tsp)
! 636: {
! 637: struct timeval tv;
! 638:
! 639: getmicrouptime(&tv);
! 640: TIMEVAL_TO_TIMESPEC(&tv, tsp);
! 641: }
! 642:
! 643: void
! 644: microuptime(struct timeval *tvp)
! 645: {
! 646: struct timeval tv;
! 647:
! 648: microtime(&tv);
! 649: timersub(&tv, &boottime, tvp);
! 650: }
! 651:
! 652: void
! 653: getmicrouptime(struct timeval *tvp)
! 654: {
! 655: int s;
! 656:
! 657: s = splhigh();
! 658: *tvp = mono_time;
! 659: splx(s);
! 660: }
! 661: #endif /* __HAVE_TIMECOUNTER */
CVSweb