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.9 (Berkeley) 09/06/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 Ecallout *TP_callfree; 75 struct Ecallout *TP_callout; 76 struct tp_ref *tp_ref; 77 int N_TPREF = 127; 78 struct tp_refinfo tp_refinfo; 79 struct tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; 80 81 /* 82 * CALLED FROM: 83 * at autoconfig time from tp_init() 84 * a combo of event, state, predicate 85 * FUNCTION and ARGUMENTS: 86 * initialize data structures for the timers 87 */ 88 void 89 tp_timerinit() 90 { 91 register struct Ecallout *e; 92 register int s; 93 #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\ 94 if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);} 95 /* 96 * Initialize storage 97 */ 98 GETME(tp_ref, struct tp_ref *, 1 + N_TPREF); 99 tp_refinfo.tpr_base = tp_ref; 100 tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */ 101 #undef GETME 102 } 103 104 /********************** e timers *************************/ 105 106 int Enoisy = 1; 107 /* 108 * CALLED FROM: 109 * tp.trans all over 110 * FUNCTION and ARGUMENTS: 111 * Set an E type timer. (refp) is the ref structure. 112 * Causes fun(arg1,arg2,arg3) to be called after time t. 113 */ 114 void 115 tp_etimeout(refp, fun, arg1, arg2, arg3, ticks) 116 struct tp_ref *refp; 117 int fun; /* function to be called */ 118 u_int arg1, arg2; 119 int arg3; 120 register int ticks; 121 { 122 123 register struct tp_pcb *tpcb = refp->tpr_pcb; 124 register struct Ccallout *callp; 125 IFDEBUG(D_TIMER) 126 printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb, 127 refp->tpr_pcb->tp_state); 128 ENDDEBUG 129 IFTRACE(D_TIMER) 130 tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref, 131 refp->tpr_state, ticks, tp_stat.ts_Eticks); 132 ENDTRACE 133 if (tpcb == 0) 134 return; 135 IncStat(ts_Eset); 136 if (ticks == 0) 137 ticks = 1; 138 if (fun == TM_data_retrans) { 139 tpcb->tp_retransargs.c_arg1 = arg1; 140 tpcb->tp_retransargs.c_arg2 = arg2; 141 tpcb->tp_retransargs.c_arg3 = arg3; 142 } 143 callp = tpcb->tp_refcallout + fun; 144 if (Enoisy && callp->c_time) 145 printf("E timer allready set: %d of ref %d\n", fun, tpcb->tp_lref); 146 if (callp->c_time == 0 || callp->c_time > ticks) 147 callp->c_time = ticks; 148 } 149 150 /* 151 * CALLED FROM: 152 * tp.trans all over 153 * FUNCTION and ARGUMENTS: 154 * Cancel all occurrences of E-timer function (fun) for reference (refp) 155 */ 156 void 157 tp_euntimeout(refp, fun) 158 struct tp_ref *refp; 159 int fun; 160 { 161 register struct tp_pcb *tpcb = refp->tpr_pcb; 162 163 IFTRACE(D_TIMER) 164 tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0); 165 ENDTRACE 166 167 if (tpcb) 168 tpcb->tp_refcallout[fun].c_time = 0; 169 } 170 171 /* 172 * CALLED FROM: 173 * tp.trans, when an incoming ACK causes things to be dropped 174 * from the retransmission queue, and we want their associated 175 * timers to be cancelled. 176 * NOTE: (by sklower) only called with TM_data_retrans. 177 * FUNCTION and ARGUMENTS: 178 * cancel all occurrences of function (fun) where (arg2) < (seq) 179 */ 180 void 181 tp_euntimeout_lss(refp, fun, seq) 182 struct tp_ref *refp; 183 int fun; 184 SeqNum seq; 185 { 186 register struct tp_pcb *tpcb = refp->tpr_pcb; 187 188 IFTRACE(D_TIMER) 189 tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0); 190 ENDTRACE 191 192 if (tpcb == 0 || tpcb->tp_refcallout[fun].c_time == 0) 193 return; 194 if (SEQ_LT(tpcb, tpcb->tp_retransargs.c_arg2, seq)) { 195 IncStat(ts_Ecan_act); 196 tpcb->tp_refcallout[fun].c_time = 0; 197 } 198 } 199 200 /**************** c timers ********************** 201 * 202 * These are not chained together; they sit 203 * in the tp_ref structure. they are the kind that 204 * are typically cancelled so it's faster not to 205 * mess with the chains 206 */ 207 208 /* 209 * CALLED FROM: 210 * the clock, every 500 ms 211 * FUNCTION and ARGUMENTS: 212 * Look for open references with active timers. 213 * If they exist, call the appropriate timer routines to update 214 * the timers and possibly generate events. 215 * (The E timers are done in other procedures; the C timers are 216 * updated here, and events for them are generated here.) 217 */ 218 ProtoHook 219 tp_slowtimo() 220 { 221 register struct Ccallout *cp, *cpbase; 222 register struct tp_ref *rp; 223 struct tp_pcb *tpcb; 224 struct tp_event E; 225 int s = splnet(), t; 226 227 /* check only open reference structures */ 228 IncStat(ts_Cticks); 229 /* tp_ref[0] is never used */ 230 for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) { 231 if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN) 232 continue; 233 cpbase = tpcb->tp_refcallout; 234 t = N_CTIMERS; 235 /* check the C-type timers */ 236 for (cp = cpbase + t; (--t, --cp) >= cpbase; ) { 237 if (cp->c_time && --(cp->c_time) <= 0 ) { 238 cp->c_time = 0; 239 E.ev_number = t; 240 if (t == TM_data_retrans) { 241 register struct Ecallarg *p1 = &tpcb->tp_retransargs; 242 E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1; 243 E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2; 244 E.ATTR(TM_data_retrans).e_retrans = p1->c_arg3; 245 } 246 IFDEBUG(D_TIMER) 247 printf("C expired! type 0x%x\n", t); 248 ENDDEBUG 249 IncStat(ts_Cexpired); 250 tp_driver( rp->tpr_pcb, &E); 251 if (t == TM_reference && tpcb->tp_state == TP_CLOSED) { 252 if (tpcb->tp_notdetached) { 253 IFDEBUG(D_CONN) 254 printf("PRU_DETACH: not detached\n"); 255 ENDDEBUG 256 tp_detach(tpcb); 257 } 258 /* XXX wart; where else to do it? */ 259 free((caddr_t)tpcb, M_PCB); 260 } 261 } 262 } 263 } 264 splx(s); 265 return 0; 266 } 267 268 int 269 tp_fasttimo() 270 { 271 register struct tp_pcb *t; 272 int s = splnet(); 273 struct tp_event E; 274 275 E.ev_number = TM_sendack; 276 while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) { 277 if (t == 0) { 278 printf("tp_fasttimeo: should panic"); 279 tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; 280 } else { 281 if (t->tp_flags & TPF_DELACK) { 282 t->tp_flags &= ~TPF_DELACK; 283 IncStat(ts_Fdelack); 284 tp_driver(t, &E); 285 t->tp_refcallout[TM_sendack].c_time = t->tp_keepalive_ticks; 286 } else 287 IncStat(ts_Fpruned); 288 tp_ftimeolist = t->tp_fasttimeo; 289 t->tp_fasttimeo = 0; 290 } 291 } 292 splx(s); 293 } 294 295 /* 296 * CALLED FROM: 297 * tp.trans, tp_emit() 298 * FUNCTION and ARGUMENTS: 299 * Set a C type timer of type (which) to go off after (ticks) time. 300 */ 301 void 302 tp_ctimeout(refp, which, ticks) 303 register struct tp_ref *refp; 304 int which, ticks; 305 { 306 register struct Ccallout *cp = &(refp->tpr_callout[which]); 307 308 IFTRACE(D_TIMER) 309 tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", 310 (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time); 311 ENDTRACE 312 if(cp->c_time) 313 IncStat(ts_Ccan_act); 314 IncStat(ts_Cset); 315 if (ticks <= 0) 316 ticks = 1; 317 cp->c_time = ticks; 318 } 319 320 /* 321 * CALLED FROM: 322 * tp.trans 323 * FUNCTION and ARGUMENTS: 324 * Version of tp_ctimeout that resets the C-type time if the 325 * parameter (ticks) is > the current value of the timer. 326 */ 327 void 328 tp_ctimeout_MIN(refp, which, ticks) 329 register struct tp_ref *refp; 330 int which, ticks; 331 { 332 register struct Ccallout *cp = &(refp->tpr_callout[which]); 333 334 IFTRACE(D_TIMER) 335 tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", 336 (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time); 337 ENDTRACE 338 IncStat(ts_Cset); 339 if (cp->c_time) { 340 cp->c_time = MIN(ticks, cp->c_time); 341 IncStat(ts_Ccan_act); 342 } else 343 cp->c_time = ticks; 344 } 345 346 /* 347 * CALLED FROM: 348 * tp.trans 349 * FUNCTION and ARGUMENTS: 350 * Cancel the (which) timer in the ref structure indicated by (refp). 351 */ 352 void 353 tp_cuntimeout(refp, which) 354 int which; 355 register struct tp_ref *refp; 356 { 357 register struct Ccallout *cp; 358 359 cp = &(refp->tpr_callout[which]); 360 361 IFDEBUG(D_TIMER) 362 printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_time); 363 ENDDEBUG 364 365 IFTRACE(D_TIMER) 366 tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, 367 which, cp->c_time, 0); 368 ENDTRACE 369 370 if (cp->c_time) 371 IncStat(ts_Ccan_act); 372 else 373 IncStat(ts_Ccan_inact); 374 cp->c_time = 0; 375 } 376