|
|
1.1 root 1: /* $Header: /y/coh.386/RCS/clock.c,v 1.9 93/04/14 10:06:19 root Exp $ */
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 a 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: #include <sys/coherent.h>
49: #include <sys/con.h>
50: #include <sys/proc.h>
51: #include <sys/sched.h>
52: #include <sys/stat.h>
53: #include <sys/timeout.h>
54: #include <sys/mdata.h>
55:
56: int (*altclk)(); /* pointer to higher-speed clock function */
57:
58: #ifndef _I386
59: int altsel; /* if nonzero, CS for LOADABLE driver owning altclk() */
60: #endif
61:
62: int clocks;
63:
64: /*
65: * This routine is called once every tick (1/HZ seconds).
66: * It gets called with the program counter that was interrupted
67: * and the CPL of the interrupted code (0..3).
68: */
69: clock(pc, umode)
70: caddr_t pc;
71: {
72: register PROC *pp;
73:
74: /*
75: * Ignore clock interrupts till we are ready.
76: */
77: if (batflag == 0)
78: return;
79:
80: /*
81: * Hook for alternate clock interrupt;
82: * Call polling function ("altclk") if there is one.
83: *
84: * For near function, "altsel" is 0 and "altclk" is offset.
85: * For far function, "altsel" is the CS selector and "altclk"
86: * is the offset.
87: *
88: * Since the polling function ends with a near rather than
89: * far return, far invocation is via ld_call() (ldas.s) which uses
90: * the despatch routine at CS:4 (ld.s) in any loadable driver.
91: */
92: if (altclk) {
93: #ifndef _I386
94: if (altsel) { /* will do far call to altclk fn */
95: if (ld_call(altsel, altclk))
96: return;
97: } else
98: #endif
99: if ((*altclk)())
100: return;
101: }
102:
103: /*
104: * Update timers. Decrement time slice.
105: */
106: utimer += 1;
107: clocks += 1;
108: timer.t_tick += 1;
109: quantum -= 1;
110:
111: #ifndef _I386
112: /*
113: * Give processes their schedule values per tick.
114: */
115: if (procq.p_lforw->p_cval > CVCLOCK) {
116: procq.p_lforw->p_cval -= CVCLOCK;
117: procq.p_cval += CVCLOCK;
118: }
119: #endif
120:
121: /*
122: * Tax current process and update his times.
123: */
124: pp = SELF;
125: #ifndef _I386
126: pp->p_cval >>= 1;
127: #endif
128: if (umode == R_USR) {
129: pp->p_utime++;
130: u.u_ppc = pc;
131: } else
132: pp->p_stime++;
133: }
134:
135: /*
136: * stand()
137: *
138: * Called when there is an interrupt or trap.
139: */
140: stand()
141: {
142: int s;
143:
144: #ifdef TIMING
145: /*
146: * Every 500th call to stand(), dump logged intervals.
147: *
148: * Log a group of events doing
149: * LOGIN(label);
150: * ...
151: * LOGOUT();
152: *
153: * If you want to group several selected events in one total,
154: * do LOGPAUSE() to halt between events and LOGRESUME() to
155: * add in the time for another event. Event count is displayed.
156: * For example:
157: * LOGIN(label);
158: * while (...) {
159: * LOGPAUSE();
160: * ... stuff you don't want timed...
161: * LOGRESUME();
162: * ... stuff you want timed...
163: * }
164: * LOGOUT();
165: *
166: * Display is for the 3 longest intervals seen in latest logging
167: * period.
168: *
169: * Timing between in & out is displayed with ~1 usec resolution.
170: * Overhead per event is ~20 usec.
171: */
172: static int call_ct; /* DEBUG */
173:
174: call_ct++;
175: if (call_ct >= 500) {
176: call_ct = 0;
177: LOGLIST();
178: }
179: #endif
180:
181: u.u_error = 0;
182:
183: /*
184: * Update the clock.
185: */
186: while (timer.t_tick >= HZ) {
187: timer.t_time++;
188: timer.t_tick -= HZ;
189: outflag = 1;
190: }
191:
192: /*
193: * Check expiration of quantum.
194: */
195: if (quantum <= 0) {
196: quantum = 0;
197: disflag = 1;
198: }
199:
200: /*
201: * Check the timed function queue if necessary.
202: */
203: if (clocks > 0)
204: do {
205: register TIM * np;
206: register TIM * tp;
207:
208: /*
209: * Update [serviced] clock ticks since startup.
210: */
211: lbolt++;
212: clocks--;
213:
214: /*
215: * Remove timing list from queue, creating new temporary queue.
216: */
217: tp = (TIM *) &timq[ lbolt % nel(timq) ];
218: s = sphi();
219:
220: /*
221: * Scan timing list.
222: */
223: for (np = tp->t_next; tp = np;) {
224:
225: /*
226: * Remember next function in timing list.
227: * NOTE: Must be done before function is invoked,
228: * since it may start a new timer.
229: */
230: np = tp->t_next;
231:
232: /*
233: * Function has not timed out: leave it on timing list.
234: */
235: if (tp->t_lbolt != lbolt)
236: continue;
237:
238: /*
239: * Remove function from timing list.
240: */
241: if (tp->t_last->t_next = tp->t_next)
242: tp->t_next->t_last = tp->t_last;
243: tp->t_last = NULL;
244:
245: /*
246: * Invoke function.
247: */
248: spl(s);
249: (*tp->t_func)(tp->t_farg, tp);
250: sphi();
251: }
252:
253: spl(s);
254:
255: STREAMS_TIMEOUT ();
256:
257: } while (clocks);
258:
259: /*
260: * Timeout any devices.
261: */
262: if (outflag) {
263: register int n;
264:
265: outflag = 0;
266: for (n=0; n<drvn; n++) {
267: if (drvl[n].d_time == 0)
268: continue;
269: s = sphi();
270: dtime((dev_t)makedev(n, 0));
271: spl(s);
272: }
273: }
274:
275: /*
276: * Do profiling.
277: */
278: #ifdef _I386 /* profiling */
279: if (u.u_pscale & ~1) { /* if scale is not zero or one */
280: /*
281: * Treat u.u_pscale as fixed-point fraction 0xXXXX.YYYY.
282: * Increment the (short) profiling entry at
283: * base + (pc - offset) * scale
284: */
285: register caddr_t a;
286:
287: a = (caddr_t) ((long) (u.u_pbase + pscale(u.u_ppc-u.u_pofft,
288: u.u_pscale)) & ~1);
289: if (a < u.u_pbend)
290: putusd(a, getusd(a)+1);
291: }
292: #else /* profiling */
293: if (u.u_pscale) {
294: register unsigned p;
295: register caddr_t a;
296:
297: p = u.u_pscale;
298: a = (int *)u.u_pbase +
299: pscale((int)(u.u_ppc-u.u_pofft), p/sizeof (int));
300: if (a < u.u_pbend)
301: putuwd(a, getuwd(a)+1);
302: }
303: #endif /* profiling */
304:
305: /*
306: * Check for signals and execute them.
307: */
308: if (SELF->p_ssig) {
309: actvsig();
310: }
311:
312: /*
313: * Execute deferred functions.
314: */
315: defend();
316:
317: /*
318: * Should we dispatch?
319: */
320: if ((SELF->p_flags&PFDISP) != 0) {
321: SELF->p_flags &= ~PFDISP;
322: disflag = 1;
323: if (stimer.t_last != 0)
324: wakeup((char *)&stimer);
325: }
326:
327: /*
328: * Redispatch.
329: */
330: if (disflag) {
331: register PROC *pp;
332:
333: s=sphi();
334: if ((pp=SELF)!=iprocp)
335: setrun(pp);
336: dispatch();
337: spl(s);
338: }
339:
340: STREAMS_SCHEDULER ();
341:
342: return;
343: }
344:
345: #ifdef TIMING
346:
347: #define EIMAX 3
348:
349: static int label, b_in, t_in;
350: static int b_pause, t_pause, e_pause, paused, timing;
351:
352: struct H_event {
353: int f; /* timing label */
354: int b; /* delta ticks */
355: int t; /* delta timer */
356: int e; /* event count */
357: } Ltab[EIMAX];
358:
359: LOGIN(lab)
360: {
361: paused = 0;
362: b_pause = t_pause = 0;
363: e_pause = 1;
364: label = lab;
365: b_in = clocks + lbolt;
366: t_in = read_t0();
367: timing = 1;
368: }
369:
370: LOGOUT()
371: {
372: int i;
373:
374: if (!timing)
375: return;
376: if (!paused) {
377: b_pause += clocks + lbolt - b_in;
378: t_pause += (t_in - read_t0());
379: if (t_pause < 0)
380: t_pause += 11932;
381: }
382: for (i = 0; i < EIMAX; i++) {
383: if (b_pause > Ltab[i].b) {
384: Ltab[i].b = b_pause;
385: Ltab[i].t = t_pause;
386: Ltab[i].f = label;
387: Ltab[i].e = e_pause;
388: break;
389: } else if (b_pause == Ltab[i].b) {
390: if (t_pause > Ltab[i].t) {
391: Ltab[i].t = t_pause;
392: Ltab[i].f = label;
393: Ltab[i].e = e_pause;
394: break;
395: } else if (t_pause == Ltab[i].t) {
396: break;
397: }
398: }
399: }
400: timing = 0;
401: }
402:
403: LOGLIST()
404: {
405: int i, printed = 0;
406:
407: for (i = 0; i < EIMAX; i++)
408: if (Ltab[i].t || Ltab[i].b) {
409: if (printed == 0) {
410: printf("\npsw=%x ", read_psw());
411: printed = 1;
412: }
413: printf("f=%x b=%d t=%d e=%d ",
414: Ltab[i].f, Ltab[i].b, Ltab[i].t, Ltab[i].e);
415: Ltab[i].f = Ltab[i].b = Ltab[i].t = 0;
416: } else
417: break;
418: }
419:
420: LOGPAUSE()
421: {
422: if (!timing)
423: return;
424: if (!paused) {
425: b_pause += clocks + lbolt - b_in;
426: t_pause += (t_in - read_t0());
427: if (t_pause < 0)
428: t_pause += 11932;
429: paused = 1;
430: }
431: }
432:
433: LOGRESUME()
434: {
435: if (!timing)
436: return;
437: if (paused) {
438: b_in = clocks + lbolt;
439: t_in = read_t0();
440: paused = 0;
441: e_pause++;
442: }
443: }
444: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.