/**************************************************************************** * wireless/pktradio/pktradio_metadata.c * * Copyright (C) 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * 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 #include #include #include #include #include #include #include #include #include /**************************************************************************** * Private Data ****************************************************************************/ /* The g_free_metadata is a list of meta-data structures that are available for * general use. The number of messages in this list is a system configuration * item. */ static struct pktradio_metadata_s *g_free_metadata; /* Supports mutually exclusive access to the free list */ static sem_t g_metadata_sem; /* Idempotence support */ static bool g_metadata_initialized; /* Pool of pre-allocated meta-data stuctures */ static struct pktradio_metadata_s g_metadata_pool[CONFIG_PKTRADIO_NRXMETA]; /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: pktradio_metadata_initialize * * Description: * This function initializes the meta-data allocator. This function must * be called early in the initialization sequence before any radios * begin operation. * * Inputs: * None * * Return Value: * None * ****************************************************************************/ void pktradio_metadata_initialize(void) { FAR struct pktradio_metadata_s *metadata; int i; if (!g_metadata_initialized) { /* Initialize g_free_metadata, the list of meta-data structures that * are available for allocation. */ g_free_metadata = NULL; for (i = 0, metadata = g_metadata_pool; i < CONFIG_PKTRADIO_NRXMETA; i++, metadata++) { /* Add the next meta data structure from the pool to the list of * general structures. */ metadata->pm_flink = g_free_metadata; g_free_metadata = metadata; } /* Initialize the mutual exclusion semaphore */ sem_init(&g_metadata_sem, 0, 1); g_metadata_initialized = true; } } /**************************************************************************** * Name: pktradio_metadata_allocate * * Description: * The pktradio_metadata_allocate function will get a free meta-data * structure for use by the packet radio. * * This function will first attempt to allocate from the g_free_metadata * list. If that the list is empty, then the meta-data structure will be * allocated from the dynamic memory pool. * * Inputs: * None * * Return Value: * A reference to the allocated metadata structure. All user fields in this * structure have been zeroed. On a failure to allocate, NULL is * returned. * ****************************************************************************/ FAR struct pktradio_metadata_s *pktradio_metadata_allocate(void) { FAR struct pktradio_metadata_s *metadata; uint8_t pool; /* Get exclusive access to the free list */ while (sem_wait(&g_metadata_sem) < 0) { DEBUGASSERT(errno == EINTR); } /* Try the free list first */ if (g_free_metadata != NULL) { metadata = g_free_metadata; g_free_metadata = metadata->pm_flink; pool = PKTRADIO_POOL_PREALLOCATED; /* We are finished with the free list */ sem_post(&g_metadata_sem); } else { /* If we cannot get a meta-data instance from the free list, then we * will have to allocate one from the kernal memory pool. We won't * access the free list. */ sem_post(&g_metadata_sem); metadata = (FAR struct pktradio_metadata_s *) kmm_malloc((sizeof (struct pktradio_metadata_s))); pool = PKTRADIO_POOL_DYNAMIC; } /* We have successfully allocated memory from some source? */ if (metadata != NULL) { /* Zero and tag the alloated meta-data structure. */ memset(metadata, 0, sizeof(struct pktradio_metadata_s)); metadata->pm_pool = pool; } return metadata; } /**************************************************************************** * Name: pktradio_metadata_free * * Description: * The pktradio_metadata_free function will return a metadata structure * to the free list of messages if it was a pre-allocated metadata * structure. If the metadata structure was allocated dynamically it will * be deallocated. * * Inputs: * metadata - metadata structure to free * * Return Value: * None * ****************************************************************************/ void pktradio_metadata_free(FAR struct pktradio_metadata_s *metadata) { /* Get exclusive access to the free list */ while (sem_wait(&g_metadata_sem) < 0) { DEBUGASSERT(errno == EINTR); } /* If this is a pre-allocated meta-data structure, then just put it back * in the free list. */ if (metadata->pm_pool == PKTRADIO_POOL_PREALLOCATED) { metadata->pm_flink = g_free_metadata; g_free_metadata = metadata; /* We are finished with the free list */ sem_post(&g_metadata_sem); } else { DEBUGASSERT(metadata->pm_pool == PKTRADIO_POOL_DYNAMIC); /* Otherwise, deallocate it. We won't access the free list */ sem_post(&g_metadata_sem); sched_kfree(metadata); } }