http://wenku.baidu.com/view/31fe434dfe4733687e21aae1.html
http://apps.hi.baidu.com/share/detail/33027791
http://down.chinaz.com/server/201201/1577_1.htm
http://www.abo321.org/archives/109
http://www.cnblogs.com/sld666666/archive/2010/06/27/1766255.html
多个pool 使用d.next指针来窜起来,large链表指向大块的分配,
特定的分配算法有特定的应用场合!!
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_PALLOC_H_INCLUDED_
#define _NGX_PALLOC_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
/*
* NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
* On Windows NT it decreases a number of locked pages in a kernel.
*/
#define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1)
#define NGX_DEFAULT_POOL_SIZE (16 * 1024)
#define NGX_POOL_ALIGNMENT 16
#define NGX_MIN_POOL_SIZE \
ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)), \
NGX_POOL_ALIGNMENT)
typedef void (*ngx_pool_cleanup_pt)(void *data);
typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
struct ngx_pool_cleanup_s {
ngx_pool_cleanup_pt handler;
void *data;
ngx_pool_cleanup_t *next;
};
typedef struct ngx_pool_large_s ngx_pool_large_t;
struct ngx_pool_large_s {
ngx_pool_large_t *next;
void *alloc;
};
typedef struct {
u_char *last;
u_char *end;
ngx_pool_t *next;
ngx_uint_t failed;
} ngx_pool_data_t;
struct ngx_pool_s {
ngx_pool_data_t d;
size_t max;
ngx_pool_t *current;
ngx_chain_t *chain;
ngx_pool_large_t *large;
ngx_pool_cleanup_t *cleanup;
ngx_log_t *log;
};
typedef struct {
ngx_fd_t fd;
u_char *name;
ngx_log_t *log;
} ngx_pool_cleanup_file_t;
void *ngx_alloc(size_t size, ngx_log_t *log);
void *ngx_calloc(size_t size, ngx_log_t *log);
ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
void ngx_destroy_pool(ngx_pool_t *pool);
void ngx_reset_pool(ngx_pool_t *pool);
void *ngx_palloc(ngx_pool_t *pool, size_t size);
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
void ngx_pool_cleanup_file(void *data);
void ngx_pool_delete_file(void *data);
#endif /* _NGX_PALLOC_H_INCLUDED_ */
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
static void *ngx_palloc_block( ngx_pool_t *pool, size_t size );
static void *ngx_palloc_large( ngx_pool_t *pool, size_t size );
ngx_pool_t *
ngx_create_pool( size_t size, ngx_log_t *log )
{
ngx_pool_t *p;
// 地址从16的倍数开始
p = ngx_memalign( NGX_POOL_ALIGNMENT, size, log );
if ( p == NULL )
{
return NULL;
}
//创建新pool,last从第一个位置开始,分配后会向下移动
p->d.last = (u_char *) p + sizeof ( ngx_pool_t );
p->d.end = (u_char *) p + size; // end指向最后,不变
p->d.next = NULL; // 下一个pool为null
p->d.failed = 0; // 失败次数初始化为0
size = size - sizeof ( ngx_pool_t );
p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
p->current = p; //当前pool指向p
p->chain = NULL;
p->large = NULL;
p->cleanup = NULL;
p->log = log;
return p;
}
void
ngx_destroy_pool( ngx_pool_t *pool )
{
ngx_pool_t *p, *n;
ngx_pool_large_t *l;
ngx_pool_cleanup_t *c;
//调用cleanup链表中的每个cleanup的handler函数来回收c的data
for ( c = pool->cleanup; c; c = c->next )
{
if ( c->handler )
{
ngx_log_debug1( NGX_LOG_DEBUG_ALLOC, pool->log, 0,
"run cleanup: %p", c );
c->handler( c->data );
}
}
//free 掉large链表中的所有alloc不为null的项,free large块时已经释放了一部分了
for ( l = pool->large; l; l = l->next )
{
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);
if ( l->alloc )
{
ngx_free(l->alloc);
}
}
#if (NGX_DEBUG)
/*
* we could allocate the pool->log from this pool
* so we can not use this log while the free()ing the pool
*/
for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next)
{
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
"free: %p, unused: %uz", p, p->d.end - p->d.last);
if (n == NULL)
{
break;
}
}
#endif
//释放pool开始的,d的next指向的各个pool,这里才释放pool,程序运行时是不会释放的
//考虑http处理时的特性!!!!!不是多次分配和释放,而是一次性大量分配,然后一次性释放所有!!
for ( p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next )
{
ngx_free( p );
if ( n == NULL )
{
break;
}
}
}
void
ngx_reset_pool( ngx_pool_t *pool )
{
ngx_pool_t *p;
ngx_pool_large_t *l;
// free掉large链表中的所有项
for ( l = pool->large; l; l = l->next)
{
if ( l->alloc )
{
ngx_free( l->alloc );
}
}
pool->large = NULL;
//不free pool指向的所有项,仅仅只是调整d.last的指针指向最初位置,调整pool开始的所有的pool链表
for ( p = pool; p; p = p->d.next )
{
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
}
}
//指针按照4字节对齐分配
void *
ngx_palloc( ngx_pool_t *pool, size_t size )
{
u_char *m;
ngx_pool_t *p;
if ( size <= pool->max )
{
p = pool->current;
//从current开始,遍历所有的pool,如果找到了,就调整last指针,如果没有找到就看下一个pool
do
{
m = ngx_align_ptr( p->d.last, NGX_ALIGNMENT );
if ( (size_t) (p->d.end - m) >= size )
{
p->d.last = m + size;
return m;
}
p = p->d.next;
} while ( p );
//所有的pool中都没有,只能再次分配一个全新的pool了,挂接到当前pool链表中
return ngx_palloc_block( pool, size );
}
//比最大块还要大,只能malloc一下
return ngx_palloc_large( pool, size );
}
//指针没有按照4字节对齐的分配
void *
ngx_pnalloc( ngx_pool_t *pool, size_t size )
{
u_char *m;
ngx_pool_t *p;
if ( size <= pool->max )
{
//从上一次成功分配空间的指针current开始,向下找,一直找到last,
p = pool->current;
do
{
m = p->d.last;
if ( (size_t) ( p->d.end - m ) >= size )
{
p->d.last = m + size;
return m;
}
p = p->d.next;
} while ( p );
//从current找到last还是没找到,则只能再次分配一个block了
return ngx_palloc_block( pool, size );
}
return ngx_palloc_large( pool, size );
}
//分配一个新的pool,链接到pool的d.next指向的pool链表中
static void *
ngx_palloc_block( ngx_pool_t *pool, size_t size )
{
u_char *m;
size_t psize;
ngx_pool_t *p, *newp, *current;
psize = (size_t) ( pool->d.end - (u_char *) pool );
m = ngx_memalign( NGX_POOL_ALIGNMENT, psize, pool->log );
if ( m == NULL )
{
return NULL;
}
newp = (ngx_pool_t *) m;
newp->d.end = m + psize;
newp->d.next = NULL;
newp->d.failed = 0;
m += sizeof ( ngx_pool_data_t );
m = ngx_align_ptr( m, NGX_ALIGNMENT );
newp->d.last = m + size;
//current指向的块可能已经失败次数过多了,则不看current了,向下找,找到一个failed小于4的项
//d.next为单向链表,只向后找,不向前找,current一旦新增了就只向后看了,分配的时候一般都是先用前面的,
//前面的不够了才用后面的
current = pool->current;
for ( p = current; p->d.next; p = p->d.next )
{
if ( p->d.failed++ > 4 )
{
current = p->d.next;
}
}
p->d.next = newp; // 链接到d.next pool 链表中
//调整current指针为当前failed小于4的项,可能分配新项
pool->current = current ? current : newp;
return m;
}
static void *
ngx_palloc_large( ngx_pool_t *pool, size_t size )
{
void *p;
ngx_uint_t n;
ngx_pool_large_t *large;
//分配size大小的项
p = ngx_alloc( size, pool->log );
if ( p == NULL )
{
return NULL;
}
n = 0;
//在large链表中找到一项,alloc设置为刚分配的p,只扫描3项
for ( large = pool->large; large; large = large->next )
{
if ( large->alloc == NULL )
{
large->alloc = p;
return p;
}
if ( n++ > 3 )
{
break;
}
}
//分配一个ngx_pool_large_t结构,将之加入到pool的large链表的头部
large = ngx_palloc( pool, sizeof ( ngx_pool_large_t ) );
if ( large == NULL )
{
ngx_free( p );
return NULL;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
//分配一个large_t结构,分配size大小的内存,加入到pool的large链表的头部
void *
ngx_pmemalign( ngx_pool_t *pool, size_t size, size_t alignment )
{
void *p;
ngx_pool_large_t *large;
p = ngx_memalign( alignment, size, pool->log );
if ( p == NULL )
{
return NULL;
}
large = ngx_palloc( pool, sizeof ( ngx_pool_large_t ) );
if ( large == NULL )
{
ngx_free( p );
return NULL;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
//只处理large链表,不管pool里面的内存,在destroy的时候一次性干掉之
ngx_int_t
ngx_pfree( ngx_pool_t *pool, void *p )
{
ngx_pool_large_t *l;
//首先在large链表中找,如果是large块,则直接free
for ( l = pool->large; l; l = l->next)
{
if ( p == l->alloc )
{
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
"free: %p", l->alloc);
ngx_free( l->alloc );
l->alloc = NULL;
return NGX_OK;
}
}
return NGX_DECLINED;
}
void *
ngx_pcalloc(ngx_pool_t *pool, size_t size)
{
void *p;
p = ngx_palloc( pool, size );
if ( p )
{
ngx_memzero( p, size );
}
return p;
}
ngx_pool_cleanup_t *
ngx_pool_cleanup_add( ngx_pool_t *p, size_t size )
{
ngx_pool_cleanup_t *c;
c = ngx_palloc( p, sizeof ( ngx_pool_cleanup_t ) );
if ( c == NULL )
{
return NULL;
}
if ( size )
{
c->data = ngx_palloc( p, size );
if ( c->data == NULL )
{
return NULL;
}
}
else
{
c->data = NULL;
}
c->handler = NULL;
c->next = p->cleanup;
p->cleanup = c;
ngx_log_debug1( NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c );
return c;
}
void
ngx_pool_run_cleanup_file( ngx_pool_t *p, ngx_fd_t fd )
{
ngx_pool_cleanup_t *c;
ngx_pool_cleanup_file_t *cf;
for ( c = p->cleanup; c; c = c->next )
{
if ( c->handler == ngx_pool_cleanup_file )
{
cf = c->data;
if ( cf->fd == fd )
{
c->handler( cf );
c->handler = NULL;
return;
}
}
}
}
void
ngx_pool_cleanup_file( void *data )
{
ngx_pool_cleanup_file_t *c = data;
ngx_log_debug1( NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d",
c->fd );
if ( ngx_close_file( c->fd ) == NGX_FILE_ERROR )
{
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
ngx_close_file_n " \"%s\" failed", c->name);
}
}
void
ngx_pool_delete_file( void *data )
{
ngx_pool_cleanup_file_t *c = data;
ngx_err_t err;
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s",
c->fd, c->name);
if ( ngx_delete_file( c->name ) == NGX_FILE_ERROR )
{
err = ngx_errno;
if ( err != NGX_ENOENT )
{
ngx_log_error( NGX_LOG_CRIT, c->log, err,
ngx_delete_file_n " \"%s\" failed", c->name );
}
}
if ( ngx_close_file( c->fd ) == NGX_FILE_ERROR )
{
ngx_log_error( NGX_LOG_ALERT, c->log, ngx_errno,
ngx_close_file_n " \"%s\" failed", c->name );
}
}
#if 0
static void *
ngx_get_cached_block(size_t size)
{
void *p;
ngx_cached_block_slot_t *slot;
if (ngx_cycle->cache == NULL)
{
return NULL;
}
slot = &ngx_cycle->cache[(size + ngx_pagesize - 1) / ngx_pagesize];
slot->tries++;
if (slot->number)
{
p = slot->block;
slot->block = slot->block->next;
slot->number--;
return p;
}
return NULL;
}
#endif