/*
设计说明:
当page划分的slot块小于128个字节时候,pre的后两位为NGX_SLAB_SMALL
当page划分的slot块等于128个字节时候,pre的后两位为NGX_SLAB_EXACT
当page划分的slot块大于128个字节时候,pre的后两位为NGX_SLAB_BIG
当page划分的slot块大于2048个字节时候,pre的后两位为NGX_SLAB_PAGE
*/
#define NGX_SLAB_PAGE_MASK 3
#define NGX_SLAB_PAGE 0
#define NGX_SLAB_BIG 1
#define NGX_SLAB_EXACT 2
#define NGX_SLAB_SMALL 3
#if (NGX_PTR_SIZE == 4)
#define NGX_SLAB_PAGE_FREE 0
#define NGX_SLAB_PAGE_BUSY 0xffffffff
#define NGX_SLAB_PAGE_START 0x80000000
#define NGX_SLAB_SHIFT_MASK 0x0000000f
#define NGX_SLAB_MAP_MASK 0xffff0000
#define NGX_SLAB_MAP_SHIFT 16
#define NGX_SLAB_BUSY 0xffffffff
#else /* (NGX_PTR_SIZE == 8) */
#define NGX_SLAB_PAGE_FREE 0
#define NGX_SLAB_PAGE_BUSY 0xffffffffffffffff
#define NGX_SLAB_PAGE_START 0x8000000000000000
#define NGX_SLAB_SHIFT_MASK 0x000000000000000f
#define NGX_SLAB_MAP_MASK 0xffffffff00000000
#define NGX_SLAB_MAP_SHIFT 32
#define NGX_SLAB_BUSY 0xffffffffffffffff
#endif
#define ngx_slab_slots(pool) \
(ngx_slab_page_t *) ((u_char *) (pool) + sizeof(ngx_slab_pool_t))
#define ngx_slab_page_type(page) ((page)->prev & NGX_SLAB_PAGE_MASK)
#define ngx_slab_page_prev(page) \
(ngx_slab_page_t *) ((page)->prev & ~NGX_SLAB_PAGE_MASK)
#define ngx_slab_page_addr(pool, page) \
((((page) - (pool)->pages) << ngx_pagesize_shift) \
+ (uintptr_t) (pool)->start)
#if (NGX_DEBUG_MALLOC)
#define ngx_slab_junk(p, size) ngx_memset(p, 0xA5, size)
#elif (NGX_HAVE_DEBUG_MALLOC)
#define ngx_slab_junk(p, size) \
if (ngx_debug_malloc) ngx_memset(p, 0xA5, size)
#else
#define ngx_slab_junk(p, size)
#endif
static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool,
ngx_uint_t pages);
static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
ngx_uint_t pages);
static void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level,
char *text);
static ngx_uint_t ngx_slab_max_size;
static ngx_uint_t ngx_slab_exact_size;
static ngx_uint_t ngx_slab_exact_shift;
void ngx_slab_sizes_init(void)
{
ngx_uint_t n;
/*
知识补充:
32位机器上,ngx_pagesize一般为4096字节
*/
/*
设计说明:
ngx_slab_max_size 2048字节
ngx_slab_exact_size 128字节
ngx_slab_exact_shift 7 ngx_slab_exact_size对应的页偏移量,4096对应的偏移量是12
*/
ngx_slab_max_size = ngx_pagesize / 2;
ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t));
for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++)
{
/* void */
}
}
void ngx_slab_init(ngx_slab_pool_t *pool)
{
u_char *p;
size_t size;
ngx_int_t m;
ngx_uint_t i, n, pages;
ngx_slab_page_t *slots, *page;
// 设置可以分配的最小字节数,pool->min_shift默认是3,即pool->min_size = 8
pool->min_size = (size_t) 1 << pool->min_shift;
// 获取slot相对地址
slots = ngx_slab_slots(pool);
p = (u_char *) slots;
// 获取slab池子大小
size = pool->end - p;
// 初始化数据(没啥意义)
ngx_slab_junk(p, size);
/*
设计说明:
ngx_pagesize_shift 是页偏移量,4096字节的偏移量是12
*/
n = ngx_pagesize_shift - pool->min_shift;
/*
设计说明:
slot 一般只用来标记 8 16 32 64 128 256 512 1024 2048 一个9个
*/
for (i = 0; i < n; i++)
{
/* only "next" is used in list head */
slots[i].slab = 0;
slots[i].next = &slots[i];
slots[i].prev = 0;
}
// 跳过slot列表
p += n * sizeof(ngx_slab_page_t);
// 设置slab池状态
pool->stats = (ngx_slab_stat_t *) p;
ngx_memzero(pool->stats, n * sizeof(ngx_slab_stat_t));
// 跳过stats列表
p += n * sizeof(ngx_slab_stat_t);
// 更新size,刨除 slots+stats
size -= n * (sizeof(ngx_slab_page_t) + sizeof(ngx_slab_stat_t));
// 计算剩余页数
pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t)));
pool->pages = (ngx_slab_page_t *) p;
ngx_memzero(pool->pages, pages * sizeof(ngx_slab_page_t));
// 页数据
page = pool->pages;
/* only "next" is used in list head */
pool->free.slab = 0;
pool->free.next = page;
pool->free.prev = 0;
// 记录可以分配的页数目
page->slab = pages;
page->next = &pool->free;
page->prev = (uintptr_t) &pool->free;
// 设置起始点(字节对齐)
pool->start = ngx_align_ptr(p + pages * sizeof(ngx_slab_page_t),
ngx_pagesize);
/*
设计说明:
因为字节对齐,会浪费一定的内存空间,因此需要重新计算pages
*/
m = pages - (pool->end - pool->start) / ngx_pagesize;
if (m > 0) {
pages -= m;
page->slab = pages;
}
// 设置slab池的末尾节点
pool->last = pool->pages + pages;
pool->pfree = pages;
pool->log_nomem = 1;
pool->log_ctx = &pool->zero;
pool->zero = '\0';
}