summaryrefslogtreecommitdiff
path: root/nuttx/net/iob
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/net/iob')
-rw-r--r--nuttx/net/iob/Kconfig23
-rw-r--r--nuttx/net/iob/Make.defs4
-rw-r--r--nuttx/net/iob/iob.h7
-rw-r--r--nuttx/net/iob/iob_add_queue.c11
-rw-r--r--nuttx/net/iob/iob_alloc.c107
-rw-r--r--nuttx/net/iob/iob_alloc_qentry.c118
-rw-r--r--nuttx/net/iob/iob_clone.c7
-rw-r--r--nuttx/net/iob/iob_concat.c7
-rwxr-xr-xnuttx/net/iob/iob_contig.c7
-rw-r--r--nuttx/net/iob/iob_copyin.c17
-rw-r--r--nuttx/net/iob/iob_copyout.c7
-rw-r--r--nuttx/net/iob/iob_dump.c180
-rw-r--r--nuttx/net/iob/iob_free.c22
-rw-r--r--nuttx/net/iob/iob_free_chain.c27
-rw-r--r--nuttx/net/iob/iob_free_qentry.c20
-rw-r--r--nuttx/net/iob/iob_free_queue.c11
-rw-r--r--nuttx/net/iob/iob_initialize.c24
-rw-r--r--nuttx/net/iob/iob_pack.c7
-rw-r--r--nuttx/net/iob/iob_remove_queue.c10
-rw-r--r--nuttx/net/iob/iob_trimhead.c33
-rw-r--r--nuttx/net/iob/iob_trimtail.c11
21 files changed, 620 insertions, 40 deletions
diff --git a/nuttx/net/iob/Kconfig b/nuttx/net/iob/Kconfig
index f7793afa8..ea6a851cd 100644
--- a/nuttx/net/iob/Kconfig
+++ b/nuttx/net/iob/Kconfig
@@ -30,10 +30,27 @@ 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.
+
+config NET_IOB_DEBUG
+ bool "Force I/O buffer debug"
+ default n
+ depends on DEBUG
+ ---help---
+ This option will force debug output from I/O buffer logic,
+ even without network debug output. This is not normally something
+ that would want to do but is convenient if you are debugging the
+ I/O buffer logic and do not want to get overloaded with other
+ network-related debug output.
endif # NET_IOB
diff --git a/nuttx/net/iob/Make.defs b/nuttx/net/iob/Make.defs
index e522d5885..205ef72ea 100644
--- a/nuttx/net/iob/Make.defs
+++ b/nuttx/net/iob/Make.defs
@@ -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
diff --git a/nuttx/net/iob/iob.h b/nuttx/net/iob/iob.h
index 0507fa34d..03ea6d14d 100644
--- a/nuttx/net/iob/iob.h
+++ b/nuttx/net/iob/iob.h
@@ -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
****************************************************************************/
diff --git a/nuttx/net/iob/iob_add_queue.c b/nuttx/net/iob/iob_add_queue.c
index 0a2ac3d0a..f915b49a0 100644
--- a/nuttx/net/iob/iob_add_queue.c
+++ b/nuttx/net/iob/iob_add_queue.c
@@ -39,6 +39,13 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <assert.h>
#include <errno.h>
#include <debug.h>
@@ -47,6 +54,8 @@
#include "iob.h"
+#if CONFIG_IOB_NCHAINS > 0
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -102,3 +111,5 @@ int iob_add_queue(FAR struct iob_s *iob, FAR struct iob_queue_s *iobq)
return 0;
}
+
+#endif /* CONFIG_IOB_NCHAINS > 0 */
diff --git a/nuttx/net/iob/iob_alloc.c b/nuttx/net/iob/iob_alloc.c
index f9810bfa3..be6491dbb 100644
--- a/nuttx/net/iob/iob_alloc.c
+++ b/nuttx/net/iob/iob_alloc.c
@@ -39,6 +39,16 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
+#include <semaphore.h>
+#include <assert.h>
+
#include <nuttx/arch.h>
#include <nuttx/net/iob.h>
@@ -61,18 +71,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 +96,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 +116,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();
+ }
+}
diff --git a/nuttx/net/iob/iob_alloc_qentry.c b/nuttx/net/iob/iob_alloc_qentry.c
index 0c29fbec1..43813a269 100644
--- a/nuttx/net/iob/iob_alloc_qentry.c
+++ b/nuttx/net/iob/iob_alloc_qentry.c
@@ -39,11 +39,23 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
+#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
****************************************************************************/
@@ -61,6 +73,104 @@
****************************************************************************/
/****************************************************************************
+ * 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 +197,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 +213,5 @@ FAR struct iob_qentry_s *iob_alloc_qentry(void)
irqrestore(flags);
return iobq;
}
+
+#endif /* CONFIG_IOB_NCHAINS > 0 */
diff --git a/nuttx/net/iob/iob_clone.c b/nuttx/net/iob/iob_clone.c
index 9d4b849f8..ce83400d4 100644
--- a/nuttx/net/iob/iob_clone.c
+++ b/nuttx/net/iob/iob_clone.c
@@ -39,6 +39,13 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <string.h>
#include <assert.h>
#include <errno.h>
diff --git a/nuttx/net/iob/iob_concat.c b/nuttx/net/iob/iob_concat.c
index 6875984ff..68d35c480 100644
--- a/nuttx/net/iob/iob_concat.c
+++ b/nuttx/net/iob/iob_concat.c
@@ -39,6 +39,13 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <string.h>
#include <nuttx/net/iob.h>
diff --git a/nuttx/net/iob/iob_contig.c b/nuttx/net/iob/iob_contig.c
index ff9831a21..6af1b9c99 100755
--- a/nuttx/net/iob/iob_contig.c
+++ b/nuttx/net/iob/iob_contig.c
@@ -39,6 +39,13 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <string.h>
#include <assert.h>
#include <errno.h>
diff --git a/nuttx/net/iob/iob_copyin.c b/nuttx/net/iob/iob_copyin.c
index 0c9b3f037..fedd37098 100644
--- a/nuttx/net/iob/iob_copyin.c
+++ b/nuttx/net/iob/iob_copyin.c
@@ -39,6 +39,13 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <stdint.h>
#include <string.h>
#include <errno.h>
@@ -91,13 +98,14 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src,
unsigned int ncopy;
unsigned int avail;
+ nllvdbg("iob=%p len=%u offset=%u\n", iob, len, offset);
DEBUGASSERT(iob && src);
/* The offset must applied to data that is already in the I/O buffer chain */
if (offset > iob->io_pktlen)
{
- ndbg("ERROR: offset is past the end of data: %d > %d\n",
+ ndbg("ERROR: offset is past the end of data: %u > %u\n",
offset, iob->io_pktlen);
return -ESPIPE;
}
@@ -123,6 +131,8 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src,
dest = &iob->io_data[iob->io_offset + offset];
avail = iob->io_len - offset;
+ nllvdbg("iob=%p avail=%u len=%u next=%p\n", iob, avail, len, next);
+
/* Will the rest of the copy fit into this buffer, overwriting
* existing data.
*/
@@ -146,7 +156,7 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src,
/* Yes.. We can extend this buffer to the up to the very end. */
- maxlen = CONFIG_IOB_BUFSIZE - iob->io_offset;
+ maxlen = CONFIG_IOB_BUFSIZE - iob->io_offset;
/* This is the new buffer length that we need. Of course,
* clipped to the maximum possible size in this buffer.
@@ -178,6 +188,8 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src,
/* Copy from the user buffer to the I/O buffer. */
memcpy(dest, src, ncopy);
+ nllvdbg("iob=%p, Copy %u bytes, new len=%u\n",
+ iob, ncopy, iob->io_len);
/* Adjust the total length of the copy and the destination address in
* the user buffer.
@@ -204,6 +216,7 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src,
/* Add the new, empty I/O buffer to the end of the buffer chain. */
iob->io_flink = next;
+ nllvdbg("iob=%p added to the chain\n", iob);
}
iob = next;
diff --git a/nuttx/net/iob/iob_copyout.c b/nuttx/net/iob/iob_copyout.c
index 5695eb2e9..2db050d31 100644
--- a/nuttx/net/iob/iob_copyout.c
+++ b/nuttx/net/iob/iob_copyout.c
@@ -39,6 +39,13 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <stdint.h>
#include <string.h>
#include <assert.h>
diff --git a/nuttx/net/iob/iob_dump.c b/nuttx/net/iob/iob_dump.c
new file mode 100644
index 000000000..ee7cda4e3
--- /dev/null
+++ b/nuttx/net/iob/iob_dump.c
@@ -0,0 +1,180 @@
+/****************************************************************************
+ * 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
+ ****************************************************************************/
+
+ #ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* 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, unsigned int len,
+ unsigned int offset)
+{
+ FAR struct iob_s *head;
+ uint8_t data[32];
+ unsigned int maxlen;
+ unsigned int nbytes;
+ unsigned int lndx;
+ unsigned int cndx;
+
+ head = iob;
+ message("%s: iob=%p pktlen=%d\n", msg, head, head->io_pktlen);
+
+ /* Check if the offset is beyond the data in the I/O buffer chain */
+
+ if (offset > head->io_pktlen)
+ {
+ ndbg("ERROR: offset is past the end of data: %u > %u\n",
+ offset, head->io_pktlen);
+ return;
+ }
+
+ /* Dump I/O buffer headers */
+
+ for (; iob; iob = iob->io_flink)
+ {
+ message(" iob=%p len=%d offset=%d\n", iob, iob->io_len, iob->io_offset);
+ }
+
+ /* Get the amount of data to be displayed, limited by the amount that we
+ * have beyond the offset.
+ */
+
+ maxlen = head->io_pktlen - offset;
+ len = MIN(len, maxlen);
+
+ /* Then beginning printing with the buffer containing the offset in groups
+ * of 32 bytes.
+ */
+
+ for (lndx = 0; lndx < len; lndx += 32, offset += 32)
+ {
+ /* Copy 32-bytes into our local buffer from the current offset */
+
+ nbytes = iob_copyout(data, head, 32, offset);
+
+ /* Make sure that we have something to print */
+
+ if (nbytes > 0)
+ {
+ message(" %04x: ", offset);
+
+ for (cndx = 0; cndx < 32; cndx++)
+ {
+ if (cndx == 16)
+ {
+ message(" ");
+ }
+
+ if ((lndx + cndx) < len)
+ {
+ message("%02x", data[cndx]);
+ }
+ else
+ {
+ message(" ");
+ }
+ }
+
+ message(" ");
+ for (cndx = 0; cndx < 32; cndx++)
+ {
+ if (cndx == 16)
+ {
+ message(" ");
+ }
+
+ if ((lndx + cndx) < len)
+ {
+ if (data[cndx] >= 0x20 && data[cndx] < 0x7f)
+ {
+ message("%c", data[cndx]);
+ }
+ else
+ {
+ message(".");
+ }
+ }
+ }
+
+ message("\n");
+ }
+ }
+}
+
+#endif /* CONFIG_DEBUG */
diff --git a/nuttx/net/iob/iob_free.c b/nuttx/net/iob/iob_free.c
index 75d70e080..68c7fb264 100644
--- a/nuttx/net/iob/iob_free.c
+++ b/nuttx/net/iob/iob_free.c
@@ -39,7 +39,16 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
+#include <semaphore.h>
#include <assert.h>
+#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/net/iob.h>
@@ -80,13 +89,15 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
FAR struct iob_s *next = iob->io_flink;
irqstate_t flags;
+ nllvdbg("iob=%p io_pktlen=%u io_len=%u next=%p\n",
+ iob, iob->io_pktlen, iob->io_len, next);
+
/* Copy the data that only exists in the head of a I/O buffer chain into
* the next entry.
*/
if (next)
{
-
/* Copy and decrement the total packet length, being careful to
* do nothing too crazy.
*/
@@ -107,6 +118,9 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
next->io_pktlen = 0;
DEBUGASSERT(next->io_len == 0 && next->io_flink == NULL);
}
+
+ nllvdbg("next=%p io_pktlen=%u io_len=%u\n",
+ next, next->io_pktlen, next->io_len);
}
/* Free the I/O buffer by adding it to the head of the free list. We don't
@@ -115,8 +129,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 */
diff --git a/nuttx/net/iob/iob_free_chain.c b/nuttx/net/iob/iob_free_chain.c
index db9fc408c..d09a0ca97 100644
--- a/nuttx/net/iob/iob_free_chain.c
+++ b/nuttx/net/iob/iob_free_chain.c
@@ -39,6 +39,13 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <nuttx/arch.h>
#include <nuttx/net/iob.h>
@@ -75,20 +82,12 @@
void iob_free_chain(FAR struct iob_s *iob)
{
- FAR struct iob_s *last;
- irqstate_t flags;
-
- /* Find the last entry in the I/O buffer list */
-
- for (last = iob; last->io_flink; last = last->io_flink);
+ FAR struct iob_s *next;
- /* 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.
- */
+ /* Free each IOB in the chain -- one at a time to keep the count straight */
- flags = irqsave();
- last->io_flink = g_iob_freelist;
- g_iob_freelist = iob;
- irqrestore(flags);
+ for (; iob; iob = next)
+ {
+ next = iob_free(iob);
+ }
}
diff --git a/nuttx/net/iob/iob_free_qentry.c b/nuttx/net/iob/iob_free_qentry.c
index 55d4cf848..3f5a517b9 100644
--- a/nuttx/net/iob/iob_free_qentry.c
+++ b/nuttx/net/iob/iob_free_qentry.c
@@ -39,6 +39,14 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
+#include <semaphore.h>
#include <assert.h>
#include <nuttx/arch.h>
@@ -46,6 +54,8 @@
#include "iob.h"
+#if CONFIG_IOB_NCHAINS > 0
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -70,7 +80,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 +96,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 */
diff --git a/nuttx/net/iob/iob_free_queue.c b/nuttx/net/iob/iob_free_queue.c
index 1b1a51888..f23394d45 100644
--- a/nuttx/net/iob/iob_free_queue.c
+++ b/nuttx/net/iob/iob_free_queue.c
@@ -39,12 +39,21 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <assert.h>
#include <nuttx/net/iob.h>
#include "iob.h"
+#if CONFIG_IOB_NCHAINS > 0
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -112,3 +121,5 @@ void iob_free_queue(FAR struct iob_queue_s *qhead)
iob_free_chain(iob);
}
}
+
+#endif /* CONFIG_IOB_NCHAINS > 0 */
diff --git a/nuttx/net/iob/iob_initialize.c b/nuttx/net/iob/iob_initialize.c
index 5c4c122c3..319e75b8a 100644
--- a/nuttx/net/iob/iob_initialize.c
+++ b/nuttx/net/iob/iob_initialize.c
@@ -39,7 +39,15 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <stdbool.h>
+#include <semaphore.h>
#include <nuttx/net/iob.h>
@@ -60,7 +68,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 +82,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 +126,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 +141,8 @@ void iob_initialize(void)
g_iob_freeqlist = iobq;
}
+ sem_init(&g_qentry_sem, 0, CONFIG_IOB_NCHAINS);
+#endif
initialized = true;
}
}
diff --git a/nuttx/net/iob/iob_pack.c b/nuttx/net/iob/iob_pack.c
index eb2c772c4..f129e7357 100644
--- a/nuttx/net/iob/iob_pack.c
+++ b/nuttx/net/iob/iob_pack.c
@@ -39,6 +39,13 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <string.h>
#include <nuttx/net/iob.h>
diff --git a/nuttx/net/iob/iob_remove_queue.c b/nuttx/net/iob/iob_remove_queue.c
index 7a64d47c7..e8ee794e3 100644
--- a/nuttx/net/iob/iob_remove_queue.c
+++ b/nuttx/net/iob/iob_remove_queue.c
@@ -39,12 +39,21 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <debug.h>
#include <nuttx/net/iob.h>
#include "iob.h"
+#if CONFIG_IOB_NCHAINS > 0
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -92,3 +101,4 @@ FAR struct iob_s *iob_remove_queue(FAR struct iob_queue_s *iobq)
return iob;
}
+#endif /* CONFIG_IOB_NCHAINS > 0 */
diff --git a/nuttx/net/iob/iob_trimhead.c b/nuttx/net/iob/iob_trimhead.c
index 0fe349023..6ea684b9a 100644
--- a/nuttx/net/iob/iob_trimhead.c
+++ b/nuttx/net/iob/iob_trimhead.c
@@ -39,7 +39,15 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <assert.h>
+#include <debug.h>
#include <nuttx/net/iob.h>
@@ -81,20 +89,22 @@
FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen)
{
uint16_t pktlen;
- unsigned int len;
+
+ nllvdbg("iob=%p trimlen=%d\n", iob, trimlen);
if (iob && trimlen > 0)
{
/* Trim from the head of the I/IO buffer chain */
pktlen = iob->io_pktlen;
- len = trimlen;
-
- while (len > 0 && iob != NULL)
+ while (trimlen > 0 && iob != NULL)
{
/* Do we trim this entire I/O buffer away? */
- if (iob->io_len <= len)
+ nllvdbg("iob=%p io_len=%d pktlen=%d trimlen=%d\n",
+ iob, iob->io_len, pktlen, trimlen);
+
+ if (iob->io_len <= trimlen)
{
FAR struct iob_s *next;
@@ -103,7 +113,7 @@ FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen)
*/
pktlen -= iob->io_len;
- len -= iob->io_len;
+ trimlen -= iob->io_len;
iob->io_len = 0;
iob->io_offset = 0;
@@ -122,8 +132,9 @@ FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen)
/* Free this entry and set the next I/O buffer as the head */
+ nllvdbg("iob=%p: Freeing\n", iob);
(void)iob_free(iob);
- iob = next;
+ iob = next;
}
else
{
@@ -131,10 +142,10 @@ FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen)
* stop the trim.
*/
- pktlen -= len;
- iob->io_len -= len;
- iob->io_offset += len;
- len = 0;
+ pktlen -= trimlen;
+ iob->io_len -= trimlen;
+ iob->io_offset += trimlen;
+ trimlen = 0;
}
}
diff --git a/nuttx/net/iob/iob_trimtail.c b/nuttx/net/iob/iob_trimtail.c
index 872560a49..c87de712f 100644
--- a/nuttx/net/iob/iob_trimtail.c
+++ b/nuttx/net/iob/iob_trimtail.c
@@ -39,7 +39,15 @@
#include <nuttx/config.h>
+#if defined(CONFIG_DEBUG) && defined(CONFIG_NET_IOB_DEBUG)
+/* Force debug output (from this file only) */
+
+# undef CONFIG_DEBUG_NET
+# define CONFIG_DEBUG_NET 1
+#endif
+
#include <string.h>
+#include <debug.h>
#include <nuttx/net/iob.h>
@@ -81,6 +89,8 @@ FAR struct iob_s *iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen)
unsigned int iosize;
int len;
+ nlldbg("iob=%p pktlen=%d trimlen=%d\n", iob, iob->io_pktlen, trimlen);
+
if (iob && trimlen > 0)
{
len = trimlen;
@@ -113,6 +123,7 @@ FAR struct iob_s *iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen)
* I/O buffer away?
*/
+ nllvdbg("iob=%p len=%d vs %d\n", last, last->io_len, len);
if (last->io_len <= len)
{
/* Yes.. Consume the entire buffer */