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