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