diff options
author | andre <andre@FreeBSD.org> | 2007-04-11 09:45:16 +0000 |
---|---|---|
committer | andre <andre@FreeBSD.org> | 2007-04-11 09:45:16 +0000 |
commit | bd6041301a0ba459f34d99a6e4e526ebaafc48b0 (patch) | |
tree | db2065ed42263113dca9aaa7ad58c859f3975c57 /sys/netinet/tcp_subr.c | |
parent | bda6bd3e38175b52aef99a649001fdc4143dfb11 (diff) | |
download | FreeBSD-src-bd6041301a0ba459f34d99a6e4e526ebaafc48b0.zip FreeBSD-src-bd6041301a0ba459f34d99a6e4e526ebaafc48b0.tar.gz |
Change the TCP timer system from using the callout system five times
directly to a merged model where only one callout, the next to fire,
is registered.
Instead of callout_reset(9) and callout_stop(9) the new function
tcp_timer_activate() is used which then internally manages the callout.
The single new callout is a mutex callout on inpcb simplifying the
locking a bit.
tcp_timer() is the called function which handles all race conditions
in one place and then dispatches the individual timer functions.
Reviewed by: rwatson (earlier version)
Diffstat (limited to 'sys/netinet/tcp_subr.c')
-rw-r--r-- | sys/netinet/tcp_subr.c | 29 |
1 files changed, 14 insertions, 15 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index c705121e..dc4a695 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -262,10 +262,9 @@ static void tcp_isn_tick(void *); * separate because the tcpcb structure is exported to userland for sysctl * parsing purposes, which do not know about callouts. */ -struct tcpcb_mem { - struct tcpcb tcb; - struct callout tcpcb_mem_rexmt, tcpcb_mem_persist, tcpcb_mem_keep; - struct callout tcpcb_mem_2msl, tcpcb_mem_delack; +struct tcpcb_mem { + struct tcpcb tcb; + struct tcp_timer tt; }; static uma_zone_t tcpcb_zone; @@ -490,7 +489,6 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, if (tp != NULL) { inp = tp->t_inpcb; KASSERT(inp != NULL, ("tcp control block w/o inpcb")); - INP_INFO_WLOCK_ASSERT(&tcbinfo); INP_LOCK_ASSERT(inp); } else inp = NULL; @@ -645,6 +643,7 @@ tcp_newtcpcb(struct inpcb *inp) if (tm == NULL) return (NULL); tp = &tm->tcb; + tp->t_timers = &tm->tt; /* LIST_INIT(&tp->t_segq); */ /* XXX covered by M_ZERO */ tp->t_maxseg = tp->t_maxopd = #ifdef INET6 @@ -653,11 +652,8 @@ tcp_newtcpcb(struct inpcb *inp) tcp_mssdflt; /* Set up our timeouts. */ - callout_init(tp->tt_rexmt = &tm->tcpcb_mem_rexmt, NET_CALLOUT_MPSAFE); - callout_init(tp->tt_persist = &tm->tcpcb_mem_persist, NET_CALLOUT_MPSAFE); - callout_init(tp->tt_keep = &tm->tcpcb_mem_keep, NET_CALLOUT_MPSAFE); - callout_init(tp->tt_2msl = &tm->tcpcb_mem_2msl, NET_CALLOUT_MPSAFE); - callout_init(tp->tt_delack = &tm->tcpcb_mem_delack, NET_CALLOUT_MPSAFE); + callout_init_mtx(&tp->t_timers->tt_timer, &inp->inp_mtx, + CALLOUT_RETURNUNLOCKED); if (tcp_do_rfc1323) tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP); @@ -728,12 +724,15 @@ tcp_discardcb(struct tcpcb *tp) /* * Make sure that all of our timers are stopped before we * delete the PCB. + * + * XXX: callout_stop() may race and a callout may already + * try to obtain the INP_LOCK. Only callout_drain() would + * stop this but it would cause a LOR thus we can't use it. + * The tcp_timer() function contains a lot of checks to + * handle this case rather gracefully. */ - callout_stop(tp->tt_rexmt); - callout_stop(tp->tt_persist); - callout_stop(tp->tt_keep); - callout_stop(tp->tt_2msl); - callout_stop(tp->tt_delack); + tp->t_timers->tt_active = 0; + callout_stop(&tp->t_timers->tt_timer); /* * If we got enough samples through the srtt filter, |