First cut at conversion of write-buffering to use I/O buffer chaings (IOBs)

This commit is contained in:
Gregory Nutt
2014-06-22 11:27:57 -06:00
parent 7e83501ce5
commit 356d25b503
27 changed files with 1083 additions and 234 deletions
+27 -3
View File
@@ -55,10 +55,12 @@
#define IOB_DATA(p) (&(p)->io_data[(p)->io_offset])
#define IOB_FREESPACE(p) (CONFIG_IOB_BUFSIZE - (p)->io_len - (p)->io_offset)
#if CONFIG_IOB_NCHAINS > 0
/* Queue helpers */
#define IOB_QINIT(q) do { (q)->qh_head = 0; (q)->qh_tail = 0; } while (0)
#define IOB_QEMPTY(q) ((q)->head == NULL)
# define IOB_QINIT(q) do { (q)->qh_head = 0; (q)->qh_tail = 0; } while (0)
# define IOB_QEMPTY(q) ((q)->head == NULL)
#endif
/****************************************************************************
* Public Types
@@ -89,6 +91,7 @@ struct iob_s
uint8_t io_data[CONFIG_IOB_BUFSIZE];
};
#if CONFIG_IOB_NCHAINS > 0
/* This container structure supports queuing of I/O buffer chains. This
* structure is intended only for internal use by the IOB module.
*/
@@ -113,6 +116,7 @@ struct iob_queue_s
FAR struct iob_qentry_s *qh_head;
FAR struct iob_qentry_s *qh_tail;
};
#endif /* CONFIG_IOB_NCHAINS > 0 */
/****************************************************************************
* Global Data
@@ -173,7 +177,9 @@ void iob_free_chain(FAR struct iob_s *iob);
*
****************************************************************************/
#if CONFIG_IOB_NCHAINS > 0
int iob_add_queue(FAR struct iob_s *iob, FAR struct iob_queue_s *iobq);
#endif /* CONFIG_IOB_NCHAINS > 0 */
/****************************************************************************
* Name: iob_add_queue
@@ -183,7 +189,9 @@ int iob_add_queue(FAR struct iob_s *iob, FAR struct iob_queue_s *iobq);
*
****************************************************************************/
#if CONFIG_IOB_NCHAINS > 0
FAR struct iob_s *iob_remove_queue(FAR struct iob_queue_s *iobq);
#endif /* CONFIG_IOB_NCHAINS > 0 */
/****************************************************************************
* Name: iob_free_queue
@@ -193,7 +201,9 @@ FAR struct iob_s *iob_remove_queue(FAR struct iob_queue_s *iobq);
*
****************************************************************************/
#if CONFIG_IOB_NCHAINS > 0
void iob_free_queue(FAR struct iob_queue_s *qhead);
#endif /* CONFIG_IOB_NCHAINS > 0 */
/****************************************************************************
* Name: iob_copyin
@@ -278,11 +288,25 @@ FAR struct iob_s *iob_pack(FAR struct iob_s *iob);
* Name: iob_contig
*
* Description:
* Ensure that there is'len' bytes of contiguous space at the beginning
* Ensure that there is 'len' bytes of contiguous space at the beginning
* of the I/O buffer chain starting at 'iob'.
*
****************************************************************************/
int iob_contig(FAR struct iob_s *iob, unsigned int len);
/****************************************************************************
* Function: iob_dump
*
* Description:
* Dump the contents of a I/O buffer chain
*
****************************************************************************/
#ifdef CONFIG_DEBUG
void iob_dump(FAR const char *msg, FAR struct iob_s *iob);
#else
# define tcp_writebuffer_dump(wrb)
#endif
#endif /* _INCLUDE_NUTTX_NET_IOB_H */
+34 -7
View File
@@ -56,6 +56,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/net/uip/uipopt.h>
#include <nuttx/net/uip/uip.h>
/****************************************************************************
* Pre-processor Definitions
@@ -123,6 +124,25 @@
# define UIP_TCP_INITIAL_MSS UIP_TCP_MSS
#endif
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* TCP write buffer access macros */
# define WRB_SEQNO(wrb) ((wrb)->wb_seqno)
# define WRB_PKTLEN(wrb) ((wrb)->wb_iob->io_pktlen)
# define WRB_SENT(wrb) ((wrb)->wb_sent)
# define WRB_NRTX(wrb) ((wrb)->wb_nrtx)
# define WRB_IOB(wrb) ((wrb)->wb_iob)
# define WRB_COPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0))
# define WRB_COPYIN(wrb,src,n) (iob_copyin((wrb)->wb_iob,src,(n),0))
# define WRB_TRIM(wrb,n) (iob_trimhead((wrb)->wb_iob,(n)))
#ifdef CONFIG_DEBUG
# define WRB_DUMP(msg,wrb) tcp_writebuffer_dump(msg,wrb)
#else
# define WRB_DUMP(mgs,wrb)
#endif
#endif
/****************************************************************************
* Public Type Definitions
****************************************************************************/
@@ -170,22 +190,28 @@ struct uip_conn
/* Read-ahead buffering.
*
* readahead - A singly linked list of type struct uip_readahead_s
* where the TCP/IP read-ahead data is retained.
* readahead - A singly linked list of type struct uip_readahead_s
* where the TCP/IP read-ahead data is retained.
*/
#ifdef CONFIG_NET_TCP_READAHEAD
sq_queue_t readahead; /* Read-ahead buffering */
#endif
/* Write buffering */
/* Write buffering
*
* write_q - The queue of unsent I/O buffers. The head of this
* list may be partially sent. FIFO ordering.
* unacked_q - A queue of completely sent, but unacked I/O buffer
* chains. Sequence number ordering.
*/
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
sq_queue_t write_q; /* Write buffering for segments */
sq_queue_t unacked_q; /* Write buffering for un-ACKed segments */
size_t expired; /* Number segments retransmitted but not yet ACKed,
uint16_t expired; /* Number segments retransmitted but not yet ACKed,
* it can only be updated at UIP_ESTABLISHED state */
size_t sent; /* The number of bytes sent */
uint16_t sent; /* The number of bytes sent */
uint32_t isn; /* Initial sequence number */
#endif
@@ -261,14 +287,15 @@ struct uip_readahead_s
/* This structure supports TCP write buffering */
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
struct iob_s; /* Forward reference */
struct tcp_wrbuffer_s
{
sq_entry_t wb_node; /* Supports a singly linked list */
uint32_t wb_seqno; /* Sequence number of the write segment */
uint16_t wb_nbytes; /* Number of bytes available in this buffer */
uint16_t wb_sent; /* Number of bytes sent from the I/O buffer chain */
uint8_t wb_nrtx; /* The number of retransmissions for the last
* segment sent */
uint8_t wb_buffer[CONFIG_NET_TCP_WRITE_BUFSIZE];
struct iob_s *wb_iob; /* Head of the I/O buffer chain */
};
#endif
+8 -1
View File
@@ -391,7 +391,14 @@ extern int uip_lockedwait(sem_t *sem);
* len The maximum amount of data bytes to be sent.
*/
extern void uip_send(struct uip_driver_s *dev, const void *buf, int len);
extern void uip_send(FAR struct uip_driver_s *dev, FAR const void *buf,
int len);
#ifdef CONFIG_NET_IOB
struct iob_s;
extern void uip_iobsend(FAR struct uip_driver_s *dev, FAR struct iob_s *buf,
unsigned int len, unsigned int offset);
#endif
/* uIP convenience and converting functions.
*
-24
View File
@@ -305,30 +305,6 @@
# undef CONFIG_NET_NTCP_READAHEAD_BUFFERS
#endif
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* Number of TCP write buffers */
# ifndef CONFIG_NET_NTCP_WRITE_BUFFERS
# define CONFIG_NET_NTCP_WRITE_BUFFERS 1
# endif
/* The size of one TCP write buffer */
# ifndef CONFIG_NET_TCP_WRITE_BUFSIZE
# define CONFIG_NET_TCP_WRITE_BUFSIZE UIP_TCP_MSS
# endif
/* The size of the write buffer should not exceed the maximum TCP MSS */
# if CONFIG_NET_TCP_WRITE_BUFSIZE > UIP_TCP_MSS
# error CONFIG_NET_TCP_WRITE_BUFSIZE must not exceed UIP_TCP_MSS
# endif
#else
# undef CONFIG_NET_TCP_WRITE_BUFSIZE
# undef CONFIG_NET_NTCP_WRITE_BUFFERS
#endif
/* Delay after receive to catch a following packet. No delay should be
* required if TCP/IP read-ahead buffering is enabled.
*/
+9 -3
View File
@@ -30,10 +30,16 @@ config IOB_BUFSIZE
config IOB_NCHAINS
int "Number of pre-allocated I/O buffer chain heads"
default 8
default 0
---help---
These tiny nodes are used as "containers" to suppor queueing of
These tiny nodes are used as "containers" to support queueing of
I/O buffer chains. This will limit the number of I/O transactions
that can be "in-flight" at any give time.
that can be "in-flight" at any give time. The default value of
zero disables this features.
These generic I/O buffer chain containers are not currently used
by any logic in NuttX. That is because their other other specialized
I/O buffer chain containers that also carry a payload of usage
specific information.
endif # NET_IOB
+4
View File
@@ -43,6 +43,10 @@ NET_CSRCS += iob_free_chain.c iob_free_qentry.c iob_free_queue.c
NET_CSRCS += iob_initialize.c iob_pack.c iob_remove_queue.c iob_trimhead.c
NET_CSRCS += iob_trimtail.c
ifeq ($(CONFIG_DEBUG),y)
NET_CSRCS += iob_dump.c
endif
# Include iob build support
DEPPATH += --dep-path iob
+7
View File
@@ -42,6 +42,8 @@
#include <nuttx/config.h>
#include <semaphore.h>
#include <nuttx/net/iob.h>
/****************************************************************************
@@ -64,6 +66,11 @@ extern FAR struct iob_s *g_iob_freelist;
extern FAR struct iob_qentry_s *g_iob_freeqlist;
/* Counting semaphores that tracks the number of free IOBs/qentries */
extern sem_t g_iob_sem;
extern sem_t g_qentry_sem;
/****************************************************************************
* Public Data
****************************************************************************/
+4
View File
@@ -47,6 +47,8 @@
#include "iob.h"
#if CONFIG_IOB_NCHAINS > 0
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -102,3 +104,5 @@ int iob_add_queue(FAR struct iob_s *iob, FAR struct iob_queue_s *iobq)
return 0;
}
#endif /* CONFIG_IOB_NCHAINS > 0 */
+95 -5
View File
@@ -39,6 +39,9 @@
#include <nuttx/config.h>
#include <semaphore.h>
#include <assert.h>
#include <nuttx/arch.h>
#include <nuttx/net/iob.h>
@@ -61,18 +64,19 @@
****************************************************************************/
/****************************************************************************
* Public Functions
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: iob_alloc
* Name: iob_tryalloc
*
* Description:
* Allocate an I/O buffer by taking the buffer at the head of the free list.
* Try to allocate an I/O buffer by taking the buffer at the head of the
* free list.
*
****************************************************************************/
FAR struct iob_s *iob_alloc(void)
static FAR struct iob_s *iob_tryalloc(void)
{
FAR struct iob_s *iob;
irqstate_t flags;
@@ -85,9 +89,12 @@ FAR struct iob_s *iob_alloc(void)
iob = g_iob_freelist;
if (iob)
{
/* Remove the I/O buffer from the free list */
/* Remove the I/O buffer from the free list and decrement the counting
* semaphore that tracks the number of free IOBs.
*/
g_iob_freelist = iob->io_flink;
DEBUGVERIFY(sem_trywait(&g_iob_sem));
irqrestore(flags);
/* Put the I/O buffer in a known state */
@@ -102,3 +109,86 @@ FAR struct iob_s *iob_alloc(void)
irqrestore(flags);
return NULL;
}
/****************************************************************************
* Name: iob_allocwait
*
* Description:
* Allocate an I/O buffer, waiting if necessary. This function cannot be
* called from any interrupt level logic.
*
****************************************************************************/
static FAR struct iob_s *iob_allocwait(void)
{
FAR struct iob_s *iob;
irqstate_t flags;
int ret;
/* The following must be atomic; interrupt must be disabled so that there
* is no conflict with interrupt level I/O buffer allocations. This is
* not as bad as it sounds because interrupts will be re-enabled while
* we are waiting for I/O buffers to become free.
*/
flags = irqsave();
do
{
/* Try to get an I/O buffer. If successful, the semaphore count
* will be decremented atomically.
*/
iob = iob_tryalloc();
if (!iob)
{
/* If not successful, then the semaphore count was less than or
* equal to zero (meaning that there are no free buffers). We
* need to wait for an I/O buffer to be released when the semaphore
* count will be incremented.
*/
ret = sem_wait(&g_iob_sem);
/* When we wake up from wait, an I/O buffer was returned to
* the free list. However, if there are concurrent allocations
* from interrupt handling, then I suspect that there is a
* race condition. But no harm, we will just wait again in
* that case.
*/
}
}
while (ret == OK && !iob);
irqrestore(flags);
return iob;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: iob_alloc
*
* Description:
* Allocate an I/O buffer by taking the buffer at the head of the free list.
*
****************************************************************************/
FAR struct iob_s *iob_alloc(void)
{
/* Were we called from the interrupt level? */
if (up_interrupt_context())
{
/* Yes, then try to allocate an I/O buffer without waiting */
return iob_tryalloc();
}
else
{
/* Then allocate an I/O buffer, waiting as necessary */
return iob_allocwait();
}
}
+110 -1
View File
@@ -39,11 +39,16 @@
#include <nuttx/config.h>
#include <semaphore.h>
#include <assert.h>
#include <nuttx/arch.h>
#include <nuttx/net/iob.h>
#include "iob.h"
#if CONFIG_IOB_NCHAINS > 0
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -60,6 +65,104 @@
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: iob_tryalloc_qentry
*
* Description:
* Try to allocate an I/O buffer chain container by taking the buffer at
* the head of the free list. This function is intended only for internal
* use by the IOB module.
*
****************************************************************************/
static FAR struct iob_qentry_s *iob_tryalloc_qentry(void)
{
FAR struct iob_qentry_s *iobq;
irqstate_t flags;
/* We don't know what context we are called from so we use extreme measures
* to protect the free list: We disable interrupts very briefly.
*/
flags = irqsave();
iobq = g_iob_freeqlist;
if (iobq)
{
/* Remove the I/O buffer chain container from the free list and
* decrement the counting semaphore that tracks the number of free
* containers.
*/
g_iob_freeqlist = iobq->qe_flink;
DEBVERIFY(sem_trywait(&g_qentry_sem));
/* Put the I/O buffer in a known state */
iobq->qe_head = NULL; /* Nothing is contained */
}
irqrestore(flags);
return iobq;
}
/****************************************************************************
* Name: iob_allocwait_qentry
*
* Description:
* Allocate an I/O buffer chain container by taking the buffer at the head
* of the free list. This function is intended only for internal use by
* the IOB module.
*
****************************************************************************/
static FAR struct iob_qentry_s *iob_allocwait_qentry(void)
{
FAR struct iob_qentry_s *qentry;
irqstate_t flags;
int ret;
/* The following must be atomic; interrupt must be disabled so that there
* is no conflict with interrupt level I/O buffer chain container
* allocations. This is not as bad as it sounds because interrupts will be
* re-enabled while we are waiting for I/O buffers to become free.
*/
flags = irqsave();
do
{
/* Try to get an I/O buffer chain container. If successful, the
* semaphore count will be decremented atomically.
*/
qentry = iob_tryalloc_qentry();
if (!qentry)
{
/* If not successful, then the semaphore count was less than or
* equal to zero (meaning that there are no free buffers). We
* need to wait for an I/O buffer chain container to be released
* when the semaphore count will be incremented.
*/
ret = sem_wait(&g_qentry_sem);
/* When we wake up from wait, an I/O buffer chain container was
* returned to the free list. However, if there are concurrent
* allocations from interrupt handling, then I suspect that there
* is a race condition. But no harm, we will just wait again in
* that case.
*/
}
}
while (ret == OK && !qentry);
irqrestore(flags);
return qentry;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -87,9 +190,13 @@ FAR struct iob_qentry_s *iob_alloc_qentry(void)
iobq = g_iob_freeqlist;
if (iobq)
{
/* Remove the I/O buffer chain container from the free list */
/* Remove the I/O buffer chain container from the free list and
* decrement the counting semaphore that tracks the number of free
* containers.
*/
g_iob_freeqlist = iobq->qe_flink;
DEBVERIFY(sem_trywait(&g_qentry_sem));
/* Put the I/O buffer in a known state */
@@ -99,3 +206,5 @@ FAR struct iob_qentry_s *iob_alloc_qentry(void)
irqrestore(flags);
return iobq;
}
#endif /* CONFIG_IOB_NCHAINS > 0 */
+177
View File
@@ -0,0 +1,177 @@
/****************************************************************************
* net/iob/iob_dump.c
*
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <debug.h>
#include <nuttx/net/iob.h>
#ifdef CONFIG_DEBUG
/****************************************************************************
* Pre-processor definitions
****************************************************************************/
/* Select the lowest level debug interface available */
#ifdef CONFIG_CPP_HAVE_VARARGS
# ifdef CONFIG_ARCH_LOWPUTC
# define message(format, ...) lowsyslog(format, ##__VA_ARGS__)
# else
# define message(format, ...) syslog(format, ##__VA_ARGS__)
# endif
#else
# ifdef CONFIG_ARCH_LOWPUTC
# define message lowsyslog
# else
# define message syslog
# endif
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Function: iob_dump
*
* Description:
* Dump the contents of a I/O buffer chain
*
****************************************************************************/
void iob_dump(FAR const char *msg, FAR struct iob_s *iob)
{
FAR struct iob_s *head = iob;
FAR const uint8_t *buffer;
uint8_t data[32];
unsigned int nbytes;
unsigned int i;
unsigned int j;
int len;
message("%s: IOB=%p pktlen=%d\n", msg, head, head->io_pktlen);
buffer = &iob->io_data[iob->io_offset];
len = iob->io_len;
for (i = 0; i < head->io_pktlen && iob; i += 32)
{
/* Copy 32-bytes into our local buffer */
for (nbytes = 0; nbytes < 32; nbytes++)
{
data[nbytes] = *buffer++;
/* If we have exhausted the data in this I/O buffer,
* then skip to the next I/O buffer in the chain.
*/
if (--len <= 0)
{
iob = iob->io_flink;
if (!iob)
{
/* Ooops... we are at the end of the chain.
* break out with iob = NULL, len == 0, and
* nbytes <= 32.
*/
len = 0;
break;
}
/* Get the data from the next I/O buffer in the chain */
buffer = &iob->io_data[iob->io_offset];
len = iob->io_len;
}
}
/* Make sure that we have something to print */
if (nbytes > 0)
{
message("%04x: ", i);
for (j = 0; j < 32; j++)
{
if (j == 16)
{
message(" ");
}
if (i + j < head->io_pktlen)
{
message("%02x", buffer[j]);
}
else
{
message(" ");
}
}
message(" ");
for (j = 0; j < 32; j++)
{
if (j == 16)
{
message(" ");
}
if (i + j < head->io_pktlen)
{
if (buffer[j] >= 0x20 && buffer[j] < 0x7f)
{
message("%c", buffer[j]);
}
else
{
message(".");
}
}
}
message("\n");
}
}
}
#endif /* CONFIG_DEBUG */
+6 -2
View File
@@ -39,6 +39,7 @@
#include <nuttx/config.h>
#include <semaphore.h>
#include <assert.h>
#include <nuttx/arch.h>
@@ -86,7 +87,6 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
if (next)
{
/* Copy and decrement the total packet length, being careful to
* do nothing too crazy.
*/
@@ -115,8 +115,12 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
*/
flags = irqsave();
iob->io_flink = g_iob_freelist;
iob->io_flink = g_iob_freelist;
g_iob_freelist = iob;
/* Signal that an IOB is available */
sem_post(&g_iob_sem);
irqrestore(flags);
/* And return the I/O buffer after the one that was freed */
+6 -14
View File
@@ -75,20 +75,12 @@
void iob_free_chain(FAR struct iob_s *iob)
{
FAR struct iob_s *last;
irqstate_t flags;
FAR struct iob_s *next;
/* Find the last entry in the I/O buffer list */
/* Free each IOB in the chain -- one at a time to keep the count straight */
for (last = iob; last->io_flink; last = last->io_flink);
/* Free the I/O buffer chain by adding it to the head of the free list. We
* don't know what context we are called from so we use extreme measures to
* protect the free list: We disable interrupts very briefly.
*/
flags = irqsave();
last->io_flink = g_iob_freelist;
g_iob_freelist = iob;
irqrestore(flags);
for (; iob; iob = next)
{
next = iob_free(iob);
}
}
+11 -2
View File
@@ -39,6 +39,7 @@
#include <nuttx/config.h>
#include <semaphore.h>
#include <assert.h>
#include <nuttx/arch.h>
@@ -46,6 +47,8 @@
#include "iob.h"
#if CONFIG_IOB_NCHAINS > 0
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -70,7 +73,7 @@
* Name: iob_free_qentry
*
* Description:
* Free the I/O buffer chain container by returning it to the free list.
* Free the I/O buffer chain container by returning it to the free list.
* The link to the next I/O buffer in the chain is return.
*
****************************************************************************/
@@ -86,11 +89,17 @@ FAR struct iob_qentry_s *iob_free_qentry(FAR struct iob_qentry_s *iobq)
*/
flags = irqsave();
iobq->qe_flink = g_iob_freeqlist;
iobq->qe_flink = g_iob_freeqlist;
g_iob_freeqlist = iobq;
/* Signal that an I/O buffer chain container is available */
sem_post(&g_qentry_sem);
irqrestore(flags);
/* And return the I/O buffer chain container after the one that was freed */
return nextq;
}
#endif /* CONFIG_IOB_NCHAINS > 0 */
+4
View File
@@ -45,6 +45,8 @@
#include "iob.h"
#if CONFIG_IOB_NCHAINS > 0
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -112,3 +114,5 @@ void iob_free_queue(FAR struct iob_queue_s *qhead)
iob_free_chain(iob);
}
}
#endif /* CONFIG_IOB_NCHAINS > 0 */
+17
View File
@@ -40,6 +40,7 @@
#include <nuttx/config.h>
#include <stdbool.h>
#include <semaphore.h>
#include <nuttx/net/iob.h>
@@ -60,7 +61,9 @@
/* This is a pool of pre-allocated I/O buffers */
static struct iob_s g_iob_pool[CONFIG_IOB_NBUFFERS];
#if CONFIG_IOB_NCHAINS > 0
static struct iob_qentry_s g_iob_qpool[CONFIG_IOB_NCHAINS];
#endif
/****************************************************************************
* Public Data
@@ -72,7 +75,16 @@ FAR struct iob_s *g_iob_freelist;
/* A list of all free, unallocated I/O buffer queue containers */
#if CONFIG_IOB_NCHAINS > 0
FAR struct iob_qentry_s *g_iob_freeqlist;
#endif
/* Counting semaphores that tracks the number of free IOBs/qentries */
sem_t g_iob_sem;
#if CONFIG_IOB_NCHAINS > 0
sem_t g_qentry_sem;
#endif
/****************************************************************************
* Public Functions
@@ -107,6 +119,9 @@ void iob_initialize(void)
g_iob_freelist = iob;
}
sem_init(&g_iob_sem, 0, CONFIG_IOB_NBUFFERS);
#if CONFIG_IOB_NCHAINS > 0
/* Add each I/O buffer chain queue container to the free list */
for (i = 0; i < CONFIG_IOB_NCHAINS; i++)
@@ -119,6 +134,8 @@ void iob_initialize(void)
g_iob_freeqlist = iobq;
}
sem_init(&g_qentry_sem, 0, CONFIG_IOB_NCHAINS);
#endif
initialized = true;
}
}
+3
View File
@@ -45,6 +45,8 @@
#include "iob.h"
#if CONFIG_IOB_NCHAINS > 0
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -92,3 +94,4 @@ FAR struct iob_s *iob_remove_queue(FAR struct iob_queue_s *iobq)
return iob;
}
#endif /* CONFIG_IOB_NCHAINS > 0 */
+281 -113
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -467,7 +467,6 @@ static uint16_t tcpsend_interrupt(FAR struct uip_driver_s *dev,
uint32_t sndlen = pstate->snd_buflen - pstate->snd_sent;
#if defined(CONFIG_NET_TCP_SPLIT)
/* RFC 1122 states that a host may delay ACKing for up to 500ms but
+8 -26
View File
@@ -82,6 +82,7 @@ endif # NET_TCP_READAHEAD
config NET_TCP_WRITE_BUFFERS
bool "Enable TCP/IP write buffering"
default n
select NET_IOB
---help---
Write buffers allows buffering of ongoing TCP/IP packets, providing
for higher performance, streamed output.
@@ -91,34 +92,15 @@ config NET_TCP_WRITE_BUFFERS
if NET_TCP_WRITE_BUFFERS
config NET_TCP_WRITE_BUFSIZE
int "TCP/IP write buffer size"
default 1220 if !NET_SLIP && NET_IPv6
default 536 if !NET_SLIP && !NET_IPv6
default 256 if NET_SLIP && !NET_IPv6
---help---
Write buffers allows buffering of ongoing TCP/IP packets, providing
for higher performance, streamed output.
The size of the write buffer will determine the maximum size of an
outgoing TCP packet payload (MSS). This value should NOT exceed the
maximum MSS which is determined by NET_BUFSIZE minus the size of
TCP, IP, and Ethernet headers (assuming you are using the Ethernet
transport). IPv4 hosts are required to be able to handle an MSS
of 536 octets and IPv6 hosts are required to be able to handle an
MSS of 1220 octets.
This setting specifies the size of one TCP/IP write buffer. This
should best be a equal to the maximum packet size (NET_BUFSIZE).
config NET_NTCP_WRITE_BUFFERS
int "Number of TCP/IP write buffers"
config NET_TCP_NWRBCHAINS
int "Number of pre-allocated I/O buffer chain heads"
default 8
---help---
Write buffers allows buffering of ongoing TCP/IP packets, providing
for higher performance, streamed output.
This setting specifies the number of TCP/IP write buffers.
These tiny nodes are used as "containers" to support queueing of
TCP write buffers. This setting will limit the number of TCP write
operations that can be "in-flight" at any give time. So a good
choice for this value would be the same as the maximum number of
TCP connections.
config NET_TCP_WRBUFFER_DEBUG
bool "Force write buffer debug"
+3
View File
@@ -51,6 +51,9 @@ endif
ifeq ($(CONFIG_NET_TCP_WRITE_BUFFERS),y)
NET_CSRCS += tcp_wrbuffer.c
ifeq ($(CONFIG_DEBUG),y)
NET_CSRCS += tcp_wrbuffer_dump.c
endif
endif
# Include TCP build support
+18 -4
View File
@@ -98,10 +98,8 @@ void tcp_wrbuffer_initialize(void);
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
struct tcp_wrbuffer_s;
struct timespec;
FAR struct tcp_wrbuffer_s *
tcp_wrbuffer_alloc(FAR const struct timespec *abstime);
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void);
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
/****************************************************************************
@@ -118,7 +116,23 @@ tcp_wrbuffer_alloc(FAR const struct timespec *abstime);
****************************************************************************/
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrbuffer);
void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrb);
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
/****************************************************************************
* Function: tcp_writebuffer_dump
*
* Description:
* Dump the contents of a write buffer.
*
****************************************************************************/
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
#ifdef CONFIG_DEBUG
void tcp_writebuffer_dump(FAR const char *msg, FAR struct tcp_wrbuffer_s *wrb);
#else
# define tcp_writebuffer_dump(msg,wrb)
#endif
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
#undef EXTERN
+46 -19
View File
@@ -50,9 +50,13 @@
#include <queue.h>
#include <semaphore.h>
#include <string.h>
#include <assert.h>
#include <debug.h>
#include "uip/uip_internal.h"
#include "tcp/tcp.h"
#include "nuttx/net/iob.h"
#include "nuttx/net/uip/uip-tcp.h"
/****************************************************************************
* Private Types
@@ -72,7 +76,7 @@ struct wrbuffer_s
/* These are the pre-allocated write buffers */
struct tcp_wrbuffer_s buffers[CONFIG_NET_NTCP_WRITE_BUFFERS];
struct tcp_wrbuffer_s buffers[CONFIG_NET_TCP_NWRBCHAINS];
};
/****************************************************************************
@@ -108,12 +112,12 @@ void tcp_wrbuffer_initialize(void)
sq_init(&g_wrbuffer.freebuffers);
for (i = 0; i < CONFIG_NET_NTCP_WRITE_BUFFERS; i++)
for (i = 0; i < CONFIG_NET_TCP_NWRBCHAINS; i++)
{
sq_addfirst(&g_wrbuffer.buffers[i].wb_node, &g_wrbuffer.freebuffers);
}
sem_init(&g_wrbuffer.sem, 0, CONFIG_NET_NTCP_WRITE_BUFFERS);
sem_init(&g_wrbuffer.sem, 0, CONFIG_NET_TCP_NWRBCHAINS);
}
/****************************************************************************
@@ -129,26 +133,39 @@ void tcp_wrbuffer_initialize(void)
*
****************************************************************************/
FAR struct tcp_wrbuffer_s *
tcp_wrbuffer_alloc(FAR const struct timespec *abstime)
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void)
{
int ret;
FAR struct tcp_wrbuffer_s *wrb;
if (abstime)
{
ret = sem_timedwait(&g_wrbuffer.sem, abstime);
}
else
{
ret = sem_wait(&g_wrbuffer.sem);
}
/* We need to allocate two things: (1) A write buffer structure and (2)
* at least one I/O buffer to start the chain.
*
* Allocate the write buffer structure first then the IOBG. In order to
* avoid deadlocks, we will need to free the IOB first, then the write
* buffer
*/
if (ret != 0)
DEBUGVERIFY(sem_wait(&g_wrbuffer.sem));
/* Now, we are guaranteed to have a write buffer structure reserved
* for us in the free list.
*/
wrb = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers);
DEBUGASSERT(wrb);
memset(wrb, 0, sizeof(struct tcp_wrbuffer_s));
/* Now get the first I/O buffer for the write buffer structure */
wrb->wb_iob = iob_alloc();
if (!wrb->wb_iob)
{
ndbg("ERROR: Failed to allocate I/O buffer\n");
tcp_wrbuffer_release(wrb);
return NULL;
}
return (FAR struct tcp_wrbuffer_s*)sq_remfirst(&g_wrbuffer.freebuffers);
return wrb;
}
/****************************************************************************
@@ -164,9 +181,19 @@ tcp_wrbuffer_alloc(FAR const struct timespec *abstime)
*
****************************************************************************/
void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrbuffer)
void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrb)
{
sq_addlast(&wrbuffer->wb_node, &g_wrbuffer.freebuffers);
DEBUGASSERT(wrb && wrb->wb_iob);
/* To avoid deadlocks, we must following this ordering: Release the I/O
* buffer chain first, then the write buffer structure.
*/
iob_free_chain(wrb->wb_iob);
/* Then free the write buffer structure */
sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers);
sem_post(&g_wrbuffer.sem);
}
+89
View File
@@ -0,0 +1,89 @@
/****************************************************************************
* net/tcp/tcp_wrbuffer_dump.c
*
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <debug.h>
#include <nuttx/net/iob.h>
#include <nuttx/net/uip/uip-tcp.h>
#ifdef CONFIG_DEBUG
/****************************************************************************
* Pre-processor definitions
****************************************************************************/
/* Select the lowest level debug interface available */
#ifdef CONFIG_CPP_HAVE_VARARGS
# ifdef CONFIG_ARCH_LOWPUTC
# define message(format, ...) lowsyslog(format, ##__VA_ARGS__)
# else
# define message(format, ...) syslog(format, ##__VA_ARGS__)
# endif
#else
# ifdef CONFIG_ARCH_LOWPUTC
# define message lowsyslog
# else
# define message syslog
# endif
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: tcp_wrbuffer_dump
*
* Description:
* Dump the contents of a write buffer
*
****************************************************************************/
void tcp_wrbuffer_dump(FAR const char *msg, FAR struct tcp_wrbuffer_s *wrb)
{
message("%s: WRB=%p segno=%d sent=%d nrtx=%d\n",
msg, wrb, WRB_SEQNO(wrb), WRB_SENT(wrb), WRB_NRTX(wrb));
iob_dump("I/O Buffer Chain", WRB_IOB(wrb));
}
#endif /* CONFIG_DEBUG */
+6
View File
@@ -40,6 +40,12 @@ ifeq ($(CONFIG_NET),y)
NET_CSRCS += uip_initialize.c uip_setipid.c uip_input.c uip_send.c
NET_CSRCS += uip_poll.c uip_chksum.c uip_callback.c
# I/O buffer chain support required?
ifeq ($(CONFIG_NET_IOB),y)
NET_CSRCS += uip_iobsend.c
endif
# Non-interrupt level support required?
ifeq ($(CONFIG_NET_NOINTS),y)
+105
View File
@@ -0,0 +1,105 @@
/****************************************************************************
* net/uip/uip_iobsend.c
*
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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
* COPYRIGHT OWNER 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <string.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/net/iob.h>
#include <nuttx/net/uip/uip.h>
#include <nuttx/net/uip/uip-arch.h>
#ifdef CONFIG_NET_IOB
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Global Constant Data
****************************************************************************/
/****************************************************************************
* Global Variables
****************************************************************************/
/****************************************************************************
* Private Constant Data
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Global Functions
****************************************************************************/
/****************************************************************************
* Name: uip_iobsend
*
* Description:
* Called from socket logic in response to a xmit or poll request from the
* the network interface driver.
*
* Assumptions:
* Called from the interrupt level or, at a minimum, with interrupts
* disabled.
*
****************************************************************************/
void uip_iobsend(FAR struct uip_driver_s *dev, FAR struct iob_s *iob,
unsigned int len, unsigned int offset)
{
DEBUGASSERT(dev && len > 0 && len < CONFIG_NET_BUFSIZE);
iob_copyout(dev->d_snddata, iob, len, offset);
dev->d_sndlen = len;
}
#endif /* CONFIG_NET_IOB */
+5 -9
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* net/uip/uip_send.c
*
* Copyright (C) 2007i, 2008 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Based in part on uIP which also has a BSD stylie license:
@@ -42,6 +42,7 @@
****************************************************************************/
#include <string.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/net/uip/uip.h>
@@ -94,13 +95,8 @@
void uip_send(struct uip_driver_s *dev, const void *buf, int len)
{
/* Some sanity checks -- note that the actually available length in the
* buffer is considerably less than CONFIG_NET_BUFSIZE.
*/
DEBUGASSERT(dev && len > 0 && len < CONFIG_NET_BUFSIZE);
if (dev && len > 0 && len < CONFIG_NET_BUFSIZE)
{
memcpy(dev->d_snddata, buf, len);
dev->d_sndlen = len;
}
memcpy(dev->d_snddata, buf, len);
dev->d_sndlen = len;
}