blob: df53b715316ab0ef8c9bcfe633054a8251e7cbff [file] [log] [blame]
/******************************************************************************
Copyright (c) 2006-2015 Lantiq Deutschland GmbH
Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
Copyright 2018, Intel Corporation.
For licensing information, see the file 'LICENSE' in the root folder of
this software module.
******************************************************************************/
/**
\file dxs_mempool.c
XXXXXX
\remarks
XXXXXX
*/
/* ========================================================================== */
/* Includes */
/* ========================================================================== */
#include <stdlib.h>
#include <pthread.h>
#include "dxs_mempool.h"
#include "dxs_error.h"
/* ========================================================================== */
/* Macro definitions */
/* ========================================================================== */
#define DXS_MAX_MEMPOOLS 16
#define DXS_MAX_MEMPOOL_ELEMENTS 32
/* ========================================================================== */
/* Type definitions */
/* ========================================================================== */
struct __mempool
{
uint8_t in_use;
pthread_mutex_t mtx;
struct __buffer *free;
struct __buffer *allocated;
};
struct __buffer
{
void *p;
struct __buffer *next;
};
/* ========================================================================== */
/* Global variables */
/* ========================================================================== */
static struct __mempool mempool[DXS_MAX_MEMPOOLS] = {{0},};
static struct __buffer buffers[DXS_MAX_MEMPOOLS * DXS_MAX_MEMPOOL_ELEMENTS];
/* ========================================================================== */
/* Function implementation */
/* ========================================================================== */
/**
Initialize a memory buffer pool.
\param mem Address of continuous memory block
on which to organize a pool.
\param size Size of continuous memory block in bytes.
\param elem_num Number of buffers to create.
\param elem_size Size of each individual buffer in bytes.
\param *pool_id pool instance to return.
\return
DXS_MPOOL_OK success
DXS_MPOOL_PARAMS invalid parameters
DXS_MPOOL_NOT_ENOUGH not enough memory for a pool
DXS_MPOOL_NO_FREE_POOLS cannot allocate a pool
*/
int32_t mempool_init(void *mem, uint32_t size, uint16_t elem_num,
uint16_t elem_size, void **pool_id)
{
int i, err;
struct __mempool *pool;
struct __buffer *curr;
if (mem == NULL || size == 0)
return DXS_MPOOL_PARAMS;
if (elem_num > DXS_MAX_MEMPOOL_ELEMENTS)
elem_num = DXS_MAX_MEMPOOL_ELEMENTS;
if ((elem_num * elem_size) > size)
return DXS_MPOOL_NOT_ENOUGH;
/* get next available pool */
for (i=0; i<DXS_MAX_MEMPOOLS; i++)
{
pool = &mempool[i];
if (!pool->in_use)
break;
}
if (i == DXS_MAX_MEMPOOLS)
{
/* cannot allocate a free pool */
return DXS_MPOOL_NO_FREE_POOLS;
}
pool->in_use = 1;
pthread_mutex_init(&pool->mtx, NULL);
err = pthread_mutex_lock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
/* create a head node */
curr = pool->free = &buffers[i * DXS_MAX_MEMPOOL_ELEMENTS];
curr->p = mem;
curr->next = NULL;
/* initialize remaining nodes */
for (i=1; i<elem_num; i++)
{
/* get the new buffer */
struct __buffer *b = pool->free + i;
b->p = (void *)((uint8_t *)mem + i * elem_size);
b->next = NULL;
/* add the new buffer to the tail */
curr->next = b;
curr = b;
}
/* allocated list is initially empty */
pool->allocated = NULL;
/* return a pool instance */
*pool_id = (void *)pool;
err = pthread_mutex_unlock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
return DXS_MPOOL_OK;
}
/**
Get a buffer from the pool.
\param pool_id Memory pool selector.
\return
A memory buffer or NULL in case of an error.
*/
void *mempool_get(void *pool_id)
{
int err;
struct __mempool *pool = (struct __mempool *)pool_id;
struct __buffer *buff;
/* TODO: trap on wild pool_id ? */
err = pthread_mutex_lock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
/* get the buffer from the free list head */
buff = pool->free;
if (buff == NULL)
{
/* empty list - no buffers available */
err = pthread_mutex_unlock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
return (void *)NULL;
}
/* advance the free list head */
pool->free = buff->next;
/* buff now goes to the tail of the allocated list */
buff->next = NULL;
if (pool->allocated == NULL)
{
pool->allocated = buff;
}
else
{
struct __buffer *b = pool->allocated;
while (b->next != NULL)
b = b->next;
b->next = buff;
}
err = pthread_mutex_unlock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
return (buff->p);
}
/**
Return a buffer to the pool.
\param pool_id Memory pool selector.
\param p Memory buffer to return to the pool.
\return
DXS_MPOOL_OK
DXS_MPOOL_BUF_NOT_FOUND
*/
int32_t mempool_put(void *pool_id, void *p)
{
struct __mempool *pool = (struct __mempool *)pool_id;
struct __buffer *prev = NULL, *buff;
uint8_t found = 0;
int err;
/* TODO: trap on wild pool_id ? */
err = pthread_mutex_lock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
buff = pool->allocated;
/* search the allocated list for the buffer */
while (buff != NULL)
{
if (buff->p == p)
{
found = 1;
break;
}
else
{
prev = buff;
buff = buff->next;
}
}
if (!found)
{
/* buffer is not found in the allocated list */
err = pthread_mutex_unlock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
return DXS_MPOOL_BUF_NOT_FOUND;
}
/* remove buff from the allocated list */
if (prev != NULL)
prev->next = buff->next;
else
pool->allocated = buff->next;
/* add buff to the tail of the free list */
buff->next = NULL;
if (pool->free == NULL)
{
pool->free = buff;
}
else
{
struct __buffer *b = pool->free;
while (b->next != NULL)
b = b->next;
b->next = buff;
}
err = pthread_mutex_unlock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
return DXS_MPOOL_OK;
}
/**
Obtain the number of busy and free buffers in a pool.
\param pool_id Memory pool selector.
\param *busy Returned parameter reflecting number of busy buffers.
\param *free Returned parameter reflecting number of free buffers.
\return
None.
*/
void mempool_status(void *pool_id, uint16_t *busy, uint16_t *free)
{
struct __mempool *pool = (struct __mempool *)pool_id;
struct __buffer *b;
int err;
/* TODO: trap on wild pool_id ? */
err = pthread_mutex_lock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
*free = 0;
b = pool->free;
if (b != NULL)
{
while (b != NULL)
{
(*free)++;
b = b->next;
}
}
*busy = 0;
b = pool->allocated;
if (b != NULL)
{
while (b != NULL)
{
(*busy)++;
b = b->next;
}
}
err = pthread_mutex_unlock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
}
/**
Destroy a memory buffer pool.
\param pool_id Memory pool selector.
\return
None.
*/
void mempool_destroy(void *pool_id)
{
struct __mempool *pool = (struct __mempool *)pool_id;
int err;
/* TODO: trap on wild pool_id ? */
err = pthread_mutex_lock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
pool->in_use = 0;
err = pthread_mutex_unlock (&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
err = pthread_mutex_destroy(&pool->mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
}