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 $ 32 * 33 * Contains all the timer code. 34 * There are two sources of calls to these routines: 35 * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time) 36 * 37 * Timers come in two flavors - those that generally get 38 * cancelled (tp_ctimeout, tp_cuntimeout) 39 * and those that either usually expire (tp_etimeout, 40 * tp_euntimeout, tp_slowtimo) or may require more than one instance 41 * of the timer active at a time. 42 * 43 * The C timers are stored in the tp_ref structure. Their "going off" 44 * is manifested by a driver event of the TM_xxx form. 45 * 46 * The E timers are handled like the generic kernel callouts. 47 * Their "going off" is manifested by a function call w/ 3 arguments. 48 */ 49 50 #ifndef lint 51 static char *rcsid = "$Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $"; 52 #endif lint 53 54 #include "param.h" 55 #include "types.h" 56 #include "time.h" 57 58 #include "../netiso/tp_param.h" 59 #include "../netiso/tp_timer.h" 60 #include "../netiso/tp_stat.h" 61 #include "../netiso/tp_pcb.h" 62 #include "../netiso/tp_tpdu.h" 63 #include "../netiso/argo_debug.h" 64 #include "../netiso/tp_trace.h" 65 #include "../netiso/tp_seq.h" 66 67 static struct Ecallout *TP_callfree; 68 static struct Ecallout TP_callout[N_TPREF*2]; 69 70 extern int tp_maxrefopen; /* highest ref # of an open tp connection */ 71 72 /* 73 * CALLED FROM: 74 * at autoconfig time from tp_init() 75 * a combo of event, state, predicate 76 * FUNCTION and ARGUMENTS: 77 * initialize data structures for the timers 78 */ 79 void 80 tp_timerinit() 81 { 82 register int i; 83 /* 84 * Initialize callouts 85 */ 86 TP_callfree = TP_callout; 87 for (i = 1; i < N_TPREF*2; i++) 88 TP_callout[i-1].c_next = &TP_callout[i]; 89 90 bzero( (caddr_t)tp_ref, N_TPREF * sizeof(struct tp_ref) ); 91 92 /* hate to do this but we really don't want zero to be a legit ref */ 93 tp_maxrefopen = 1; 94 tp_ref[0].tpr_state = REF_FROZEN; /* white lie -- no ref timer, don't 95 * want this one to be allocated- ever 96 * unless, of course, you make refs and address instead of an 97 * index - then 0 can be allocated 98 */ 99 100 } 101 102 /********************** e timers *************************/ 103 104 /* 105 * CALLED FROM: 106 * tp_slowtimo() every 1/2 second, for each open reference 107 * FUNCTION and ARGUMENTS: 108 * (refp) indicates a reference structure that is in use. 109 * This ref structure may contain active E-type timers. 110 * Update the timers and if any expire, create an event and 111 * call the driver. 112 */ 113 static void 114 tp_Eclock(refp) 115 struct tp_ref *refp; /* the reference structure */ 116 { 117 register struct Ecallout *p1; /* to drift through the list of callouts */ 118 struct tp_event E; /* event to pass to tp_driver() */ 119 int tp_driver(); /* drives the FSM */ 120 121 /* 122 * Update real-time timeout queue. 123 * At front of queue are some number of events which are ``due''. 124 * The time to these is <= 0 and if negative represents the 125 * number of ticks which have passed since it was supposed to happen. 126 * The rest of the q elements (times > 0) are events yet to happen, 127 * where the time for each is given as a delta from the previous. 128 * Decrementing just the first of these serves to decrement the time 129 * to all events. 130 * 131 * This version, which calls the driver directly, doesn't pass 132 * along the ticks - may want to add the ticks if there's any use 133 * for them. 134 */ 135 IncStat(ts_Eticks); 136 p1 = refp->tpr_calltodo.c_next; 137 while (p1) { 138 if (--p1->c_time > 0) 139 break; 140 if (p1->c_time == 0) 141 break; 142 p1 = p1->c_next; 143 } 144 145 for (;;) { 146 if ((p1 = refp->tpr_calltodo.c_next) == 0 || p1->c_time > 0) { 147 break; 148 } 149 refp->tpr_calltodo.c_next = p1->c_next; 150 p1->c_next = TP_callfree; 151 152 #ifndef lint 153 E.ev_number = p1->c_func; 154 E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1; 155 E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2; 156 E.ATTR(TM_data_retrans).e_retrans = p1->c_arg3; 157 #endif lint 158 IFDEBUG(D_TIMER) 159 printf("E expired! event 0x%x (0x%x,0x%x), pcb 0x%x ref %d\n", 160 p1->c_func, p1->c_arg1, p1->c_arg2, refp->tpr_pcb, 161 refp-tp_ref); 162 ENDDEBUG 163 164 TP_callfree = p1; 165 IncStat(ts_Eexpired); 166 (void) tp_driver( refp->tpr_pcb, &E); 167 } 168 } 169 170 /* 171 * CALLED FROM: 172 * tp.trans all over 173 * FUNCTION and ARGUMENTS: 174 * Set an E type timer. (refp) is the ref structure. 175 * Causes fun(arg1,arg2,arg3) to be called after time t. 176 */ 177 void 178 tp_etimeout(refp, fun, arg1, arg2, arg3, ticks) 179 struct tp_ref *refp; 180 int fun; /* function to be called */ 181 u_int arg1, arg2; 182 int arg3; 183 register int ticks; 184 { 185 register struct Ecallout *p1, *p2, *pnew; 186 /* p1 and p2 drift through the list of timeout callout structures, 187 * pnew points to the newly created callout structure 188 */ 189 190 IFDEBUG(D_TIMER) 191 printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb, 192 refp->tpr_pcb->tp_state); 193 ENDDEBUG 194 IFTRACE(D_TIMER) 195 tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref, 196 refp->tpr_state, ticks, tp_stat.ts_Eticks); 197 ENDTRACE 198 199 IncStat(ts_Eset); 200 if (ticks == 0) 201 ticks = 1; 202 pnew = TP_callfree; 203 if (pnew == (struct Ecallout *)0) 204 panic("tp timeout table overflow"); 205 TP_callfree = pnew->c_next; 206 pnew->c_arg1 = arg1; 207 pnew->c_arg2 = arg2; 208 pnew->c_arg3 = arg3; 209 pnew->c_func = fun; 210 for (p1 = &(refp->tpr_calltodo); 211 (p2 = p1->c_next) && p2->c_time < ticks; p1 = p2) 212 if (p2->c_time > 0) 213 ticks -= p2->c_time; 214 p1->c_next = pnew; 215 pnew->c_next = p2; 216 pnew->c_time = ticks; 217 if (p2) 218 p2->c_time -= ticks; 219 } 220 221 /* 222 * CALLED FROM: 223 * tp.trans all over 224 * FUNCTION and ARGUMENTS: 225 * Cancel all occurrences of E-timer function (fun) for reference (refp) 226 */ 227 void 228 tp_euntimeout(refp, fun) 229 struct tp_ref *refp; 230 int fun; 231 { 232 register struct Ecallout *p1, *p2; /* ptrs to drift through the list */ 233 234 IFTRACE(D_TIMER) 235 tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0); 236 ENDTRACE 237 238 p1 = &refp->tpr_calltodo; 239 while ( (p2 = p1->c_next) != 0) { 240 if (p2->c_func == fun) { 241 if (p2->c_next && p2->c_time > 0) 242 p2->c_next->c_time += p2->c_time; 243 p1->c_next = p2->c_next; 244 p2->c_next = TP_callfree; 245 TP_callfree = p2; 246 IncStat(ts_Ecan_act); 247 continue; 248 } 249 p1 = p2; 250 } 251 } 252 253 /* 254 * CALLED FROM: 255 * tp.trans, when an incoming ACK causes things to be dropped 256 * from the retransmission queue, and we want their associated 257 * timers to be cancelled. 258 * FUNCTION and ARGUMENTS: 259 * cancel all occurrences of function (fun) where (arg2) < (seq) 260 */ 261 void 262 tp_euntimeout_lss(refp, fun, seq) 263 struct tp_ref *refp; 264 int fun; 265 SeqNum seq; 266 { 267 register struct Ecallout *p1, *p2; 268 269 IFTRACE(D_TIMER) 270 tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0); 271 ENDTRACE 272 273 p1 = &refp->tpr_calltodo; 274 while ( (p2 = p1->c_next) != 0) { 275 if ((p2->c_func == fun) && SEQ_LT(refp->tpr_pcb, p2->c_arg2, seq)) { 276 if (p2->c_next && p2->c_time > 0) 277 p2->c_next->c_time += p2->c_time; 278 p1->c_next = p2->c_next; 279 p2->c_next = TP_callfree; 280 TP_callfree = p2; 281 IncStat(ts_Ecan_act); 282 continue; 283 } 284 p1 = p2; 285 } 286 } 287 288 /**************** c timers ********************** 289 * 290 * These are not chained together; they sit 291 * in the tp_ref structure. they are the kind that 292 * are typically cancelled so it's faster not to 293 * mess with the chains 294 */ 295 296 /* 297 * CALLED FROM: 298 * the clock, every 500 ms 299 * FUNCTION and ARGUMENTS: 300 * Look for open references with active timers. 301 * If they exist, call the appropriate timer routines to update 302 * the timers and possibly generate events. 303 * (The E timers are done in other procedures; the C timers are 304 * updated here, and events for them are generated here.) 305 */ 306 ProtoHook 307 tp_slowtimo() 308 { 309 register int r,t; 310 struct Ccallout *cp; 311 struct tp_ref *rp = tp_ref; 312 struct tp_event E; 313 int s = splnet(); 314 315 /* check only open reference structures */ 316 IncStat(ts_Cticks); 317 rp++; /* tp_ref[0] is never used */ 318 for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) { 319 if (rp->tpr_state < REF_OPEN) 320 continue; 321 322 /* check the C-type timers */ 323 cp = rp->tpr_callout; 324 for (t=0 ; t < N_CTIMERS; t++,cp++) { 325 if( cp->c_active ) { 326 if( --cp->c_time <= 0 ) { 327 cp->c_active = FALSE; 328 E.ev_number = t; 329 IFDEBUG(D_TIMER) 330 printf("C expired! type 0x%x\n", t); 331 ENDDEBUG 332 IncStat(ts_Cexpired); 333 tp_driver( rp->tpr_pcb, &E); 334 } 335 } 336 } 337 /* now update the list */ 338 tp_Eclock(rp); 339 } 340 splx(s); 341 return 0; 342 } 343 344 /* 345 * CALLED FROM: 346 * tp.trans, tp_emit() 347 * FUNCTION and ARGUMENTS: 348 * Set a C type timer of type (which) to go off after (ticks) time. 349 */ 350 void 351 tp_ctimeout(refp, which, ticks) 352 register struct tp_ref *refp; 353 int which, ticks; 354 { 355 register struct Ccallout *cp = &(refp->tpr_callout[which]); 356 357 IFTRACE(D_TIMER) 358 tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", 359 (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active); 360 ENDTRACE 361 if(cp->c_active) 362 IncStat(ts_Ccan_act); 363 IncStat(ts_Cset); 364 cp->c_time = ticks; 365 cp->c_active = TRUE; 366 } 367 368 /* 369 * CALLED FROM: 370 * tp.trans 371 * FUNCTION and ARGUMENTS: 372 * Version of tp_ctimeout that resets the C-type time if the 373 * parameter (ticks) is > the current value of the timer. 374 */ 375 void 376 tp_ctimeout_MIN(refp, which, ticks) 377 register struct tp_ref *refp; 378 int which, ticks; 379 { 380 register struct Ccallout *cp = &(refp->tpr_callout[which]); 381 382 IFTRACE(D_TIMER) 383 tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", 384 (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active); 385 ENDTRACE 386 if(cp->c_active) 387 IncStat(ts_Ccan_act); 388 IncStat(ts_Cset); 389 if( cp->c_active ) 390 cp->c_time = MIN(ticks, cp->c_time); 391 else { 392 cp->c_time = ticks; 393 cp->c_active = TRUE; 394 } 395 } 396 397 /* 398 * CALLED FROM: 399 * tp.trans 400 * FUNCTION and ARGUMENTS: 401 * Cancel the (which) timer in the ref structure indicated by (refp). 402 */ 403 void 404 tp_cuntimeout(refp, which) 405 int which; 406 register struct tp_ref *refp; 407 { 408 register struct Ccallout *cp; 409 410 cp = &(refp->tpr_callout[which]); 411 412 IFDEBUG(D_TIMER) 413 printf("tp_cuntimeout(0x%x, %d) active\n", refp, which, cp->c_active); 414 ENDDEBUG 415 416 IFTRACE(D_TIMER) 417 tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, 418 which, cp->c_active, 0); 419 ENDTRACE 420 421 if(cp->c_active) 422 IncStat(ts_Ccan_act); 423 else 424 IncStat(ts_Ccan_inact); 425 cp->c_active = FALSE; 426 } 427