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