/* * Copyright (c) 2020 YuQing <384681@qq.com> * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the Lesser GNU General Public License, version 3 * or later ("LGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the Lesser GNU General Public License * along with this program. If not, see . */ //fast_mblock.h #ifndef _FAST_MBLOCK_H #define _FAST_MBLOCK_H #include #include #include #include #include "common_define.h" #include "fc_memory.h" #include "logger.h" /* following two macros for debug only */ /* #define FAST_MBLOCK_MAGIC_CHECK 1 #define FAST_MBLOCK_MAGIC_NUMBER 1234567890 */ #define FAST_MBLOCK_NAME_SIZE 32 #define FAST_MBLOCK_ORDER_BY_ALLOC_BYTES 1 #define FAST_MBLOCK_ORDER_BY_ELEMENT_SIZE 2 #define FAST_MBLOCK_ORDER_BY_USED_RATIO 3 enum fast_mblock_notify_type { fast_mblock_notify_type_alloc, fast_mblock_notify_type_reclaim, }; /* free node chain */ struct fast_mblock_node { struct fast_mblock_node *next; int offset; //trunk offset int recycle_timestamp; #ifdef FAST_MBLOCK_MAGIC_CHECK int index; int magic; //magic number #endif char data[0]; //the data buffer }; /* malloc chain */ struct fast_mblock_malloc { int64_t ref_count; //refference count int alloc_count; //allocated element count int trunk_size; //trunk bytes struct fast_mblock_malloc *prev; struct fast_mblock_malloc *next; }; struct fast_mblock_chain { struct fast_mblock_node *head; struct fast_mblock_node *tail; }; /* call by alloc trunk */ typedef int (*fast_mblock_object_init_func)(void *element, void *args); /* call by free trunk */ typedef void (*fast_mblock_object_destroy_func)(void *element, void *args); typedef int (*fast_mblock_malloc_trunk_check_func)( const int alloc_bytes, void *args); typedef void (*fast_mblock_malloc_trunk_notify_func)( const enum fast_mblock_notify_type type, const struct fast_mblock_malloc *node, void *args); struct fast_mblock_info { char name[FAST_MBLOCK_NAME_SIZE]; int element_size; //element size int trunk_size; //trunk size int instance_count; //instance count int block_size; int64_t element_total_count; //total element count int64_t element_used_count; //used element count int64_t delay_free_elements; //delay free element count int64_t trunk_total_count; //total trunk count int64_t trunk_used_count; //used trunk count }; struct fast_mblock_trunks { struct fast_mblock_malloc head; //malloc chain to be freed }; struct fast_mblock_object_callbacks { fast_mblock_object_init_func init_func; fast_mblock_object_destroy_func destroy_func; void *args; }; struct fast_mblock_trunk_callbacks { fast_mblock_malloc_trunk_check_func check_func; fast_mblock_malloc_trunk_notify_func notify_func; void *args; }; struct fast_mblock_man { struct fast_mblock_info info; struct { bool need_wait; int exceed_log_level; //for exceed limit int once; //alloc elements once int64_t limit; //<= 0 for no limit bool *pcontinue_flag; } alloc_elements; struct { struct fast_mblock_node *head; int count; } freelist; //free node chain struct fast_mblock_trunks trunks; struct fast_mblock_chain delay_free_chain; //delay free node chain struct fast_mblock_object_callbacks object_callbacks; struct fast_mblock_trunk_callbacks trunk_callbacks; bool need_lock; //if need mutex lock pthread_lock_cond_pair_t lcp; //for read / write free node chain struct fast_mblock_man *prev; //for stat manager struct fast_mblock_man *next; //for stat manager }; #define fast_mblock_get_block_size(element_size) \ (MEM_ALIGN(sizeof(struct fast_mblock_node) + element_size)) #define fast_mblock_get_trunk_size(block_size, element_count) \ (sizeof(struct fast_mblock_malloc) + block_size * element_count) #define fast_mblock_to_node_ptr(data_ptr) \ (struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \ &((struct fast_mblock_node *)0)->data)) #ifdef __cplusplus extern "C" { #endif #define fast_mblock_init(mblock, element_size, alloc_elements_once) \ fast_mblock_init_ex(mblock, element_size, alloc_elements_once, \ 0, NULL, NULL, true) /** mblock init parameters: name: the mblock name mblock: the mblock pointer element_size: element size, such as sizeof(struct xxx) alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once alloc_elements_limit: malloc elements limit, <= 0 for no limit prealloc_trunk_count: prealloc trunk node count object_callbacks: the object callback functions and args need_lock: if need lock trunk_callbacks: the trunk callback functions and args return error no, 0 for success, != 0 fail */ int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name, const int element_size, const int alloc_elements_once, const int64_t alloc_elements_limit, const int prealloc_trunk_count, struct fast_mblock_object_callbacks *object_callbacks, const bool need_lock, struct fast_mblock_trunk_callbacks *trunk_callbacks); /** mblock init parameters: name: the mblock name mblock: the mblock pointer element_size: element size, such as sizeof(struct xxx) alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once alloc_elements_limit: malloc elements limit, <= 0 for no limit init_func: the object init function init_args: the args for object init function need_lock: if need lock return error no, 0 for success, != 0 fail */ static inline int fast_mblock_init_ex1(struct fast_mblock_man *mblock, const char *name, const int element_size, const int alloc_elements_once, const int64_t alloc_elements_limit, fast_mblock_object_init_func init_func, void *init_args, const bool need_lock) { const int prealloc_trunk_count = 0; struct fast_mblock_object_callbacks object_callbacks; object_callbacks.init_func = init_func; object_callbacks.destroy_func = NULL; object_callbacks.args = init_args; return fast_mblock_init_ex2(mblock, name, element_size, alloc_elements_once, alloc_elements_limit, prealloc_trunk_count, &object_callbacks, need_lock, NULL); } /** mblock init parameters: mblock: the mblock pointer element_size: element size, such as sizeof(struct xxx) alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once alloc_elements_limit: malloc elements limit, <= 0 for no limit object_callbacks: the object callback functions and args need_lock: if need lock return error no, 0 for success, != 0 fail */ static inline int fast_mblock_init_ex(struct fast_mblock_man *mblock, const int element_size, const int alloc_elements_once, const int64_t alloc_elements_limit, fast_mblock_object_init_func init_func, void *init_args, const bool need_lock) { return fast_mblock_init_ex1(mblock, NULL, element_size, alloc_elements_once, alloc_elements_limit, init_func, init_args, need_lock); } /** mblock destroy parameters: mblock: the mblock pointer */ void fast_mblock_destroy(struct fast_mblock_man *mblock); static inline int fast_mblock_set_need_wait(struct fast_mblock_man *mblock, const bool need_wait, bool * volatile pcontinue_flag) { if (!mblock->need_lock || mblock->alloc_elements.limit <= 0) { logError("file: "__FILE__", line: %d, " "need_lock: %d != 1 or alloc_elements.limit: %"PRId64" <= 0", __LINE__, mblock->need_lock, mblock->alloc_elements.limit); return EINVAL; } mblock->alloc_elements.need_wait = need_wait; mblock->alloc_elements.pcontinue_flag = pcontinue_flag; if (need_wait) { mblock->alloc_elements.exceed_log_level = LOG_NOTHING; } return 0; } static inline void fast_mblock_set_exceed_log_level( struct fast_mblock_man *mblock, const int log_level) { mblock->alloc_elements.exceed_log_level = log_level; } #define fast_mblock_set_exceed_silence(mblock) \ fast_mblock_set_exceed_log_level(mblock, LOG_NOTHING) /** alloc a node from the mblock parameters: mblock: the mblock pointer return the alloced node, return NULL if fail */ struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock); /** free a node (put a node to the mblock) parameters: mblock: the mblock pointer pNode: the node to free return 0 for success, return none zero if fail */ int fast_mblock_free(struct fast_mblock_man *mblock, struct fast_mblock_node *pNode); /** batch alloc nodes from the mblock parameters: mblock: the mblock pointer count: alloc count chain: return the mblock node chain return 0 for success, return none zero if fail */ int fast_mblock_batch_alloc(struct fast_mblock_man *mblock, const int count, struct fast_mblock_chain *chain); /** batch alloc nodes from the mblock parameters: mblock: the mblock pointer count: alloc count return the alloced node head, return NULL if fail */ static inline struct fast_mblock_node *fast_mblock_batch_alloc1( struct fast_mblock_man *mblock, const int count) { struct fast_mblock_chain chain; if (fast_mblock_batch_alloc(mblock, count, &chain) == 0) { return chain.head; } else { return NULL; } } /** batch free nodes parameters: mblock: the mblock pointer chain: the node chain to free return 0 for success, return none zero if fail */ int fast_mblock_batch_free(struct fast_mblock_man *mblock, struct fast_mblock_chain *chain); /** delay free a node (put a node to the mblock) parameters: mblock: the mblock pointer pNode: the node to free delay: delay seconds to free return 0 for success, return none zero if fail */ int fast_mblock_delay_free(struct fast_mblock_man *mblock, struct fast_mblock_node *pNode, const int delay); /** alloc a object from the mblock parameters: mblock: the mblock pointer return the alloced object, return NULL if fail */ static inline void *fast_mblock_alloc_object(struct fast_mblock_man *mblock) { struct fast_mblock_node *node; node = fast_mblock_alloc(mblock); if (node == NULL) { return NULL; } return node->data; } /** free a object (put the object to the mblock) parameters: mblock: the mblock pointer object: the object to free return 0 for success, return none zero if fail */ static inline int fast_mblock_free_object(struct fast_mblock_man *mblock, void *object) { return fast_mblock_free(mblock, fast_mblock_to_node_ptr(object)); } /** free objects (put objects to the mblock) parameters: mblock: the mblock pointer objs: the object array to free count: the count of the object array return none */ void fast_mblock_free_objects(struct fast_mblock_man *mblock, void **objs, const int count); /** delay free a object (put a node to the mblock) parameters: mblock: the mblock pointer pNode: the node to free delay: delay seconds to free return 0 for success, return none zero if fail */ static inline int fast_mblock_delay_free_object(struct fast_mblock_man *mblock, void *object, const int delay) { return fast_mblock_delay_free(mblock, fast_mblock_to_node_ptr(object), delay); } /** get node count of the mblock parameters: mblock: the mblock pointer return the free node count of the mblock, return -1 if fail */ int fast_mblock_free_count(struct fast_mblock_man *mblock); /** get delay free node count of the mblock parameters: mblock: the mblock pointer return the delay free node count of the mblock, return -1 if fail */ int fast_mblock_delay_free_count(struct fast_mblock_man *mblock); #define fast_mblock_total_count(mblock) (mblock)->info.element_total_count /** init mblock manager parameters: return error no, 0 for success, != 0 fail */ int fast_mblock_manager_init(); /** get mblock stat parameters: stats: return mblock stats size: max size of stats count: return mblock stat count return error no, 0 for success, != 0 fail */ int fast_mblock_manager_stat(struct fast_mblock_info *stats, const int size, int *count); /** print mblock manager stat parameters: hide_empty: if hide empty order_by: order by which field return error no, 0 for success, != 0 fail */ int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by); #define fast_mblock_manager_stat_print(hide_empty) \ fast_mblock_manager_stat_print_ex(hide_empty, FAST_MBLOCK_ORDER_BY_ALLOC_BYTES) typedef void (*fast_mblock_free_trunks_func)(struct fast_mblock_man *mblock, struct fast_mblock_malloc *freelist); /** free the trunks parameters: mblock: the mblock pointer freelist: the trunks to free return error no, 0 for success, != 0 fail */ void fast_mblock_free_trunks(struct fast_mblock_man *mblock, struct fast_mblock_malloc *freelist); /** reclaim the free trunks of the mblock parameters: mblock: the mblock pointer reclaim_target: reclaim target trunks, 0 for no limit reclaim_count: reclaimed trunk count freelist: the free trunks return error no, 0 for success, != 0 fail */ int fast_mblock_reclaim(struct fast_mblock_man *mblock, const int reclaim_target, int *reclaim_count, fast_mblock_free_trunks_func free_trunks_func); #ifdef __cplusplus } #endif #endif