tcp: Allow pure asynchronized pru_send
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 3 Nov 2011 13:38:49 +0000 (21:38 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 3 Nov 2011 13:38:49 +0000 (21:38 +0800)
- net.inet.tcp.sosnd_async is added to allow pure asynchronized pru_send.
  It is default to off currently.
- To prevent soclose() and soshutdown() from interfering TCP processing on
  the loopback interface, so_pru_sync() is added, which will make sure
  that so_pru_disconnect() and so_pru_shutdown() run only after all of the
  previous sent packets had been requeued to netisr (the semantics of the
  original half asynchronized pru_send).

sys/kern/uipc_msg.c
sys/kern/uipc_socket.c
sys/netinet/tcp_input.c
sys/sys/socketops.h

index 791c42b..ea0e700 100644 (file)
@@ -317,6 +317,22 @@ so_pru_send(struct socket *so, int flags, struct mbuf *m,
        return (error);
 }
 
+static void
+so_pru_sync_handler(netmsg_t msg)
+{
+       lwkt_replymsg(&msg->lmsg, 0);
+}
+
+void
+so_pru_sync(struct socket *so)
+{
+       struct netmsg_base msg;
+
+       netmsg_init(&msg, so, &curthread->td_msgport, 0,
+           so_pru_sync_handler);
+       lwkt_domsg(so->so_port, &msg.lmsg, 0);
+}
+
 void
 so_pru_send_async(struct socket *so, int flags, struct mbuf *m,
            struct sockaddr *addr, struct mbuf *control, struct thread *td)
index 013e464..6fa618a 100644 (file)
@@ -98,6 +98,7 @@
 #include <machine/limits.h>
 
 extern int tcp_sosnd_agglim;
+extern int tcp_sosnd_async;
 
 #ifdef INET
 static int      do_setopt_accept_filter(struct socket *so, struct sockopt *sopt);
@@ -390,6 +391,7 @@ soclose(struct socket *so, int fflag)
        if (so->so_pcb == NULL)
                goto discard;
        if (so->so_state & SS_ISCONNECTED) {
+               so_pru_sync(so);
                if ((so->so_state & SS_ISDISCONNECTING) == 0) {
                        error = sodisconnect(so);
                        if (error)
@@ -910,7 +912,7 @@ restart:
                }
                mp = &top;
                do {
-                   int cnt = 0;
+                   int cnt = 0, async = 0;
 
                    if (uio == NULL) {
                        /*
@@ -946,8 +948,11 @@ restart:
                    } else if (resid > 0 && space > 0) {
                            /* If there is more to send, set PRUS_MORETOCOME */
                            pru_flags = PRUS_MORETOCOME;
+                           async = 1;
                    } else {
                            pru_flags = 0;
+                           if (tcp_sosnd_async)
+                               async = 1;
                    }
 
                    /*
@@ -959,8 +964,7 @@ restart:
                     * here, but there are probably other places that this
                     * also happens.  We must rethink this.
                     */
-                   if ((pru_flags & PRUS_OOB) ||
-                       (pru_flags & PRUS_MORETOCOME) == 0) {
+                   if (!async) {
                            error = so_pru_send(so, pru_flags, top,
                                NULL, NULL, td);
                    } else {
@@ -1369,8 +1373,10 @@ soshutdown(struct socket *so, int how)
                sorflush(so);
                /*ssb_unlock(&so->so_rcv);*/
        }
-       if (how != SHUT_RD)
+       if (how != SHUT_RD) {
+               so_pru_sync(so);
                return (so_pru_shutdown(so));
+       }
        return (0);
 }
 
index 7bb4d5f..ead3b61 100644 (file)
@@ -231,6 +231,10 @@ int tcp_sosnd_agglim = 2;
 SYSCTL_INT(_net_inet_tcp, OID_AUTO, sosnd_agglim, CTLFLAG_RW,
     &tcp_sosnd_agglim, 0, "TCP sosend mbuf aggregation limit");
 
+int tcp_sosnd_async = 0;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, sosnd_async, CTLFLAG_RW,
+    &tcp_sosnd_async, 0, "TCP asynchronized pru_send");
+
 static void     tcp_dooptions(struct tcpopt *, u_char *, int, boolean_t);
 static void     tcp_pulloutofband(struct socket *,
                     struct tcphdr *, struct mbuf *, int);
index 2274435..6159c8d 100644 (file)
@@ -92,6 +92,7 @@ int so_pru_listen (struct socket *so, struct thread *td);
 int so_pru_peeraddr (struct socket *so, struct sockaddr **nam);
 int so_pru_rcvd (struct socket *so, int flags);
 int so_pru_rcvoob (struct socket *so, struct mbuf *m, int flags);
+void so_pru_sync (struct socket *so);
 int so_pru_send (struct socket *so, int flags, struct mbuf *m,
                struct sockaddr *addr, struct mbuf *control,
                struct thread *td);