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