Restore the semantic of callout_active() testing on tcp timers.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 15 Dec 2008 14:29:35 +0000 (22:29 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 16 Dec 2008 14:32:59 +0000 (22:32 +0800)
Originally there is no time gap between the running of the tcp timer
handler and the deactivation of the tcp timer callout, but the message
based tcp timer has a time gap in between these two actions.  This
time gap affects the code path which depends on the current state of
the tcp timer, i.e. return value of callout_active(tcp_timer).  To
close this time gap, we take the pending and running tcp timer tasks
into consideration when testing the current state of the tcp timer.

Reviewed-by: dillon@
sys/netinet/tcp_input.c
sys/netinet/tcp_output.c
sys/netinet/tcp_subr.c
sys/netinet/tcp_syncache.c
sys/netinet/tcp_timer.c
sys/netinet/tcp_timer.h
sys/netinet/tcp_timer2.h [new file with mode: 0644]
sys/netinet/tcp_usrreq.c
sys/netinet/tcp_var.h

index d728f42..e5c759a 100644 (file)
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
 #include <netinet/tcp_timer.h>
+#include <netinet/tcp_timer2.h>
 #include <netinet/tcp_var.h>
 #include <netinet6/tcp6_var.h>
 #include <netinet/tcpip.h>
@@ -241,7 +242,7 @@ do { \
  *       the ack that opens up a 0-sized window.
  */
 #define DELAY_ACK(tp) \
-       (tcp_delack_enabled && !callout_pending(tp->tt_delack) && \
+       (tcp_delack_enabled && !tcp_callout_pending(tp, tp->tt_delack) && \
        !(tp->t_flags & TF_RXWIN0SENT))
 
 #define acceptable_window_update(tp, th, tiwin)                                \
@@ -1037,11 +1038,12 @@ findpcb:
                             (tlen != 0 &&
                              ((isipv6 && in6_localaddr(&inp->in6p_faddr)) ||
                               (!isipv6 && in_localaddr(inp->inp_faddr)))))) {
-                               callout_reset(tp->tt_delack, tcp_delacktime,
-                                               tcp_timer_delack, tp);
+                               tcp_callout_reset(tp, tp->tt_delack,
+                                   tcp_delacktime, tcp_timer_delack);
                                tp->t_flags |= TF_NEEDSYN;
-                       } else
+                       } else {
                                tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN);
+                       }
 
                        tcpstat.tcps_connects++;
                        soisconnected(so);
@@ -1059,8 +1061,10 @@ after_listen:
         * Reset idle time and keep-alive timer.
         */
        tp->t_rcvtime = ticks;
-       if (TCPS_HAVEESTABLISHED(tp->t_state))
-               callout_reset(tp->tt_keep, tcp_keepidle, tcp_timer_keep, tp);
+       if (TCPS_HAVEESTABLISHED(tp->t_state)) {
+               tcp_callout_reset(tp, tp->tt_keep, tcp_keepidle,
+                   tcp_timer_keep);
+       }
 
        /*
         * Process options.
@@ -1215,12 +1219,13 @@ after_listen:
                                 * are ready to send, let tcp_output
                                 * decide between more output or persist.
                                 */
-                               if (tp->snd_una == tp->snd_max)
-                                       callout_stop(tp->tt_rexmt);
-                               else if (!callout_active(tp->tt_persist))
-                                       callout_reset(tp->tt_rexmt,
-                                                     tp->t_rxtcur,
-                                                     tcp_timer_rexmt, tp);
+                               if (tp->snd_una == tp->snd_max) {
+                                       tcp_callout_stop(tp, tp->tt_rexmt);
+                               } else if (!tcp_callout_active(tp,
+                                           tp->tt_persist)) {
+                                       tcp_callout_reset(tp, tp->tt_rexmt,
+                                           tp->t_rxtcur, tcp_timer_rexmt);
+                               }
                                sowwakeup(so);
                                if (so->so_snd.ssb_cc > 0)
                                        tcp_output(tp);
@@ -1274,8 +1279,8 @@ after_listen:
                         * to turn the feature off.
                         */
                        if (DELAY_ACK(tp)) {
-                               callout_reset(tp->tt_delack, tcp_delacktime,
-                                   tcp_timer_delack, tp);
+                               tcp_callout_reset(tp, tp->tt_delack,
+                                   tcp_delacktime, tcp_timer_delack);
                        } else if (tcp_aggregate_acks) {
                                tp->t_flags |= TF_ACKNOW;
                                if (!(tp->t_flags & TF_ONOUTPUTQ)) {
@@ -1400,16 +1405,17 @@ after_listen:
 
                        tp->rcv_adv += tp->rcv_wnd;
                        tp->snd_una++;          /* SYN is acked */
-                       callout_stop(tp->tt_rexmt);
+                       tcp_callout_stop(tp, tp->tt_rexmt);
                        /*
                         * If there's data, delay ACK; if there's also a FIN
                         * ACKNOW will be turned on later.
                         */
-                       if (DELAY_ACK(tp) && tlen != 0)
-                               callout_reset(tp->tt_delack, tcp_delacktime,
-                                   tcp_timer_delack, tp);
-                       else
+                       if (DELAY_ACK(tp) && tlen != 0) {
+                               tcp_callout_reset(tp, tp->tt_delack,
+                                   tcp_delacktime, tcp_timer_delack);
+                       } else {
                                tp->t_flags |= TF_ACKNOW;
+                       }
                        /*
                         * Received <SYN,ACK> in SYN_SENT[*] state.
                         * Transitions:
@@ -1423,8 +1429,8 @@ after_listen:
                                thflags &= ~TH_SYN;
                        } else {
                                tp->t_state = TCPS_ESTABLISHED;
-                               callout_reset(tp->tt_keep, tcp_keepidle,
-                                             tcp_timer_keep, tp);
+                               tcp_callout_reset(tp, tp->tt_keep, tcp_keepidle,
+                                   tcp_timer_keep);
                        }
                } else {
                        /*
@@ -1438,7 +1444,7 @@ after_listen:
                         * If there was no CC option, clear cached CC value.
                         */
                        tp->t_flags |= TF_ACKNOW;
-                       callout_stop(tp->tt_rexmt);
+                       tcp_callout_stop(tp, tp->tt_rexmt);
                        if (to.to_flags & TOF_CC) {
                                if (taop->tao_cc != 0 &&
                                    CC_GT(to.to_cc, taop->tao_cc)) {
@@ -1454,10 +1460,9 @@ after_listen:
                                                tp->t_flags &= ~TF_NEEDFIN;
                                        } else {
                                                tp->t_state = TCPS_ESTABLISHED;
-                                               callout_reset(tp->tt_keep,
-                                                             tcp_keepidle,
-                                                             tcp_timer_keep,
-                                                             tp);
+                                               tcp_callout_reset(tp,
+                                                   tp->tt_keep, tcp_keepidle,
+                                                   tcp_timer_keep);
                                        }
                                        tp->t_flags |= TF_NEEDSYN;
                                } else
@@ -1869,8 +1874,8 @@ trimthenstep6:
                        tp->t_flags &= ~TF_NEEDFIN;
                } else {
                        tp->t_state = TCPS_ESTABLISHED;
-                       callout_reset(tp->tt_keep, tcp_keepidle,
-                                     tcp_timer_keep, tp);
+                       tcp_callout_reset(tp, tp->tt_keep, tcp_keepidle,
+                           tcp_timer_keep);
                }
                /*
                 * If segment contains data or ACK, will call tcp_reass()
@@ -1904,7 +1909,7 @@ trimthenstep6:
                                break;
                        }
                        tcpstat.tcps_rcvdupack++;
-                       if (!callout_active(tp->tt_rexmt) ||
+                       if (!tcp_callout_active(tp, tp->tt_rexmt) ||
                            th->th_ack != tp->snd_una) {
                                tp->t_dupacks = 0;
                                break;
@@ -1965,7 +1970,7 @@ fastretransmit:
                                tp->snd_ssthresh = win * tp->t_maxseg;
                                ENTER_FASTRECOVERY(tp);
                                tp->snd_recover = tp->snd_max;
-                               callout_stop(tp->tt_rexmt);
+                               tcp_callout_stop(tp, tp->tt_rexmt);
                                tp->t_rtttime = 0;
                                old_snd_nxt = tp->snd_nxt;
                                tp->snd_nxt = th->th_ack;
@@ -2248,11 +2253,12 @@ process_ACK:
                 * timer, using current (possibly backed-off) value.
                 */
                if (th->th_ack == tp->snd_max) {
-                       callout_stop(tp->tt_rexmt);
+                       tcp_callout_stop(tp, tp->tt_rexmt);
                        needoutput = TRUE;
-               } else if (!callout_active(tp->tt_persist))
-                       callout_reset(tp->tt_rexmt, tp->t_rxtcur,
-                                     tcp_timer_rexmt, tp);
+               } else if (!tcp_callout_active(tp, tp->tt_persist)) {
+                       tcp_callout_reset(tp, tp->tt_rexmt, tp->t_rxtcur,
+                           tcp_timer_rexmt);
+               }
 
                switch (tp->t_state) {
                /*
@@ -2271,8 +2277,8 @@ process_ACK:
                                 */
                                if (so->so_state & SS_CANTRCVMORE) {
                                        soisdisconnected(so);
-                                       callout_reset(tp->tt_2msl, tcp_maxidle,
-                                                     tcp_timer_2msl, tp);
+                                       tcp_callout_reset(tp, tp->tt_2msl,
+                                           tcp_maxidle, tcp_timer_2msl);
                                }
                                tp->t_state = TCPS_FIN_WAIT_2;
                        }
@@ -2290,13 +2296,14 @@ process_ACK:
                                tcp_canceltimers(tp);
                                /* Shorten TIME_WAIT [RFC-1644, p.28] */
                                if (tp->cc_recv != 0 &&
-                                   (ticks - tp->t_starttime) < tcp_msl)
-                                       callout_reset(tp->tt_2msl,
+                                   (ticks - tp->t_starttime) < tcp_msl) {
+                                       tcp_callout_reset(tp, tp->tt_2msl,
                                            tp->t_rxtcur * TCPTV_TWTRUNC,
-                                           tcp_timer_2msl, tp);
-                               else
-                                       callout_reset(tp->tt_2msl, 2 * tcp_msl,
-                                           tcp_timer_2msl, tp);
+                                           tcp_timer_2msl);
+                               } else {
+                                       tcp_callout_reset(tp, tp->tt_2msl,
+                                           2 * tcp_msl, tcp_timer_2msl);
+                               }
                                soisdisconnected(so);
                        }
                        break;
@@ -2320,8 +2327,8 @@ process_ACK:
                 * it and restart the finack timer.
                 */
                case TCPS_TIME_WAIT:
-                       callout_reset(tp->tt_2msl, 2 * tcp_msl,
-                                     tcp_timer_2msl, tp);
+                       tcp_callout_reset(tp, tp->tt_2msl, 2 * tcp_msl,
+                           tcp_timer_2msl);
                        goto dropafterack;
                }
        }
@@ -2431,11 +2438,12 @@ dodata:                                                 /* XXX */
                if (th->th_seq == tp->rcv_nxt &&
                    LIST_EMPTY(&tp->t_segq) &&
                    TCPS_HAVEESTABLISHED(tp->t_state)) {
-                       if (DELAY_ACK(tp))
-                               callout_reset(tp->tt_delack, tcp_delacktime,
-                                             tcp_timer_delack, tp);
-                       else
+                       if (DELAY_ACK(tp)) {
+                               tcp_callout_reset(tp, tp->tt_delack,
+                                   tcp_delacktime, tcp_timer_delack);
+                       } else {
                                tp->t_flags |= TF_ACKNOW;
+                       }
                        tp->rcv_nxt += tlen;
                        thflags = th->th_flags & TH_FIN;
                        tcpstat.tcps_rcvpack++;
@@ -2482,11 +2490,12 @@ dodata:                                                 /* XXX */
                         * Otherwise, since we received a FIN then no
                         * more input can be expected, send ACK now.
                         */
-                       if (DELAY_ACK(tp) && (tp->t_flags & TF_NEEDSYN))
-                               callout_reset(tp->tt_delack, tcp_delacktime,
-                                   tcp_timer_delack, tp);
-                       else
+                       if (DELAY_ACK(tp) && (tp->t_flags & TF_NEEDSYN)) {
+                               tcp_callout_reset(tp, tp->tt_delack,
+                                   tcp_delacktime, tcp_timer_delack);
+                       } else {
                                tp->t_flags |= TF_ACKNOW;
+                       }
                        tp->rcv_nxt++;
                }
 
@@ -2521,15 +2530,15 @@ dodata:                                                 /* XXX */
                        /* Shorten TIME_WAIT [RFC-1644, p.28] */
                        if (tp->cc_recv != 0 &&
                            (ticks - tp->t_starttime) < tcp_msl) {
-                               callout_reset(tp->tt_2msl,
-                                             tp->t_rxtcur * TCPTV_TWTRUNC,
-                                             tcp_timer_2msl, tp);
+                               tcp_callout_reset(tp, tp->tt_2msl,
+                                   tp->t_rxtcur * TCPTV_TWTRUNC,
+                                   tcp_timer_2msl);
                                /* For transaction client, force ACK now. */
                                tp->t_flags |= TF_ACKNOW;
+                       } else {
+                               tcp_callout_reset(tp, tp->tt_2msl, 2 * tcp_msl,
+                                   tcp_timer_2msl);
                        }
-                       else
-                               callout_reset(tp->tt_2msl, 2 * tcp_msl,
-                                             tcp_timer_2msl, tp);
                        soisdisconnected(so);
                        break;
 
@@ -2537,8 +2546,8 @@ dodata:                                                   /* XXX */
                 * In TIME_WAIT state restart the 2 MSL time_wait timer.
                 */
                case TCPS_TIME_WAIT:
-                       callout_reset(tp->tt_2msl, 2 * tcp_msl,
-                                     tcp_timer_2msl, tp);
+                       tcp_callout_reset(tp, tp->tt_2msl, 2 * tcp_msl,
+                           tcp_timer_2msl);
                        break;
                }
        }
@@ -3118,7 +3127,7 @@ tcp_newreno_partial_ack(struct tcpcb *tp, struct tcphdr *th, int acked)
        tcp_seq old_snd_nxt = tp->snd_nxt;
        u_long ocwnd = tp->snd_cwnd;
 
-       callout_stop(tp->tt_rexmt);
+       tcp_callout_stop(tp, tp->tt_rexmt);
        tp->t_rtttime = 0;
        tp->snd_nxt = th->th_ack;
        /* Set snd_cwnd to one segment beyond acknowledged offset. */
@@ -3165,7 +3174,7 @@ tcp_sack_rexmt(struct tcpcb *tp, struct tcphdr *th)
                tp->snd_cwnd = nextrexmt - tp->snd_una + seglen;
                old_snd_max = tp->snd_max;
                if (nextrexmt == tp->snd_una)
-                       callout_stop(tp->tt_rexmt);
+                       tcp_callout_stop(tp, tp->tt_rexmt);
                error = tcp_output(tp);
                if (error != 0)
                        break;
index 8bd87ab..6370088 100644 (file)
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
 #include <netinet/tcp_timer.h>
+#include <netinet/tcp_timer2.h>
 #include <netinet/tcp_var.h>
 #include <netinet/tcpip.h>
 #ifdef TCPDEBUG
@@ -247,7 +248,7 @@ again:
                                flags &= ~TH_FIN;
                        sendwin = 1;
                } else {
-                       callout_stop(tp->tt_persist);
+                       tcp_callout_stop(tp, tp->tt_persist);
                        tp->t_rxtshift = 0;
                }
        }
@@ -306,10 +307,10 @@ again:
                 */
                len = 0;
                if (sendwin == 0) {
-                       callout_stop(tp->tt_rexmt);
+                       tcp_callout_stop(tp, tp->tt_rexmt);
                        tp->t_rxtshift = 0;
                        tp->snd_nxt = tp->snd_una;
-                       if (!callout_active(tp->tt_persist))
+                       if (!tcp_callout_active(tp, tp->tt_persist))
                                tcp_setpersist(tp);
                }
        }
@@ -430,11 +431,11 @@ again:
         *      persisting              to move a small or zero window
         *      (re)transmitting        and thereby not persisting
         *
-        * callout_active(tp->tt_persist)
+        * tcp_callout_active(tp, tp->tt_persist)
         *      is true when we are in persist state.
         * The TF_FORCE flag in tp->t_flags
         *      is set when we are called to send a persist packet.
-        * callout_active(tp->tt_rexmt)
+        * tcp_callout_active(tp, tp->tt_rexmt)
         *      is set when we are retransmitting
         * The output side is idle when both timers are zero.
         *
@@ -445,7 +446,8 @@ again:
         * otherwise force out a byte.
         */
        if (so->so_snd.ssb_cc > 0 &&
-           !callout_active(tp->tt_rexmt) && !callout_active(tp->tt_persist)) {
+           !tcp_callout_active(tp, tp->tt_rexmt) &&
+           !tcp_callout_active(tp, tp->tt_persist)) {
                tp->t_rxtshift = 0;
                tcp_setpersist(tp);
        }
@@ -763,7 +765,8 @@ send:
         * case, since we know we aren't doing a retransmission.
         * (retransmit and persist are mutually exclusive...)
         */
-       if (len || (flags & (TH_SYN|TH_FIN)) || callout_active(tp->tt_persist))
+       if (len || (flags & (TH_SYN|TH_FIN)) ||
+           tcp_callout_active(tp, tp->tt_persist))
                th->th_seq = htonl(tp->snd_nxt);
        else
                th->th_seq = htonl(tp->snd_max);
@@ -840,7 +843,8 @@ send:
         * In transmit state, time the transmission and arrange for
         * the retransmit.  In persist state, just set snd_max.
         */
-       if (!(tp->t_flags & TF_FORCE) || !callout_active(tp->tt_persist)) {
+       if (!(tp->t_flags & TF_FORCE) ||
+           !tcp_callout_active(tp, tp->tt_persist)) {
                tcp_seq startseq = tp->snd_nxt;
 
                /*
@@ -876,14 +880,14 @@ send:
                 * Initialize shift counter which is used for backoff
                 * of retransmit time.
                 */
-               if (!callout_active(tp->tt_rexmt) &&
+               if (!tcp_callout_active(tp, tp->tt_rexmt) &&
                    tp->snd_nxt != tp->snd_una) {
-                       if (callout_active(tp->tt_persist)) {
-                               callout_stop(tp->tt_persist);
+                       if (tcp_callout_active(tp, tp->tt_persist)) {
+                               tcp_callout_stop(tp, tp->tt_persist);
                                tp->t_rxtshift = 0;
                        }
-                       callout_reset(tp->tt_rexmt, tp->t_rxtcur,
-                                     tcp_timer_rexmt, tp);
+                       tcp_callout_reset(tp, tp->tt_rexmt, tp->t_rxtcur,
+                           tcp_timer_rexmt);
                }
        } else {
                /*
@@ -969,7 +973,7 @@ send:
                 * sequence number advance, if any.
                 */
                if (!(tp->t_flags & TF_FORCE) ||
-                   !callout_active(tp->tt_persist)) {
+                   !tcp_callout_active(tp, tp->tt_persist)) {
                        /*
                         * No need to check for TH_FIN here because
                         * the TF_SENTFIN flag handles that case.
@@ -985,8 +989,8 @@ out:
                         * to get us going again later.  Persist state
                         * is not necessarily right, but it is close enough.
                         */
-                       if (!callout_active(tp->tt_rexmt) &&
-                           !callout_active(tp->tt_persist)) {
+                       if (!tcp_callout_active(tp, tp->tt_rexmt) &&
+                           !tcp_callout_active(tp, tp->tt_persist)) {
                                tp->t_rxtshift = 0;
                                tcp_setpersist(tp);
                        }
@@ -1023,7 +1027,7 @@ out:
        tp->last_ack_sent = tp->rcv_nxt;
        tp->t_flags &= ~TF_ACKNOW;
        if (tcp_delack_enabled)
-               callout_stop(tp->tt_delack);
+               tcp_callout_stop(tp, tp->tt_delack);
        if (sendalot)
                goto again;
        return (0);
@@ -1035,14 +1039,14 @@ tcp_setpersist(struct tcpcb *tp)
        int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;
        int tt;
 
-       if (callout_active(tp->tt_rexmt))
+       if (tcp_callout_active(tp, tp->tt_rexmt))
                panic("tcp_setpersist: retransmit pending");
        /*
         * Start/restart persistance timer.
         */
        TCPT_RANGESET(tt, t * tcp_backoff[tp->t_rxtshift], TCPTV_PERSMIN,
                      TCPTV_PERSMAX);
-       callout_reset(tp->tt_persist, tt, tcp_timer_persist, tp);
+       tcp_callout_reset(tp, tp->tt_persist, tt, tcp_timer_persist);
        if (tp->t_rxtshift < TCP_MAXRXTSHIFT)
                tp->t_rxtshift++;
 }
index 00bd942..f8802e5 100644 (file)
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
 #include <netinet/tcp_timer.h>
+#include <netinet/tcp_timer2.h>
 #include <netinet/tcp_var.h>
 #include <netinet6/tcp6_var.h>
 #include <netinet/tcpip.h>
@@ -293,8 +294,11 @@ struct     inp_tp {
                char    align[(sizeof(struct inpcb) + ALIGNM1) & ~ALIGNM1];
        } inp_tp_u;
        struct  tcpcb tcb;
-       struct  callout inp_tp_rexmt, inp_tp_persist, inp_tp_keep, inp_tp_2msl;
-       struct  callout inp_tp_delack;
+       struct  tcp_callout inp_tp_rexmt;
+       struct  tcp_callout inp_tp_persist;
+       struct  tcp_callout inp_tp_keep;
+       struct  tcp_callout inp_tp_2msl;
+       struct  tcp_callout inp_tp_delack;
        struct  netmsg_tcp_timer inp_tp_timermsg;
 };
 #undef ALIGNMENT
@@ -700,11 +704,12 @@ tcp_newtcpcb(struct inpcb *inp)
        tp->t_maxseg = tp->t_maxopd = isipv6 ? tcp_v6mssdflt : tcp_mssdflt;
 
        /* Set up our timeouts. */
-       callout_init(tp->tt_rexmt = &it->inp_tp_rexmt);
-       callout_init(tp->tt_persist = &it->inp_tp_persist);
-       callout_init(tp->tt_keep = &it->inp_tp_keep);
-       callout_init(tp->tt_2msl = &it->inp_tp_2msl);
-       callout_init(tp->tt_delack = &it->inp_tp_delack);
+       tp->tt_rexmt = &it->inp_tp_rexmt;
+       tp->tt_persist = &it->inp_tp_persist;
+       tp->tt_keep = &it->inp_tp_keep;
+       tp->tt_2msl = &it->inp_tp_2msl;
+       tp->tt_delack = &it->inp_tp_delack;
+       tcp_inittimers(tp);
 
        tp->tt_msg = &it->inp_tp_timermsg;
        if (isipv6) {
@@ -858,11 +863,11 @@ tcp_close(struct tcpcb *tp)
         * Make sure that all of our timers are stopped before we
         * delete the PCB.
         */
-       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);
+       tcp_callout_stop(tp, tp->tt_rexmt);
+       tcp_callout_stop(tp, tp->tt_persist);
+       tcp_callout_stop(tp, tp->tt_keep);
+       tcp_callout_stop(tp, tp->tt_2msl);
+       tcp_callout_stop(tp, tp->tt_delack);
 
        if (tp->t_flags & TF_ONOUTPUTQ) {
                KKASSERT(tp->tt_cpu == mycpu->gd_cpuid);
index 0f7cd34..22f5f9f 100644 (file)
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
 #include <netinet/tcp_timer.h>
+#include <netinet/tcp_timer2.h>
 #include <netinet/tcp_var.h>
 #include <netinet6/tcp6_var.h>
 
@@ -792,7 +793,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
        if (sc->sc_rxtslot != 0)
                tp->snd_cwnd = tp->t_maxseg;
        tcp_create_timermsg(tp);
-       callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
+       tcp_callout_reset(tp, tp->tt_keep, tcp_keepinit, tcp_timer_keep);
 
        tcpstat.tcps_accepts++;
        return (so);
index b978388..a7944a5 100644 (file)
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
 #include <netinet/tcp_timer.h>
+#include <netinet/tcp_timer2.h>
 #include <netinet/tcp_var.h>
 #include <netinet/tcpip.h>
 #ifdef TCPDEBUG
@@ -124,8 +125,8 @@ static const struct tcp_timer {
        struct tcpcb    *(*tt_handler)(struct tcpcb *);
 } tcp_timer_handlers[] = {
        { TCP_TIMER_DELACK,     tcp_timer_delack_handler },
-       { TCP_TIMER_PERSIST,    tcp_timer_persist_handler },
        { TCP_TIMER_REXMT,      tcp_timer_rexmt_handler },
+       { TCP_TIMER_PERSIST,    tcp_timer_persist_handler },
        { TCP_TIMER_KEEP,       tcp_timer_keep_handler },
        { TCP_TIMER_2MSL,       tcp_timer_2msl_handler },
        { 0, NULL }
@@ -210,10 +211,10 @@ tcp_slowtimo(void)
 void
 tcp_canceltimers(struct tcpcb *tp)
 {
-       callout_stop(tp->tt_2msl);
-       callout_stop(tp->tt_persist);
-       callout_stop(tp->tt_keep);
-       callout_stop(tp->tt_rexmt);
+       tcp_callout_stop(tp, tp->tt_2msl);
+       tcp_callout_stop(tp, tp->tt_persist);
+       tcp_callout_stop(tp, tp->tt_keep);
+       tcp_callout_stop(tp, tp->tt_rexmt);
 }
 
 /*
@@ -257,13 +258,14 @@ void
 tcp_timer_delack(void *xtp)
 {
        struct tcpcb *tp = xtp;
+       struct callout *co = &tp->tt_delack->tc_callout;
 
        crit_enter();
-       if (callout_pending(tp->tt_delack) || !callout_active(tp->tt_delack)) {
+       if (callout_pending(co) || !callout_active(co)) {
                crit_exit();
                return;
        }
-       callout_deactivate(tp->tt_delack);
+       callout_deactivate(co);
        tcp_send_timermsg(tp, TCP_TIMER_DELACK);
        crit_exit();
 }
@@ -286,11 +288,12 @@ tcp_timer_2msl_handler(struct tcpcb *tp)
         * control block.  Otherwise, check again in a bit.
         */
        if (tp->t_state != TCPS_TIME_WAIT &&
-           (ticks - tp->t_rcvtime) <= tcp_maxidle)
-               callout_reset(tp->tt_2msl, tcp_keepintvl,
-                             tcp_timer_2msl, tp);
-       else
+           (ticks - tp->t_rcvtime) <= tcp_maxidle) {
+               tcp_callout_reset(tp, tp->tt_2msl, tcp_keepintvl,
+                                 tcp_timer_2msl);
+       } else {
                tp = tcp_close(tp);
+       }
 
 #ifdef TCPDEBUG
        if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
@@ -303,13 +306,14 @@ void
 tcp_timer_2msl(void *xtp)
 {
        struct tcpcb *tp = xtp;
+       struct callout *co = &tp->tt_2msl->tc_callout;
 
        crit_enter();
-       if (callout_pending(tp->tt_2msl) || !callout_active(tp->tt_2msl)) {
+       if (callout_pending(co) || !callout_active(co)) {
                crit_exit();
                return;
        }
-       callout_deactivate(tp->tt_2msl);
+       callout_deactivate(co);
        tcp_send_timermsg(tp, TCP_TIMER_2MSL);
        crit_exit();
 }
@@ -358,9 +362,12 @@ tcp_timer_keep_handler(struct tcpcb *tp)
                                    tp->rcv_nxt, tp->snd_una - 1, 0);
                        tcp_freetemplate(t_template);
                }
-               callout_reset(tp->tt_keep, tcp_keepintvl, tcp_timer_keep, tp);
-       } else
-               callout_reset(tp->tt_keep, tcp_keepidle, tcp_timer_keep, tp);
+               tcp_callout_reset(tp, tp->tt_keep, tcp_keepintvl,
+                                 tcp_timer_keep);
+       } else {
+               tcp_callout_reset(tp, tp->tt_keep, tcp_keepidle,
+                                 tcp_timer_keep);
+       }
 
 #ifdef TCPDEBUG
        if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
@@ -383,13 +390,14 @@ void
 tcp_timer_keep(void *xtp)
 {
        struct tcpcb *tp = xtp;
+       struct callout *co = &tp->tt_keep->tc_callout;
 
        crit_enter();
-       if (callout_pending(tp->tt_keep) || !callout_active(tp->tt_keep)) {
+       if (callout_pending(co) || !callout_active(co)) {
                crit_exit();
                return;
        }
-       callout_deactivate(tp->tt_keep);
+       callout_deactivate(co);
        tcp_send_timermsg(tp, TCP_TIMER_KEEP);
        crit_exit();
 }
@@ -441,13 +449,14 @@ void
 tcp_timer_persist(void *xtp)
 {
        struct tcpcb *tp = xtp;
+       struct callout *co = &tp->tt_persist->tc_callout;
 
        crit_enter();
-       if (callout_pending(tp->tt_persist) || !callout_active(tp->tt_persist)){
+       if (callout_pending(co) || !callout_active(co)){
                crit_exit();
                return;
        }
-       callout_deactivate(tp->tt_persist);
+       callout_deactivate(co);
        tcp_send_timermsg(tp, TCP_TIMER_PERSIST);
        crit_exit();
 }
@@ -629,13 +638,14 @@ void
 tcp_timer_rexmt(void *xtp)
 {
        struct tcpcb *tp = xtp;
+       struct callout *co = &tp->tt_rexmt->tc_callout;
 
        crit_enter();
-       if (callout_pending(tp->tt_rexmt) || !callout_active(tp->tt_rexmt)) {
+       if (callout_pending(co) || !callout_active(co)) {
                crit_exit();
                return;
        }
-       callout_deactivate(tp->tt_rexmt);
+       callout_deactivate(co);
        tcp_send_timermsg(tp, TCP_TIMER_REXMT);
        crit_exit();
 }
@@ -646,7 +656,6 @@ tcp_timer_handler(struct netmsg *nmsg)
        struct netmsg_tcp_timer *tmsg = (struct netmsg_tcp_timer *)nmsg;
        const struct tcp_timer *tt;
        struct tcpcb *tp;
-       uint32_t tasks;
 
        crit_enter();
 
@@ -654,22 +663,32 @@ tcp_timer_handler(struct netmsg *nmsg)
        tp = tmsg->tt_tcb;
 
        /* Save pending tasks and reset the tasks in message */
-       tasks = tmsg->tt_tasks;
+       tmsg->tt_running_tasks = tmsg->tt_tasks;
+       tmsg->tt_prev_tasks = tmsg->tt_tasks;
        tmsg->tt_tasks = 0;
 
        /* Reply ASAP */
        lwkt_replymsg(&tmsg->tt_nmsg.nm_lmsg, 0);
 
+       if (tmsg->tt_running_tasks == 0) {
+               /*
+                * All of the timers are cancelled when the message
+                * is pending; bail out.
+                */
+               crit_exit();
+               return;
+       }
+
        for (tt = tcp_timer_handlers; tt->tt_handler != NULL; ++tt) {
-               if ((tasks & tt->tt_task) == 0)
+               if ((tmsg->tt_running_tasks & tt->tt_task) == 0)
                        continue;
 
+               tmsg->tt_running_tasks &= ~tt->tt_task;
                tp = tt->tt_handler(tp);
                if (tp == NULL)
                        break;
 
-               tasks &= ~tt->tt_task;
-               if (tasks == 0) /* nothing left to do */
+               if (tmsg->tt_running_tasks == 0) /* nothing left to do */
                        break;
        }
 
@@ -708,3 +727,20 @@ tcp_destroy_timermsg(struct tcpcb *tp)
        }
        crit_exit();
 }
+
+static __inline void
+tcp_callout_init(struct tcp_callout *tc, uint32_t task)
+{
+       callout_init(&tc->tc_callout);
+       tc->tc_task = task;
+}
+
+void
+tcp_inittimers(struct tcpcb *tp)
+{
+       tcp_callout_init(tp->tt_rexmt, TCP_TIMER_REXMT);
+       tcp_callout_init(tp->tt_persist, TCP_TIMER_PERSIST);
+       tcp_callout_init(tp->tt_keep, TCP_TIMER_KEEP);
+       tcp_callout_init(tp->tt_2msl, TCP_TIMER_2MSL);
+       tcp_callout_init(tp->tt_delack, TCP_TIMER_DELACK);
+}
index 92dd1ba..bb2e78f 100644 (file)
@@ -134,8 +134,15 @@ struct tcpcb;
 struct netmsg_tcp_timer {
        struct netmsg   tt_nmsg;
        struct tcpcb    *tt_tcb;
-       int             tt_cpuid;
-       uint32_t        tt_tasks;
+       int             tt_cpuid;               /* owner cpuid */
+       uint32_t        tt_tasks;               /* pending tasks */
+       uint32_t        tt_running_tasks;       /* running tasks */
+       uint32_t        tt_prev_tasks;          /* prev pending tasks (debug) */
+};
+
+struct tcp_callout {
+       struct callout  tc_callout;
+       uint32_t        tc_task;                /* callout's task id */
 };
 
 extern int tcp_keepinit;               /* time to establish connection */
@@ -150,11 +157,12 @@ extern int tcp_msl;
 extern int tcp_ttl;                    /* time to live for TCP segs */
 extern int tcp_backoff[];
 
-void   tcp_timer_2msl (void *xtp);
-void   tcp_timer_keep (void *xtp);
-void   tcp_timer_persist (void *xtp);
-void   tcp_timer_rexmt (void *xtp);
-void   tcp_timer_delack (void *xtp);
+void   tcp_timer_2msl(void *xtp);
+void   tcp_timer_keep(void *xtp);
+void   tcp_timer_persist(void *xtp);
+void   tcp_timer_rexmt(void *xtp);
+void   tcp_timer_delack(void *xtp);
+void   tcp_inittimers(struct tcpcb *);
 
 void   tcp_create_timermsg(struct tcpcb *);
 void   tcp_destroy_timermsg(struct tcpcb *);
diff --git a/sys/netinet/tcp_timer2.h b/sys/netinet/tcp_timer2.h
new file mode 100644 (file)
index 0000000..ad2ce4c
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93
+ * $FreeBSD: src/sys/netinet/tcp_timer.h,v 1.18.2.1 2002/08/16 22:16:39 dillon Exp $
+ * $DragonFly: src/sys/netinet/tcp_timer.h,v 1.3 2003/08/23 11:18:00 rob Exp $
+ */
+
+#ifndef _NETINET_TCP_TIMER2_H_
+#define _NETINET_TCP_TIMER2_H_
+
+#ifdef _KERNEL
+
+#ifndef _SYS_THREAD2_H_
+#include <sys/thread2.h>
+#endif
+
+#ifndef _SYS_CALLOUT_H_
+#include <sys/callout.h>
+#endif
+
+#ifndef _NETINET_TCP_VAR_H_
+#include <netinet/tcp_var.h>
+#endif
+
+#ifndef _NETINET_TCP_TIMER_H_
+#include <netinet/tcp_timer.h>
+#endif
+
+static __inline void
+tcp_callout_stop(struct tcpcb *_tp, struct tcp_callout *_tc)
+{
+       crit_enter();
+       callout_stop(&_tc->tc_callout);
+       if (_tp->tt_msg != NULL) {
+               _tp->tt_msg->tt_tasks &= ~_tc->tc_task;
+               _tp->tt_msg->tt_running_tasks &= ~_tc->tc_task;
+       }
+       crit_exit();
+}
+
+static __inline void
+tcp_callout_reset(struct tcpcb *_tp, struct tcp_callout *_tc, int _to_ticks,
+                 void (*_func)(void *))
+{
+       crit_enter();
+       callout_reset(&_tc->tc_callout, _to_ticks, _func, _tp);
+       if (_tp->tt_msg != NULL) {
+               _tp->tt_msg->tt_tasks &= ~_tc->tc_task;
+               _tp->tt_msg->tt_running_tasks &= ~_tc->tc_task;
+       }
+       crit_exit();
+}
+
+static __inline int
+tcp_callout_active(struct tcpcb *_tp, struct tcp_callout *_tc)
+{
+       int _act;
+
+       crit_enter();
+       _act = callout_active(&_tc->tc_callout);
+       if (!_act && _tp->tt_msg != NULL) {
+               _act = (_tp->tt_msg->tt_tasks |
+                       _tp->tt_msg->tt_running_tasks) & _tc->tc_task;
+       }
+       crit_exit();
+       return _act;
+}
+
+static __inline int
+tcp_callout_pending(struct tcpcb *_tp __unused, struct tcp_callout *_tc)
+{
+       return callout_pending(&_tc->tc_callout);
+}
+
+#endif /* !_KERNEL */
+
+#endif /* _NETINET_TCP_TIMER2_H_ */
index 89a7b93..1acefbc 100644 (file)
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
 #include <netinet/tcp_timer.h>
+#include <netinet/tcp_timer2.h>
 #include <netinet/tcp_var.h>
 #include <netinet/tcpip.h>
 #ifdef TCPDEBUG
@@ -937,7 +938,7 @@ tcp_connect_oncpu(struct tcpcb *tp, struct sockaddr_in *sin,
        soisconnecting(so);
        tcpstat.tcps_connattempt++;
        tp->t_state = TCPS_SYN_SENT;
-       callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
+       tcp_callout_reset(tp, tp->tt_keep, tcp_keepinit, tcp_timer_keep);
        tp->iss = tcp_new_isn(tp);
        tcp_sendseqinit(tp);
 
@@ -1108,7 +1109,7 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
        soisconnecting(so);
        tcpstat.tcps_connattempt++;
        tp->t_state = TCPS_SYN_SENT;
-       callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp);
+       tcp_callout_reset(tp, tp->tt_keep, tcp_keepinit, tcp_timer_keep);
        tp->iss = tcp_new_isn(tp);
        tcp_sendseqinit(tp);
 
@@ -1375,9 +1376,10 @@ tcp_usrclosed(struct tcpcb *tp)
        if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
                soisdisconnected(tp->t_inpcb->inp_socket);
                /* To prevent the connection hanging in FIN_WAIT_2 forever. */
-               if (tp->t_state == TCPS_FIN_WAIT_2)
-                       callout_reset(tp->tt_2msl, tcp_maxidle,
-                                     tcp_timer_2msl, tp);
+               if (tp->t_state == TCPS_FIN_WAIT_2) {
+                       tcp_callout_reset(tp, tp->tt_2msl, tcp_maxidle,
+                           tcp_timer_2msl);
+               }
        }
        return (tp);
 }
index 00defcd..4cb7894 100644 (file)
@@ -137,11 +137,11 @@ struct tcpcb {
        int     t_dupacks;              /* consecutive dup acks recd */
        int     tt_cpu;                 /* sanity check the cpu */
 
-       struct  callout *tt_rexmt;      /* retransmit timer */
-       struct  callout *tt_persist;    /* retransmit persistence */
-       struct  callout *tt_keep;       /* keepalive */
-       struct  callout *tt_2msl;       /* 2*msl TIME_WAIT timer */
-       struct  callout *tt_delack;     /* delayed ACK timer */
+       struct  tcp_callout *tt_rexmt;  /* retransmit timer */
+       struct  tcp_callout *tt_persist;/* retransmit persistence */
+       struct  tcp_callout *tt_keep;   /* keepalive */
+       struct  tcp_callout *tt_2msl;   /* 2*msl TIME_WAIT timer */
+       struct  tcp_callout *tt_delack; /* delayed ACK timer */
        struct  netmsg_tcp_timer *tt_msg; /* timer message */
 
        struct  inpcb *t_inpcb;         /* back pointer to internet pcb */