Commit | Line | Data |
---|---|---|
b65ddd42 KS |
1 | /*********************************************************** |
2 | Copyright IBM Corporation 1987 | |
3 | ||
4 | All Rights Reserved | |
5 | ||
6 | Permission to use, copy, modify, and distribute this software and its | |
7 | documentation for any purpose and without fee is hereby granted, | |
8 | provided that the above copyright notice appear in all copies and that | |
9 | both that copyright notice and this permission notice appear in | |
10 | supporting documentation, and that the name of IBM not be | |
11 | used in advertising or publicity pertaining to distribution of the | |
12 | software without specific, written prior permission. | |
13 | ||
14 | IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
15 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
16 | IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
17 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
18 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
19 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
20 | SOFTWARE. | |
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 | |
52 | static 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 | |
69 | static struct Ecallout *TP_callfree; | |
70 | static struct Ecallout TP_callout[N_TPREF*2]; | |
71 | ||
72 | extern 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 | */ | |
81 | void | |
82 | tp_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 | */ | |
115 | static void | |
116 | tp_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 | */ | |
182 | void | |
183 | tp_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 | */ | |
232 | void | |
233 | tp_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 | */ | |
266 | void | |
267 | tp_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 | */ | |
311 | ProtoHook | |
312 | tp_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 | */ | |
355 | void | |
356 | tp_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 | */ | |
380 | void | |
381 | tp_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 | */ | |
408 | void | |
409 | tp_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 | } |