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