diff options
Diffstat (limited to 'nuttx/net/iob')
-rw-r--r-- | nuttx/net/iob/Kconfig | 23 | ||||
-rw-r--r-- | nuttx/net/iob/Make.defs | 4 | ||||
-rw-r--r-- | nuttx/net/iob/iob.h | 7 | ||||
-rw-r--r-- | nuttx/net/iob/iob_add_queue.c | 11 | ||||
-rw-r--r-- | nuttx/net/iob/iob_alloc.c | 107 | ||||
-rw-r--r-- | nuttx/net/iob/iob_alloc_qentry.c | 118 | ||||
-rw-r--r-- | nuttx/net/iob/iob_clone.c | 7 | ||||
-rw-r--r-- | nuttx/net/iob/iob_concat.c | 7 | ||||
-rwxr-xr-x | nuttx/net/iob/iob_contig.c | 7 | ||||
-rw-r--r-- | nuttx/net/iob/iob_copyin.c | 17 | ||||
-rw-r--r-- | nuttx/net/iob/iob_copyout.c | 7 | ||||
-rw-r--r-- | nuttx/net/iob/iob_dump.c | 180 | ||||
-rw-r--r-- | nuttx/net/iob/iob_free.c | 22 | ||||
-rw-r--r-- | nuttx/net/iob/iob_free_chain.c | 27 | ||||
-rw-r--r-- | nuttx/net/iob/iob_free_qentry.c | 20 | ||||
-rw-r--r-- | nuttx/net/iob/iob_free_queue.c | 11 | ||||
-rw-r--r-- | nuttx/net/iob/iob_initialize.c | 24 | ||||
-rw-r--r-- | nuttx/net/iob/iob_pack.c | 7 | ||||
-rw-r--r-- | nuttx/net/iob/iob_remove_queue.c | 10 | ||||
-rw-r--r-- | nuttx/net/iob/iob_trimhead.c | 33 | ||||
-rw-r--r-- | nuttx/net/iob/iob_trimtail.c | 11 |
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 */ |