diff options
Diffstat (limited to 'nuttx/net/iob/iob_alloc_qentry.c')
-rw-r--r-- | nuttx/net/iob/iob_alloc_qentry.c | 118 |
1 files changed, 117 insertions, 1 deletions
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 */ |