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