|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1994-1988 Carnegie Mellon University. ! 4: * Copyright (c) 1993,1994 The University of Utah and ! 5: * the Computer Systems Laboratory (CSL). ! 6: * All rights reserved. ! 7: * ! 8: * Permission to use, copy, modify and distribute this software and its ! 9: * documentation is hereby granted, provided that both the copyright ! 10: * notice and this permission notice appear in all copies of the ! 11: * software, derivative works or modified versions, and any portions ! 12: * thereof, and that both notices appear in supporting documentation. ! 13: * ! 14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF ! 15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY ! 16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF ! 17: * THIS SOFTWARE. ! 18: * ! 19: * Carnegie Mellon requests users of this software to return to ! 20: * ! 21: * Software Distribution Coordinator or [email protected] ! 22: * School of Computer Science ! 23: * Carnegie Mellon University ! 24: * Pittsburgh PA 15213-3890 ! 25: * ! 26: * any improvements or extensions that they make and grant Carnegie Mellon ! 27: * the rights to redistribute these changes. ! 28: */ ! 29: /* ! 30: * File: clock_prim.c ! 31: * Author: Avadis Tevanian, Jr. ! 32: * Date: 1986 ! 33: * ! 34: * Clock primitives. ! 35: */ ! 36: #include <cpus.h> ! 37: #include <mach_pcsample.h> ! 38: #include <stat_time.h> ! 39: ! 40: #include <mach/boolean.h> ! 41: #include <mach/machine.h> ! 42: #include <mach/time_value.h> ! 43: #include <mach/vm_param.h> ! 44: #include <mach/vm_prot.h> ! 45: #include <kern/counters.h> ! 46: #include "cpu_number.h" ! 47: #include <kern/host.h> ! 48: #include <kern/lock.h> ! 49: #include <kern/mach_param.h> ! 50: #include <kern/processor.h> ! 51: #include <kern/sched.h> ! 52: #include <kern/sched_prim.h> ! 53: #include <kern/thread.h> ! 54: #include <kern/time_out.h> ! 55: #include <kern/time_stamp.h> ! 56: #include <vm/vm_kern.h> ! 57: #include <sys/time.h> ! 58: #include <machine/mach_param.h> /* HZ */ ! 59: #include <machine/machspl.h> ! 60: ! 61: #if MACH_PCSAMPLE ! 62: #include <kern/pc_sample.h> ! 63: #endif ! 64: ! 65: ! 66: void softclock(); /* forward */ ! 67: ! 68: int hz = HZ; /* number of ticks per second */ ! 69: int tick = (1000000 / HZ); /* number of usec per tick */ ! 70: time_value_t time = { 0, 0 }; /* time since bootup (uncorrected) */ ! 71: unsigned long elapsed_ticks; /* ticks elapsed since bootup */ ! 72: unsigned long timeout_tick; /* tick value for softclock timeouts */ ! 73: ! 74: int timedelta = 0; ! 75: int tickdelta = 0; ! 76: ! 77: #if HZ > 500 ! 78: int tickadj = 1; /* can adjust HZ usecs per second */ ! 79: #else ! 80: int tickadj = 500 / HZ; /* can adjust 100 usecs per second */ ! 81: #endif ! 82: int bigadj = 1000000; /* adjust 10*tickadj if adjustment ! 83: > bigadj */ ! 84: ! 85: /* ! 86: * This update protocol, with a check value, allows ! 87: * do { ! 88: * secs = mtime->seconds; ! 89: * usecs = mtime->microseconds; ! 90: * } while (secs != mtime->check_seconds); ! 91: * to read the time correctly. (On a multiprocessor this assumes ! 92: * that processors see each other's writes in the correct order. ! 93: * We may have to insert fence operations.) ! 94: */ ! 95: ! 96: mapped_time_value_t *mtime = 0; ! 97: ! 98: #define update_mapped_time(time) \ ! 99: MACRO_BEGIN \ ! 100: if (mtime != 0) { \ ! 101: mtime->check_seconds = (time)->seconds; \ ! 102: mtime->microseconds = (time)->microseconds; \ ! 103: mtime->seconds = (time)->seconds; \ ! 104: } \ ! 105: MACRO_END ! 106: ! 107: decl_simple_lock_data(, timer_lock) /* lock for ... */ ! 108: timer_elt_data_t timer_head; /* ordered list of timeouts */ ! 109: /* (doubles as end-of-list) */ ! 110: ! 111: /* ! 112: * Handle clock interrupts. ! 113: * ! 114: * The clock interrupt is assumed to be called at a (more or less) ! 115: * constant rate. The rate must be identical on all CPUS (XXX - fix). ! 116: * ! 117: * Usec is the number of microseconds that have elapsed since the ! 118: * last clock tick. It may be constant or computed, depending on ! 119: * the accuracy of the hardware clock. ! 120: * ! 121: */ ! 122: void clock_interrupt(usec, usermode, basepri) ! 123: register int usec; /* microseconds per tick */ ! 124: boolean_t usermode; /* executing user code */ ! 125: boolean_t basepri; /* at base priority */ ! 126: { ! 127: register int my_cpu = cpu_number(); ! 128: register thread_t thread = current_thread(); ! 129: ! 130: counter(c_clock_ticks++); ! 131: counter(c_threads_total += c_threads_current); ! 132: counter(c_stacks_total += c_stacks_current); ! 133: ! 134: #if STAT_TIME ! 135: /* ! 136: * Increment the thread time, if using ! 137: * statistical timing. ! 138: */ ! 139: if (usermode) { ! 140: timer_bump(&thread->user_timer, usec); ! 141: } ! 142: else { ! 143: timer_bump(&thread->system_timer, usec); ! 144: } ! 145: #endif /* STAT_TIME */ ! 146: ! 147: /* ! 148: * Increment the CPU time statistics. ! 149: */ ! 150: { ! 151: extern void thread_quantum_update(); /* in priority.c */ ! 152: register int state; ! 153: ! 154: if (usermode) ! 155: state = CPU_STATE_USER; ! 156: else if (!cpu_idle(my_cpu)) ! 157: state = CPU_STATE_SYSTEM; ! 158: else ! 159: state = CPU_STATE_IDLE; ! 160: ! 161: machine_slot[my_cpu].cpu_ticks[state]++; ! 162: ! 163: /* ! 164: * Adjust the thread's priority and check for ! 165: * quantum expiration. ! 166: */ ! 167: ! 168: thread_quantum_update(my_cpu, thread, 1, state); ! 169: } ! 170: ! 171: #if MACH_PCSAMPLE ! 172: /* ! 173: * Take a sample of pc for the user if required. ! 174: * This had better be MP safe. It might be interesting ! 175: * to keep track of cpu in the sample. ! 176: */ ! 177: if (usermode) { ! 178: take_pc_sample_macro(thread, SAMPLED_PC_PERIODIC); ! 179: } ! 180: #endif /* MACH_PCSAMPLE */ ! 181: ! 182: /* ! 183: * Time-of-day and time-out list are updated only ! 184: * on the master CPU. ! 185: */ ! 186: if (my_cpu == master_cpu) { ! 187: ! 188: register spl_t s; ! 189: register timer_elt_t telt; ! 190: ! 191: #if TS_FORMAT == 1 ! 192: /* ! 193: * Increment the tick count for the timestamping routine. ! 194: */ ! 195: ts_tick_count++; ! 196: #endif /* TS_FORMAT == 1 */ ! 197: ! 198: /* ! 199: * Update the tick count since bootup, and handle ! 200: * timeouts. ! 201: */ ! 202: ! 203: s = splsched(); ! 204: simple_lock(&timer_lock); ! 205: ! 206: elapsed_ticks++; ! 207: ! 208: telt = (timer_elt_t)queue_first(&timer_head.chain); ! 209: if (telt->ticks <= elapsed_ticks) ! 210: timeout_tick = elapsed_ticks; ! 211: simple_unlock(&timer_lock); ! 212: splx(s); ! 213: ! 214: /* ! 215: * Increment the time-of-day clock. ! 216: */ ! 217: if (timedelta == 0) { ! 218: time_value_add_usec(&time, usec); ! 219: } ! 220: else { ! 221: register int delta; ! 222: ! 223: if (timedelta < 0) { ! 224: delta = usec - tickdelta; ! 225: timedelta += tickdelta; ! 226: } ! 227: else { ! 228: delta = usec + tickdelta; ! 229: timedelta -= tickdelta; ! 230: } ! 231: time_value_add_usec(&time, delta); ! 232: } ! 233: update_mapped_time(&time); ! 234: ! 235: /* ! 236: * We always run softclock so it can deliver oskit clock ticks. ! 237: * The value of TIMEOUT_TICK tells softclock whether we detected ! 238: * a (Mach) timeout above. ! 239: */ ! 240: if (basepri) { ! 241: (void) splsoftclock(); ! 242: softclock(); ! 243: } ! 244: else { ! 245: setsoftclock(); ! 246: } ! 247: } ! 248: } ! 249: ! 250: /* ! 251: * There is a nasty race between softclock and reset_timeout. ! 252: * For example, scheduling code looks at timer_set and calls ! 253: * reset_timeout, thinking the timer is set. However, softclock ! 254: * has already removed the timer but hasn't called thread_timeout ! 255: * yet. ! 256: * ! 257: * Interim solution: We initialize timers after pulling ! 258: * them out of the queue, so a race with reset_timeout won't ! 259: * hurt. The timeout functions (eg, thread_timeout, ! 260: * thread_depress_timeout) check timer_set/depress_priority ! 261: * to see if the timer has been cancelled and if so do nothing. ! 262: * ! 263: * This still isn't correct. For example, softclock pulls a ! 264: * timer off the queue, then thread_go resets timer_set (but ! 265: * reset_timeout does nothing), then thread_set_timeout puts the ! 266: * timer back on the queue and sets timer_set, then ! 267: * thread_timeout finally runs and clears timer_set, then ! 268: * thread_set_timeout tries to put the timer on the queue again ! 269: * and corrupts it. ! 270: */ ! 271: ! 272: void softclock() ! 273: { ! 274: /* ! 275: * Handle timeouts. ! 276: */ ! 277: spl_t s; ! 278: register timer_elt_t telt; ! 279: register int (*fcn)(); ! 280: register char *param; ! 281: ! 282: if (timeout_tick == elapsed_ticks) ! 283: while (TRUE) { ! 284: s = splsched(); ! 285: simple_lock(&timer_lock); ! 286: telt = (timer_elt_t) queue_first(&timer_head.chain); ! 287: if (telt->ticks > elapsed_ticks) { ! 288: simple_unlock(&timer_lock); ! 289: splx(s); ! 290: break; ! 291: } ! 292: fcn = telt->fcn; ! 293: param = telt->param; ! 294: ! 295: remqueue(&timer_head.chain, (queue_entry_t)telt); ! 296: telt->set = TELT_UNSET; ! 297: simple_unlock(&timer_lock); ! 298: splx(s); ! 299: ! 300: assert(fcn != 0); ! 301: (*fcn)(param); ! 302: } ! 303: ! 304: /* Give the oskit a clock tick. */ ! 305: softclock_oskit (); ! 306: } ! 307: ! 308: /* ! 309: * Set timeout. ! 310: * ! 311: * Parameters: ! 312: * telt timer element. Function and param are already set. ! 313: * interval time-out interval, in hz. ! 314: */ ! 315: void set_timeout(telt, interval) ! 316: register timer_elt_t telt; /* already loaded */ ! 317: register unsigned int interval; ! 318: { ! 319: spl_t s; ! 320: register timer_elt_t next; ! 321: ! 322: s = splsched(); ! 323: simple_lock(&timer_lock); ! 324: ! 325: interval += elapsed_ticks; ! 326: ! 327: for (next = (timer_elt_t)queue_first(&timer_head.chain); ! 328: ; ! 329: next = (timer_elt_t)queue_next((queue_entry_t)next)) { ! 330: ! 331: if (next->ticks > interval) ! 332: break; ! 333: } ! 334: telt->ticks = interval; ! 335: /* ! 336: * Insert new timer element before 'next' ! 337: * (after 'next'->prev) ! 338: */ ! 339: insque((queue_entry_t) telt, ((queue_entry_t)next)->prev); ! 340: telt->set = TELT_SET; ! 341: simple_unlock(&timer_lock); ! 342: splx(s); ! 343: } ! 344: ! 345: boolean_t reset_timeout(telt) ! 346: register timer_elt_t telt; ! 347: { ! 348: spl_t s; ! 349: ! 350: s = splsched(); ! 351: simple_lock(&timer_lock); ! 352: if (telt->set) { ! 353: remqueue(&timer_head.chain, (queue_entry_t)telt); ! 354: telt->set = TELT_UNSET; ! 355: simple_unlock(&timer_lock); ! 356: splx(s); ! 357: return TRUE; ! 358: } ! 359: else { ! 360: simple_unlock(&timer_lock); ! 361: splx(s); ! 362: return FALSE; ! 363: } ! 364: } ! 365: ! 366: void init_timeout() ! 367: { ! 368: simple_lock_init(&timer_lock); ! 369: queue_init(&timer_head.chain); ! 370: timer_head.ticks = ~0; /* MAXUINT - sentinel */ ! 371: ! 372: elapsed_ticks = 0; ! 373: } ! 374: ! 375: /* ! 376: * Record a timestamp in STAMP. ! 377: */ ! 378: void ! 379: record_time_stamp (time_value_t *stamp) ! 380: { ! 381: do { ! 382: stamp->seconds = mtime->seconds; ! 383: stamp->microseconds = mtime->microseconds; ! 384: } while (stamp->seconds != mtime->check_seconds); ! 385: } ! 386: ! 387: ! 388: /* ! 389: * Read the time. ! 390: */ ! 391: kern_return_t ! 392: host_get_time(host, current_time) ! 393: host_t host; ! 394: time_value_t *current_time; /* OUT */ ! 395: { ! 396: if (host == HOST_NULL) ! 397: return(KERN_INVALID_HOST); ! 398: ! 399: do { ! 400: current_time->seconds = mtime->seconds; ! 401: current_time->microseconds = mtime->microseconds; ! 402: } while (current_time->seconds != mtime->check_seconds); ! 403: ! 404: return (KERN_SUCCESS); ! 405: } ! 406: ! 407: /* ! 408: * Set the time. Only available to privileged users. ! 409: */ ! 410: kern_return_t ! 411: host_set_time(host, new_time) ! 412: host_t host; ! 413: time_value_t new_time; ! 414: { ! 415: spl_t s; ! 416: ! 417: if (host == HOST_NULL) ! 418: return(KERN_INVALID_HOST); ! 419: ! 420: #if NCPUS > 1 ! 421: /* ! 422: * Switch to the master CPU to synchronize correctly. ! 423: */ ! 424: thread_bind(current_thread(), master_processor); ! 425: if (current_processor() != master_processor) ! 426: thread_block((void (*)) 0); ! 427: #endif /* NCPUS > 1 */ ! 428: ! 429: s = splhigh(); ! 430: time = new_time; ! 431: update_mapped_time(&time); ! 432: resettodr(); ! 433: splx(s); ! 434: ! 435: #if NCPUS > 1 ! 436: /* ! 437: * Switch off the master CPU. ! 438: */ ! 439: thread_bind(current_thread(), PROCESSOR_NULL); ! 440: #endif /* NCPUS > 1 */ ! 441: ! 442: return (KERN_SUCCESS); ! 443: } ! 444: ! 445: /* ! 446: * Adjust the time gradually. ! 447: */ ! 448: kern_return_t ! 449: host_adjust_time(host, new_adjustment, old_adjustment) ! 450: host_t host; ! 451: time_value_t new_adjustment; ! 452: time_value_t *old_adjustment; /* OUT */ ! 453: { ! 454: time_value_t oadj; ! 455: unsigned int ndelta; ! 456: spl_t s; ! 457: ! 458: if (host == HOST_NULL) ! 459: return (KERN_INVALID_HOST); ! 460: ! 461: ndelta = new_adjustment.seconds * 1000000 ! 462: + new_adjustment.microseconds; ! 463: ! 464: #if NCPUS > 1 ! 465: thread_bind(current_thread(), master_processor); ! 466: if (current_processor() != master_processor) ! 467: thread_block((void (*)) 0); ! 468: #endif /* NCPUS > 1 */ ! 469: ! 470: s = splclock(); ! 471: ! 472: oadj.seconds = timedelta / 1000000; ! 473: oadj.microseconds = timedelta % 1000000; ! 474: ! 475: if (timedelta == 0) { ! 476: if (ndelta > bigadj) ! 477: tickdelta = 10 * tickadj; ! 478: else ! 479: tickdelta = tickadj; ! 480: } ! 481: if (ndelta % tickdelta) ! 482: ndelta = ndelta / tickdelta * tickdelta; ! 483: ! 484: timedelta = ndelta; ! 485: ! 486: splx(s); ! 487: #if NCPUS > 1 ! 488: thread_bind(current_thread(), PROCESSOR_NULL); ! 489: #endif /* NCPUS > 1 */ ! 490: ! 491: *old_adjustment = oadj; ! 492: ! 493: return (KERN_SUCCESS); ! 494: } ! 495: ! 496: void mapable_time_init() ! 497: { ! 498: if (kmem_alloc_wired(kernel_map, (vm_offset_t *) &mtime, PAGE_SIZE) ! 499: != KERN_SUCCESS) ! 500: panic("mapable_time_init"); ! 501: bzero((char *)mtime, PAGE_SIZE); ! 502: update_mapped_time(&time); ! 503: } ! 504: ! 505: int timeopen() ! 506: { ! 507: return(0); ! 508: } ! 509: int timeclose() ! 510: { ! 511: return(0); ! 512: } ! 513: ! 514: /* ! 515: * Compatibility for device drivers. ! 516: * New code should use set_timeout/reset_timeout and private timers. ! 517: * These code can't use a zone to allocate timers, because ! 518: * it can be called from interrupt handlers. ! 519: */ ! 520: ! 521: #define NTIMERS 20 ! 522: ! 523: timer_elt_data_t timeout_timers[NTIMERS]; ! 524: ! 525: /* ! 526: * Set timeout. ! 527: * ! 528: * fcn: function to call ! 529: * param: parameter to pass to function ! 530: * interval: timeout interval, in hz. ! 531: */ ! 532: void timeout(fcn, param, interval) ! 533: int (*fcn)(/* char * param */); ! 534: char * param; ! 535: int interval; ! 536: { ! 537: spl_t s; ! 538: register timer_elt_t elt; ! 539: ! 540: s = splsched(); ! 541: simple_lock(&timer_lock); ! 542: for (elt = &timeout_timers[0]; elt < &timeout_timers[NTIMERS]; elt++) ! 543: if (elt->set == TELT_UNSET) ! 544: break; ! 545: if (elt == &timeout_timers[NTIMERS]) ! 546: panic("timeout"); ! 547: elt->fcn = fcn; ! 548: elt->param = param; ! 549: elt->set = TELT_ALLOC; ! 550: simple_unlock(&timer_lock); ! 551: splx(s); ! 552: ! 553: set_timeout(elt, (unsigned int)interval); ! 554: } ! 555: ! 556: /* ! 557: * Returns a boolean indicating whether the timeout element was found ! 558: * and removed. ! 559: */ ! 560: boolean_t untimeout(fcn, param) ! 561: register int (*fcn)(); ! 562: register char * param; ! 563: { ! 564: spl_t s; ! 565: register timer_elt_t elt; ! 566: ! 567: s = splsched(); ! 568: simple_lock(&timer_lock); ! 569: queue_iterate(&timer_head.chain, elt, timer_elt_t, chain) { ! 570: ! 571: if ((fcn == elt->fcn) && (param == elt->param)) { ! 572: /* ! 573: * Found it. ! 574: */ ! 575: remqueue(&timer_head.chain, (queue_entry_t)elt); ! 576: elt->set = TELT_UNSET; ! 577: ! 578: simple_unlock(&timer_lock); ! 579: splx(s); ! 580: return (TRUE); ! 581: } ! 582: } ! 583: simple_unlock(&timer_lock); ! 584: splx(s); ! 585: return (FALSE); ! 586: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.