|
|
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
1.1.1.7 ! root 77: unsigned tickadj = 1; /* can adjust HZ usecs per second */
1.1 root 78: #else
1.1.1.7 ! root 79: unsigned tickadj = 500 / HZ; /* can adjust 100 usecs per second */
1.1 root 80: #endif
1.1.1.7 ! root 81: unsigned bigadj = 1000000; /* adjust 10*tickadj if adjustment
1.1 root 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 */
1.1.1.7 ! root 136: boolean_t basepri, /* at base priority */
! 137: vm_offset_t pc) /* address of interrupted instruction */
1.1 root 138: {
1.1.1.5 root 139: int my_cpu = cpu_number();
140: thread_t thread = current_thread();
1.1 root 141:
142: counter(c_clock_ticks++);
143: counter(c_threads_total += c_threads_current);
144: counter(c_stacks_total += c_stacks_current);
145:
146: #if STAT_TIME
147: /*
148: * Increment the thread time, if using
149: * statistical timing.
150: */
151: if (usermode) {
152: timer_bump(&thread->user_timer, usec);
153: }
154: else {
155: timer_bump(&thread->system_timer, usec);
156: }
1.1.1.3 root 157: #endif /* STAT_TIME */
1.1 root 158:
159: /*
160: * Increment the CPU time statistics.
161: */
162: {
1.1.1.5 root 163: int state;
1.1 root 164:
165: if (usermode)
166: state = CPU_STATE_USER;
167: else if (!cpu_idle(my_cpu))
168: state = CPU_STATE_SYSTEM;
169: else
170: state = CPU_STATE_IDLE;
171:
172: machine_slot[my_cpu].cpu_ticks[state]++;
173:
174: /*
175: * Adjust the thread's priority and check for
176: * quantum expiration.
177: */
178:
179: thread_quantum_update(my_cpu, thread, 1, state);
180: }
181:
1.1.1.2 root 182: #if MACH_PCSAMPLE
1.1 root 183: /*
184: * Take a sample of pc for the user if required.
185: * This had better be MP safe. It might be interesting
186: * to keep track of cpu in the sample.
187: */
1.1.1.7 ! root 188: #ifndef MACH_KERNSAMPLE
! 189: if (usermode)
! 190: #endif
! 191: {
! 192: take_pc_sample_macro(thread, SAMPLED_PC_PERIODIC, usermode, pc);
1.1 root 193: }
194: #endif /* MACH_PCSAMPLE */
195:
196: /*
197: * Time-of-day and time-out list are updated only
198: * on the master CPU.
199: */
200: if (my_cpu == master_cpu) {
201:
1.1.1.5 root 202: spl_t s;
203: timer_elt_t telt;
1.1 root 204: boolean_t needsoft = FALSE;
205:
206: #if TS_FORMAT == 1
207: /*
208: * Increment the tick count for the timestamping routine.
209: */
210: ts_tick_count++;
1.1.1.3 root 211: #endif /* TS_FORMAT == 1 */
1.1 root 212:
213: /*
214: * Update the tick count since bootup, and handle
215: * timeouts.
216: */
217:
218: s = splsched();
219: simple_lock(&timer_lock);
220:
221: elapsed_ticks++;
222:
223: telt = (timer_elt_t)queue_first(&timer_head.chain);
224: if (telt->ticks <= elapsed_ticks)
225: needsoft = TRUE;
226: simple_unlock(&timer_lock);
227: splx(s);
228:
229: /*
230: * Increment the time-of-day clock.
231: */
232: if (timedelta == 0) {
233: time_value_add_usec(&time, usec);
234: }
235: else {
1.1.1.5 root 236: int delta;
1.1 root 237:
238: if (timedelta < 0) {
1.1.1.6 root 239: if (usec > tickdelta) {
240: delta = usec - tickdelta;
241: timedelta += tickdelta;
242: } else {
243: /* Not enough time has passed, defer overflowing
244: * correction for later, keep only one microsecond
245: * delta */
246: delta = 1;
247: timedelta += usec - 1;
248: }
1.1 root 249: }
250: else {
251: delta = usec + tickdelta;
252: timedelta -= tickdelta;
253: }
254: time_value_add_usec(&time, delta);
255: }
256: update_mapped_time(&time);
257:
258: /*
1.1.1.5 root 259: * Schedule soft-interrupt for timeout if needed
1.1 root 260: */
261: if (needsoft) {
262: if (basepri) {
263: (void) splsoftclock();
264: softclock();
265: }
266: else {
267: setsoftclock();
268: }
269: }
270: }
271: }
272:
273: /*
274: * There is a nasty race between softclock and reset_timeout.
275: * For example, scheduling code looks at timer_set and calls
276: * reset_timeout, thinking the timer is set. However, softclock
277: * has already removed the timer but hasn't called thread_timeout
278: * yet.
279: *
280: * Interim solution: We initialize timers after pulling
281: * them out of the queue, so a race with reset_timeout won't
282: * hurt. The timeout functions (eg, thread_timeout,
283: * thread_depress_timeout) check timer_set/depress_priority
284: * to see if the timer has been cancelled and if so do nothing.
285: *
286: * This still isn't correct. For example, softclock pulls a
287: * timer off the queue, then thread_go resets timer_set (but
288: * reset_timeout does nothing), then thread_set_timeout puts the
289: * timer back on the queue and sets timer_set, then
290: * thread_timeout finally runs and clears timer_set, then
291: * thread_set_timeout tries to put the timer on the queue again
292: * and corrupts it.
293: */
294:
1.1.1.5 root 295: void softclock(void)
1.1 root 296: {
297: /*
298: * Handle timeouts.
299: */
300: spl_t s;
1.1.1.5 root 301: timer_elt_t telt;
302: void (*fcn)( void * param );
303: void *param;
1.1 root 304:
305: while (TRUE) {
306: s = splsched();
307: simple_lock(&timer_lock);
308: telt = (timer_elt_t) queue_first(&timer_head.chain);
309: if (telt->ticks > elapsed_ticks) {
310: simple_unlock(&timer_lock);
311: splx(s);
312: break;
313: }
314: fcn = telt->fcn;
315: param = telt->param;
316:
317: remqueue(&timer_head.chain, (queue_entry_t)telt);
318: telt->set = TELT_UNSET;
319: simple_unlock(&timer_lock);
320: splx(s);
321:
322: assert(fcn != 0);
323: (*fcn)(param);
324: }
325: }
326:
327: /*
328: * Set timeout.
329: *
330: * Parameters:
331: * telt timer element. Function and param are already set.
332: * interval time-out interval, in hz.
333: */
1.1.1.5 root 334: void set_timeout(
335: timer_elt_t telt, /* already loaded */
336: unsigned int interval)
1.1 root 337: {
338: spl_t s;
1.1.1.5 root 339: timer_elt_t next;
1.1 root 340:
341: s = splsched();
342: simple_lock(&timer_lock);
343:
344: interval += elapsed_ticks;
345:
346: for (next = (timer_elt_t)queue_first(&timer_head.chain);
347: ;
348: next = (timer_elt_t)queue_next((queue_entry_t)next)) {
349:
350: if (next->ticks > interval)
351: break;
352: }
353: telt->ticks = interval;
354: /*
355: * Insert new timer element before 'next'
356: * (after 'next'->prev)
357: */
358: insque((queue_entry_t) telt, ((queue_entry_t)next)->prev);
359: telt->set = TELT_SET;
360: simple_unlock(&timer_lock);
361: splx(s);
362: }
363:
1.1.1.5 root 364: boolean_t reset_timeout(timer_elt_t telt)
1.1 root 365: {
366: spl_t s;
367:
368: s = splsched();
369: simple_lock(&timer_lock);
370: if (telt->set) {
371: remqueue(&timer_head.chain, (queue_entry_t)telt);
372: telt->set = TELT_UNSET;
373: simple_unlock(&timer_lock);
374: splx(s);
375: return TRUE;
376: }
377: else {
378: simple_unlock(&timer_lock);
379: splx(s);
380: return FALSE;
381: }
382: }
383:
1.1.1.5 root 384: void init_timeout(void)
1.1 root 385: {
386: simple_lock_init(&timer_lock);
387: queue_init(&timer_head.chain);
388: timer_head.ticks = ~0; /* MAXUINT - sentinel */
389:
390: elapsed_ticks = 0;
391: }
1.1.1.6 root 392:
393: /*
394: * We record timestamps using the boot-time clock. We keep track of
395: * the boot-time clock by storing the difference to the real-time
396: * clock.
397: */
398: struct time_value clock_boottime_offset;
399:
400: /*
401: * Update the offset of the boot-time clock from the real-time clock.
402: * This function must be called when the real-time clock is updated.
403: * This function must be called at SPLHIGH.
404: */
405: void
406: clock_boottime_update(struct time_value *new_time)
407: {
408: struct time_value delta = time;
409: time_value_sub(&delta, new_time);
410: time_value_add(&clock_boottime_offset, &delta);
411: }
1.1 root 412:
413: /*
1.1.1.6 root 414: * Record a timestamp in STAMP. Records values in the boot-time clock
415: * frame.
1.1.1.2 root 416: */
417: void
418: record_time_stamp (time_value_t *stamp)
419: {
1.1.1.6 root 420: read_mapped_time(stamp);
421: time_value_add(stamp, &clock_boottime_offset);
422: }
423:
424: /*
425: * Read a timestamp in STAMP into RESULT. Returns values in the
426: * real-time clock frame.
427: */
428: void
429: read_time_stamp (time_value_t *stamp, time_value_t *result)
430: {
431: *result = *stamp;
432: time_value_sub(result, &clock_boottime_offset);
1.1.1.2 root 433: }
434:
435:
436: /*
1.1 root 437: * Read the time.
438: */
439: kern_return_t
440: host_get_time(host, current_time)
1.1.1.5 root 441: const host_t host;
1.1 root 442: time_value_t *current_time; /* OUT */
443: {
444: if (host == HOST_NULL)
445: return(KERN_INVALID_HOST);
446:
1.1.1.6 root 447: read_mapped_time(current_time);
1.1 root 448: return (KERN_SUCCESS);
449: }
450:
451: /*
452: * Set the time. Only available to privileged users.
453: */
454: kern_return_t
455: host_set_time(host, new_time)
1.1.1.5 root 456: const host_t host;
1.1 root 457: time_value_t new_time;
458: {
459: spl_t s;
460:
461: if (host == HOST_NULL)
462: return(KERN_INVALID_HOST);
463:
464: #if NCPUS > 1
465: /*
466: * Switch to the master CPU to synchronize correctly.
467: */
468: thread_bind(current_thread(), master_processor);
469: if (current_processor() != master_processor)
470: thread_block((void (*)) 0);
1.1.1.3 root 471: #endif /* NCPUS > 1 */
1.1 root 472:
473: s = splhigh();
1.1.1.6 root 474: clock_boottime_update(&new_time);
1.1 root 475: time = new_time;
476: update_mapped_time(&time);
477: resettodr();
478: splx(s);
479:
480: #if NCPUS > 1
481: /*
482: * Switch off the master CPU.
483: */
484: thread_bind(current_thread(), PROCESSOR_NULL);
1.1.1.3 root 485: #endif /* NCPUS > 1 */
1.1 root 486:
487: return (KERN_SUCCESS);
488: }
489:
490: /*
491: * Adjust the time gradually.
492: */
493: kern_return_t
494: host_adjust_time(host, new_adjustment, old_adjustment)
1.1.1.5 root 495: const host_t host;
1.1 root 496: time_value_t new_adjustment;
497: time_value_t *old_adjustment; /* OUT */
498: {
499: time_value_t oadj;
500: unsigned int ndelta;
501: spl_t s;
502:
503: if (host == HOST_NULL)
504: return (KERN_INVALID_HOST);
505:
506: ndelta = new_adjustment.seconds * 1000000
507: + new_adjustment.microseconds;
508:
509: #if NCPUS > 1
510: thread_bind(current_thread(), master_processor);
511: if (current_processor() != master_processor)
512: thread_block((void (*)) 0);
1.1.1.3 root 513: #endif /* NCPUS > 1 */
1.1 root 514:
515: s = splclock();
516:
517: oadj.seconds = timedelta / 1000000;
518: oadj.microseconds = timedelta % 1000000;
519:
520: if (timedelta == 0) {
521: if (ndelta > bigadj)
522: tickdelta = 10 * tickadj;
523: else
524: tickdelta = tickadj;
525: }
526: if (ndelta % tickdelta)
527: ndelta = ndelta / tickdelta * tickdelta;
528:
529: timedelta = ndelta;
530:
531: splx(s);
532: #if NCPUS > 1
533: thread_bind(current_thread(), PROCESSOR_NULL);
1.1.1.3 root 534: #endif /* NCPUS > 1 */
1.1 root 535:
536: *old_adjustment = oadj;
537:
538: return (KERN_SUCCESS);
539: }
540:
1.1.1.5 root 541: void mapable_time_init(void)
1.1 root 542: {
543: if (kmem_alloc_wired(kernel_map, (vm_offset_t *) &mtime, PAGE_SIZE)
544: != KERN_SUCCESS)
545: panic("mapable_time_init");
1.1.1.7 ! root 546: memset((void *) mtime, 0, PAGE_SIZE);
1.1 root 547: update_mapped_time(&time);
548: }
549:
1.1.1.5 root 550: int timeopen(dev_t dev, int flag, io_req_t ior)
1.1 root 551: {
552: return(0);
553: }
1.1.1.5 root 554: void timeclose(dev_t dev, int flag)
1.1 root 555: {
1.1.1.5 root 556: return;
1.1 root 557: }
558:
559: /*
560: * Compatibility for device drivers.
561: * New code should use set_timeout/reset_timeout and private timers.
1.1.1.4 root 562: * These code can't use a cache to allocate timers, because
1.1 root 563: * it can be called from interrupt handlers.
564: */
565:
566: #define NTIMERS 20
567:
568: timer_elt_data_t timeout_timers[NTIMERS];
569:
570: /*
571: * Set timeout.
572: *
573: * fcn: function to call
574: * param: parameter to pass to function
575: * interval: timeout interval, in hz.
576: */
1.1.1.5 root 577: void timeout(
578: void (*fcn)(void *param),
579: void * param,
580: int interval)
1.1 root 581: {
582: spl_t s;
1.1.1.5 root 583: timer_elt_t elt;
1.1 root 584:
585: s = splsched();
586: simple_lock(&timer_lock);
587: for (elt = &timeout_timers[0]; elt < &timeout_timers[NTIMERS]; elt++)
588: if (elt->set == TELT_UNSET)
589: break;
590: if (elt == &timeout_timers[NTIMERS])
591: panic("timeout");
592: elt->fcn = fcn;
593: elt->param = param;
594: elt->set = TELT_ALLOC;
595: simple_unlock(&timer_lock);
596: splx(s);
597:
598: set_timeout(elt, (unsigned int)interval);
599: }
600:
601: /*
602: * Returns a boolean indicating whether the timeout element was found
603: * and removed.
604: */
605: boolean_t untimeout(fcn, param)
1.1.1.5 root 606: void (*fcn)( void * param );
607: const void * param;
1.1 root 608: {
609: spl_t s;
1.1.1.5 root 610: timer_elt_t elt;
1.1 root 611:
612: s = splsched();
613: simple_lock(&timer_lock);
614: queue_iterate(&timer_head.chain, elt, timer_elt_t, chain) {
615:
616: if ((fcn == elt->fcn) && (param == elt->param)) {
617: /*
618: * Found it.
619: */
620: remqueue(&timer_head.chain, (queue_entry_t)elt);
621: elt->set = TELT_UNSET;
622:
623: simple_unlock(&timer_lock);
624: splx(s);
625: return (TRUE);
626: }
627: }
628: simple_unlock(&timer_lock);
629: splx(s);
630: return (FALSE);
631: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.