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;
 | ||
| }
 |