|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1994-1988 Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
1.1.1.5 root 30: * File: mach_clock.c
1.1 root 31: * Author: Avadis Tevanian, Jr.
32: * Date: 1986
33: *
34: * Clock primitives.
35: */
1.1.1.4 root 36:
37: #include <string.h>
1.1 root 38:
39: #include <mach/boolean.h>
40: #include <mach/machine.h>
41: #include <mach/time_value.h>
42: #include <mach/vm_param.h>
43: #include <mach/vm_prot.h>
44: #include <kern/counters.h>
45: #include "cpu_number.h"
1.1.1.4 root 46: #include <kern/debug.h>
1.1 root 47: #include <kern/host.h>
48: #include <kern/lock.h>
1.1.1.4 root 49: #include <kern/mach_clock.h>
1.1 root 50: #include <kern/processor.h>
1.1.1.4 root 51: #include <kern/queue.h>
1.1 root 52: #include <kern/sched.h>
53: #include <kern/sched_prim.h>
54: #include <kern/thread.h>
55: #include <kern/time_stamp.h>
1.1.1.4 root 56: #include <kern/timer.h>
1.1.1.5 root 57: #include <kern/priority.h>
1.1 root 58: #include <vm/vm_kern.h>
59: #include <sys/time.h>
60: #include <machine/mach_param.h> /* HZ */
61: #include <machine/machspl.h>
1.1.1.4 root 62: #include <machine/model_dep.h>
1.1 root 63:
64: #if MACH_PCSAMPLE
65: #include <kern/pc_sample.h>
66: #endif
67:
68: int hz = HZ; /* number of ticks per second */
69: int tick = (1000000 / HZ); /* number of usec per tick */
70: time_value_t time = { 0, 0 }; /* time since bootup (uncorrected) */
71: unsigned long elapsed_ticks = 0; /* ticks elapsed since bootup */
72:
73: int timedelta = 0;
74: int tickdelta = 0;
75:
76: #if HZ > 500
77: int tickadj = 1; /* can adjust HZ usecs per second */
78: #else
79: int tickadj = 500 / HZ; /* can adjust 100 usecs per second */
80: #endif
81: int bigadj = 1000000; /* adjust 10*tickadj if adjustment
82: > bigadj */
83:
84: /*
85: * This update protocol, with a check value, allows
86: * do {
87: * secs = mtime->seconds;
1.1.1.6 ! root 88: * __sync_synchronize();
1.1 root 89: * usecs = mtime->microseconds;
1.1.1.6 ! root 90: * __sync_synchronize();
1.1 root 91: * } while (secs != mtime->check_seconds);
1.1.1.6 ! root 92: * to read the time correctly.
1.1 root 93: */
94:
1.1.1.6 ! root 95: volatile mapped_time_value_t *mtime = 0;
1.1 root 96:
97: #define update_mapped_time(time) \
98: MACRO_BEGIN \
99: if (mtime != 0) { \
100: mtime->check_seconds = (time)->seconds; \
1.1.1.6 ! root 101: __sync_synchronize(); \
1.1 root 102: mtime->microseconds = (time)->microseconds; \
1.1.1.6 ! root 103: __sync_synchronize(); \
1.1 root 104: mtime->seconds = (time)->seconds; \
105: } \
106: MACRO_END
107:
1.1.1.6 ! root 108: #define read_mapped_time(time) \
! 109: MACRO_BEGIN \
! 110: do { \
! 111: time->seconds = mtime->seconds; \
! 112: __sync_synchronize(); \
! 113: time->microseconds = mtime->microseconds; \
! 114: __sync_synchronize(); \
! 115: } while (time->seconds != mtime->check_seconds); \
! 116: MACRO_END
! 117:
1.1 root 118: decl_simple_lock_data(, timer_lock) /* lock for ... */
119: timer_elt_data_t timer_head; /* ordered list of timeouts */
120: /* (doubles as end-of-list) */
121:
122: /*
123: * Handle clock interrupts.
124: *
125: * The clock interrupt is assumed to be called at a (more or less)
126: * constant rate. The rate must be identical on all CPUS (XXX - fix).
127: *
128: * Usec is the number of microseconds that have elapsed since the
129: * last clock tick. It may be constant or computed, depending on
130: * the accuracy of the hardware clock.
131: *
132: */
1.1.1.5 root 133: void clock_interrupt(
134: int usec, /* microseconds per tick */
135: boolean_t usermode, /* executing user code */
136: boolean_t basepri) /* at base priority */
1.1 root 137: {
1.1.1.5 root 138: int my_cpu = cpu_number();
139: thread_t thread = current_thread();
1.1 root 140:
141: counter(c_clock_ticks++);
142: counter(c_threads_total += c_threads_current);
143: counter(c_stacks_total += c_stacks_current);
144:
145: #if STAT_TIME
146: /*
147: * Increment the thread time, if using
148: * statistical timing.
149: */
150: if (usermode) {
151: timer_bump(&thread->user_timer, usec);
152: }
153: else {
154: timer_bump(&thread->system_timer, usec);
155: }
1.1.1.3 root 156: #endif /* STAT_TIME */
1.1 root 157:
158: /*
159: * Increment the CPU time statistics.
160: */
161: {
1.1.1.5 root 162: int state;
1.1 root 163:
164: if (usermode)
165: state = CPU_STATE_USER;
166: else if (!cpu_idle(my_cpu))
167: state = CPU_STATE_SYSTEM;
168: else
169: state = CPU_STATE_IDLE;
170:
171: machine_slot[my_cpu].cpu_ticks[state]++;
172:
173: /*
174: * Adjust the thread's priority and check for
175: * quantum expiration.
176: */
177:
178: thread_quantum_update(my_cpu, thread, 1, state);
179: }
180:
1.1.1.2 root 181: #if MACH_PCSAMPLE
1.1 root 182: /*
183: * Take a sample of pc for the user if required.
184: * This had better be MP safe. It might be interesting
185: * to keep track of cpu in the sample.
186: */
187: if (usermode) {
188: take_pc_sample_macro(thread, SAMPLED_PC_PERIODIC);
189: }
190: #endif /* MACH_PCSAMPLE */
191:
192: /*
193: * Time-of-day and time-out list are updated only
194: * on the master CPU.
195: */
196: if (my_cpu == master_cpu) {
197:
1.1.1.5 root 198: spl_t s;
199: timer_elt_t telt;
1.1 root 200: boolean_t needsoft = FALSE;
201:
202: #if TS_FORMAT == 1
203: /*
204: * Increment the tick count for the timestamping routine.
205: */
206: ts_tick_count++;
1.1.1.3 root 207: #endif /* TS_FORMAT == 1 */
1.1 root 208:
209: /*
210: * Update the tick count since bootup, and handle
211: * timeouts.
212: */
213:
214: s = splsched();
215: simple_lock(&timer_lock);
216:
217: elapsed_ticks++;
218:
219: telt = (timer_elt_t)queue_first(&timer_head.chain);
220: if (telt->ticks <= elapsed_ticks)
221: needsoft = TRUE;
222: simple_unlock(&timer_lock);
223: splx(s);
224:
225: /*
226: * Increment the time-of-day clock.
227: */
228: if (timedelta == 0) {
229: time_value_add_usec(&time, usec);
230: }
231: else {
1.1.1.5 root 232: int delta;
1.1 root 233:
234: if (timedelta < 0) {
1.1.1.6 ! root 235: if (usec > tickdelta) {
! 236: delta = usec - tickdelta;
! 237: timedelta += tickdelta;
! 238: } else {
! 239: /* Not enough time has passed, defer overflowing
! 240: * correction for later, keep only one microsecond
! 241: * delta */
! 242: delta = 1;
! 243: timedelta += usec - 1;
! 244: }
1.1 root 245: }
246: else {
247: delta = usec + tickdelta;
248: timedelta -= tickdelta;
249: }
250: time_value_add_usec(&time, delta);
251: }
252: update_mapped_time(&time);
253:
254: /*
1.1.1.5 root 255: * Schedule soft-interrupt for timeout if needed
1.1 root 256: */
257: if (needsoft) {
258: if (basepri) {
259: (void) splsoftclock();
260: softclock();
261: }
262: else {
263: setsoftclock();
264: }
265: }
266: }
267: }
268:
269: /*
270: * There is a nasty race between softclock and reset_timeout.
271: * For example, scheduling code looks at timer_set and calls
272: * reset_timeout, thinking the timer is set. However, softclock
273: * has already removed the timer but hasn't called thread_timeout
274: * yet.
275: *
276: * Interim solution: We initialize timers after pulling
277: * them out of the queue, so a race with reset_timeout won't
278: * hurt. The timeout functions (eg, thread_timeout,
279: * thread_depress_timeout) check timer_set/depress_priority
280: * to see if the timer has been cancelled and if so do nothing.
281: *
282: * This still isn't correct. For example, softclock pulls a
283: * timer off the queue, then thread_go resets timer_set (but
284: * reset_timeout does nothing), then thread_set_timeout puts the
285: * timer back on the queue and sets timer_set, then
286: * thread_timeout finally runs and clears timer_set, then
287: * thread_set_timeout tries to put the timer on the queue again
288: * and corrupts it.
289: */
290:
1.1.1.5 root 291: void softclock(void)
1.1 root 292: {
293: /*
294: * Handle timeouts.
295: */
296: spl_t s;
1.1.1.5 root 297: timer_elt_t telt;
298: void (*fcn)( void * param );
299: void *param;
1.1 root 300:
301: while (TRUE) {
302: s = splsched();
303: simple_lock(&timer_lock);
304: telt = (timer_elt_t) queue_first(&timer_head.chain);
305: if (telt->ticks > elapsed_ticks) {
306: simple_unlock(&timer_lock);
307: splx(s);
308: break;
309: }
310: fcn = telt->fcn;
311: param = telt->param;
312:
313: remqueue(&timer_head.chain, (queue_entry_t)telt);
314: telt->set = TELT_UNSET;
315: simple_unlock(&timer_lock);
316: splx(s);
317:
318: assert(fcn != 0);
319: (*fcn)(param);
320: }
321: }
322:
323: /*
324: * Set timeout.
325: *
326: * Parameters:
327: * telt timer element. Function and param are already set.
328: * interval time-out interval, in hz.
329: */
1.1.1.5 root 330: void set_timeout(
331: timer_elt_t telt, /* already loaded */
332: unsigned int interval)
1.1 root 333: {
334: spl_t s;
1.1.1.5 root 335: timer_elt_t next;
1.1 root 336:
337: s = splsched();
338: simple_lock(&timer_lock);
339:
340: interval += elapsed_ticks;
341:
342: for (next = (timer_elt_t)queue_first(&timer_head.chain);
343: ;
344: next = (timer_elt_t)queue_next((queue_entry_t)next)) {
345:
346: if (next->ticks > interval)
347: break;
348: }
349: telt->ticks = interval;
350: /*
351: * Insert new timer element before 'next'
352: * (after 'next'->prev)
353: */
354: insque((queue_entry_t) telt, ((queue_entry_t)next)->prev);
355: telt->set = TELT_SET;
356: simple_unlock(&timer_lock);
357: splx(s);
358: }
359:
1.1.1.5 root 360: boolean_t reset_timeout(timer_elt_t telt)
1.1 root 361: {
362: spl_t s;
363:
364: s = splsched();
365: simple_lock(&timer_lock);
366: if (telt->set) {
367: remqueue(&timer_head.chain, (queue_entry_t)telt);
368: telt->set = TELT_UNSET;
369: simple_unlock(&timer_lock);
370: splx(s);
371: return TRUE;
372: }
373: else {
374: simple_unlock(&timer_lock);
375: splx(s);
376: return FALSE;
377: }
378: }
379:
1.1.1.5 root 380: void init_timeout(void)
1.1 root 381: {
382: simple_lock_init(&timer_lock);
383: queue_init(&timer_head.chain);
384: timer_head.ticks = ~0; /* MAXUINT - sentinel */
385:
386: elapsed_ticks = 0;
387: }
1.1.1.6 ! root 388:
! 389: /*
! 390: * We record timestamps using the boot-time clock. We keep track of
! 391: * the boot-time clock by storing the difference to the real-time
! 392: * clock.
! 393: */
! 394: struct time_value clock_boottime_offset;
! 395:
! 396: /*
! 397: * Update the offset of the boot-time clock from the real-time clock.
! 398: * This function must be called when the real-time clock is updated.
! 399: * This function must be called at SPLHIGH.
! 400: */
! 401: void
! 402: clock_boottime_update(struct time_value *new_time)
! 403: {
! 404: struct time_value delta = time;
! 405: time_value_sub(&delta, new_time);
! 406: time_value_add(&clock_boottime_offset, &delta);
! 407: }
1.1 root 408:
409: /*
1.1.1.6 ! root 410: * Record a timestamp in STAMP. Records values in the boot-time clock
! 411: * frame.
1.1.1.2 root 412: */
413: void
414: record_time_stamp (time_value_t *stamp)
415: {
1.1.1.6 ! root 416: read_mapped_time(stamp);
! 417: time_value_add(stamp, &clock_boottime_offset);
! 418: }
! 419:
! 420: /*
! 421: * Read a timestamp in STAMP into RESULT. Returns values in the
! 422: * real-time clock frame.
! 423: */
! 424: void
! 425: read_time_stamp (time_value_t *stamp, time_value_t *result)
! 426: {
! 427: *result = *stamp;
! 428: time_value_sub(result, &clock_boottime_offset);
1.1.1.2 root 429: }
430:
431:
432: /*
1.1 root 433: * Read the time.
434: */
435: kern_return_t
436: host_get_time(host, current_time)
1.1.1.5 root 437: const host_t host;
1.1 root 438: time_value_t *current_time; /* OUT */
439: {
440: if (host == HOST_NULL)
441: return(KERN_INVALID_HOST);
442:
1.1.1.6 ! root 443: read_mapped_time(current_time);
1.1 root 444: return (KERN_SUCCESS);
445: }
446:
447: /*
448: * Set the time. Only available to privileged users.
449: */
450: kern_return_t
451: host_set_time(host, new_time)
1.1.1.5 root 452: const host_t host;
1.1 root 453: time_value_t new_time;
454: {
455: spl_t s;
456:
457: if (host == HOST_NULL)
458: return(KERN_INVALID_HOST);
459:
460: #if NCPUS > 1
461: /*
462: * Switch to the master CPU to synchronize correctly.
463: */
464: thread_bind(current_thread(), master_processor);
465: if (current_processor() != master_processor)
466: thread_block((void (*)) 0);
1.1.1.3 root 467: #endif /* NCPUS > 1 */
1.1 root 468:
469: s = splhigh();
1.1.1.6 ! root 470: clock_boottime_update(&new_time);
1.1 root 471: time = new_time;
472: update_mapped_time(&time);
473: resettodr();
474: splx(s);
475:
476: #if NCPUS > 1
477: /*
478: * Switch off the master CPU.
479: */
480: thread_bind(current_thread(), PROCESSOR_NULL);
1.1.1.3 root 481: #endif /* NCPUS > 1 */
1.1 root 482:
483: return (KERN_SUCCESS);
484: }
485:
486: /*
487: * Adjust the time gradually.
488: */
489: kern_return_t
490: host_adjust_time(host, new_adjustment, old_adjustment)
1.1.1.5 root 491: const host_t host;
1.1 root 492: time_value_t new_adjustment;
493: time_value_t *old_adjustment; /* OUT */
494: {
495: time_value_t oadj;
496: unsigned int ndelta;
497: spl_t s;
498:
499: if (host == HOST_NULL)
500: return (KERN_INVALID_HOST);
501:
502: ndelta = new_adjustment.seconds * 1000000
503: + new_adjustment.microseconds;
504:
505: #if NCPUS > 1
506: thread_bind(current_thread(), master_processor);
507: if (current_processor() != master_processor)
508: thread_block((void (*)) 0);
1.1.1.3 root 509: #endif /* NCPUS > 1 */
1.1 root 510:
511: s = splclock();
512:
513: oadj.seconds = timedelta / 1000000;
514: oadj.microseconds = timedelta % 1000000;
515:
516: if (timedelta == 0) {
517: if (ndelta > bigadj)
518: tickdelta = 10 * tickadj;
519: else
520: tickdelta = tickadj;
521: }
522: if (ndelta % tickdelta)
523: ndelta = ndelta / tickdelta * tickdelta;
524:
525: timedelta = ndelta;
526:
527: splx(s);
528: #if NCPUS > 1
529: thread_bind(current_thread(), PROCESSOR_NULL);
1.1.1.3 root 530: #endif /* NCPUS > 1 */
1.1 root 531:
532: *old_adjustment = oadj;
533:
534: return (KERN_SUCCESS);
535: }
536:
1.1.1.5 root 537: void mapable_time_init(void)
1.1 root 538: {
539: if (kmem_alloc_wired(kernel_map, (vm_offset_t *) &mtime, PAGE_SIZE)
540: != KERN_SUCCESS)
541: panic("mapable_time_init");
1.1.1.4 root 542: memset(mtime, 0, PAGE_SIZE);
1.1 root 543: update_mapped_time(&time);
544: }
545:
1.1.1.5 root 546: int timeopen(dev_t dev, int flag, io_req_t ior)
1.1 root 547: {
548: return(0);
549: }
1.1.1.5 root 550: void timeclose(dev_t dev, int flag)
1.1 root 551: {
1.1.1.5 root 552: return;
1.1 root 553: }
554:
555: /*
556: * Compatibility for device drivers.
557: * New code should use set_timeout/reset_timeout and private timers.
1.1.1.4 root 558: * These code can't use a cache to allocate timers, because
1.1 root 559: * it can be called from interrupt handlers.
560: */
561:
562: #define NTIMERS 20
563:
564: timer_elt_data_t timeout_timers[NTIMERS];
565:
566: /*
567: * Set timeout.
568: *
569: * fcn: function to call
570: * param: parameter to pass to function
571: * interval: timeout interval, in hz.
572: */
1.1.1.5 root 573: void timeout(
574: void (*fcn)(void *param),
575: void * param,
576: int interval)
1.1 root 577: {
578: spl_t s;
1.1.1.5 root 579: timer_elt_t elt;
1.1 root 580:
581: s = splsched();
582: simple_lock(&timer_lock);
583: for (elt = &timeout_timers[0]; elt < &timeout_timers[NTIMERS]; elt++)
584: if (elt->set == TELT_UNSET)
585: break;
586: if (elt == &timeout_timers[NTIMERS])
587: panic("timeout");
588: elt->fcn = fcn;
589: elt->param = param;
590: elt->set = TELT_ALLOC;
591: simple_unlock(&timer_lock);
592: splx(s);
593:
594: set_timeout(elt, (unsigned int)interval);
595: }
596:
597: /*
598: * Returns a boolean indicating whether the timeout element was found
599: * and removed.
600: */
601: boolean_t untimeout(fcn, param)
1.1.1.5 root 602: void (*fcn)( void * param );
603: const void * param;
1.1 root 604: {
605: spl_t s;
1.1.1.5 root 606: timer_elt_t elt;
1.1 root 607:
608: s = splsched();
609: simple_lock(&timer_lock);
610: queue_iterate(&timer_head.chain, elt, timer_elt_t, chain) {
611:
612: if ((fcn == elt->fcn) && (param == elt->param)) {
613: /*
614: * Found it.
615: */
616: remqueue(&timer_head.chain, (queue_entry_t)elt);
617: elt->set = TELT_UNSET;
618:
619: simple_unlock(&timer_lock);
620: splx(s);
621: return (TRUE);
622: }
623: }
624: simple_unlock(&timer_lock);
625: splx(s);
626: return (FALSE);
627: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.