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.12 (Berkeley) 10/02/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 */ 43 44 #include "param.h" 45 #include "systm.h" 46 #include "time.h" 47 #include "malloc.h" 48 #include "protosw.h" 49 #include "socket.h" 50 #include "kernel.h" 51 52 #include "argo_debug.h" 53 #include "tp_param.h" 54 #include "tp_timer.h" 55 #include "tp_stat.h" 56 #include "tp_pcb.h" 57 #include "tp_tpdu.h" 58 #include "tp_trace.h" 59 #include "tp_seq.h" 60 61 struct tp_ref *tp_ref; 62 int tp_rttdiv, tp_rttadd, N_TPREF = 127; 63 struct tp_refinfo tp_refinfo; 64 struct tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; 65 66 /* 67 * CALLED FROM: 68 * at autoconfig time from tp_init() 69 * a combo of event, state, predicate 70 * FUNCTION and ARGUMENTS: 71 * initialize data structures for the timers 72 */ 73 void 74 tp_timerinit() 75 { 76 register int s; 77 /* 78 * Initialize storage 79 */ 80 if (tp_refinfo.tpr_base) 81 return; 82 tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */ 83 s = sizeof(*tp_ref) * tp_refinfo.tpr_size; 84 if ((tp_ref = (struct tp_ref *) malloc(s, M_PCB, M_NOWAIT)) == 0) 85 panic("tp_timerinit"); 86 tp_refinfo.tpr_base = tp_ref; 87 tp_rttdiv = hz / PR_SLOWHZ; 88 tp_rttadd = (2 * tp_rttdiv) - 1; 89 } 90 #ifdef TP_DEBUG_TIMERS 91 /********************** e timers *************************/ 92 93 /* 94 * CALLED FROM: 95 * tp.trans all over 96 * FUNCTION and ARGUMENTS: 97 * Set an E type timer. 98 */ 99 void 100 tp_etimeout(tpcb, fun, ticks) 101 register struct tp_pcb *tpcb; 102 int fun; /* function to be called */ 103 int ticks; 104 { 105 106 register u_int *callp; 107 IFDEBUG(D_TIMER) 108 printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state); 109 ENDDEBUG 110 IFTRACE(D_TIMER) 111 tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref, 112 tpcb->tp_state, ticks, tp_stat.ts_Eticks); 113 ENDTRACE 114 if (tpcb == 0) 115 return; 116 IncStat(ts_Eset); 117 if (ticks == 0) 118 ticks = 1; 119 callp = tpcb->tp_timer + fun; 120 if (*callp == 0 || *callp > ticks) 121 *callp = ticks; 122 } 123 124 /* 125 * CALLED FROM: 126 * tp.trans all over 127 * FUNCTION and ARGUMENTS: 128 * Cancel all occurrences of E-timer function (fun) for reference (refp) 129 */ 130 void 131 tp_euntimeout(tpcb, fun) 132 register struct tp_pcb *tpcb; 133 int fun; 134 { 135 IFTRACE(D_TIMER) 136 tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0); 137 ENDTRACE 138 139 if (tpcb) 140 tpcb->tp_timer[fun] = 0; 141 } 142 143 /**************** c timers ********************** 144 * 145 * These are not chained together; they sit 146 * in the tp_ref structure. they are the kind that 147 * are typically cancelled so it's faster not to 148 * mess with the chains 149 */ 150 #endif 151 /* 152 * CALLED FROM: 153 * the clock, every 500 ms 154 * FUNCTION and ARGUMENTS: 155 * Look for open references with active timers. 156 * If they exist, call the appropriate timer routines to update 157 * the timers and possibly generate events. 158 * (The E timers are done in other procedures; the C timers are 159 * updated here, and events for them are generated here.) 160 */ 161 ProtoHook 162 tp_slowtimo() 163 { 164 register u_int *cp, *cpbase; 165 register struct tp_ref *rp; 166 struct tp_pcb *tpcb; 167 struct tp_event E; 168 int s = splnet(), t; 169 170 /* check only open reference structures */ 171 IncStat(ts_Cticks); 172 /* tp_ref[0] is never used */ 173 for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) { 174 if ((tpcb = rp->tpr_pcb) == 0 || tpcb->tp_refstate < REF_OPEN) 175 continue; 176 cpbase = tpcb->tp_timer; 177 t = TM_NTIMERS; 178 /* check the timers */ 179 for (cp = cpbase + t; (--t, --cp) >= cpbase; ) { 180 if (*cp && --(*cp) <= 0 ) { 181 *cp = 0; 182 E.ev_number = t; 183 IFDEBUG(D_TIMER) 184 printf("C expired! type 0x%x\n", t); 185 ENDDEBUG 186 IncStat(ts_Cexpired); 187 tp_driver( rp->tpr_pcb, &E); 188 if (t == TM_reference && tpcb->tp_state == TP_CLOSED) { 189 if (tpcb->tp_notdetached) { 190 IFDEBUG(D_CONN) 191 printf("PRU_DETACH: not detached\n"); 192 ENDDEBUG 193 tp_detach(tpcb); 194 } 195 /* XXX wart; where else to do it? */ 196 free((caddr_t)tpcb, M_PCB); 197 } 198 } 199 } 200 } 201 splx(s); 202 return 0; 203 } 204 205 /* 206 * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off. 207 */ 208 tp_data_retrans(tpcb) 209 register struct tp_pcb *tpcb; 210 { 211 int rexmt, win; 212 tpcb->tp_rttemit = 0; /* cancel current round trip time */ 213 tpcb->tp_dupacks = 0; 214 tpcb->tp_sndnxt = tpcb->tp_snduna; 215 if (tpcb->tp_fcredit == 0) { 216 /* 217 * We transmitted new data, started timing it and the window 218 * got shrunk under us. This can only happen if all data 219 * that they wanted us to send got acked, so don't 220 * bother shrinking the congestion windows, et. al. 221 * The retransmission timer should have been reset in goodack() 222 */ 223 tpcb->tp_rxtshift = 0; 224 tpcb->tp_timer[TM_data_retrans] = 0; 225 tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; 226 } 227 rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT); 228 win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2)); 229 win = max(win, 2); 230 tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* slow start again. */ 231 tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; 232 /* We're losing; our srtt estimate is probably bogus. 233 * Clobber it so we'll take the next rtt measurement as our srtt; 234 * Maintain current rxt times until then. 235 */ 236 if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) { 237 /* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */ 238 tpcb->tp_rtt = 0; 239 } 240 TP_RANGESET(tpcb->tp_rxtcur, rexmt, tpcb->tp_peer_acktime, 128); 241 tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur; 242 tp_send(tpcb); 243 } 244 245 int 246 tp_fasttimo() 247 { 248 register struct tp_pcb *t; 249 int s = splnet(); 250 struct tp_event E; 251 252 E.ev_number = TM_sendack; 253 while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) { 254 if (t == 0) { 255 printf("tp_fasttimeo: should panic"); 256 tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; 257 } else { 258 if (t->tp_flags & TPF_DELACK) { 259 t->tp_flags &= ~TPF_DELACK; 260 IncStat(ts_Fdelack); 261 tp_driver(t, &E); 262 t->tp_timer[TM_sendack] = t->tp_keepalive_ticks; 263 } else 264 IncStat(ts_Fpruned); 265 tp_ftimeolist = t->tp_fasttimeo; 266 t->tp_fasttimeo = 0; 267 } 268 } 269 splx(s); 270 } 271 272 #ifdef TP_DEBUG_TIMERS 273 /* 274 * CALLED FROM: 275 * tp.trans, tp_emit() 276 * FUNCTION and ARGUMENTS: 277 * Set a C type timer of type (which) to go off after (ticks) time. 278 */ 279 void 280 tp_ctimeout(tpcb, which, ticks) 281 register struct tp_pcb *tpcb; 282 int which, ticks; 283 { 284 285 IFTRACE(D_TIMER) 286 tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", 287 tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); 288 ENDTRACE 289 if(tpcb->tp_timer[which]) 290 IncStat(ts_Ccan_act); 291 IncStat(ts_Cset); 292 if (ticks <= 0) 293 ticks = 1; 294 tpcb->tp_timer[which] = ticks; 295 } 296 297 /* 298 * CALLED FROM: 299 * tp.trans 300 * FUNCTION and ARGUMENTS: 301 * Version of tp_ctimeout that resets the C-type time if the 302 * parameter (ticks) is > the current value of the timer. 303 */ 304 void 305 tp_ctimeout_MIN(tpcb, which, ticks) 306 register struct tp_pcb *tpcb; 307 int which, ticks; 308 { 309 IFTRACE(D_TIMER) 310 tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", 311 tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); 312 ENDTRACE 313 IncStat(ts_Cset); 314 if (tpcb->tp_timer[which]) { 315 tpcb->tp_timer[which] = MIN(ticks, tpcb->tp_timer[which]); 316 IncStat(ts_Ccan_act); 317 } else 318 tpcb->tp_timer[which] = ticks; 319 } 320 321 /* 322 * CALLED FROM: 323 * tp.trans 324 * FUNCTION and ARGUMENTS: 325 * Cancel the (which) timer in the ref structure indicated by (refp). 326 */ 327 void 328 tp_cuntimeout(tpcb, which) 329 register struct tp_pcb *tpcb; 330 int which; 331 { 332 IFDEBUG(D_TIMER) 333 printf("tp_cuntimeout(0x%x, %d) active %d\n", 334 tpcb, which, tpcb->tp_timer[which]); 335 ENDDEBUG 336 337 IFTRACE(D_TIMER) 338 tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, 339 which, tpcb->tp_timer[which], 0); 340 ENDTRACE 341 342 if (tpcb->tp_timer[which]) 343 IncStat(ts_Ccan_act); 344 else 345 IncStat(ts_Ccan_inact); 346 tpcb->tp_timer[which] = 0; 347 } 348 #endif 349