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