summaryrefslogtreecommitdiff
path: root/nuttx/net/iob/iob_alloc_qentry.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/net/iob/iob_alloc_qentry.c')
-rw-r--r--nuttx/net/iob/iob_alloc_qentry.c118
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 */