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