275 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/****************************************************************************
 | 
						||
The MIT License (MIT)
 | 
						||
Copyright(c) 2015-2016 David Newman
 | 
						||
https://github.com/djoldman/fmpool/blob/master/fmpool.h
 | 
						||
 | 
						||
Permission is hereby granted, free of charge, to any person obtaining a
 | 
						||
copy of this software and associated documentation files (the "Software"),
 | 
						||
to deal in the Software without restriction, including without limitation
 | 
						||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
						||
and/or sell copies of the Software, and to permit persons to whom the
 | 
						||
Software is furnished to do so, subject to the following conditions:
 | 
						||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
 | 
						||
  The above copyright notice and this permission notice shall be included
 | 
						||
  in all copies or substantial portions of the Software.
 | 
						||
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | 
						||
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						||
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
						||
  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						||
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						||
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
						||
  THE SOFTWARE.
 | 
						||
 | 
						||
****************************************************************************
 | 
						||
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
 | 
						||
 | 
						||
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
 | 
						||
be copied by any method or incorporated into another program without
 | 
						||
the express written consent of Aerospace C.Power. This Information or any portion
 | 
						||
thereof remains the property of Aerospace C.Power. The Information contained herein
 | 
						||
is believed to be accurate and Aerospace C.Power assumes no responsibility or
 | 
						||
liability for its use in any way and conveys no license or title under
 | 
						||
any patent or copyright and makes no representation or warranty that this
 | 
						||
Information is free from patent or copyright infringement.
 | 
						||
 | 
						||
****************************************************************************/
 | 
						||
/* This is file is modified for embeded use, as the memory is limited, the
 | 
						||
* macro define version inlined would take IRAM for every instance, so we
 | 
						||
* change it to the function version
 | 
						||
*/
 | 
						||
 | 
						||
#include "iot_mem_pool.h"
 | 
						||
#include "iot_errno.h"
 | 
						||
#include "os_mem.h"
 | 
						||
 | 
						||
/*
 | 
						||
 *  create a memory pool structure
 | 
						||
 *  block_num - how many blocks can be used max
 | 
						||
 *  block_size - sizeof(block)
 | 
						||
 *  (OUT)pool_ptr - allocated start pointer for the pool if successful
 | 
						||
 *  use_mutex - flag to mark if use mutex lock. if the pool will be used in
 | 
						||
 *  multiple threads, set to 1. otherwise, set to 0.
 | 
						||
 *
 | 
						||
 *  return 0 for success, other for error
 | 
						||
 */
 | 
						||
uint32_t iot_mem_pool_new(module_id_t m_id, uint32_t block_num,
 | 
						||
    uint32_t block_size, iot_mem_pool_t **pool_ptr, uint8_t use_mutex)
 | 
						||
{
 | 
						||
    if (block_num == 0 || block_size == 0) {
 | 
						||
        pool_ptr = NULL;
 | 
						||
        return ERR_INVAL;
 | 
						||
    }
 | 
						||
    iot_mem_pool_t *p = os_mem_malloc(m_id, sizeof(iot_mem_pool_t));
 | 
						||
    if (p == NULL) {
 | 
						||
        pool_ptr = NULL;
 | 
						||
        return ERR_NOMEM;
 | 
						||
    }
 | 
						||
    else {
 | 
						||
        if (iot_mem_pool_init(m_id, block_num, block_size, p, use_mutex)) {
 | 
						||
            /* return fail */
 | 
						||
            os_mem_free(p);
 | 
						||
            pool_ptr = NULL;
 | 
						||
            return ERR_NOMEM;
 | 
						||
        }
 | 
						||
        *pool_ptr = p;
 | 
						||
    }
 | 
						||
 | 
						||
    return 0;
 | 
						||
}
 | 
						||
 | 
						||
/*
 | 
						||
 *  init an exist memory pool structure
 | 
						||
 *  block_num - how many blocks can be used max
 | 
						||
 *  block_size - sizeof(block)
 | 
						||
 *  (IN)pool_ptr - allocated start pointer for the pool if successful
 | 
						||
 *  use_mutex - flag to mark if use mutex lock. if the pool will be used in
 | 
						||
 *  multiple threads, set to 1. otherwise, set to 0.
 | 
						||
 *
 | 
						||
 *  (OUT)return 0 for success, other for error
 | 
						||
 */
 | 
						||
uint32_t iot_mem_pool_init(module_id_t m_id,
 | 
						||
    uint32_t block_num, uint32_t block_size, iot_mem_pool_t *pool_ptr,
 | 
						||
    uint8_t use_mutex)
 | 
						||
{
 | 
						||
    uint32_t size;
 | 
						||
    iot_mem_pool_entry_t *block_addr = NULL;
 | 
						||
    if (block_num == 0 || block_size == 0 || pool_ptr == 0) {
 | 
						||
        pool_ptr = NULL;
 | 
						||
        return ERR_INVAL;
 | 
						||
    }
 | 
						||
    IOT_ASSERT(block_num < 65535);
 | 
						||
    /* alloc the pool's mem, make it word align */
 | 
						||
    if (block_size % sizeof(iot_mem_pool_entry_t)) {
 | 
						||
        size = block_size / sizeof(iot_mem_pool_entry_t) + 1;
 | 
						||
    } else {
 | 
						||
        size = block_size / sizeof(iot_mem_pool_entry_t);
 | 
						||
    }
 | 
						||
    iot_mem_pool_t *p = pool_ptr;
 | 
						||
    {
 | 
						||
        p->entries = os_mem_malloc(m_id,
 | 
						||
            block_num * size * sizeof(iot_mem_pool_entry_t));
 | 
						||
        if (p->entries == NULL) {
 | 
						||
            pool_ptr = NULL;
 | 
						||
            return ERR_NOMEM;
 | 
						||
        }
 | 
						||
        p->pool_mutex = NULL;
 | 
						||
        if (use_mutex && (NULL == (p->pool_mutex = os_create_mutex(m_id)))) {
 | 
						||
            os_mem_free(p->entries);
 | 
						||
            pool_ptr = NULL;
 | 
						||
            return ERR_NOMEM;
 | 
						||
        }
 | 
						||
    }
 | 
						||
    /* init the pool */
 | 
						||
    p->head = (iot_mem_pool_entry_t*)&p->entries->data; /* the first data */
 | 
						||
    p->num = block_num;
 | 
						||
    p->free_num = block_num;
 | 
						||
    p->align_block_word_size = size;
 | 
						||
    for (uint32_t i = 0; i < block_num; i++) {
 | 
						||
        block_addr = p->entries + (size * i);
 | 
						||
        block_addr->next = (iot_mem_pool_entry_t*)&(block_addr + size)->data;
 | 
						||
        if (size > 1) {
 | 
						||
            *((uint32_t *)&block_addr->data + 1) = IOT_MEM_POOL_POISON;
 | 
						||
        }
 | 
						||
    }
 | 
						||
    /* fill last block's next to NULL */
 | 
						||
    block_addr->next = NULL;
 | 
						||
 | 
						||
    return 0;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/* destroy the pool
 | 
						||
*   NB: we shouldn't free the pool normally right now,
 | 
						||
*   for fast allocate and recall without memory frag
 | 
						||
*
 | 
						||
*   TODO: consider the multi-context case
 | 
						||
*   pool_ptr - allocated start pointer for the pool if successful
 | 
						||
*   return 0 for success, other for error
 | 
						||
*/
 | 
						||
uint32_t iot_mem_pool_destroy(iot_mem_pool_t *pool_ptr)
 | 
						||
{
 | 
						||
    if (pool_ptr) {
 | 
						||
        IOT_ASSERT(pool_ptr->free_num == pool_ptr->num);
 | 
						||
        if (pool_ptr->pool_mutex) {
 | 
						||
            os_delete_mutex(pool_ptr->pool_mutex);
 | 
						||
        }
 | 
						||
        os_mem_free(pool_ptr->entries);
 | 
						||
        pool_ptr->entries = NULL;
 | 
						||
        os_mem_free(pool_ptr);
 | 
						||
        return 0;
 | 
						||
    }
 | 
						||
    return ERR_INVAL;
 | 
						||
}
 | 
						||
 | 
						||
void * iot_mem_pool_alloc_with_reserve(iot_mem_pool_t *pool_ptr,
 | 
						||
    uint32_t reserved)
 | 
						||
{
 | 
						||
    iot_mem_pool_entry_t *p_entry;
 | 
						||
 | 
						||
    if (pool_ptr == NULL) {
 | 
						||
        return NULL;
 | 
						||
    }
 | 
						||
 | 
						||
    if (pool_ptr->pool_mutex) {
 | 
						||
        os_acquire_mutex(pool_ptr->pool_mutex);
 | 
						||
    }
 | 
						||
 | 
						||
    if (pool_ptr->free_num <= reserved) {
 | 
						||
        if (pool_ptr->pool_mutex) {
 | 
						||
            os_release_mutex(pool_ptr->pool_mutex);
 | 
						||
        }
 | 
						||
        return NULL;
 | 
						||
    }
 | 
						||
 | 
						||
    p_entry = pool_ptr->head;
 | 
						||
    pool_ptr->head = p_entry->next;
 | 
						||
    pool_ptr->free_num--;
 | 
						||
 | 
						||
    if ((pool_ptr->num - pool_ptr->free_num) > pool_ptr->max_num) {
 | 
						||
        pool_ptr->max_num = (uint16_t)(pool_ptr->num - pool_ptr->free_num);
 | 
						||
    }
 | 
						||
    if (pool_ptr->pool_mutex) {
 | 
						||
        os_release_mutex(pool_ptr->pool_mutex);
 | 
						||
    }
 | 
						||
 | 
						||
    return &p_entry->data;
 | 
						||
}
 | 
						||
 | 
						||
uint32_t iot_mem_pool_free(iot_mem_pool_t *pool_ptr, void *data)
 | 
						||
{
 | 
						||
    if (NULL == pool_ptr) {
 | 
						||
        return ERR_INVAL;
 | 
						||
    }
 | 
						||
    iot_mem_pool_t *p = pool_ptr;
 | 
						||
    iot_mem_pool_entry_t *p_entry = (iot_mem_pool_entry_t *)data;
 | 
						||
 | 
						||
    if ((uint32_t)p_entry < (uint32_t)&p->entries->data
 | 
						||
        || (uint32_t)p_entry >
 | 
						||
        (uint32_t)(&p->entries->data + p->num * p->align_block_word_size)) {
 | 
						||
        IOT_ASSERT(0);
 | 
						||
        return ERR_INVAL;
 | 
						||
    }
 | 
						||
    /* improved check if the correct entry address */
 | 
						||
    IOT_ASSERT((((uint32_t*)data - &p->entries->data) \
 | 
						||
        % (p->align_block_word_size)) == 0);
 | 
						||
 | 
						||
    if (pool_ptr->align_block_word_size > 1) {
 | 
						||
        uint32_t *free_ck_addr = (uint32_t *)data + 1;
 | 
						||
#if IOT_MEM_POOL_DOUBLE_FREE_DBG
 | 
						||
        IOT_ASSERT((uint32_t)IOT_MEM_POOL_POISON != *free_ck_addr);
 | 
						||
#endif
 | 
						||
        *free_ck_addr = (uint32_t)IOT_MEM_POOL_POISON;
 | 
						||
    }
 | 
						||
    if (pool_ptr->pool_mutex) {
 | 
						||
        os_acquire_mutex(pool_ptr->pool_mutex);
 | 
						||
    }
 | 
						||
    p_entry->next = p->head;
 | 
						||
    p->head = p_entry;
 | 
						||
    pool_ptr->free_num++;
 | 
						||
    if (pool_ptr->pool_mutex) {
 | 
						||
        os_release_mutex(pool_ptr->pool_mutex);
 | 
						||
    }
 | 
						||
    return 0;
 | 
						||
}
 | 
						||
 | 
						||
uint32_t iot_mem_pool_force_free(iot_mem_pool_t *pool_ptr, void *data)
 | 
						||
{
 | 
						||
    if (NULL == pool_ptr) {
 | 
						||
        return ERR_INVAL;
 | 
						||
    }
 | 
						||
    iot_mem_pool_t *p = pool_ptr;
 | 
						||
    iot_mem_pool_entry_t *p_entry = (iot_mem_pool_entry_t *)data;
 | 
						||
 | 
						||
    if ((uint32_t)p_entry < (uint32_t)&p->entries->data
 | 
						||
        || (uint32_t)p_entry >
 | 
						||
        (uint32_t)(&p->entries->data + p->num * p->align_block_word_size)) {
 | 
						||
        //IOT_ASSERT(0);
 | 
						||
        return ERR_INVAL;
 | 
						||
    }
 | 
						||
    return iot_mem_pool_free(pool_ptr, data);
 | 
						||
}
 | 
						||
 | 
						||
uint32_t iot_mem_pool_get_freenum(iot_mem_pool_t *pool_ptr)
 | 
						||
{
 | 
						||
    uint32_t freenum = 0;
 | 
						||
    if (NULL == pool_ptr) {
 | 
						||
       return freenum;
 | 
						||
    }
 | 
						||
 | 
						||
    freenum = pool_ptr->free_num;
 | 
						||
 | 
						||
    return freenum;
 | 
						||
}
 | 
						||
 | 
						||
uint32_t iot_mem_pool_get_align_size(iot_mem_pool_t *pool_ptr)
 | 
						||
{
 | 
						||
    uint32_t align_size = 0;
 | 
						||
    if (NULL == pool_ptr) {
 | 
						||
       return align_size;
 | 
						||
    }
 | 
						||
 | 
						||
    align_size = pool_ptr->align_block_word_size * sizeof(iot_mem_pool_entry_t);
 | 
						||
 | 
						||
    return align_size;
 | 
						||
}
 |