Removed definition "LIB= rpc". We want libc.a to contain librpc.a, not
[unix-history] / .ref-386BSD-0.1-patchkit / usr / src / sys.386bsd / netiso / tp_timer.c
CommitLineData
0ba8a294
RG
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
41Permission to use, copy, modify, and distribute this software and its
42documentation for any purpose and without fee is hereby granted,
43provided that the above copyright notice appear in all copies and that
44both that copyright notice and this permission notice appear in
45supporting documentation, and that the name of IBM not be
46used in advertising or publicity pertaining to distribution of the
47software without specific, written prior permission.
48
49IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
50ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
51IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
52ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
53WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
54ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55SOFTWARE.
56
57******************************************************************/
58
59/*
60 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 */
62/*
63 * ARGO TP
64 *
65 * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $
66 * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $
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
100struct Ecallout *TP_callfree;
101struct Ecallout *TP_callout;
102struct tp_ref *tp_ref;
103int N_TPREF = 100;
104
105extern 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 */
114void
115tp_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);\
120if (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 */
152static void
153tp_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 */
219void
220tp_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 */
269void
270tp_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 */
303void
304tp_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 */
348ProtoHook
349tp_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 */
392void
393tp_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 */
417void
418tp_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 */
445void
446tp_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}