FreeBSD/Linux Kernel Cross Reference
sys/kern/timer.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
4 * All Rights Reserved.
5 *
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.
11 *
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.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: timer.c,v $
29 * Revision 2.8 92/08/03 17:40:24 jfriedl
30 * removed silly prototypes
31 * [92/08/02 jfriedl]
32 *
33 * Revision 2.7 92/05/21 17:17:02 jfriedl
34 * Made fcns void that needed it.
35 * [92/05/16 jfriedl]
36 *
37 * Revision 2.6 92/02/19 13:43:42 elf
38 * Add include of <kern/assert.h>. Under MACH_ASSERT conditionals,
39 * make the loop in timer_grab fail assertion fail if it loops more
40 * than 10000 times.
41 * [92/01/15 danner]
42 * Added version to timer grab that can be called by the kernel debugger.
43 * Will work even if the time is not normalized.
44 * [91/09/19 13:47:32 danner]
45 *
46 * Revision 2.6 92/02/18 18:00:20 elf
47 * Merged up.
48 * [92/01/22 18:45:01 danner]
49 *
50 * Revision 2.5 91/07/31 17:51:35 dbg
51 * Allow all routines to be defined in machine-dependent code.
52 * [91/07/30 17:08:39 dbg]
53 *
54 * Revision 2.4 91/05/14 16:49:52 mrt
55 * Correcting copyright
56 *
57 * Revision 2.3 91/02/05 17:31:02 mrt
58 * Changed to new Mach copyright
59 * [91/02/01 16:20:58 mrt]
60 *
61 * Revision 2.2 90/08/07 17:59:21 rpd
62 * Converted timer_grab to a real function.
63 * Picked up optimized timer_normalize and timer_grab,
64 * based on new timer representation.
65 * [90/08/07 rpd]
66 *
67 * Revision 2.1 89/08/03 15:47:54 rwd
68 * Created.
69 *
70 * 8-Dec-88 David Golub (dbg) at Carnegie-Mellon University
71 * Fixed include files for MACH_KERNEL.
72 *
73 * 26-Oct-88 David Black (dlb) at Carnegie-Mellon University
74 * New overflow logic. Check low_bits directly for risk of
75 * overflow. Gets rid of service_timers(). Suggested by dbg.
76 *
77 * 20-Oct-88 David Golub (dbg) at Carnegie-Mellon University
78 * Use macro_help to avoid lint.
79 *
80 * 18-May-88 David Golub (dbg) at Carnegie-Mellon University
81 * HC compiler does not consider '| =' to be the same as '|='.
82 *
83 * 9-May-88 David Golub (dbg) at Carnegie-Mellon University
84 * Added register declarations. Not all machines enjoy the luxury
85 * of a reasonable compiler.
86 *
87 * 20-Apr-88 David Black (dlb) at Carnegie-Mellon University
88 * Removed thread_times system call.
89 *
90 * 29-Mar-88 David Black (dlb) at Carnegie-Mellon University
91 * Normalize old timer on interrupt exit if needed.
92 *
93 * 19-Feb-88 David Black (dlb) at Carnegie-Mellon University
94 * Massive changes - parametrize most constants to deal with
95 * different clock frequencies, field name changes in timer
96 * structure. Replace array in thread structure with individual
97 * timers. Implemented timer_delta and timer_current_delta routines
98 * to efficiently read timing information for scheduler.
99 *
100 * 12-Feb-88 David Black (dlb) at Carnegie-Mellon University
101 * Use time_value_t's instead of struct timeval's.
102 *
103 * 28-Jan-88 David Black (dlb) at Carnegie-Mellon University
104 * Rewrote thread_times for new port naming and thread referencing
105 * logic.
106 *
107 * 26-Mar-87 David Black (dlb) at Carnegie-Mellon University
108 * Changed trap entry and exit routines to always set correct timer
109 * regardless of current timer.
110 *
111 * 18-Mar-87 David L. Black (dlb) at Carnegie-Mellon University
112 * Moved kickoff of service_timers() into init_main.c because
113 * callout queue is not initialized when init_timers is called.
114 *
115 * 23-Feb-87 David L. Black (dlb) at Carnegie-Mellon University
116 * Created.
117 */
118
119 #include <cpus.h>
120 #include <stat_time.h>
121
122 #include <mach/kern_return.h>
123 #include <mach/port.h>
124 #include <kern/queue.h>
125 #include <kern/thread.h>
126 #include <mach/time_value.h>
127 #include <kern/timer.h>
128 #include <kern/cpu_number.h>
129
130 #include <kern/assert.h>
131 #include <kern/macro_help.h>
132
133
134
135 timer_t current_timer[NCPUS];
136 timer_data_t kernel_timer[NCPUS];
137
138 void timer_init(); /* forward */
139
140 /*
141 * init_timers initializes all non-thread timers and puts the
142 * service routine on the callout queue. All timers must be
143 * serviced by the callout routine once an hour.
144 */
145 void init_timers()
146 {
147 register int i;
148 register timer_t this_timer;
149
150 /*
151 * Initialize all the kernel timers and start the one
152 * for this cpu (master) slaves start theirs later.
153 */
154 this_timer = &kernel_timer[0];
155 for ( i=0 ; i<NCPUS ; i++, this_timer++) {
156 timer_init(this_timer);
157 current_timer[i] = (timer_t) 0;
158 }
159
160 start_timer(&kernel_timer[cpu_number()]);
161 }
162
163 /*
164 * timer_init initializes a single timer.
165 */
166 void timer_init(this_timer)
167 register
168 timer_t this_timer;
169 {
170 this_timer->low_bits = 0;
171 this_timer->high_bits = 0;
172 this_timer->tstamp = 0;
173 this_timer->high_bits_check = 0;
174 }
175
176 #if STAT_TIME
177 #else STAT_TIME
178
179 #ifdef MACHINE_TIMER_ROUTINES
180
181 /*
182 * Machine-dependent code implements the timer routines.
183 */
184
185 #else /* MACHINE_TIMER_ROUTINES */
186
187 /*
188 * start_timer starts the given timer for this cpu. It is called
189 * exactly once for each cpu during the boot sequence.
190 */
191 void
192 start_timer(timer)
193 timer_t timer;
194 {
195 timer->tstamp = get_timestamp();
196 current_timer[cpu_number()] = timer;
197 }
198
199 /*
200 * time_trap_uentry does trap entry timing. Caller must lock out
201 * interrupts and take a timestamp. ts is a timestamp taken after
202 * interrupts were locked out. Must only be called if trap was
203 * from user mode.
204 */
205 void
206 time_trap_uentry(ts)
207 unsigned ts;
208 {
209 int elapsed;
210 int mycpu;
211 timer_t mytimer;
212
213 /*
214 * Calculate elapsed time.
215 */
216 mycpu = cpu_number();
217 mytimer = current_timer[mycpu];
218 elapsed = ts - mytimer->tstamp;
219 #ifdef TIMER_MAX
220 if (elapsed < 0) elapsed += TIMER_MAX;
221 #endif TIMER_MAX
222
223 /*
224 * Update current timer.
225 */
226 mytimer->low_bits += elapsed;
227 mytimer->tstamp = 0;
228
229 if (mytimer->low_bits & TIMER_LOW_FULL) {
230 timer_normalize(mytimer);
231 }
232
233 /*
234 * Record new timer.
235 */
236 mytimer = &(active_threads[mycpu]->system_timer);
237 current_timer[mycpu] = mytimer;
238 mytimer->tstamp = ts;
239 }
240
241 /*
242 * time_trap_uexit does trap exit timing. Caller must lock out
243 * interrupts and take a timestamp. ts is a timestamp taken after
244 * interrupts were locked out. Must only be called if returning to
245 * user mode.
246 */
247 void
248 time_trap_uexit(ts)
249 {
250 int elapsed;
251 int mycpu;
252 timer_t mytimer;
253
254 /*
255 * Calculate elapsed time.
256 */
257 mycpu = cpu_number();
258 mytimer = current_timer[mycpu];
259 elapsed = ts - mytimer->tstamp;
260 #ifdef TIMER_MAX
261 if (elapsed < 0) elapsed += TIMER_MAX;
262 #endif TIMER_MAX
263
264 /*
265 * Update current timer.
266 */
267 mytimer->low_bits += elapsed;
268 mytimer->tstamp = 0;
269
270 if (mytimer->low_bits & TIMER_LOW_FULL) {
271 timer_normalize(mytimer); /* SYSTEMMODE */
272 }
273
274 mytimer = &(active_threads[mycpu]->user_timer);
275
276 /*
277 * Record new timer.
278 */
279 current_timer[mycpu] = mytimer;
280 mytimer->tstamp = ts;
281 }
282
283 /*
284 * time_int_entry does interrupt entry timing. Caller must lock out
285 * interrupts and take a timestamp. ts is a timestamp taken after
286 * interrupts were locked out. new_timer is the new timer to
287 * switch to. This routine returns the currently running timer,
288 * which MUST be pushed onto the stack by the caller, or otherwise
289 * saved for time_int_exit.
290 */
291 timer_t
292 time_int_entry(ts,new_timer)
293 unsigned ts;
294 timer_t new_timer;
295 {
296 int elapsed;
297 int mycpu;
298 timer_t mytimer;
299
300 /*
301 * Calculate elapsed time.
302 */
303 mycpu = cpu_number();
304 mytimer = current_timer[mycpu];
305
306 elapsed = ts - mytimer->tstamp;
307 #ifdef TIMER_MAX
308 if (elapsed < 0) elapsed += TIMER_MAX;
309 #endif TIMER_MAX
310
311 /*
312 * Update current timer.
313 */
314 mytimer->low_bits += elapsed;
315 mytimer->tstamp = 0;
316
317 /*
318 * Switch to new timer, and save old one on stack.
319 */
320 new_timer->tstamp = ts;
321 current_timer[mycpu] = new_timer;
322 return(mytimer);
323 }
324
325 /*
326 * time_int_exit does interrupt exit timing. Caller must lock out
327 * interrupts and take a timestamp. ts is a timestamp taken after
328 * interrupts were locked out. old_timer is the timer value pushed
329 * onto the stack or otherwise saved after time_int_entry returned
330 * it.
331 */
332 void
333 time_int_exit(ts, old_timer)
334 unsigned ts;
335 timer_t old_timer;
336 {
337 int elapsed;
338 int mycpu;
339 timer_t mytimer;
340
341 /*
342 * Calculate elapsed time.
343 */
344 mycpu = cpu_number();
345 mytimer = current_timer[mycpu];
346 elapsed = ts - mytimer->tstamp;
347 #ifdef TIMER_MAX
348 if (elapsed < 0) elapsed += TIMER_MAX;
349 #endif TIMER_MAX
350
351 /*
352 * Update current timer.
353 */
354 mytimer->low_bits += elapsed;
355 mytimer->tstamp = 0;
356
357 /*
358 * If normalization requested, do it.
359 */
360 if (mytimer->low_bits & TIMER_LOW_FULL) {
361 timer_normalize(mytimer);
362 }
363 if (old_timer->low_bits & TIMER_LOW_FULL) {
364 timer_normalize(old_timer);
365 }
366
367 /*
368 * Start timer that was running before interrupt.
369 */
370 old_timer->tstamp = ts;
371 current_timer[mycpu] = old_timer;
372 }
373
374 /*
375 * timer_switch switches to a new timer. The machine
376 * dependent routine/macro get_timestamp must return a timestamp.
377 * Caller must lock out interrupts.
378 */
379 void
380 timer_switch(new_timer)
381 timer_t new_timer;
382 {
383 int elapsed;
384 int mycpu;
385 timer_t mytimer;
386 unsigned ts;
387
388 /*
389 * Calculate elapsed time.
390 */
391 mycpu = cpu_number();
392 mytimer = current_timer[mycpu];
393 ts = get_timestamp();
394 elapsed = ts - mytimer->tstamp;
395 #ifdef TIMER_MAX
396 if (elapsed < 0) elapsed += TIMER_MAX;
397 #endif TIMER_MAX
398
399 /*
400 * Update current timer.
401 */
402 mytimer->low_bits += elapsed;
403 mytimer->tstamp = 0;
404
405 /*
406 * Normalization check
407 */
408 if (mytimer->low_bits & TIMER_LOW_FULL) {
409 timer_normalize(mytimer);
410 }
411
412 /*
413 * Record new timer.
414 */
415 current_timer[mycpu] = new_timer;
416 new_timer->tstamp = ts;
417 }
418
419 #endif /* MACHINE_TIMER_ROUTINES */
420 #endif STAT_TIME
421
422 /*
423 * timer_normalize normalizes the value of a timer. It is
424 * called only rarely, to make sure low_bits never overflows.
425 */
426 void timer_normalize(timer)
427 register
428 timer_t timer;
429 {
430 unsigned int high_increment;
431
432 /*
433 * Calculate high_increment, then write high check field first
434 * followed by low and high. timer_grab() reads these fields in
435 * reverse order so if high and high check match, we know
436 * that the values read are ok.
437 */
438
439 high_increment = timer->low_bits/TIMER_HIGH_UNIT;
440 timer->high_bits_check += high_increment;
441 timer->low_bits %= TIMER_HIGH_UNIT;
442 timer->high_bits += high_increment;
443 }
444
445 /*
446 * timer_grab() retrieves the value of a timer.
447 *
448 * Critical scheduling code uses TIMER_DELTA macro in timer.h
449 * (called from thread_timer_delta in sched.h).
450 *
451 * Keep coherent with db_time_grab below.
452 */
453
454 void timer_grab(timer, save)
455 timer_t timer;
456 timer_save_t save;
457 {
458 #if MACH_ASSERT
459 unsigned int passes=0;
460 #endif
461 do {
462 (save)->high = (timer)->high_bits;
463 (save)->low = (timer)->low_bits;
464 /*
465 * If the timer was normalized while we were doing this,
466 * the high_bits value read above and the high_bits check
467 * value will not match because high_bits_check is the first
468 * field touched by the normalization procedure, and
469 * high_bits is the last.
470 *
471 * Additions to timer only touch low bits and
472 * are therefore atomic with respect to this.
473 */
474 #if MACH_ASSERT
475 passes++;
476 assert(passes < 10000);
477 #endif
478 } while ( (save)->high != (timer)->high_bits_check);
479 }
480
481 /*
482 *
483 * Db_timer_grab(): used by db_thread_read_times. An nonblocking
484 * version of db_thread_get_times. Keep coherent with timer_grab
485 * above.
486 *
487 */
488 void db_timer_grab(timer, save)
489 timer_t timer;
490 timer_save_t save;
491 {
492 /* Don't worry about coherency */
493
494 (save)->high = (timer)->high_bits;
495 (save)->low = (timer)->low_bits;
496 }
497
498
499 /*
500 * timer_read reads the value of a timer into a time_value_t. If the
501 * timer was modified during the read, retry. The value returned
502 * is accurate to the last update; time accumulated by a running
503 * timer since its last timestamp is not included.
504 */
505
506 void
507 timer_read(timer, tv)
508 timer_t timer;
509 register
510 time_value_t *tv;
511 {
512 timer_save_data_t temp;
513
514 timer_grab(timer,&temp);
515 /*
516 * Normalize the result
517 */
518 #ifdef TIMER_ADJUST
519 TIMER_ADJUST(&temp);
520 #endif TIMER_ADJUST
521 tv->seconds = temp.high + temp.low/1000000;
522 tv->microseconds = temp.low%1000000;
523
524 }
525
526 /*
527 * thread_read_times reads the user and system times from a thread.
528 * Time accumulated since last timestamp is not included. Should
529 * be called at splsched() to avoid having user and system times
530 * be out of step. Doesn't care if caller locked thread.
531 *
532 * Needs to be kept coherent with thread_read_times ahead.
533 */
534 void thread_read_times(thread, user_time_p, system_time_p)
535 thread_t thread;
536 time_value_t *user_time_p;
537 time_value_t *system_time_p;
538 {
539 timer_save_data_t temp;
540 register timer_t timer;
541
542 timer = &thread->user_timer;
543 timer_grab(timer, &temp);
544
545 #ifdef TIMER_ADJUST
546 TIMER_ADJUST(&temp);
547 #endif TIMER_ADJUST
548 user_time_p->seconds = temp.high + temp.low/1000000;
549 user_time_p->microseconds = temp.low % 1000000;
550
551 timer = &thread->system_timer;
552 timer_grab(timer, &temp);
553
554 #ifdef TIMER_ADJUST
555 TIMER_ADJUST(&temp);
556 #endif TIMER_ADJUST
557 system_time_p->seconds = temp.high + temp.low/1000000;
558 system_time_p->microseconds = temp.low % 1000000;
559 }
560
561 /*
562 * Db_thread_read_times: A version of thread_read_times that
563 * can be called by the debugger. This version does not call
564 * timer_grab, which can block. Please keep it up to date with
565 * thread_read_times above.
566 *
567 */
568 void db_thread_read_times(thread, user_time_p, system_time_p)
569 thread_t thread;
570 time_value_t *user_time_p;
571 time_value_t *system_time_p;
572 {
573 timer_save_data_t temp;
574 register timer_t timer;
575
576 timer = &thread->user_timer;
577 db_timer_grab(timer, &temp);
578
579 #ifdef TIMER_ADJUST
580 TIMER_ADJUST(&temp);
581 #endif TIMER_ADJUST
582 user_time_p->seconds = temp.high + temp.low/1000000;
583 user_time_p->microseconds = temp.low % 1000000;
584
585 timer = &thread->system_timer;
586 timer_grab(timer, &temp);
587
588 #ifdef TIMER_ADJUST
589 TIMER_ADJUST(&temp);
590 #endif TIMER_ADJUST
591 system_time_p->seconds = temp.high + temp.low/1000000;
592 system_time_p->microseconds = temp.low % 1000000;
593 }
594
595 /*
596 * timer_delta takes the difference of a saved timer value
597 * and the current one, and updates the saved value to current.
598 * The difference is returned as a function value. See
599 * TIMER_DELTA macro (timer.h) for optimization to this.
600 */
601
602 unsigned
603 timer_delta(timer, save)
604 register
605 timer_t timer;
606 timer_save_t save;
607 {
608 timer_save_data_t new_save;
609 register unsigned result;
610
611 timer_grab(timer,&new_save);
612 result = (new_save.high - save->high) * TIMER_HIGH_UNIT +
613 new_save.low - save->low;
614 save->high = new_save.high;
615 save->low = new_save.low;
616 return(result);
617 }
Cache object: fff07ba491ef2fd9b565ad5f42b3ca6c
|