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