nuttx/wireless/pktradio/pktradio_metadata.c

249 lines
7.4 KiB
C

/****************************************************************************
* wireless/pktradio/pktradio_metadata.c
*
* Copyright (C) 2017 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 <stdbool.h>
#include <string.h>
#include <semaphore.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mm/iob.h>
#include <nuttx/wireless/pktradio.h>
/****************************************************************************
* 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);
}
}