]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/commitdiff
task #10167 (sockets: speed up TCP recv by not allocating a netbuf): added function...
authorgoldsimon <goldsimon>
Sat, 6 Mar 2010 11:29:01 +0000 (11:29 +0000)
committergoldsimon <goldsimon>
Sat, 6 Mar 2010 11:29:01 +0000 (11:29 +0000)
CHANGELOG
src/api/api_lib.c
src/api/sockets.c
src/include/lwip/api.h

index d528ef86b0b4e588d9490ba9cfbd5076eb18ec4e..6e3d1b4395aa27fd59899316465a7c005597a446 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -13,6 +13,12 @@ HISTORY
 
   ++ New features:
 
+  2010-03-06: Simon Goldschmidt
+  * api.h, api_lib.c, sockets.c: task #10167 (sockets: speed up TCP recv
+    by not allocating a netbuf): added function netconn_recv_tcp_pbuf()
+    for tcp netconns to receive pbufs, not netbufs; use that function
+    for tcp sockets.
+
   2010-03-05: Jakob Ole Stoklundsen / Simon Goldschmidt
   * opt.h, tcp.h, tcp_impl.h, tcp.c, tcp_in.c, tcp_out.c: task #7040:
     Work on tcp_enqueue: Don't waste memory when chaining segments,
index 01fdae4a60fd9e939278d8e3e71981675407afdf..25106d60339ba09dd336d7e0260f99ffdbca3681 100644 (file)
@@ -316,19 +316,19 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
 }
 
 /**
- * Receive data (in form of a netbuf containing a packet buffer) from a netconn
+ * Receive data: actual implementation that doesn't care whether pbuf or netbuf
+ * is received
  *
  * @param conn the netconn from which to receive data
- * @param new_buf pointer where a new netbuf is stored when received data
+ * @param new_buf pointer where a new pbuf/netbuf is stored when received data
  * @return ERR_OK if data has been received, an error code otherwise (timeout,
  *                memory error or another error)
  */
-err_t
-netconn_recv(struct netconn *conn, struct netbuf **new_buf)
+static err_t
+netconn_recv_data(struct netconn *conn, void **new_buf)
 {
   struct api_msg msg;
-  struct netbuf *buf = NULL;
-  struct pbuf *p;
+  void *buf = NULL;
   u16_t len;
   err_t err;
 
@@ -346,50 +346,17 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
     return err;
   }
 
-  if (conn->type == NETCONN_TCP) {
-#if LWIP_TCP
-    /* This is not a listening netconn, since recvmbox is set */
-
-    buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
-    if (buf == NULL) {
-      NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
-      return ERR_MEM;
-    }
-
 #if LWIP_SO_RCVTIMEO
-    if (sys_arch_mbox_fetch(&conn->recvmbox, (void **)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
-      memp_free(MEMP_NETBUF, buf);
-      NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
-      return ERR_TIMEOUT;
-    }
+  if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
+    NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
+    return ERR_TIMEOUT;
+  }
 #else
-    sys_arch_mbox_fetch(&conn->recvmbox, (void **)&p, 0);
+  sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
 #endif /* LWIP_SO_RCVTIMEO*/
 
-    if (p != NULL) {
-      len = p->tot_len;
-      SYS_ARCH_DEC(conn->recv_avail, len);
-    } else {
-      /* This means the connection has been closed */ 
-      len = 0;
-    }
-
-    /* Register event with callback */
-    API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
-
-    /* If we are closed, we indicate that we no longer wish to use the socket */
-    if (p == NULL) {
-      memp_free(MEMP_NETBUF, buf);
-      /* Avoid to lose any previous error code */
-      NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
-      return ERR_CLSD;
-    }
-
-    buf->p = p;
-    buf->ptr = p;
-    buf->port = 0;
-    buf->addr = NULL;
-
+#if LWIP_TCP
+  if (conn->type == NETCONN_TCP) {
     if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
       /* Let the stack know that we have taken the data. */
       /* TODO: Speedup: Don't block and wait for the answer here
@@ -397,40 +364,115 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
       msg.function = do_recv;
       msg.msg.conn = conn;
       if (buf != NULL) {
-        msg.msg.msg.r.len = buf->p->tot_len;
+        msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
       } else {
         msg.msg.msg.r.len = 1;
       }
       /* don't care for the return value of do_recv */
       TCPIP_APIMSG(&msg);
     }
+
+    /* If we are closed, we indicate that we no longer wish to use the socket */
+    if (buf == NULL) {
+      API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
+      /* Avoid to lose any previous error code */
+      NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
+      return ERR_CLSD;
+    }
+    len = ((struct pbuf *)buf)->tot_len;
+  }
 #endif /* LWIP_TCP */
-  } else {
+#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
+  else
+#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
 #if (LWIP_UDP || LWIP_RAW)
-#if LWIP_SO_RCVTIMEO
-    if (sys_arch_mbox_fetch(&conn->recvmbox, (void **)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
-      NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
-      return ERR_TIMEOUT;
-    }
-#else
-    sys_arch_mbox_fetch(&conn->recvmbox, (void **)&buf, 0);
-#endif /* LWIP_SO_RCVTIMEO*/
+  {
     LWIP_ASSERT("buf != NULL", buf != NULL);
-
-    SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len);
-    /* Register event with callback */
-    API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
-#endif /* (LWIP_UDP || LWIP_RAW) */
+    len = netbuf_len((struct netbuf *)buf);
   }
-  LWIP_ASSERT("buf != NULL", buf != NULL);
+#endif /* (LWIP_UDP || LWIP_RAW) */
+
+  SYS_ARCH_DEC(conn->recv_avail, len);
+  /* Register event with callback */
+  API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
 
-  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p\n", (void *)buf));
+  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
 
   *new_buf = buf;
   /* don't set conn->last_err: it's only ERR_OK, anyway */
   return ERR_OK;
 }
 
+/**
+ * Receive data (in form of a pbuf) from a TCP netconn
+ *
+ * @param conn the netconn from which to receive data
+ * @param new_buf pointer where a new pbuf is stored when received data
+ * @return ERR_OK if data has been received, an error code otherwise (timeout,
+ *                memory error or another error)
+ *         ERR_ARG if conn is not a TCP netconn
+ */
+err_t
+netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
+{
+  LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
+             netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
+
+  return netconn_recv_data(conn, new_buf);
+}
+
+/**
+ * Receive data (in form of a netbuf containing a packet buffer) from a netconn
+ *
+ * @param conn the netconn from which to receive data
+ * @param new_buf pointer where a new netbuf is stored when received data
+ * @return ERR_OK if data has been received, an error code otherwise (timeout,
+ *                memory error or another error)
+ */
+err_t
+netconn_recv(struct netconn *conn, struct netbuf **new_buf)
+{
+  struct netbuf *buf = NULL;
+  err_t err;
+
+  LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
+  *new_buf = NULL;
+  LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
+  LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
+
+  if (conn->type == NETCONN_TCP) {
+#if LWIP_TCP
+    struct pbuf *p = NULL;
+    /* This is not a listening netconn, since recvmbox is set */
+
+    buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
+    if (buf == NULL) {
+      NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
+      return ERR_MEM;
+    }
+
+    err = netconn_recv_data(conn, &p);
+    if (err != ERR_OK) {
+      memp_free(MEMP_NETBUF, buf);
+      return err;
+    }
+    LWIP_ASSERT("p != NULL", p != NULL);
+
+    buf->p = p;
+    buf->ptr = p;
+    buf->port = 0;
+    buf->addr = NULL;
+    *new_buf = buf;
+    /* don't set conn->last_err: it's only ERR_OK, anyway */
+    return ERR_OK;
+#endif /* LWIP_TCP */
+  } else {
+#if (LWIP_UDP || LWIP_RAW)
+    return netconn_recv_data(conn, new_buf);
+#endif /* (LWIP_UDP || LWIP_RAW) */
+  }
+}
+
 /**
  * TCP: update the receive window: by calling this, the application
  * tells the stack that it has processed data and is able to accept
index 81a8e63d428132ab728d1634d49c084726e9e19d..a988727ccf69e3fe42987a3058b33d82302a5b0c 100644 (file)
@@ -51,6 +51,7 @@
 #include "lwip/raw.h"
 #include "lwip/udp.h"
 #include "lwip/tcpip.h"
+#include "lwip/pbuf.h"
 
 #include <string.h>
 
@@ -61,7 +62,7 @@ struct lwip_sock {
   /** sockets currently are built on netconns, each socket has one netconn */
   struct netconn *conn;
   /** data that was left from the previous read */
-  struct netbuf *lastdata;
+  void *lastdata;
   /** offset in the data that was left from the previous read */
   u16_t lastoffset;
   /** number of times data was received, set by event_callback(),
@@ -248,11 +249,12 @@ alloc_socket(struct netconn *newconn, int accepted)
  * delete before!
  *
  * @param sock the socket to free
+ * @param is_tcp != 0 for TCP sockets, used to free lastdata
  */
 static void
-free_socket(struct lwip_sock *sock)
+free_socket(struct lwip_sock *sock, int is_tcp)
 {
-  struct netbuf *lastdata;
+  void *lastdata;
   SYS_ARCH_DECL_PROTECT(lev);
 
   lastdata         = sock->lastdata;
@@ -266,7 +268,11 @@ free_socket(struct lwip_sock *sock)
   SYS_ARCH_UNPROTECT(lev);
 
   if (lastdata != NULL) {
-    netbuf_delete(lastdata);
+    if (is_tcp) {
+      pbuf_free((struct pbuf *)lastdata);
+    } else {
+      netbuf_delete((struct netbuf *)lastdata);
+    }
   }
 }
 
@@ -404,6 +410,7 @@ int
 lwip_close(int s)
 {
   struct lwip_sock *sock;
+  int is_tcp = 0;
 
   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
 
@@ -412,9 +419,15 @@ lwip_close(int s)
     return -1;
   }
 
+  if(sock->conn != NULL) {
+    is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
+  } else {
+    LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
+  }
+
   netconn_delete(sock->conn);
 
-  free_socket(sock);
+  free_socket(sock, is_tcp);
   set_errno(0);
   return 0;
 }
@@ -501,13 +514,14 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
         struct sockaddr *from, socklen_t *fromlen)
 {
   struct lwip_sock *sock;
-  struct netbuf      *buf;
-  u16_t               buflen, copylen;
-  int                 off = 0;
-  ip_addr_t          *addr;
-  u16_t               port;
-  u8_t                done = 0;
-  err_t               err;
+  void             *buf = NULL;
+  struct pbuf      *p;
+  u16_t            buflen, copylen;
+  int              off = 0;
+  ip_addr_t        *addr;
+  u16_t            port;
+  u8_t             done = 0;
+  err_t            err;
 
   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
   sock = get_socket(s);
@@ -515,7 +529,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
     return -1;
 
   do {
-    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata));
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
     /* Check if there is data left from the last recv operation. */
     if (sock->lastdata) {
       buf = sock->lastdata;
@@ -537,9 +551,13 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
 
       /* No data was left from the previous operation, so we try to get
          some from the network. */
-      err = netconn_recv(sock->conn, &buf);
+      if (netconn_type(sock->conn) == NETCONN_TCP) {
+        err = netconn_recv_tcp_pbuf(sock->conn, &(struct pbuf *)buf);
+      } else {
+        err = netconn_recv(sock->conn, &(struct netbuf *)buf);
+      }
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
-        err, (void*)buf));
+        err, buf));
 
       if (err != ERR_OK) {
         if (off > 0) {
@@ -563,7 +581,12 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
       sock->lastdata = buf;
     }
 
-    buflen = netbuf_len(buf);
+    if (netconn_type(sock->conn) == NETCONN_TCP) {
+      p = (struct pbuf *)buf;
+    } else {
+      p = ((struct netbuf *)buf)->p;
+    }
+    buflen = p->tot_len;
     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
       buflen, len, off, sock->lastoffset));
 
@@ -577,7 +600,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
 
     /* copy the contents of the received buffer into
     the supplied memory pointer mem */
-    netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset);
+    pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
 
     off += copylen;
 
@@ -585,7 +608,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
       LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
       len -= copylen;
       if ( (len <= 0) || 
-           (buf->p->flags & PBUF_FLAG_PUSH) || 
+           (p->flags & PBUF_FLAG_PUSH) || 
            (sock->rcvevent <= 0) || 
            ((flags & MSG_PEEK)!=0)) {
         done = 1;
@@ -604,8 +627,8 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
           addr = &fromaddr;
           netconn_getaddr(sock->conn, addr, &port, 0);
         } else {
-          addr = netbuf_fromaddr(buf);
-          port = netbuf_fromport(buf);
+          addr = netbuf_fromaddr((struct netbuf *)buf);
+          port = netbuf_fromport((struct netbuf *)buf);
         }
 
         memset(&sin, 0, sizeof(sin));
@@ -629,8 +652,8 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
           addr = &fromaddr;
           netconn_getaddr(sock->conn, addr, &port, 0);
         } else {
-          addr = netbuf_fromaddr(buf);
-          port = netbuf_fromport(buf);
+          addr = netbuf_fromaddr((struct netbuf *)buf);
+          port = netbuf_fromport((struct netbuf *)buf);
         }
 
         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
@@ -648,12 +671,16 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
       if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
         sock->lastdata = buf;
         sock->lastoffset += copylen;
-        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf));
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
       } else {
         sock->lastdata = NULL;
         sock->lastoffset = 0;
-        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf));
-        netbuf_delete(buf);
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
+        if (netconn_type(sock->conn) == NETCONN_TCP) {
+          pbuf_free((struct pbuf *)buf);
+        } else {
+          netbuf_delete((struct netbuf *)buf);
+        }
       }
     }
   } while (!done);
@@ -2031,7 +2058,11 @@ lwip_ioctl(int s, long cmd, void *argp)
 
     /* Check if there is data left from the last recv operation. /maq 041215 */
     if (sock->lastdata) {
-      buflen = netbuf_len(sock->lastdata);
+      struct pbuf *p = (struct pbuf *)sock->lastdata;
+      if (netconn_type(sock->conn) != NETCONN_TCP) {
+        p = ((struct netbuf *)p)->p;
+      }
+      buflen = p->tot_len;
       buflen -= sock->lastoffset;
 
       *((u16_t*)argp) += buflen;
index 27aa41ece366a3b7a48be62a3bcd62c9411758cb..5065d31ca9f3d57eb0ce24a3e0ac33892f2f7e01 100644 (file)
@@ -224,6 +224,7 @@ err_t   netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
 #define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
 err_t   netconn_accept(struct netconn *conn, struct netconn **new_conn);
 err_t   netconn_recv(struct netconn *conn, struct netbuf **new_buf);
+err_t   netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf);
 void    netconn_recved(struct netconn *conn, u32_t length);
 err_t   netconn_sendto(struct netconn *conn, struct netbuf *buf,
                        ip_addr_t *addr, u16_t port);