|
|
1.1.1.2 ! root 1: /* 1.1 root 2: * Mach Operating System 3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University 4: * All Rights Reserved. 1.1.1.2 ! root 5: * 1.1 root 6: * Permission to use, copy, modify and distribute this software and its 7: * documentation is hereby granted, provided that both the copyright 8: * notice and this permission notice appear in all copies of the 9: * software, derivative works or modified versions, and any portions 10: * thereof, and that both notices appear in supporting documentation. 1.1.1.2 ! root 11: * 1.1 root 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 1.1.1.2 ! root 15: * 1.1 root 16: * Carnegie Mellon requests users of this software to return to 1.1.1.2 ! root 17: * 1.1 root 18: * Software Distribution Coordinator or [email protected] 19: * School of Computer Science 20: * Carnegie Mellon University 21: * Pittsburgh PA 15213-3890 1.1.1.2 ! root 22: * 1.1 root 23: * any improvements or extensions that they make and grant Carnegie Mellon 24: * the rights to redistribute these changes. 25: */ 26: 27: #include <cpus.h> 28: #include <stat_time.h> 29: 30: #include <mach/kern_return.h> 31: #include <mach/port.h> 32: #include <kern/queue.h> 33: #include <kern/thread.h> 34: #include <mach/time_value.h> 35: #include <kern/timer.h> 36: #include <kern/cpu_number.h> 37: 38: #include <kern/assert.h> 39: #include <kern/macro_help.h> 40: 41: 42: 43: timer_t current_timer[NCPUS]; 44: timer_data_t kernel_timer[NCPUS]; 45: 46: void timer_init(); /* forward */ 47: 48: /* 49: * init_timers initializes all non-thread timers and puts the 50: * service routine on the callout queue. All timers must be 51: * serviced by the callout routine once an hour. 52: */ 53: void init_timers() 54: { 55: register int i; 56: register timer_t this_timer; 57: 58: /* 59: * Initialize all the kernel timers and start the one 60: * for this cpu (master) slaves start theirs later. 61: */ 62: this_timer = &kernel_timer[0]; 63: for ( i=0 ; i<NCPUS ; i++, this_timer++) { 64: timer_init(this_timer); 65: current_timer[i] = (timer_t) 0; 66: } 67: 68: start_timer(&kernel_timer[cpu_number()]); 69: } 70: 71: /* 72: * timer_init initializes a single timer. 73: */ 74: void timer_init(this_timer) 75: register 76: timer_t this_timer; 77: { 78: this_timer->low_bits = 0; 79: this_timer->high_bits = 0; 80: this_timer->tstamp = 0; 81: this_timer->high_bits_check = 0; 82: } 83: 84: #if STAT_TIME 1.1.1.2 ! root 85: #else /* STAT_TIME */ 1.1 root 86: 87: #ifdef MACHINE_TIMER_ROUTINES 88: 89: /* 90: * Machine-dependent code implements the timer routines. 91: */ 92: 93: #else /* MACHINE_TIMER_ROUTINES */ 94: 95: /* 96: * start_timer starts the given timer for this cpu. It is called 97: * exactly once for each cpu during the boot sequence. 98: */ 99: void 100: start_timer(timer) 101: timer_t timer; 102: { 103: timer->tstamp = get_timestamp(); 104: current_timer[cpu_number()] = timer; 105: } 106: 107: /* 108: * time_trap_uentry does trap entry timing. Caller must lock out 109: * interrupts and take a timestamp. ts is a timestamp taken after 110: * interrupts were locked out. Must only be called if trap was 111: * from user mode. 112: */ 113: void 114: time_trap_uentry(ts) 115: unsigned ts; 116: { 117: int elapsed; 118: int mycpu; 119: timer_t mytimer; 120: 121: /* 122: * Calculate elapsed time. 123: */ 124: mycpu = cpu_number(); 125: mytimer = current_timer[mycpu]; 126: elapsed = ts - mytimer->tstamp; 127: #ifdef TIMER_MAX 128: if (elapsed < 0) elapsed += TIMER_MAX; 1.1.1.2 ! root 129: #endif /* TIMER_MAX */ 1.1 root 130: 131: /* 132: * Update current timer. 133: */ 134: mytimer->low_bits += elapsed; 135: mytimer->tstamp = 0; 136: 137: if (mytimer->low_bits & TIMER_LOW_FULL) { 138: timer_normalize(mytimer); 139: } 140: 141: /* 142: * Record new timer. 143: */ 144: mytimer = &(active_threads[mycpu]->system_timer); 145: current_timer[mycpu] = mytimer; 146: mytimer->tstamp = ts; 147: } 148: 149: /* 150: * time_trap_uexit does trap exit timing. Caller must lock out 151: * interrupts and take a timestamp. ts is a timestamp taken after 152: * interrupts were locked out. Must only be called if returning to 153: * user mode. 154: */ 155: void 156: time_trap_uexit(ts) 157: { 158: int elapsed; 159: int mycpu; 160: timer_t mytimer; 161: 162: /* 163: * Calculate elapsed time. 164: */ 165: mycpu = cpu_number(); 166: mytimer = current_timer[mycpu]; 167: elapsed = ts - mytimer->tstamp; 168: #ifdef TIMER_MAX 169: if (elapsed < 0) elapsed += TIMER_MAX; 1.1.1.2 ! root 170: #endif /* TIMER_MAX */ 1.1 root 171: 172: /* 173: * Update current timer. 174: */ 175: mytimer->low_bits += elapsed; 176: mytimer->tstamp = 0; 177: 178: if (mytimer->low_bits & TIMER_LOW_FULL) { 179: timer_normalize(mytimer); /* SYSTEMMODE */ 180: } 181: 182: mytimer = &(active_threads[mycpu]->user_timer); 183: 184: /* 185: * Record new timer. 186: */ 187: current_timer[mycpu] = mytimer; 188: mytimer->tstamp = ts; 189: } 190: 191: /* 192: * time_int_entry does interrupt entry timing. Caller must lock out 193: * interrupts and take a timestamp. ts is a timestamp taken after 194: * interrupts were locked out. new_timer is the new timer to 195: * switch to. This routine returns the currently running timer, 196: * which MUST be pushed onto the stack by the caller, or otherwise 197: * saved for time_int_exit. 198: */ 199: timer_t 200: time_int_entry(ts,new_timer) 201: unsigned ts; 202: timer_t new_timer; 203: { 204: int elapsed; 205: int mycpu; 206: timer_t mytimer; 207: 208: /* 209: * Calculate elapsed time. 210: */ 211: mycpu = cpu_number(); 212: mytimer = current_timer[mycpu]; 213: 214: elapsed = ts - mytimer->tstamp; 215: #ifdef TIMER_MAX 216: if (elapsed < 0) elapsed += TIMER_MAX; 1.1.1.2 ! root 217: #endif /* TIMER_MAX */ 1.1 root 218: 219: /* 220: * Update current timer. 221: */ 222: mytimer->low_bits += elapsed; 223: mytimer->tstamp = 0; 224: 225: /* 226: * Switch to new timer, and save old one on stack. 227: */ 228: new_timer->tstamp = ts; 229: current_timer[mycpu] = new_timer; 230: return(mytimer); 231: } 232: 233: /* 234: * time_int_exit does interrupt exit timing. Caller must lock out 235: * interrupts and take a timestamp. ts is a timestamp taken after 236: * interrupts were locked out. old_timer is the timer value pushed 237: * onto the stack or otherwise saved after time_int_entry returned 238: * it. 239: */ 240: void 241: time_int_exit(ts, old_timer) 242: unsigned ts; 243: timer_t old_timer; 244: { 245: int elapsed; 246: int mycpu; 247: timer_t mytimer; 248: 249: /* 250: * Calculate elapsed time. 251: */ 252: mycpu = cpu_number(); 253: mytimer = current_timer[mycpu]; 254: elapsed = ts - mytimer->tstamp; 255: #ifdef TIMER_MAX 256: if (elapsed < 0) elapsed += TIMER_MAX; 1.1.1.2 ! root 257: #endif /* TIMER_MAX */ 1.1 root 258: 259: /* 260: * Update current timer. 261: */ 262: mytimer->low_bits += elapsed; 263: mytimer->tstamp = 0; 264: 265: /* 266: * If normalization requested, do it. 267: */ 268: if (mytimer->low_bits & TIMER_LOW_FULL) { 269: timer_normalize(mytimer); 270: } 271: if (old_timer->low_bits & TIMER_LOW_FULL) { 272: timer_normalize(old_timer); 273: } 274: 275: /* 276: * Start timer that was running before interrupt. 277: */ 278: old_timer->tstamp = ts; 279: current_timer[mycpu] = old_timer; 280: } 281: 282: /* 283: * timer_switch switches to a new timer. The machine 284: * dependent routine/macro get_timestamp must return a timestamp. 285: * Caller must lock out interrupts. 286: */ 287: void 288: timer_switch(new_timer) 289: timer_t new_timer; 290: { 291: int elapsed; 292: int mycpu; 293: timer_t mytimer; 294: unsigned ts; 295: 296: /* 297: * Calculate elapsed time. 298: */ 299: mycpu = cpu_number(); 300: mytimer = current_timer[mycpu]; 301: ts = get_timestamp(); 302: elapsed = ts - mytimer->tstamp; 303: #ifdef TIMER_MAX 304: if (elapsed < 0) elapsed += TIMER_MAX; 1.1.1.2 ! root 305: #endif /* TIMER_MAX */ 1.1 root 306: 307: /* 308: * Update current timer. 309: */ 310: mytimer->low_bits += elapsed; 311: mytimer->tstamp = 0; 312: 313: /* 314: * Normalization check 315: */ 316: if (mytimer->low_bits & TIMER_LOW_FULL) { 317: timer_normalize(mytimer); 318: } 319: 320: /* 321: * Record new timer. 322: */ 323: current_timer[mycpu] = new_timer; 324: new_timer->tstamp = ts; 325: } 326: 327: #endif /* MACHINE_TIMER_ROUTINES */ 1.1.1.2 ! root 328: #endif /* STAT_TIME */ 1.1 root 329: 330: /* 331: * timer_normalize normalizes the value of a timer. It is 332: * called only rarely, to make sure low_bits never overflows. 333: */ 334: void timer_normalize(timer) 335: register 336: timer_t timer; 337: { 338: unsigned int high_increment; 339: 340: /* 341: * Calculate high_increment, then write high check field first 342: * followed by low and high. timer_grab() reads these fields in 343: * reverse order so if high and high check match, we know 344: * that the values read are ok. 345: */ 346: 347: high_increment = timer->low_bits/TIMER_HIGH_UNIT; 348: timer->high_bits_check += high_increment; 349: timer->low_bits %= TIMER_HIGH_UNIT; 350: timer->high_bits += high_increment; 351: } 352: 353: /* 354: * timer_grab() retrieves the value of a timer. 355: * 356: * Critical scheduling code uses TIMER_DELTA macro in timer.h 357: * (called from thread_timer_delta in sched.h). 1.1.1.2 ! root 358: * 1.1 root 359: * Keep coherent with db_time_grab below. 360: */ 361: 362: static void timer_grab(timer, save) 363: timer_t timer; 364: timer_save_t save; 365: { 366: #if MACH_ASSERT 367: unsigned int passes=0; 368: #endif 369: do { 370: (save)->high = (timer)->high_bits; 371: (save)->low = (timer)->low_bits; 372: /* 373: * If the timer was normalized while we were doing this, 374: * the high_bits value read above and the high_bits check 375: * value will not match because high_bits_check is the first 376: * field touched by the normalization procedure, and 377: * high_bits is the last. 378: * 379: * Additions to timer only touch low bits and 380: * are therefore atomic with respect to this. 381: */ 382: #if MACH_ASSERT 383: passes++; 384: assert((passes < 10000) ? (1) : ((timer->high_bits_check = save->high), 0)); 1.1.1.2 ! root 385: #endif 1.1 root 386: } while ( (save)->high != (timer)->high_bits_check); 387: } 388: 389: /* 390: * 391: * Db_timer_grab(): used by db_thread_read_times. An nonblocking 392: * version of db_thread_get_times. Keep coherent with timer_grab 393: * above. 394: * 395: */ 396: void db_timer_grab(timer, save) 397: timer_t timer; 398: timer_save_t save; 399: { 400: /* Don't worry about coherency */ 401: 402: (save)->high = (timer)->high_bits; 403: (save)->low = (timer)->low_bits; 404: } 405: 406: 407: /* 408: * timer_read reads the value of a timer into a time_value_t. If the 409: * timer was modified during the read, retry. The value returned 410: * is accurate to the last update; time accumulated by a running 411: * timer since its last timestamp is not included. 412: */ 413: 414: void 415: timer_read(timer, tv) 416: timer_t timer; 417: register 418: time_value_t *tv; 419: { 420: timer_save_data_t temp; 421: 422: timer_grab(timer,&temp); 423: /* 424: * Normalize the result 425: */ 426: #ifdef TIMER_ADJUST 427: TIMER_ADJUST(&temp); 1.1.1.2 ! root 428: #endif /* TIMER_ADJUST */ 1.1 root 429: tv->seconds = temp.high + temp.low/1000000; 430: tv->microseconds = temp.low%1000000; 431: 432: } 433: 434: /* 435: * thread_read_times reads the user and system times from a thread. 436: * Time accumulated since last timestamp is not included. Should 437: * be called at splsched() to avoid having user and system times 438: * be out of step. Doesn't care if caller locked thread. 439: * 440: * Needs to be kept coherent with thread_read_times ahead. 441: */ 442: void thread_read_times(thread, user_time_p, system_time_p) 443: thread_t thread; 444: time_value_t *user_time_p; 445: time_value_t *system_time_p; 446: { 447: timer_save_data_t temp; 448: register timer_t timer; 449: 450: timer = &thread->user_timer; 451: timer_grab(timer, &temp); 452: 453: #ifdef TIMER_ADJUST 454: TIMER_ADJUST(&temp); 1.1.1.2 ! root 455: #endif /* TIMER_ADJUST */ 1.1 root 456: user_time_p->seconds = temp.high + temp.low/1000000; 457: user_time_p->microseconds = temp.low % 1000000; 458: 459: timer = &thread->system_timer; 460: timer_grab(timer, &temp); 461: 462: #ifdef TIMER_ADJUST 463: TIMER_ADJUST(&temp); 1.1.1.2 ! root 464: #endif /* TIMER_ADJUST */ 1.1 root 465: system_time_p->seconds = temp.high + temp.low/1000000; 466: system_time_p->microseconds = temp.low % 1000000; 467: } 468: 469: /* 470: * Db_thread_read_times: A version of thread_read_times that 471: * can be called by the debugger. This version does not call 472: * timer_grab, which can block. Please keep it up to date with 473: * thread_read_times above. 474: * 475: */ 476: void db_thread_read_times(thread, user_time_p, system_time_p) 477: thread_t thread; 478: time_value_t *user_time_p; 479: time_value_t *system_time_p; 480: { 481: timer_save_data_t temp; 482: register timer_t timer; 483: 484: timer = &thread->user_timer; 485: db_timer_grab(timer, &temp); 486: 487: #ifdef TIMER_ADJUST 488: TIMER_ADJUST(&temp); 1.1.1.2 ! root 489: #endif /* TIMER_ADJUST */ 1.1 root 490: user_time_p->seconds = temp.high + temp.low/1000000; 491: user_time_p->microseconds = temp.low % 1000000; 492: 493: timer = &thread->system_timer; 494: timer_grab(timer, &temp); 495: 496: #ifdef TIMER_ADJUST 497: TIMER_ADJUST(&temp); 1.1.1.2 ! root 498: #endif /* TIMER_ADJUST */ 1.1 root 499: system_time_p->seconds = temp.high + temp.low/1000000; 500: system_time_p->microseconds = temp.low % 1000000; 501: } 502: 503: /* 504: * timer_delta takes the difference of a saved timer value 505: * and the current one, and updates the saved value to current. 506: * The difference is returned as a function value. See 507: * TIMER_DELTA macro (timer.h) for optimization to this. 508: */ 509: 510: unsigned 511: timer_delta(timer, save) 512: register 513: timer_t timer; 514: timer_save_t save; 515: { 516: timer_save_data_t new_save; 517: register unsigned result; 518: 519: timer_grab(timer,&new_save); 520: result = (new_save.high - save->high) * TIMER_HIGH_UNIT + 521: new_save.low - save->low; 522: save->high = new_save.high; 523: save->low = new_save.low; 524: return(result); 525: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.