|
|
1.1 root 1: /* $Header: /src386/STREAMS/coh.386/RCS/clock.c,v 2.3 93/08/09 13:35:15 bin Exp Locker: bin $ */
2: /* (lgl-
3: * The information contained herein is a trade secret of Mark Williams
4: * Company, and is confidential information. It is provided under a
5: * license agreement, and may be copied or disclosed only under the
6: * terms of that agreement. Any reproduction or disclosure of this
7: * material without the express written authorization of Mark Williams
8: * Company or persuant to the license agreement is unlawful.
9: *
10: * COHERENT Version 5.0
11: * Copyright (c) 1982, 1993.
12: * An unpublished work by Mark Williams Company, Chicago.
13: * All rights reserved.
14: -lgl) */
15: /*
16: * Coherent.
17: * Clock.
18: * The clock comes in two parts. There is the routine `clock' which
19: * gets called every tick at high priority. It does the minimum it
20: * can and returns as soon as possible. The second routine, `stand',
21: * gets called whenever we are about to return from an interrupt to
22: * user mode at low priority. It can look at flags that the clock set
23: * and do the things the clock really wanted to do but didn't have time.
24: * Stand is truly the kernel of the system.
25: *
26: * 90/08/13 Hal Snyder /usr/src/sys/coh/clock.c
27: * Add external altclk to allow polled device drivers.
28: * (extern'ed in coherent.h)
29: *
30: * 87/10/26 Allan cornish /usr/src/sys/coh/clock.c
31: * Timed functions are now invoked with TIM * tp as second argument.
32: * This facilitates the use of timed functions within loadable drivers.
33: *
34: * 87/07/07 Allan Cornish /usr/src/sys/coh/clock.c
35: * Clocks static variable added - incremented by clock, decremented by stand().
36: * Lbolt variable added - clock ticks since startup - incremented by stand().
37: * Support for multiple timing queues ported from RTX.
38: *
39: * 87/01/05 Allan Cornish /usr/src/sys/coh/clock.c
40: * stand() now only wakes &stimer if swap timer is active.
41: *
42: * 86/11/24 Allan Cornish /usr/src/sys/coh/clock.c
43: * Added support for new t_last field in tim struct.
44: *
45: * 86/11/19 Allan Cornish /usr/src/sys/coh/clock.c
46: * Stand() calls defend() to execute functions deferred from interrupt level.
47: */
48:
49: #include <common/_gregset.h>
50: #include <common/_tricks.h>
51:
52: #include <kernel/sigproc.h>
53: #include <kernel/timeout.h>
54: #include <sys/coherent.h>
55: #include <sys/con.h>
56: #include <sys/proc.h>
57: #include <sys/sched.h>
58: #include <sys/stat.h>
59:
60: int (*altclk)(); /* pointer to higher-speed clock function */
61:
62: #if ! _I386
63: int altsel; /* if nonzero, CS for LOADABLE driver owning altclk() */
64: #endif
65:
66: int clocks;
67:
68: #ifdef TRACER
69:
70: extern char stext;
71: extern char __end_text;
72:
73: #endif
74:
75: /*
76: * This routine is called once every tick (1/HZ seconds).
77: * It gets called with the program counter that was interrupted
78: * and the CPL of the interrupted code (0..3).
79: */
80: clock(pc, umode)
81: caddr_t pc;
82: {
83: register PROC *pp;
84:
85: /*
86: * Ignore clock interrupts till we are ready.
87: */
88: if (batflag == 0)
89: return;
90:
91: /*
92: * Hook for alternate clock interrupt;
93: * Call polling function ("altclk") if there is one.
94: *
95: * For near function, "altsel" is 0 and "altclk" is offset.
96: * For far function, "altsel" is the CS selector and "altclk"
97: * is the offset.
98: *
99: * Since the polling function ends with a near rather than
100: * far return, far invocation is via ld_call() (ldas.s) which uses
101: * the despatch routine at CS:4 (ld.s) in any loadable driver.
102: */
103: if (altclk) {
104: #if ! _I386
105: if (altsel) { /* will do far call to altclk fn */
106: if (ld_call (altsel, altclk))
107: return;
108: } else
109: #endif
110: if ((* altclk) ())
111: return;
112: }
113:
114: /*
115: * Update timers. Decrement time slice.
116: */
117: utimer += 1;
118: clocks += 1;
119: timer.t_tick += 1;
120: quantum -= 1;
121:
122: #if ! _I386
123: /*
124: * Give processes their schedule values per tick.
125: */
126: if (procq.p_lforw->p_cval > CVCLOCK) {
127: procq.p_lforw->p_cval -= CVCLOCK;
128: procq.p_cval += CVCLOCK;
129: }
130: #endif
131:
132: /*
133: * Tax current process and update his times.
134: */
135: pp = SELF;
136: #if ! _I386
137: pp->p_cval >>= 1;
138: #endif
139: if (umode == R_USR) {
140: pp->p_utime ++;
141: u.u_ppc = pc;
142: } else
143: pp->p_stime ++;
144: }
145:
146: /*
147: * stand()
148: *
149: * Called when there is an interrupt or trap, and the system is about to
150: * return to user mode (or to the idle process).
151: */
152:
153: void
154: stand (regset)
155: gregset_t regset;
156: {
157: int s;
158:
159: #ifdef TIMING
160: /*
161: * Every 500th call to stand(), dump logged intervals.
162: *
163: * Log a group of events doing
164: * LOGIN(label);
165: * ...
166: * LOGOUT();
167: *
168: * If you want to group several selected events in one total,
169: * do LOGPAUSE() to halt between events and LOGRESUME() to
170: * add in the time for another event. Event count is displayed.
171: * For example:
172: * LOGIN(label);
173: * while (...) {
174: * LOGPAUSE();
175: * ... stuff you don't want timed...
176: * LOGRESUME();
177: * ... stuff you want timed...
178: * }
179: * LOGOUT();
180: *
181: * Display is for the 3 longest intervals seen in latest logging
182: * period.
183: *
184: * Timing between in & out is displayed with ~1 usec resolution.
185: * Overhead per event is ~20 usec.
186: */
187: static int call_ct; /* DEBUG */
188:
189: call_ct++;
190: if (call_ct >= 500) {
191: call_ct = 0;
192: LOGLIST();
193: }
194: #endif
195:
196: u.u_error = 0;
197:
198: /*
199: * Update the clock.
200: */
201:
202: while (timer.t_tick >= HZ) {
203: #ifdef TRACER
204: extern int checkTheSum ();
205: static int check_check;
206:
207: if (check_check ++ > 120) {
208: check_check = 0;
209: checkTheSum ();
210: }
211: #endif
212: timer.t_time ++;
213: timer.t_tick -= HZ;
214: outflag = 1;
215: }
216:
217: /*
218: * Check expiration of quantum.
219: */
220:
221: if (quantum <= 0) {
222: quantum = 0;
223: disflag = 1;
224: }
225:
226: /*
227: * Check the timed function queue if necessary.
228: */
229:
230: while (clocks) {
231: register TIM * np;
232: register TIM * tp;
233:
234: /*
235: * Update [serviced] clock ticks since startup.
236: */
237: lbolt ++;
238: clocks --;
239:
240: /*
241: * Remove timing list from queue, creating new temporary queue.
242: */
243:
244: tp = timq + (lbolt % __ARRAY_LENGTH (timq));
245: s = sphi ();
246:
247: /*
248: * Scan timing list.
249: */
250:
251: for (np = tp->t_next; tp = np;) {
252: /*
253: * Remember next function in timing list.
254: * NOTE: Must be done before function is invoked,
255: * since it may start a new timer.
256: */
257:
258: np = tp->t_next;
259:
260: /*
261: * Function has not timed out: leave it on timing list.
262: */
263:
264: if (tp->t_lbolt != lbolt)
265: continue;
266:
267: /*
268: * Remove function from timing list.
269: */
270:
271: if (tp->t_last->t_next = tp->t_next)
272: tp->t_next->t_last = tp->t_last;
273: tp->t_last = NULL;
274:
275: /*
276: * Invoke function.
277: */
278: #ifdef TRACER
279: if (tp->t_func < & stext || tp->t_func > & __end_text)
280: panic ("Bad timeout function %x in timer %x",
281: tp->t_func, tp);
282: #endif
283:
284: spl (s);
285: (* tp->t_func) (tp->t_farg, tp);
286: sphi ();
287: }
288:
289: spl (s);
290:
291: STREAMS_TIMEOUT ();
292:
293: }
294:
295: /*
296: * Timeout any devices.
297: */
298:
299: if (outflag) {
300: register int n;
301:
302: outflag = 0;
303: for (n = 0 ; n < drvn ; n ++) {
304: if (drvl [n].d_time == 0)
305: continue;
306: s = sphi ();
307: dtime ((dev_t) makedev (n, 0));
308: spl (s);
309: }
310: }
311:
312: /*
313: * Do profiling.
314: */
315:
316: #if _I386 /* profiling */
317: if (u.u_pscale & ~1) { /* if scale is not zero or one */
318: /*
319: * Treat u.u_pscale as fixed-point fraction 0xXXXX.YYYY.
320: * Increment the (short) profiling entry at
321: * base + (pc - offset) * scale
322: */
323: register caddr_t a;
324:
325: a = (caddr_t) ((long) (u.u_pbase + pscale(u.u_ppc-u.u_pofft,
326: u.u_pscale)) & ~1);
327: if (a < u.u_pbend)
328: putusd(a, getusd(a)+1);
329: }
330: #else /* profiling */
331: if (u.u_pscale) {
332: register unsigned p;
333: register caddr_t a;
334:
335: p = u.u_pscale;
336: a = (int *)u.u_pbase +
337: pscale((int)(u.u_ppc-u.u_pofft), p/sizeof (int));
338: if (a < u.u_pbend)
339: putuwd(a, getuwd(a)+1);
340: }
341: #endif /* profiling */
342:
343: /*
344: * Check for signals and execute them; we pass in the address of the
345: * user's process context rather than depend on the state of the
346: * "u.u_regl" global idiocy.
347: */
348:
349: curr_check_signals (& regset);
350:
351:
352: /*
353: * Execute deferred functions.
354: */
355:
356: defend ();
357:
358:
359: /*
360: * Should we dispatch?
361: */
362: if ((SELF->p_flags & PFDISP) != 0) {
363: SELF->p_flags &= ~ PFDISP;
364: disflag = 1;
365: if (stimer.t_last != 0)
366: wakeup ((char *)& stimer);
367: }
368:
369: /*
370: * Redispatch.
371: */
372: if (disflag) {
373: register PROC *pp;
374:
375: s = sphi ();
376: if ((pp = SELF) != iprocp)
377: setrun (pp);
378: dispatch ();
379: spl (s);
380: }
381:
382: STREAMS_SCHEDULER ();
383: }
384:
385: #ifdef TIMING
386:
387: #define EIMAX 3
388:
389: static int label, b_in, t_in;
390: static int b_pause, t_pause, e_pause, paused, timing;
391:
392: struct H_event {
393: int f; /* timing label */
394: int b; /* delta ticks */
395: int t; /* delta timer */
396: int e; /* event count */
397: } Ltab[EIMAX];
398:
399: LOGIN(lab)
400: {
401: paused = 0;
402: b_pause = t_pause = 0;
403: e_pause = 1;
404: label = lab;
405: b_in = clocks + lbolt;
406: t_in = read_t0();
407: timing = 1;
408: }
409:
410: LOGOUT()
411: {
412: int i;
413:
414: if (!timing)
415: return;
416: if (!paused) {
417: b_pause += clocks + lbolt - b_in;
418: t_pause += (t_in - read_t0());
419: if (t_pause < 0)
420: t_pause += 11932;
421: }
422: for (i = 0; i < EIMAX; i++) {
423: if (b_pause > Ltab[i].b) {
424: Ltab[i].b = b_pause;
425: Ltab[i].t = t_pause;
426: Ltab[i].f = label;
427: Ltab[i].e = e_pause;
428: break;
429: } else if (b_pause == Ltab[i].b) {
430: if (t_pause > Ltab[i].t) {
431: Ltab[i].t = t_pause;
432: Ltab[i].f = label;
433: Ltab[i].e = e_pause;
434: break;
435: } else if (t_pause == Ltab[i].t) {
436: break;
437: }
438: }
439: }
440: timing = 0;
441: }
442:
443: LOGLIST()
444: {
445: int i, printed = 0;
446:
447: for (i = 0; i < EIMAX; i++)
448: if (Ltab[i].t || Ltab[i].b) {
449: if (printed == 0) {
450: printf("\npsw=%x ", read_psw());
451: printed = 1;
452: }
453: printf("f=%x b=%d t=%d e=%d ",
454: Ltab[i].f, Ltab[i].b, Ltab[i].t, Ltab[i].e);
455: Ltab[i].f = Ltab[i].b = Ltab[i].t = 0;
456: } else
457: break;
458: }
459:
460: LOGPAUSE()
461: {
462: if (!timing)
463: return;
464: if (!paused) {
465: b_pause += clocks + lbolt - b_in;
466: t_pause += (t_in - read_t0());
467: if (t_pause < 0)
468: t_pause += 11932;
469: paused = 1;
470: }
471: }
472:
473: LOGRESUME()
474: {
475: if (!timing)
476: return;
477: if (paused) {
478: b_in = clocks + lbolt;
479: t_in = read_t0();
480: paused = 0;
481: e_pause++;
482: }
483: }
484: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.