/*
* The young Library
* Copyright (c) 2005 by Yang Huan(杨桓)
* Permission to use, copy, modify, distribute and sell this software for any
* purpose is hereby granted without fee, provided that the above copyright
* notice appear in all copies and that both that copyright notice and this
* permission notice appear in supporting documentation.
* The author make no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
*/
/*
* 内存池由 MEMORY_POOL_LISTS 个链表组成,每个链表分别管理不同大小的内存块,
* 每个链表管理的内存块大小 = MEMORY_POOL_MIN + 索引 * MEMORY_POOL_ALIGN
*
* 内存池原理图:
* 索引:0 1 2 3 ...... MEMORY_POOL_LISTS - 1
* --------------------------------------------------------------------------
* | useable | | | | ...... | |
* --------------------------------------------------------------------------
* | buffer |
* -----------
* | first |
* -----------
* |
* |
* | --------
* ->| next |--
* |------| |
* | use | |
* |------| |
* | page | |
* -------- |
* |
* ----------
* |
* | --------
* ->| next | --> NULL
* |------|
* | use | 注:使用该字的二进制位来记录内存页中各内存块的使用状态
* |------|
* | page | 注:内存页大小 = 该链表处理的内存块大小 * use的位数
* --------
*/
/******************************************************************************/
/******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "yc_memory.h"
#ifdef __cplusplus
namespace youngc { extern "C" {
#endif
/******************************************************************************/
/******************************************************************************/
enum YOUNG_LIBRARY_MEMORY_CONSTANT
{
MEMORY_ALIGN_SIZE = sizeof(int),
MEMORY_POOL_BUFFER = 8,
MEMORY_POOL_ALIGN = 4,
MEMORY_POOL_MIN = 8,
MEMORY_POOL_MAX = 128,
MEMORY_POOL_BLOCKS = sizeof(ylib_word_t) * BYTE_BITS,
MEMORY_POOL_LISTS = ( MEMORY_POOL_MAX - MEMORY_POOL_MIN )
/ MEMORY_POOL_ALIGN + 1
};
typedef struct memory_page
{
ylib_word_t use; /* 二进制位映射的内存块已使用则该位为1,否则为0 */
struct memory_page* next; /* 下一个内存页 */
} mempage_t;
typedef struct memory_list
{
size_t useable; /* 未满的可供分配的内存页数 */
mempage_t* buffer[MEMORY_POOL_BUFFER]; /* 页面缓存 */
mempage_t* first; /* 第一个内存页 */
} memlist_t;
#define MEMALLOC( bytes) malloc( bytes )
#define MEMFREE( ptr ) free( ptr )
#define LIST_INDEX( bytes ) \
( (bytes) <= MEMORY_POOL_MIN ? 0 \
: ((bytes) - MEMORY_POOL_MIN + MEMORY_POOL_ALIGN - 1) \
/ MEMORY_POOL_ALIGN )
#define BLOCK_SIZE( index ) ( MEMORY_POOL_MIN + (index) * MEMORY_POOL_ALIGN )
#define PAGE_SIZE( index ) ( BLOCK_SIZE(index) * MEMORY_POOL_BLOCKS )
/******************************************************************************/
/******************************************************************************/
static void (*pool_lock)( size_t ) = NULL;
static void (*pool_unlock)( size_t ) = NULL;
static size_t pool_alloc_count = 0;
static size_t pool_dealloc_count = 0;
static memlist_t pool[MEMORY_POOL_LISTS] = { {0, {NULL}, NULL} };
static unsigned char bitmap[] =
{
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};
/******************************************************************************/
/******************************************************************************/
size_t get_pool_lists_count( void )
{
return MEMORY_POOL_LISTS;
}
size_t get_pool_alloc_count( void )
{
return pool_alloc_count;
}
size_t get_pool_dealloc_count( void )
{
return pool_dealloc_count;
}
void set_pool_lock( void (*lock)(size_t) )
{
pool_lock = lock;
}
void set_pool_unlock( void (*unlock)(size_t) )
{
pool_unlock = unlock;
}
/******************************************************************************/
size_t memalign( size_t element_size, bool memory_type )
{
size_t residue = MEMORY_ALIGN_SIZE - 1;
size_t alignsize = element_size & ~residue;
if( element_size & residue )
alignsize += MEMORY_ALIGN_SIZE;
if( memory_type == true && alignsize < sizeof(ylib_inner_t) )
alignsize = sizeof(ylib_inner_t);
return alignsize;
}
/******************************************************************************/
void pool_print( void )
{
int i, j;
mempage_t* curr;
ylib_word_t mask;
char *str_last, bits[MEMORY_POOL_BLOCKS + 1] = { '\0' };
for( i = 0; i < MEMORY_POOL_LISTS; ++i )
{
if( !(pool[i].first) )
continue;
printf( "\npool[%d] chunk = %d", i, BLOCK_SIZE(i) );
printf( "\n\tpool[%d].useable = %u", i, pool[i].useable );
for( j = 0; j < MEMORY_POOL_BUFFER; ++j )
printf( "\n\tpool[%d].buffer[%d] = %p", i, j, pool[i].buffer[j] );
printf( "\n\tpool[%d].first = %p: ", i, pool[i].first );
curr = pool[i].first;
while( curr )
{
mask = 1;
str_last = bits + MEMORY_POOL_BLOCKS;
for( j = 0; j < MEMORY_POOL_BLOCKS; ++j, mask <<= 1 )
*--str_last = (char)(curr->use & mask ? '1' : '0');
printf( "\n\t" );
printf( "next = %p | use = %s", curr->next, bits );
curr = curr->next;
}
}
}
/******************************************************************************/
static void* page_alloc( size_t index, mempage_t* curr )
{
void* ptr = NULL;
size_t i;
/* 先找到第一个空闲块所在的字节 */
for( i = 0; i < sizeof(ylib_word_t); ++i )
{
ylib_byte_t value = (ylib_byte_t)( curr->use >> (BYTE_BITS * i) );
if( value != YLIB_BYTE_MAX )
{
ylib_word_t mask = 1;
size_t biti = bitmap[value]; /* 从映射表中查找第一个等于 0 的位 */
mask <<= ( BYTE_BITS * i + biti ); /* 计算掩码 */
curr->use |= mask; /* 设置使用标志 */
ptr = (ylib_byte_t*)curr + sizeof(mempage_t)
+ (i * BYTE_BITS + biti) * BLOCK_SIZE( index );
if( curr->use == YLIB_WORD_MAX )
--( pool[index].useable );
return ptr;
} /* end if */
} /* end for i */
return ptr;
}
/******************************************************************************/
void* pool_alloc( size_t bytes )
{
void* ptr = NULL;
if( bytes > MEMORY_POOL_MAX )
{
ptr = MEMALLOC( bytes );
}
else
{
int i;
mempage_t* pg = NULL;
size_t index = LIST_INDEX( bytes );
if( pool_lock )
pool_lock( index );
if( pool[index].first && pool[index].useable > 0 )
{
mempage_t *prev = NULL, *curr = NULL;
/* 先查找页面缓存 */
for( i = 0; i < MEMORY_POOL_BUFFER; ++i )
{
if( pool[index].buffer[i] )
{
ptr = page_alloc( index, pool[index].buffer[i] );
/* 如果该页已满,则将该页自页面缓存中退出 */
if( pool[index].buffer[i]->use == YLIB_WORD_MAX )
pool[index].buffer[i] = NULL;
else if( i > 0 )
{
/* 如果该页不在缓存首,则将该页调整至缓存首 */
pool[index].buffer[0] = pool[index].buffer[i];
pool[index].buffer[i] = NULL;
}
goto EXIT_POOL_ALLOC;
}
} /* 页面缓存 */
/* 页面缓存为空,则遍历链中的所有内存页寻找空闲的内存块 */
curr = pool[index].first;
while( curr )
{
if( curr->use == YLIB_WORD_MAX ) /* 该页中没有空闲块 */
{
/* 进入下一页 */
prev = curr;
curr = curr->next;
}
else /* 该页中有空闲块 */
{
size_t count = 0;
ptr = page_alloc( index, curr );
/* 继续遍历链表,寻找其他未满的页面,将之放入页面缓存 */
while( curr && count < pool[index].useable )
{
if( curr->use != YLIB_WORD_MAX )
{
/* 页面缓存还有位置则放入页面缓存 */
if( count < MEMORY_POOL_BUFFER )
pool[index].buffer[count] = curr;
++count;
/* 如果当前页未满并且不在链首,则将之移至链首 */
if( pool[index].first != curr )
{
prev->next = curr->next;
curr->next = pool[index].first;
pool[index].first = curr;
curr = prev->next;
continue;
}
}
prev = curr;
curr = curr->next;
}
goto EXIT_POOL_ALLOC;
} /* end else */
} /* end while */
} /* end if */
else
{
/* 该链下未分配内存页或无空闲块,此时需增加新的内存页 */
pg = (mempage_t*)MEMALLOC( sizeof(mempage_t) + PAGE_SIZE(index) );
if( pg )
{
pg->next = pool[index].first;
pool[index].first = pg;
pg->use = 1;
ptr = (ylib_byte_t*)pg + sizeof(mempage_t);
++( pool[index].useable );
pool[index].buffer[0] = pg;
}
}
EXIT_POOL_ALLOC:
if( pool_unlock )
pool_unlock( index );
} /* end else */
if( ptr )
++pool_alloc_count;
return ptr;
}
/******************************************************************************/
void pool_dealloc( void* ptr, size_t bytes )
{
if( !ptr )
return;
if( bytes <= MEMORY_POOL_MAX )
{
size_t index = LIST_INDEX( bytes );
size_t pagesize = PAGE_SIZE( index );
mempage_t *prev = NULL, *curr = pool[index].first;
ylib_byte_t *begin, *end, *blk = (ylib_byte_t*)ptr;
if( pool_lock )
pool_lock( index );
while( curr )
{
begin = (ylib_byte_t*)curr + sizeof(mempage_t);
end = begin + pagesize;
if( blk < begin || blk >= end ) /* 判断ptr是否在当前页内 */
{
prev = curr;
curr = curr->next;
}
else
{
size_t blk_size = BLOCK_SIZE( index );
/* 检查ptr是否正确 */
if( (blk - begin) % blk_size == 0 )
{
ylib_word_t mask = 1;
size_t blk_index = (blk - begin) / blk_size;
size_t old = curr->use;
mask <<= blk_index;
curr->use &= ~mask;
/* 如果当前页不在链首,则将之移至链首 */
if( pool[index].first != curr )
{
prev->next = curr->next;
curr->next = pool[index].first;
pool[index].first = curr;
}
/* 如果归还前内存页已满,则将可用页数加一 */
if( old == YLIB_WORD_MAX )
++( pool[index].useable );
++pool_dealloc_count;
}
break;
} /* end else */
} /* end while */
if( pool_unlock )
pool_unlock( index );
return;
} /* end if */
/* ptr不是由内存池分配 */
MEMFREE( ptr );
++pool_dealloc_count;
}
/******************************************************************************/
void pool_free( void* ptr, size_t bytes )
{
if( ptr )
pool_dealloc( ptr, bytes );
if( bytes <= MEMORY_POOL_MAX )
{
int i;
size_t index = LIST_INDEX( bytes );
mempage_t *erase = NULL, *prev = NULL, *curr = pool[index].first;
if( pool_lock )
pool_lock( index );
while( curr )
{
if( curr->use != 0 ) /* 判断是否是空闲页 */
{
prev = curr;
curr = curr->next;
}
else
{
/* 从页面缓存中退出 */
for( i = 0; i < MEMORY_POOL_BUFFER; ++i )
{
if( pool[index].buffer[i] == curr )
{
pool[index].buffer[i] = NULL;
break;
}
}
if( prev )
prev->next = curr->next; /* 空闲页不在链首 */
else
pool[index].first = curr->next; /* 空闲页在链首 */
/* 将空闲页释放 */
erase = curr;
curr = curr->next;
MEMFREE( erase );
--( pool[index].useable );
} /* end if */
} /* end while */
if( pool_unlock )
pool_unlock( index );
}
}
/******************************************************************************/
/******************************************************************************/
#ifdef __cplusplus
} }
#endif
/******************************************************************************/
/******************************************************************************/