|
|
1.1 root 1: /***********************************************************
2: Copyright IBM Corporation 1987
3:
4: All Rights Reserved
5:
6: Permission to use, copy, modify, and distribute this software and its
7: documentation for any purpose and without fee is hereby granted,
8: provided that the above copyright notice appear in all copies and that
9: both that copyright notice and this permission notice appear in
10: supporting documentation, and that the name of IBM not be
11: used in advertising or publicity pertaining to distribution of the
12: software without specific, written prior permission.
13:
14: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20: SOFTWARE.
21:
22: ******************************************************************/
23:
24: /*
25: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26: */
27: /*
28: * ARGO TP
29: *
30: * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $
31: * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $
32: * @(#)tp_timer.c 7.3 (Berkeley) 8/29/89 *
33: *
34: * Contains all the timer code.
35: * There are two sources of calls to these routines:
36: * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time)
37: *
38: * Timers come in two flavors - those that generally get
39: * cancelled (tp_ctimeout, tp_cuntimeout)
40: * and those that either usually expire (tp_etimeout,
41: * tp_euntimeout, tp_slowtimo) or may require more than one instance
42: * of the timer active at a time.
43: *
44: * The C timers are stored in the tp_ref structure. Their "going off"
45: * is manifested by a driver event of the TM_xxx form.
46: *
47: * The E timers are handled like the generic kernel callouts.
48: * Their "going off" is manifested by a function call w/ 3 arguments.
49: */
50:
51: #ifndef lint
52: static char *rcsid = "$Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $";
53: #endif lint
54:
55: #include "param.h"
56: #include "types.h"
57: #include "time.h"
58: #include "malloc.h"
59:
60: #include "tp_param.h"
61: #include "tp_timer.h"
62: #include "tp_stat.h"
63: #include "tp_pcb.h"
64: #include "tp_tpdu.h"
65: #include "argo_debug.h"
66: #include "tp_trace.h"
67: #include "tp_seq.h"
68:
69: static struct Ecallout *TP_callfree;
70: static struct Ecallout TP_callout[N_TPREF*2];
71:
72: extern int tp_maxrefopen; /* highest ref # of an open tp connection */
73:
74: /*
75: * CALLED FROM:
76: * at autoconfig time from tp_init()
77: * a combo of event, state, predicate
78: * FUNCTION and ARGUMENTS:
79: * initialize data structures for the timers
80: */
81: void
82: tp_timerinit()
83: {
84: register int i;
85: /*
86: * Initialize callouts
87: */
88: TP_callfree = TP_callout;
89: for (i = 1; i < N_TPREF*2; i++)
90: TP_callout[i-1].c_next = &TP_callout[i];
91:
92: bzero( (caddr_t)tp_ref, N_TPREF * sizeof(struct tp_ref) );
93:
94: /* hate to do this but we really don't want zero to be a legit ref */
95: tp_maxrefopen = 1;
96: tp_ref[0].tpr_state = REF_FROZEN; /* white lie -- no ref timer, don't
97: * want this one to be allocated- ever
98: * unless, of course, you make refs and address instead of an
99: * index - then 0 can be allocated
100: */
101:
102: }
103:
104: /********************** e timers *************************/
105:
106: /*
107: * CALLED FROM:
108: * tp_slowtimo() every 1/2 second, for each open reference
109: * FUNCTION and ARGUMENTS:
110: * (refp) indicates a reference structure that is in use.
111: * This ref structure may contain active E-type timers.
112: * Update the timers and if any expire, create an event and
113: * call the driver.
114: */
115: static void
116: tp_Eclock(refp)
117: struct tp_ref *refp; /* the reference structure */
118: {
119: register struct Ecallout *p1; /* to drift through the list of callouts */
120: struct tp_event E; /* event to pass to tp_driver() */
121: int tp_driver(); /* drives the FSM */
122:
123: /*
124: * Update real-time timeout queue.
125: * At front of queue are some number of events which are ``due''.
126: * The time to these is <= 0 and if negative represents the
127: * number of ticks which have passed since it was supposed to happen.
128: * The rest of the q elements (times > 0) are events yet to happen,
129: * where the time for each is given as a delta from the previous.
130: * Decrementing just the first of these serves to decrement the time
131: * to all events.
132: *
133: * This version, which calls the driver directly, doesn't pass
134: * along the ticks - may want to add the ticks if there's any use
135: * for them.
136: */
137: IncStat(ts_Eticks);
138: p1 = refp->tpr_calltodo.c_next;
139: while (p1) {
140: if (--p1->c_time > 0)
141: break;
142: if (p1->c_time == 0)
143: break;
144: p1 = p1->c_next;
145: }
146:
147: for (;;) {
148: struct tp_pcb *tpcb;
149: if ((p1 = refp->tpr_calltodo.c_next) == 0 || p1->c_time > 0) {
150: break;
151: }
152: refp->tpr_calltodo.c_next = p1->c_next;
153: p1->c_next = TP_callfree;
154:
155: #ifndef lint
156: E.ev_number = p1->c_func;
157: E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1;
158: E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2;
159: E.ATTR(TM_data_retrans).e_retrans = p1->c_arg3;
160: #endif lint
161: IFDEBUG(D_TIMER)
162: printf("E expired! event 0x%x (0x%x,0x%x), pcb 0x%x ref %d\n",
163: p1->c_func, p1->c_arg1, p1->c_arg2, refp->tpr_pcb,
164: refp-tp_ref);
165: ENDDEBUG
166:
167: TP_callfree = p1;
168: IncStat(ts_Eexpired);
169: (void) tp_driver( tpcb = refp->tpr_pcb, &E);
170: if (p1->c_func == TM_reference && tpcb->tp_state == TP_CLOSED)
171: free((caddr_t)tpcb, M_PCB); /* XXX wart; where else to do it? */
172: }
173: }
174:
175: /*
176: * CALLED FROM:
177: * tp.trans all over
178: * FUNCTION and ARGUMENTS:
179: * Set an E type timer. (refp) is the ref structure.
180: * Causes fun(arg1,arg2,arg3) to be called after time t.
181: */
182: void
183: tp_etimeout(refp, fun, arg1, arg2, arg3, ticks)
184: struct tp_ref *refp;
185: int fun; /* function to be called */
186: u_int arg1, arg2;
187: int arg3;
188: register int ticks;
189: {
190: register struct Ecallout *p1, *p2, *pnew;
191: /* p1 and p2 drift through the list of timeout callout structures,
192: * pnew points to the newly created callout structure
193: */
194:
195: IFDEBUG(D_TIMER)
196: printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb,
197: refp->tpr_pcb->tp_state);
198: ENDDEBUG
199: IFTRACE(D_TIMER)
200: tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref,
201: refp->tpr_state, ticks, tp_stat.ts_Eticks);
202: ENDTRACE
203:
204: IncStat(ts_Eset);
205: if (ticks == 0)
206: ticks = 1;
207: pnew = TP_callfree;
208: if (pnew == (struct Ecallout *)0)
209: panic("tp timeout table overflow");
210: TP_callfree = pnew->c_next;
211: pnew->c_arg1 = arg1;
212: pnew->c_arg2 = arg2;
213: pnew->c_arg3 = arg3;
214: pnew->c_func = fun;
215: for (p1 = &(refp->tpr_calltodo);
216: (p2 = p1->c_next) && p2->c_time < ticks; p1 = p2)
217: if (p2->c_time > 0)
218: ticks -= p2->c_time;
219: p1->c_next = pnew;
220: pnew->c_next = p2;
221: pnew->c_time = ticks;
222: if (p2)
223: p2->c_time -= ticks;
224: }
225:
226: /*
227: * CALLED FROM:
228: * tp.trans all over
229: * FUNCTION and ARGUMENTS:
230: * Cancel all occurrences of E-timer function (fun) for reference (refp)
231: */
232: void
233: tp_euntimeout(refp, fun)
234: struct tp_ref *refp;
235: int fun;
236: {
237: register struct Ecallout *p1, *p2; /* ptrs to drift through the list */
238:
239: IFTRACE(D_TIMER)
240: tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0);
241: ENDTRACE
242:
243: p1 = &refp->tpr_calltodo;
244: while ( (p2 = p1->c_next) != 0) {
245: if (p2->c_func == fun) {
246: if (p2->c_next && p2->c_time > 0)
247: p2->c_next->c_time += p2->c_time;
248: p1->c_next = p2->c_next;
249: p2->c_next = TP_callfree;
250: TP_callfree = p2;
251: IncStat(ts_Ecan_act);
252: continue;
253: }
254: p1 = p2;
255: }
256: }
257:
258: /*
259: * CALLED FROM:
260: * tp.trans, when an incoming ACK causes things to be dropped
261: * from the retransmission queue, and we want their associated
262: * timers to be cancelled.
263: * FUNCTION and ARGUMENTS:
264: * cancel all occurrences of function (fun) where (arg2) < (seq)
265: */
266: void
267: tp_euntimeout_lss(refp, fun, seq)
268: struct tp_ref *refp;
269: int fun;
270: SeqNum seq;
271: {
272: register struct Ecallout *p1, *p2;
273:
274: IFTRACE(D_TIMER)
275: tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0);
276: ENDTRACE
277:
278: p1 = &refp->tpr_calltodo;
279: while ( (p2 = p1->c_next) != 0) {
280: if ((p2->c_func == fun) && SEQ_LT(refp->tpr_pcb, p2->c_arg2, seq)) {
281: if (p2->c_next && p2->c_time > 0)
282: p2->c_next->c_time += p2->c_time;
283: p1->c_next = p2->c_next;
284: p2->c_next = TP_callfree;
285: TP_callfree = p2;
286: IncStat(ts_Ecan_act);
287: continue;
288: }
289: p1 = p2;
290: }
291: }
292:
293: /**************** c timers **********************
294: *
295: * These are not chained together; they sit
296: * in the tp_ref structure. they are the kind that
297: * are typically cancelled so it's faster not to
298: * mess with the chains
299: */
300:
301: /*
302: * CALLED FROM:
303: * the clock, every 500 ms
304: * FUNCTION and ARGUMENTS:
305: * Look for open references with active timers.
306: * If they exist, call the appropriate timer routines to update
307: * the timers and possibly generate events.
308: * (The E timers are done in other procedures; the C timers are
309: * updated here, and events for them are generated here.)
310: */
311: ProtoHook
312: tp_slowtimo()
313: {
314: register int r,t;
315: struct Ccallout *cp;
316: struct tp_ref *rp = tp_ref;
317: struct tp_event E;
318: int s = splnet();
319:
320: /* check only open reference structures */
321: IncStat(ts_Cticks);
322: rp++; /* tp_ref[0] is never used */
323: for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
324: if (rp->tpr_state < REF_OPEN)
325: continue;
326:
327: /* check the C-type timers */
328: cp = rp->tpr_callout;
329: for (t=0 ; t < N_CTIMERS; t++,cp++) {
330: if( cp->c_active ) {
331: if( --cp->c_time <= 0 ) {
332: cp->c_active = FALSE;
333: E.ev_number = t;
334: IFDEBUG(D_TIMER)
335: printf("C expired! type 0x%x\n", t);
336: ENDDEBUG
337: IncStat(ts_Cexpired);
338: tp_driver( rp->tpr_pcb, &E);
339: }
340: }
341: }
342: /* now update the list */
343: tp_Eclock(rp);
344: }
345: splx(s);
346: return 0;
347: }
348:
349: /*
350: * CALLED FROM:
351: * tp.trans, tp_emit()
352: * FUNCTION and ARGUMENTS:
353: * Set a C type timer of type (which) to go off after (ticks) time.
354: */
355: void
356: tp_ctimeout(refp, which, ticks)
357: register struct tp_ref *refp;
358: int which, ticks;
359: {
360: register struct Ccallout *cp = &(refp->tpr_callout[which]);
361:
362: IFTRACE(D_TIMER)
363: tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
364: (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
365: ENDTRACE
366: if(cp->c_active)
367: IncStat(ts_Ccan_act);
368: IncStat(ts_Cset);
369: cp->c_time = ticks;
370: cp->c_active = TRUE;
371: }
372:
373: /*
374: * CALLED FROM:
375: * tp.trans
376: * FUNCTION and ARGUMENTS:
377: * Version of tp_ctimeout that resets the C-type time if the
378: * parameter (ticks) is > the current value of the timer.
379: */
380: void
381: tp_ctimeout_MIN(refp, which, ticks)
382: register struct tp_ref *refp;
383: int which, ticks;
384: {
385: register struct Ccallout *cp = &(refp->tpr_callout[which]);
386:
387: IFTRACE(D_TIMER)
388: tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
389: (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
390: ENDTRACE
391: if(cp->c_active)
392: IncStat(ts_Ccan_act);
393: IncStat(ts_Cset);
394: if( cp->c_active )
395: cp->c_time = MIN(ticks, cp->c_time);
396: else {
397: cp->c_time = ticks;
398: cp->c_active = TRUE;
399: }
400: }
401:
402: /*
403: * CALLED FROM:
404: * tp.trans
405: * FUNCTION and ARGUMENTS:
406: * Cancel the (which) timer in the ref structure indicated by (refp).
407: */
408: void
409: tp_cuntimeout(refp, which)
410: int which;
411: register struct tp_ref *refp;
412: {
413: register struct Ccallout *cp;
414:
415: cp = &(refp->tpr_callout[which]);
416:
417: IFDEBUG(D_TIMER)
418: printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_active);
419: ENDDEBUG
420:
421: IFTRACE(D_TIMER)
422: tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
423: which, cp->c_active, 0);
424: ENDTRACE
425:
426: if(cp->c_active)
427: IncStat(ts_Ccan_act);
428: else
429: IncStat(ts_Ccan_inact);
430: cp->c_active = FALSE;
431: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.