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