| /****************************************************************************** |
| |
| 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); |
| } |