split out descend and inherit attributes; add signal tracing
[unix-history] / usr / src / sys / netiso / tp_timer.c
CommitLineData
b65ddd42
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
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 $
44f52ea5 32 * @(#)tp_timer.c 7.3 (Berkeley) %G% *
b65ddd42
KS
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
52static 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"
a50e2bc0 58#include "malloc.h"
b65ddd42 59
a50e2bc0
KS
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"
b65ddd42
KS
68
69static struct Ecallout *TP_callfree;
70static struct Ecallout TP_callout[N_TPREF*2];
71
72extern 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 */
81void
82tp_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 */
115static void
116tp_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 (;;) {
a50e2bc0 148 struct tp_pcb *tpcb;
b65ddd42
KS
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);
a50e2bc0
KS
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? */
b65ddd42
KS
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 */
182void
183tp_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 */
232void
233tp_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 */
266void
267tp_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 */
311ProtoHook
312tp_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 */
355void
356tp_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 */
380void
381tp_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 */
408void
409tp_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)
a50e2bc0 418 printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_active);
b65ddd42
KS
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}