|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1989 Carnegie-Mellon University
28: * Copyright (c) 1988 Carnegie-Mellon University
29: * Copyright (c) 1987 Carnegie-Mellon University
30: * All rights reserved. The CMU software License Agreement specifies
31: * the terms and conditions for use and redistribution.
32: */
33:
34: #import <cpus.h>
35: #import <stat_time.h>
36:
37: #import <sys/param.h>
38: #import <sys/kernel.h>
39: #import <mach/kern_return.h>
40: #import <mach/port.h>
41: #import <kern/queue.h>
42: #import <kern/thread.h>
43: #import <mach/time_value.h>
44: #import <kern/timer.h>
45: #import <bsd/machine/cpu.h>
46:
47: #import <kernserv/macro_help.h>
48:
49: timer_t current_timer[NCPUS];
50: timer_data_t kernel_timer[NCPUS];
51:
52: /*
53: * init_timers initializes all non-thread timers and puts the
54: * service routine on the callout queue. All timers must be
55: * serviced by the callout routine once an hour.
56: */
57: init_timers()
58: {
59: register int i;
60: register timer_t this_timer;
61:
62: /*
63: * Initialize all the kernel timers and start the one
64: * for this cpu (master) slaves start theirs later.
65: */
66: this_timer = &kernel_timer[0];
67: for ( i=0 ; i<NCPUS ; i++, this_timer++) {
68: timer_init(this_timer);
69: current_timer[i] = (timer_t) 0;
70: }
71:
72: start_timer(&kernel_timer[cpu_number()]);
73: }
74:
75: /*
76: * timer_init initializes a single timer.
77: */
78: timer_init(this_timer)
79: register
80: timer_t this_timer;
81: {
82: this_timer->low_bits = 0;
83: this_timer->high_bits = 0;
84: this_timer->tstamp = 0;
85: this_timer->high_bits_check = 0;
86: }
87:
88: #if STAT_TIME
89: #else STAT_TIME
90: /*
91: * start_timer starts the given timer for this cpu. It is called
92: * exactly once for each cpu during the boot sequence.
93: */
94: void
95: start_timer(timer)
96: timer_t timer;
97: {
98: timer->tstamp = get_timestamp();
99: current_timer[cpu_number()] = timer;
100: }
101:
102: /*
103: * time_trap_uentry does trap entry timing. Caller must lock out
104: * interrupts and take a timestamp. ts is a timestamp taken after
105: * interrupts were locked out. Must only be called if trap was
106: * from user mode.
107: */
108: void
109: time_trap_uentry(ts)
110: unsigned ts;
111: {
112: int elapsed;
113: int mycpu;
114: timer_t mytimer;
115:
116: /*
117: * Calculate elapsed time.
118: */
119: mycpu = cpu_number();
120: mytimer = current_timer[mycpu];
121: elapsed = ts - mytimer->tstamp;
122: #ifdef TIMER_MAX
123: if (elapsed < 0) elapsed += TIMER_MAX;
124: #endif TIMER_MAX
125:
126: /*
127: * Update current timer.
128: */
129: mytimer->low_bits += elapsed;
130: mytimer->tstamp = 0;
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
147: time_trap_uexit(ts)
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;
161: #endif TIMER_MAX
162:
163: /*
164: * Update current timer.
165: */
166: mytimer->low_bits += elapsed;
167: mytimer->tstamp = 0;
168:
169: /*
170: * Normalize old and new timers if needed.
171: */
172: if (mytimer->low_bits & TIMER_LOW_FULL) {
173: timer_normalize(mytimer); /* SYSTEMMODE */
174: }
175:
176: mytimer = &(active_threads[mycpu]->user_timer);
177:
178: if (mytimer->low_bits & TIMER_LOW_FULL) {
179: timer_normalize(mytimer); /* USERMODE */
180: }
181:
182: /*
183: * Record new timer.
184: */
185: current_timer[mycpu] = mytimer;
186: mytimer->tstamp = ts;
187: }
188:
189: /*
190: * time_int_entry does interrupt entry timing. Caller must lock out
191: * interrupts and take a timestamp. ts is a timestamp taken after
192: * interrupts were locked out. new_timer is the new timer to
193: * switch to. This routine returns the currently running timer,
194: * which MUST be pushed onto the stack by the caller, or otherwise
195: * saved for time_int_exit.
196: */
197: timer_t
198: time_int_entry(ts,new_timer)
199: unsigned ts;
200: timer_t new_timer;
201: {
202: int elapsed;
203: int mycpu;
204: timer_t mytimer;
205:
206: /*
207: * Calculate elapsed time.
208: */
209: mycpu = cpu_number();
210: mytimer = current_timer[mycpu];
211:
212: elapsed = ts - mytimer->tstamp;
213: #ifdef TIMER_MAX
214: if (elapsed < 0) elapsed += TIMER_MAX;
215: #endif TIMER_MAX
216:
217: /*
218: * Update current timer.
219: */
220: mytimer->low_bits += elapsed;
221: mytimer->tstamp = 0;
222:
223: /*
224: * Switch to new timer, and save old one on stack.
225: */
226: new_timer->tstamp = ts;
227: current_timer[mycpu] = new_timer;
228: return(mytimer);
229: }
230:
231: /*
232: * time_int_exit does interrupt exit timing. Caller must lock out
233: * interrupts and take a timestamp. ts is a timestamp taken after
234: * interrupts were locked out. old_timer is the timer value pushed
235: * onto the stack or otherwise saved after time_int_entry returned
236: * it.
237: */
238: void
239: time_int_exit(ts, old_timer)
240: unsigned ts;
241: timer_t old_timer;
242: {
243: int elapsed;
244: int mycpu;
245: timer_t mytimer;
246:
247: /*
248: * Calculate elapsed time.
249: */
250: mycpu = cpu_number();
251: mytimer = current_timer[mycpu];
252: elapsed = ts - mytimer->tstamp;
253: #ifdef TIMER_MAX
254: if (elapsed < 0) elapsed += TIMER_MAX;
255: #endif TIMER_MAX
256:
257: /*
258: * Update current timer.
259: */
260: mytimer->low_bits += elapsed;
261: mytimer->tstamp = 0;
262:
263: /*
264: * If normalization requested, do it.
265: */
266: if (mytimer->low_bits & TIMER_LOW_FULL) {
267: timer_normalize(mytimer);
268: }
269: if (old_timer->low_bits & TIMER_LOW_FULL) {
270: timer_normalize(old_timer);
271: }
272:
273: /*
274: * Start timer that was running before interrupt.
275: */
276: old_timer->tstamp = ts;
277: current_timer[mycpu] = old_timer;
278: }
279:
280: /*
281: * timer_switch switches to a new timer. The machine
282: * dependent routine/macro get_timestamp must return a timestamp.
283: * Caller must lock out interrupts.
284: */
285: void
286: timer_switch(new_timer)
287: timer_t new_timer;
288: {
289: int elapsed;
290: int mycpu;
291: timer_t mytimer;
292: unsigned ts;
293:
294: /*
295: * Calculate elapsed time.
296: */
297: mycpu = cpu_number();
298: mytimer = current_timer[mycpu];
299: ts = get_timestamp();
300: elapsed = ts - mytimer->tstamp;
301: #ifdef TIMER_MAX
302: if (elapsed < 0) elapsed += TIMER_MAX;
303: #endif TIMER_MAX
304:
305: /*
306: * Update current timer.
307: */
308: mytimer->low_bits += elapsed;
309: mytimer->tstamp = 0;
310:
311: /*
312: * Normalization check
313: */
314: if (mytimer->low_bits & TIMER_LOW_FULL) {
315: timer_normalize(mytimer);
316: }
317:
318: /*
319: * Record new timer.
320: */
321: current_timer[mycpu] = new_timer;
322: new_timer->tstamp = ts;
323: }
324: #endif STAT_TIME
325:
326: /*
327: * timer_normalize normalizes the value of a timer. It is
328: * called only rarely, to make sure low_bits never overflows.
329: */
330: timer_normalize(timer)
331: register
332: timer_t timer;
333: {
334: unsigned int high_increment;
335:
336: /*
337: * Calculate high_increment, then write high check field first
338: * followed by low and high. timer_grab() reads these fields in
339: * reverse order so if high and high check match, we know
340: * that the values read are ok.
341: */
342:
343: high_increment = timer->low_bits/TIMER_HIGH_UNIT;
344: timer->high_bits_check += high_increment;
345: timer->low_bits %= TIMER_HIGH_UNIT;
346: timer->high_bits += high_increment;
347: }
348:
349: /*
350: * timer_grab() is a macro to retrieve the value of a timer.
351: */
352:
353: #define timer_grab(timer, save) \
354: MACRO_BEGIN \
355: do { \
356: (save)->high = (timer)->high_bits; \
357: (save)->low = (timer)->low_bits; \
358: /* \
359: * If the timer was normalized while we were doing this, \
360: * the high_bits value read above and the high_bits check \
361: * value won't match because high_bits_check is the first \
362: * field touched by the normalization procedure, and \
363: * high_bits is the last. \
364: *
365: * Additions to timer only touch low bits and \
366: * are therefore atomic with respect to this. \
367: */ \
368: } while ( (save)->high != (timer)->high_bits_check); \
369: MACRO_END
370:
371:
372: /*
373: * timer_read reads the value of a timer into a time_value_t. If the
374: * timer was modified during the read, retry. The value returned
375: * is accurate to the last update; time accumulated by a running
376: * timer since its last timestamp is not included.
377: */
378:
379: void
380: timer_read(timer, tv)
381: timer_t timer;
382: register
383: time_value_t *tv;
384: {
385: timer_save_data_t temp;
386:
387: timer_grab(timer,&temp);
388: /*
389: * Normalize the result
390: */
391: #ifdef TIMER_ADJUST
392: TIMER_ADJUST(&temp);
393: #endif TIMER_ADJUST
394: tv->seconds = temp.high + temp.low/1000000;
395: tv->microseconds = temp.low%1000000;
396:
397: }
398:
399: /*
400: * thread_read_times reads the user and system times from a thread.
401: * Time accumulated since last timestamp is not included. Should
402: * be called at splsched() to avoid having user and system times
403: * be out of step. Doesn't care if caller locked thread.
404: */
405: void thread_read_times(thread, user_time_p, system_time_p)
406: thread_t thread;
407: time_value_t *user_time_p;
408: time_value_t *system_time_p;
409: {
410: timer_save_data_t temp;
411: register timer_t timer;
412:
413: timer = &thread->user_timer;
414: timer_grab(timer, &temp);
415:
416: #ifdef TIMER_ADJUST
417: TIMER_ADJUST(&temp);
418: #endif TIMER_ADJUST
419: user_time_p->seconds = temp.high + temp.low/1000000;
420: user_time_p->microseconds = temp.low % 1000000;
421:
422: timer = &thread->system_timer;
423: timer_grab(timer, &temp);
424:
425: #ifdef TIMER_ADJUST
426: TIMER_ADJUST(&temp);
427: #endif TIMER_ADJUST
428: system_time_p->seconds = temp.high + temp.low/1000000;
429: system_time_p->microseconds = temp.low % 1000000;
430: }
431:
432: /*
433: * timer_delta takes the difference of a saved timer value
434: * and the current one, and updates the saved value to current.
435: * The difference is returned as a function value. See
436: * TIMER_DELTA macro (timer.h) for optimization to this.
437: */
438:
439: unsigned
440: timer_delta(timer, save)
441: register
442: timer_t timer;
443: timer_save_t save;
444: {
445: timer_save_data_t new_save;
446: register unsigned result;
447:
448: timer_grab(timer,&new_save);
449: result = (new_save.high - save->high) * TIMER_HIGH_UNIT +
450: new_save.low - save->low;
451: save->high = new_save.high;
452: save->low = new_save.low;
453: return(result);
454: }
455:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.