mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-11-17 17:10:03 +00:00
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.
This commit is contained in:
parent
957f4d8096
commit
38fcfcdfac
@ -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,
|
||||
|
@ -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,8 +346,103 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
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, &buf, 0);
|
||||
#endif /* LWIP_SO_RCVTIMEO*/
|
||||
|
||||
#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
|
||||
(to prevent multiple thread-switches). */
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
if (buf != NULL) {
|
||||
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 */
|
||||
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
|
||||
else
|
||||
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
|
||||
#if (LWIP_UDP || LWIP_RAW)
|
||||
{
|
||||
LWIP_ASSERT("buf != NULL", buf != NULL);
|
||||
len = netbuf_len((struct netbuf *)buf);
|
||||
}
|
||||
#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_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);
|
||||
@ -356,79 +451,26 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if (sys_arch_mbox_fetch(&conn->recvmbox, (void **)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
|
||||
err = netconn_recv_data(conn, &p);
|
||||
if (err != ERR_OK) {
|
||||
memp_free(MEMP_NETBUF, buf);
|
||||
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
#else
|
||||
sys_arch_mbox_fetch(&conn->recvmbox, (void **)&p, 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;
|
||||
return err;
|
||||
}
|
||||
LWIP_ASSERT("p != NULL", p != NULL);
|
||||
|
||||
buf->p = p;
|
||||
buf->ptr = p;
|
||||
buf->port = 0;
|
||||
buf->addr = NULL;
|
||||
|
||||
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
|
||||
(to prevent multiple thread-switches). */
|
||||
msg.function = do_recv;
|
||||
msg.msg.conn = conn;
|
||||
if (buf != NULL) {
|
||||
msg.msg.msg.r.len = buf->p->tot_len;
|
||||
} else {
|
||||
msg.msg.msg.r.len = 1;
|
||||
}
|
||||
/* don't care for the return value of do_recv */
|
||||
TCPIP_APIMSG(&msg);
|
||||
}
|
||||
*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)
|
||||
#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);
|
||||
return netconn_recv_data(conn, new_buf);
|
||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
||||
}
|
||||
LWIP_ASSERT("buf != NULL", buf != NULL);
|
||||
|
||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p\n", (void *)buf));
|
||||
|
||||
*new_buf = buf;
|
||||
/* don't set conn->last_err: it's only ERR_OK, anyway */
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user