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