xref: /csrg-svn/sys/netiso/tp_timer.c (revision 51007)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)tp_timer.c	7.8 (Berkeley) 09/05/91
8  */
9 
10 /***********************************************************
11 		Copyright IBM Corporation 1987
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 
31 ******************************************************************/
32 
33 /*
34  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35  */
36 /*
37  * ARGO TP
38  *
39  * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $
40  * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $
41  *
42  * Contains all the timer code.
43  * There are two sources of calls to these routines:
44  * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time)
45  *
46  * Timers come in two flavors - those that generally get
47  * cancelled (tp_ctimeout, tp_cuntimeout)
48  * and those that either usually expire (tp_etimeout,
49  * tp_euntimeout, tp_slowtimo) or may require more than one instance
50  * of the timer active at a time.
51  *
52  * The C timers are stored in the tp_ref structure. Their "going off"
53  * is manifested by a driver event of the TM_xxx form.
54  *
55  * The E timers are handled like the generic kernel callouts.
56  * Their "going off" is manifested by a function call w/ 3 arguments.
57  */
58 
59 #include "param.h"
60 #include "types.h"
61 #include "time.h"
62 #include "malloc.h"
63 #include "socket.h"
64 
65 #include "tp_param.h"
66 #include "tp_timer.h"
67 #include "tp_stat.h"
68 #include "tp_pcb.h"
69 #include "tp_tpdu.h"
70 #include "argo_debug.h"
71 #include "tp_trace.h"
72 #include "tp_seq.h"
73 
74 struct	Ecallout *TP_callfree;
75 struct	Ecallout *TP_callout;
76 struct	tp_ref *tp_ref;
77 int		N_TPREF = 127;
78 struct	tp_refinfo tp_refinfo;
79 
80 /*
81  * CALLED FROM:
82  *  at autoconfig time from tp_init()
83  * 	a combo of event, state, predicate
84  * FUNCTION and ARGUMENTS:
85  *  initialize data structures for the timers
86  */
87 void
88 tp_timerinit()
89 {
90 	register struct Ecallout *e;
91 	register int s;
92 #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\
93 if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);}
94 	/*
95 	 * Initialize storage
96 	 */
97 	GETME(tp_ref, struct tp_ref *, 1 +  N_TPREF);
98 	tp_refinfo.tpr_base = tp_ref;
99 	tp_refinfo.tpr_size = N_TPREF + 1;  /* Need to start somewhere */
100 #undef GETME
101 }
102 
103 /**********************  e timers *************************/
104 
105 int Enoisy = 1;
106 /*
107  * CALLED FROM:
108  *  tp.trans all over
109  * FUNCTION and ARGUMENTS:
110  * Set an E type timer.  (refp) is the ref structure.
111  * Causes  fun(arg1,arg2,arg3) to be called after time t.
112  */
113 void
114 tp_etimeout(refp, fun, arg1, arg2, arg3, ticks)
115 	struct tp_ref	*refp;
116 	int 			fun; 	/* function to be called */
117 	u_int			arg1, arg2;
118 	int				arg3;
119 	register int	ticks;
120 {
121 
122 	register struct tp_pcb *tpcb = refp->tpr_pcb;
123 	register struct Ccallout *callp;
124 	IFDEBUG(D_TIMER)
125 		printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb,
126 		refp->tpr_pcb->tp_state);
127 	ENDDEBUG
128 	IFTRACE(D_TIMER)
129 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref,
130 		refp->tpr_state, ticks, tp_stat.ts_Eticks);
131 	ENDTRACE
132 	if (tpcb == 0)
133 		return;
134 	IncStat(ts_Eset);
135 	if (ticks == 0)
136 		ticks = 1;
137 	if (fun == TM_data_retrans) {
138 		tpcb->tp_retransargs.c_arg1 = arg1;
139 		tpcb->tp_retransargs.c_arg2 = arg2;
140 		tpcb->tp_retransargs.c_arg3 = arg3;
141 	}
142 	callp = tpcb->tp_refcallout + fun;
143 	if (Enoisy && callp->c_time)
144 		printf("E timer allready set: %d of ref %d\n", fun, tpcb->tp_lref);
145 	if (callp->c_time == 0 || callp->c_time > ticks)
146 		callp->c_time = ticks;
147 }
148 
149 /*
150  * CALLED FROM:
151  *  tp.trans all over
152  * FUNCTION and ARGUMENTS:
153  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
154  */
155 void
156 tp_euntimeout(refp, fun)
157 	struct tp_ref *refp;
158 	int			  fun;
159 {
160 	register struct tp_pcb *tpcb = refp->tpr_pcb;
161 
162 	IFTRACE(D_TIMER)
163 		tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0);
164 	ENDTRACE
165 
166 	if (tpcb)
167 		tpcb->tp_refcallout[fun].c_time = 0;
168 }
169 
170 /*
171  * CALLED FROM:
172  *  tp.trans, when an incoming ACK causes things to be dropped
173  *  from the retransmission queue, and we want their associated
174  *  timers to be cancelled.
175  *  NOTE: (by sklower) only called with TM_data_retrans.
176  * FUNCTION and ARGUMENTS:
177  *  cancel all occurrences of function (fun) where (arg2) < (seq)
178  */
179 void
180 tp_euntimeout_lss(refp, fun, seq)
181 	struct tp_ref *refp;
182 	int			  fun;
183 	SeqNum		  seq;
184 {
185 	register struct tp_pcb *tpcb = refp->tpr_pcb;
186 
187 	IFTRACE(D_TIMER)
188 		tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0);
189 	ENDTRACE
190 
191 	if (tpcb == 0 || tpcb->tp_refcallout[fun].c_time == 0)
192 		return;
193 	if (SEQ_LT(tpcb, tpcb->tp_retransargs.c_arg2, seq))  {
194 			IncStat(ts_Ecan_act);
195 			tpcb->tp_refcallout[fun].c_time = 0;
196 	}
197 }
198 
199 /****************  c timers **********************
200  *
201  * These are not chained together; they sit
202  * in the tp_ref structure. they are the kind that
203  * are typically cancelled so it's faster not to
204  * mess with the chains
205  */
206 
207 /*
208  * CALLED FROM:
209  *  the clock, every 500 ms
210  * FUNCTION and ARGUMENTS:
211  *  Look for open references with active timers.
212  *  If they exist, call the appropriate timer routines to update
213  *  the timers and possibly generate events.
214  *  (The E timers are done in other procedures; the C timers are
215  *  updated here, and events for them are generated here.)
216  */
217 ProtoHook
218 tp_slowtimo()
219 {
220 	register struct Ccallout 	*cp, *cpbase;
221 	register struct tp_ref		*rp;
222 	struct tp_pcb		*tpcb;
223 	struct tp_event		E;
224 	int 				s = splnet(), t;
225 
226 	/* check only open reference structures */
227 	IncStat(ts_Cticks);
228 	/* tp_ref[0] is never used */
229 	for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) {
230 		if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN)
231 			continue;
232 		cpbase = tpcb->tp_refcallout;
233 		t = N_CTIMERS;
234 		/* check the C-type timers */
235 		for (cp = cpbase + t; (--t, --cp) >= cpbase; ) {
236 			if (cp->c_time && --(cp->c_time) <= 0 ) {
237 				cp->c_time = 0;
238 				E.ev_number = t;
239 				if (t == TM_data_retrans) {
240 					register struct Ecallarg *p1 = &tpcb->tp_retransargs;
241 					E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1;
242 					E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2;
243 					E.ATTR(TM_data_retrans).e_retrans =  p1->c_arg3;
244 				}
245 				IFDEBUG(D_TIMER)
246 					printf("C expired! type 0x%x\n", t);
247 				ENDDEBUG
248 				IncStat(ts_Cexpired);
249 				tp_driver( rp->tpr_pcb, &E);
250 				if (t == TM_reference && tpcb->tp_state == TP_CLOSED) {
251 					if (tpcb->tp_notdetached) {
252 						IFDEBUG(D_CONN)
253 							printf("PRU_DETACH: not detached\n");
254 						ENDDEBUG
255 						tp_detach(tpcb);
256 					}
257 					/* XXX wart; where else to do it? */
258 					free((caddr_t)tpcb, M_PCB);
259 				}
260 			}
261 		}
262 	}
263 	splx(s);
264 	return 0;
265 }
266 
267 /*
268  * CALLED FROM:
269  *  tp.trans, tp_emit()
270  * FUNCTION and ARGUMENTS:
271  * 	Set a C type timer of type (which) to go off after (ticks) time.
272  */
273 void
274 tp_ctimeout(refp, which, ticks)
275 	register struct tp_ref	*refp;
276 	int 					which, ticks;
277 {
278 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
279 
280 	IFTRACE(D_TIMER)
281 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
282 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time);
283 	ENDTRACE
284 	if(cp->c_time)
285 		IncStat(ts_Ccan_act);
286 	IncStat(ts_Cset);
287 	if (ticks <= 0)
288 		ticks = 1;
289 	cp->c_time = ticks;
290 }
291 
292 /*
293  * CALLED FROM:
294  *  tp.trans
295  * FUNCTION and ARGUMENTS:
296  * 	Version of tp_ctimeout that resets the C-type time if the
297  * 	parameter (ticks) is > the current value of the timer.
298  */
299 void
300 tp_ctimeout_MIN(refp, which, ticks)
301 	register struct tp_ref	*refp;
302 	int						which, ticks;
303 {
304 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
305 
306 	IFTRACE(D_TIMER)
307 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
308 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time);
309 	ENDTRACE
310 	IncStat(ts_Cset);
311 	if (cp->c_time)  {
312 		cp->c_time = MIN(ticks, cp->c_time);
313 		IncStat(ts_Ccan_act);
314 	} else
315 		cp->c_time = ticks;
316 }
317 
318 /*
319  * CALLED FROM:
320  *  tp.trans
321  * FUNCTION and ARGUMENTS:
322  *  Cancel the (which) timer in the ref structure indicated by (refp).
323  */
324 void
325 tp_cuntimeout(refp, which)
326 	int						which;
327 	register struct tp_ref	*refp;
328 {
329 	register struct Ccallout *cp;
330 
331 	cp = &(refp->tpr_callout[which]);
332 
333 	IFDEBUG(D_TIMER)
334 		printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_time);
335 	ENDDEBUG
336 
337 	IFTRACE(D_TIMER)
338 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
339 			which, cp->c_time, 0);
340 	ENDTRACE
341 
342 	if (cp->c_time)
343 		IncStat(ts_Ccan_act);
344 	else
345 		IncStat(ts_Ccan_inact);
346 	cp->c_time = 0;
347 }
348