#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define MP_ALIGNMENT 32
#define MP_PAGE_SIZE 4096
#define MP_MAX_ALLOC_FROM_POOL (MP_PAGE_SIZE-1)
#define mp_align(n, alignment) (((n)+(alignment-1)) & ~(alignment-1))
#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))
// 大块内存 大小>4k
struct mp_large_s {
struct mp_large_s *next; // 指向下一个大块内存
void *alloc; // 分配内存的指针
};
// 小块内存 大小=4k
struct mp_node_s {
unsigned char *last; // 指向当前可用内存的位置
unsigned char *end; // 小块内存的结束位置
struct mp_node_s *next; // 指向下一个小块内存
size_t failed; //
};
// 内存池管理器
struct mp_pool_s {
size_t max; // 大小块区分阈值,这里是4k大小
struct mp_node_s *current; // 当前可用小块内存
struct mp_large_s *large; // 大块内存链表头
struct mp_node_s head[0]; // 柔性数组,在这里相当于是当前小块内存的标签
};
/**
* The atomic counter structure.
*/
typedef struct {
volatile int32_t cnt; /**< An internal counter value. */
}mp_atomic32_t;
/**
* Atomically set a counter to a 32-bit value.
*
* @param v
* A pointer to the atomic counter.
* @param new_value
* The new value for the counter.
*/
static inline void
mp_atomic32_set(mp_atomic32_t *v, int32_t new_value)
{
v->cnt = new_value;
}
/**
* Atomically add a 32-bit value to a counter and return the result.
*
* Atomically adds the 32-bits value (inc) to the atomic counter (v) and
* returns the value of v after addition.
*
* @param v
* A pointer to the atomic counter.
* @param inc
* The value to be added to the counter.
* @return
* The value of v after the addition.
*/
static inline int32_t
mp_atomic32_add_return(mp_atomic32_t *v, int32_t inc)
{
return __sync_add_and_fetch(&v->cnt, inc);
}
/**
* Atomically add a 32-bit value to an atomic counter.
*
* @param v
* A pointer to the atomic counter.
* @param inc
* The value to be added to the counter.
*/
static inline void
mp_atomic32_add(mp_atomic32_t *v, int32_t inc)
{
__sync_fetch_and_add(&v->cnt, inc);
}
/**
* Atomically subtract a 32-bit value from an atomic counter.
*
* @param v
* A pointer to the atomic counter.
* @param dec
* The value to be subtracted from the counter.
*/
static inline void
mp_atomic32_sub(mp_atomic32_t *v, int32_t dec)
{
__sync_fetch_and_sub(&v->cnt, dec);
}
/**
* Atomically subtract a 32-bit value from a counter and return
* the result.
*
* Atomically subtracts the 32-bit value (inc) from the atomic counter
* (v) and returns the value of v after the subtraction.
*
* @param v
* A pointer to the atomic counter.
* @param dec
* The value to be subtracted from the counter.
* @return
* The value of v after the subtraction.
*/
static inline int32_t
mp_atomic32_sub_return(mp_atomic32_t *v, int32_t dec)
{
return __sync_sub_and_fetch(&v->cnt, dec);
}
typedef struct mp_buf_s {
struct mp_pool_s * pool;
mp_atomic32_t a;
char ptr[0];
}mp_buf_t;
#define MP_ALIGN_SIZE sizeof(mp_buf_t)
// 创建内存池
struct mp_pool_s *mp_create_pool(size_t size);
// 销毁内存池
void mp_destory_pool(struct mp_pool_s *pool);
// 分配内存,内存对齐
void *mp_alloc(struct mp_pool_s *pool, size_t size);
// 分配内存,内存不对齐
void *mp_nalloc(struct mp_pool_s *pool, size_t size);
// 分配并初始化内存为0
void *mp_calloc(struct mp_pool_s *pool, size_t size);
// 释放内存
void mp_free(struct mp_pool_s *pool, void *p);
struct mp_pool_s *mp_create_pool(size_t size) {
struct mp_pool_s *p;
// 这里不使用malloc分配内存,是因为malloc适用于分配小内存,分配大内存容易出错
// posix_memalign这个函数是linux系统提供,linux在内核对也有2种内存分配管理机制,对应着malloc和posix_memalign
// 另外,管理器和第一个小内存块保存在一起,这么做是为了尽量保证不要出现内存碎片化的情况出现,因为内存池就是为了不要出现内存碎片
int ret = posix_memalign((void **)&p, MP_ALIGNMENT, size + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s));
if (ret) {
return NULL;
}
// 小块最大只能是4k大小(一页)
p->max = (size < MP_MAX_ALLOC_FROM_POOL) ? size : MP_MAX_ALLOC_FROM_POOL;
p->current = p->head;
p->large = NULL;
p->head->last = (unsigned char *)p + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s);
p->head->end = p->head->last + size;
p->head->failed = 0;
return p;
}
void mp_destory_pool(struct mp_pool_s *pool) {
struct mp_node_s *h, *n;
struct mp_large_s *l;
// 先释放大块
for (l = pool->large; l; l = l->next) {
if (l->alloc) {
free(l->alloc);
}
}
// 释放小块
h = pool->head->next;
while (h) {
n = h->next;
free(h);
h = n;
}
free(pool);
}
void mp_reset_pool(struct mp_pool_s *pool) {
struct mp_node_s *h;
struct mp_large_s *l;
for (l = pool->large; l; l = l->next) {
if (l->alloc) {
free(l->alloc);
}
}
pool->large = NULL;
for (h = pool->head; h; h = h->next) {
h->last = (unsigned char *)h + sizeof(struct mp_node_s);
}
}
static void *mp_alloc_block(struct mp_pool_s *pool, size_t size) {
unsigned char *m;
struct mp_node_s *h = pool->head; // 获取小块内存头节点
size_t psize = (size_t)(h->end - (unsigned char *)h); // 获取小块内存的大小
int ret = posix_memalign((void **)&m, MP_ALIGNMENT, psize); // 分配内存
if (ret) return NULL;
struct mp_node_s *p, *new_node, *current;
new_node = (struct mp_node_s*)m; // 新分配的小块内存指针
new_node->end = m + psize; // 设置小块内存的结束地址
new_node->next = NULL;
new_node->failed = 0;
m += sizeof(struct mp_node_s); // 小块内存start指针
m = mp_align_ptr(m, MP_ALIGNMENT); // 分配内存,内存对齐
new_node->last = m + size; // 设置结尾位置,这里设置的结尾表达的的意思是,从新的小块内存中分配了内存
current = pool->current; // 获取当前小块内存
for (p = current; p->next; p = p->next) { // 寻找小块内存最后一个节点
if (p->failed++ > 4) { // 优化搜寻小块内存的速度,如果一个节点被4次跳过,说明这个节点可用内存很小了,通过设置新的current节点,优化搜索可用小块内存的时间
current = p->next;
}
}
p->next = new_node; // 将新的小块内存加入到链表结尾
pool->current = current ? current : new_node;
return m;
}
static void *mp_alloc_large(struct mp_pool_s *pool, size_t size) {
void *p;
int ret = posix_memalign(&p, MP_ALIGNMENT, size); // 生成大块内存
if (p == NULL) return NULL;
size_t n = 0;
struct mp_large_s *large;
for (large = pool->large; large; large = large->next) {
if (large->alloc == NULL) {
large->alloc = p;
return p;
}
if (n ++ > 3) break;
}
large = mp_alloc(pool, sizeof(struct mp_large_s));
if (large == NULL) {
free(p);
return NULL;
}
large->alloc = p; // 头插法
large->next = pool->large;
pool->large = large;
return p;
}
void *mp_memalign(struct mp_pool_s *pool, size_t size, size_t alignment) {
void *p;
int ret = posix_memalign(&p, MP_ALIGNMENT, size);
if (ret) {
return NULL;
}
struct mp_large_s *large = mp_alloc(pool, sizeof(struct mp_large_s));
if (large == NULL) {
free(p);
return NULL;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
void *mp_alloc(struct mp_pool_s *pool, size_t size) {
unsigned char *m;
struct mp_node_s *p;
// 判断大小块
if (size <= pool->max) {
// p = 当前小块
p = pool->current;
// 遍历小块内存链表
do {
// 内存对齐
m = mp_align_ptr(p->last, MP_ALIGNMENT);
if ((size_t)(p->end - m) >= size) {
p->last = m + size;
return m;
}
p = p->next;
} while (p);
// 如果没有小块内存可分配,就再生成一个小块内存,从其中分配内存
return mp_alloc_block(pool, size);
}
// 如果属于大块内存,则分配大块内存
return mp_alloc_large(pool, size);
}
void *mp_nalloc(struct mp_pool_s *pool, size_t size) {
unsigned char *m;
struct mp_node_s *p;
if (size <= pool->max) {
p = pool->current;
do {
m = p->last;
if ((size_t)(p->end - m) >= size) {
p->last = m+size;
return m;
}
p = p->next;
} while (p);
return mp_alloc_block(pool, size);
}
return mp_alloc_large(pool, size);
}
void *mp_calloc(struct mp_pool_s *pool, size_t size) {
void *p = mp_alloc(pool, size);
if (p) {
memset(p, 0, size);
}
return p;
}
void mp_free(struct mp_pool_s *pool, void *p) {
struct mp_large_s *l;
for (l = pool->large; l; l = l->next) {
if (p == l->alloc) {
free(l->alloc);
l->alloc = NULL;
return ;
}
}
}
typedef struct {
struct mp_pool_s * pool;
}session_t;
void mp_buf_atomic_inc(void * buf)
{
mp_buf_t * mp_buf = (mp_buf_t*)((char*)buf - MP_ALIGN_SIZE);
mp_atomic32_add(&mp_buf->a, 1);
}
void mp_buf_atomic_dec(void * buf)
{
mp_buf_t * mp_buf = (mp_buf_t*)((char*)buf - MP_ALIGN_SIZE);
mp_atomic32_sub(&mp_buf->a, 1);
}
enum {
MEM_IS_NORMAL,
MEM_IS_MEMPOOL,
}
//该接口调用后可以正常释放
//MEM_IS_MEMPOOL类型的 调用mp_buf_free(buf)
//MEM_IS_NORMAL类型的调用 free()
int io_send_buf(void * buf, int type)
{
if (type == MEM_IS_NORMAL) {
//尽量发送,直到发送成功,或者失败
}else {
//可以放到c->io_pool上延迟发送
//如果挂载到c->io_pool上,则调用mp_buf_atomic_inc增加引用计数
//在io模块调用mp_buf_free进行释放,要保证buf->pool不会先于buf释放
}
}
void * mp_buf_alloc(session_t * session, size_t size) {
size_t total_size = size + MP_ALIGN_SIZE;
struct mp_pool_s * pool = session->pool;
void * p = mp_alloc(pool, total_size);
if (p == NULL)
return NULL;
mp_buf_t * buf = (mp_buf_t *)p;
buf->pool = pool;
mp_atomic32_set(&buf->a, 1);
return (void*)(buf + 1);
}
void mp_buf_free(void * buf)
{
mp_buf_t * mp_buf = (mp_buf_t*)((char*)buf - MP_ALIGN_SIZE);
if (mp_atomic32_sub_return(&mp_buf->a, 1) == 0) {
mp_free(mp_buf->pool, buf);
}
}
int main(int argc, char *argv[]) {
int size = 1 << 12;
session_t sess = {NULL};
sess.pool = mp_create_pool(size);
int i = 0;
for (i = 0;i < 10;i ++) {
void *mp = mp_buf_alloc(&sess, 512);
mp_buf_free(mp);
}
//printf("mp_create_pool: %ld\n", p->max);
printf("mp_align(123, 32): %d, mp_align(17, 32): %d\n", mp_align(24, 32), mp_align(17, 32));
//printf("mp_align_ptr(p->current, 32): %lx, p->current: %lx, mp_align(p->large, 32): %lx, p->large: %lx\n", mp_align_ptr(p->current, 32), p->current, mp_align_ptr(p->large, 32), p->large);
int j = 0;
for (i = 0;i < 5;i ++) {
char *pp = mp_buf_alloc(&sess, 32);
for (j = 0;j < 32;j ++) {
if (pp[j]) {
printf("calloc wrong\n");
}
printf("calloc success\n");
}
}
//printf("mp_reset_pool\n");
for (i = 0;i < 5;i ++) {
void *l = mp_buf_alloc(&sess, 8192);
mp_buf_free(sess.pool);
}
mp_reset_pool(sess.pool);
//printf("mp_destory_pool\n");
for (i = 0;i < 58;i ++) {
mp_buf_alloc(&sess, 256);
}
mp_destory_pool(sess.pool);
return 0;
}