char*ngx_http_lua_shared_dict(ngx_conf_t*cf,ngx_command_t*cmd,void*conf){ngx_http_lua_main_conf_t*lmcf=conf;ngx_str_t*value,name;ngx_shm_zone_t*zone;ngx_shm_zone_t**zp;ngx_http_lua_shdict_ctx_t*ctx;ssize_tsize;if(lmcf->shdict_zones==NULL){lmcf->shdict_zones=ngx_palloc(cf->pool,sizeof(ngx_array_t));if(lmcf->shdict_zones==NULL){returnNGX_CONF_ERROR;}if(ngx_array_init(lmcf->shdict_zones,cf->pool,2,sizeof(ngx_shm_zone_t*))!=NGX_OK){returnNGX_CONF_ERROR;}}value=cf->args->elts;ctx=NULL;if(value[1].len==0){ngx_conf_log_error(NGX_LOG_EMERG,cf,0,"invalid lua shared dict name \"%V\"",&value[1]);returnNGX_CONF_ERROR;}name=value[1];size=ngx_parse_size(&value[2]);if(size<=8191){ngx_conf_log_error(NGX_LOG_EMERG,cf,0,"invalid lua shared dict size \"%V\"",&value[2]);returnNGX_CONF_ERROR;}ctx=ngx_pcalloc(cf->pool,sizeof(ngx_http_lua_shdict_ctx_t));if(ctx==NULL){returnNGX_CONF_ERROR;}ctx->name=name;ctx->main_conf=lmcf;ctx->log=&cf->cycle->new_log;zone=ngx_http_lua_shared_memory_add(cf,&name,(size_t)size,&ngx_http_lua_module);if(zone==NULL){returnNGX_CONF_ERROR;}if(zone->data){ctx=zone->data;ngx_conf_log_error(NGX_LOG_EMERG,cf,0,"lua_shared_dict \"%V\" is already defined as ""\"%V\"",&name,&ctx->name);returnNGX_CONF_ERROR;}zone->init=ngx_http_lua_shdict_init_zone;zone->data=ctx;zp=ngx_array_push(lmcf->shdict_zones);if(zp==NULL){returnNGX_CONF_ERROR;}*zp=zone;lmcf->requires_shm=1;returnNGX_CONF_OK;}
structngx_http_lua_main_conf_s{lua_State*lua;ngx_str_tlua_path;ngx_str_tlua_cpath;ngx_cycle_t*cycle;ngx_pool_t*pool;ngx_int_tmax_pending_timers;ngx_int_tpending_timers;ngx_int_tmax_running_timers;ngx_int_trunning_timers;ngx_connection_t*watcher;/* for watching the process exit event */#if (NGX_PCRE)
ngx_int_tregex_cache_entries;ngx_int_tregex_cache_max_entries;ngx_int_tregex_match_limit;#if (LUA_HAVE_PCRE_JIT)
pcre_jit_stack*jit_stack;#endif
#endif
ngx_array_t*shm_zones;/* of ngx_shm_zone_t* */ngx_array_t*shdict_zones;/* shm zones of "shdict" */ngx_array_t*preload_hooks;/* of ngx_http_lua_preload_hook_t */ngx_flag_tpostponed_to_rewrite_phase_end;ngx_flag_tpostponed_to_access_phase_end;ngx_http_lua_main_conf_handler_ptinit_handler;ngx_str_tinit_src;ngx_http_lua_main_conf_handler_ptinit_worker_handler;ngx_str_tinit_worker_src;ngx_http_lua_balancer_peer_data_t*balancer_peer_data;/* balancer_by_lua does not support yielding and
* there cannot be any conflicts among concurrent requests,
* thus it is safe to store the peer data in the main conf.
*/ngx_uint_tshm_zones_inited;ngx_http_lua_sema_mm_t*sema_mm;ngx_uint_tmalloc_trim_cycle;/* a cycle is defined as the number
of reqeusts */ngx_uint_tmalloc_trim_req_count;#if nginx_version >= 1011011
/* the following 2 fields are only used by ngx.req.raw_headers() for now */ngx_buf_t**busy_buf_ptrs;ngx_int_tbusy_buf_ptr_count;#endif
unsignedrequires_header_filter:1;unsignedrequires_body_filter:1;unsignedrequires_capture_filter:1;unsignedrequires_rewrite:1;unsignedrequires_access:1;unsignedrequires_log:1;unsignedrequires_shm:1;unsignedrequires_capture_log:1;};
ngx_shm_zone_t*ngx_http_lua_shared_memory_add(ngx_conf_t*cf,ngx_str_t*name,size_tsize,void*tag){ngx_http_lua_main_conf_t*lmcf;ngx_shm_zone_t**zp;ngx_shm_zone_t*zone;ngx_http_lua_shm_zone_ctx_t*ctx;ngx_int_tn;lmcf=ngx_http_conf_get_module_main_conf(cf,ngx_http_lua_module);if(lmcf==NULL){returnNULL;}if(lmcf->shm_zones==NULL){lmcf->shm_zones=ngx_palloc(cf->pool,sizeof(ngx_array_t));if(lmcf->shm_zones==NULL){returnNULL;}if(ngx_array_init(lmcf->shm_zones,cf->pool,2,sizeof(ngx_shm_zone_t*))!=NGX_OK){returnNULL;}}zone=ngx_shared_memory_add(cf,name,(size_t)size,tag);if(zone==NULL){returnNULL;}if(zone->data){ctx=(ngx_http_lua_shm_zone_ctx_t*)zone->data;return&ctx->zone;}n=sizeof(ngx_http_lua_shm_zone_ctx_t);ctx=ngx_pcalloc(cf->pool,n);if(ctx==NULL){returnNULL;}ctx->lmcf=lmcf;ctx->log=&cf->cycle->new_log;ctx->cycle=cf->cycle;ngx_memcpy(&ctx->zone,zone,sizeof(ngx_shm_zone_t));zp=ngx_array_push(lmcf->shm_zones);if(zp==NULL){returnNULL;}*zp=zone;/* set zone init */zone->init=ngx_http_lua_shared_memory_init;zone->data=ctx;lmcf->requires_shm=1;return&ctx->zone;}
ngx_shm_zone_t*ngx_shared_memory_add(ngx_conf_t*cf,ngx_str_t*name,size_tsize,void*tag){ngx_uint_ti;ngx_shm_zone_t*shm_zone;ngx_list_part_t*part;part=&cf->cycle->shared_memory.part;shm_zone=part->elts;for(i=0;/* void */;i++){if(i>=part->nelts){if(part->next==NULL){break;}part=part->next;shm_zone=part->elts;i=0;}if(name->len!=shm_zone[i].shm.name.len){continue;}if(ngx_strncmp(name->data,shm_zone[i].shm.name.data,name->len)!=0){continue;}if(tag!=shm_zone[i].tag){ngx_conf_log_error(NGX_LOG_EMERG,cf,0,"the shared memory zone \"%V\" is ""already declared for a different use",&shm_zone[i].shm.name);returnNULL;}if(shm_zone[i].shm.size==0){shm_zone[i].shm.size=size;}if(size&&size!=shm_zone[i].shm.size){ngx_conf_log_error(NGX_LOG_EMERG,cf,0,"the size %uz of shared memory zone \"%V\" ""conflicts with already declared size %uz",size,&shm_zone[i].shm.name,shm_zone[i].shm.size);returnNULL;}return&shm_zone[i];}shm_zone=ngx_list_push(&cf->cycle->shared_memory);if(shm_zone==NULL){returnNULL;}shm_zone->data=NULL;shm_zone->shm.log=cf->cycle->log;shm_zone->shm.size=size;shm_zone->shm.name=*name;shm_zone->shm.exists=0;shm_zone->init=NULL;shm_zone->tag=tag;shm_zone->noreuse=0;returnshm_zone;}
if(ngx_os_init(log)!=NGX_OK){return1;}/*
* ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init()
*/if(ngx_crc32_table_init()!=NGX_OK){return1;}/*
* ngx_slab_sizes_init() requires ngx_pagesize set in ngx_os_init()
*/ngx_slab_sizes_init();if(ngx_add_inherited_sockets(&init_cycle)!=NGX_OK){return1;}if(ngx_preinit_modules()!=NGX_OK){return1;}cycle=ngx_init_cycle(&init_cycle);if(cycle==NULL){if(ngx_test_config){ngx_log_stderr(0,"configuration file %s test failed",init_cycle.conf_file.data);}return1;}
staticngx_int_tngx_init_zone_pool(ngx_cycle_t*cycle,ngx_shm_zone_t*zn){u_char*file;ngx_slab_pool_t*sp;sp=(ngx_slab_pool_t*)zn->shm.addr;if(zn->shm.exists){if(sp==sp->addr){returnNGX_OK;}#if (NGX_WIN32)
/* remap at the required address */if(ngx_shm_remap(&zn->shm,sp->addr)!=NGX_OK){returnNGX_ERROR;}sp=(ngx_slab_pool_t*)zn->shm.addr;if(sp==sp->addr){returnNGX_OK;}#endif
ngx_log_error(NGX_LOG_EMERG,cycle->log,0,"shared zone \"%V\" has no equal addresses: %p vs %p",&zn->shm.name,sp->addr,sp);returnNGX_ERROR;}sp->end=zn->shm.addr+zn->shm.size;sp->min_shift=3;sp->addr=zn->shm.addr;#if (NGX_HAVE_ATOMIC_OPS)
file=NULL;#else
file=ngx_pnalloc(cycle->pool,cycle->lock_file.len+zn->shm.name.len);if(file==NULL){returnNGX_ERROR;}(void)ngx_sprintf(file,"%V%V%Z",&cycle->lock_file,&zn->shm.name);#endif
if(ngx_shmtx_create(&sp->mutex,&sp->lock,file)!=NGX_OK){returnNGX_ERROR;}ngx_slab_init(sp);returnNGX_OK;}
voidngx_slab_init(ngx_slab_pool_t*pool){u_char*p;size_tsize;ngx_int_tm;ngx_uint_ti,n,pages;ngx_slab_page_t*slots,*page;pool->min_size=(size_t)1<<pool->min_shift;slots=ngx_slab_slots(pool);p=(u_char*)slots;size=pool->end-p;ngx_slab_junk(p,size);n=ngx_pagesize_shift-pool->min_shift;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;}p+=n*sizeof(ngx_slab_page_t);pool->stats=(ngx_slab_stat_t*)p;ngx_memzero(pool->stats,n*sizeof(ngx_slab_stat_t));p+=n*sizeof(ngx_slab_stat_t);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);m=pages-(pool->end-pool->start)/ngx_pagesize;if(m>0){pages-=m;page->slab=pages;}pool->last=pool->pages+pages;pool->pfree=pages;pool->log_nomem=1;pool->log_ctx=&pool->zero;pool->zero='\0';}
staticintngx_http_lua_shdict_set_helper(lua_State*L,intflags){inti,n;ngx_str_tkey;uint32_thash;ngx_int_trc;ngx_http_lua_shdict_ctx_t*ctx;ngx_http_lua_shdict_node_t*sd;ngx_str_tvalue;intvalue_type;doublenum;u_charc;lua_Numberexptime=0;u_char*p;ngx_rbtree_node_t*node;ngx_time_t*tp;ngx_shm_zone_t*zone;intforcible=0;/* indicates whether to foricibly override other
* valid entries */int32_tuser_flags=0;ngx_queue_t*queue,*q;n=lua_gettop(L);if(n!=3&&n!=4&&n!=5){returnluaL_error(L,"expecting 3, 4 or 5 arguments, ""but only seen %d",n);}if(lua_type(L,1)!=LUA_TTABLE){returnluaL_error(L,"bad \"zone\" argument");}zone=ngx_http_lua_shdict_get_zone(L,1);if(zone==NULL){returnluaL_error(L,"bad \"zone\" argument");}ctx=zone->data;if(lua_isnil(L,2)){lua_pushnil(L);lua_pushliteral(L,"nil key");return2;}key.data=(u_char*)luaL_checklstring(L,2,&key.len);if(key.len==0){lua_pushnil(L);lua_pushliteral(L,"empty key");return2;}if(key.len>65535){lua_pushnil(L);lua_pushliteral(L,"key too long");return2;}hash=ngx_crc32_short(key.data,key.len);value_type=lua_type(L,3);switch(value_type){caseSHDICT_TSTRING:value.data=(u_char*)lua_tolstring(L,3,&value.len);break;caseSHDICT_TNUMBER:value.len=sizeof(double);num=lua_tonumber(L,3);value.data=(u_char*)#break;caseSHDICT_TBOOLEAN:value.len=sizeof(u_char);c=lua_toboolean(L,3)?1:0;value.data=&c;break;caseLUA_TNIL:if(flags&(NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)){lua_pushnil(L);lua_pushliteral(L,"attempt to add or replace nil values");return2;}ngx_str_null(&value);break;default:lua_pushnil(L);lua_pushliteral(L,"bad value type");return2;}if(n>=4){exptime=luaL_checknumber(L,4);if(exptime<0){returnluaL_error(L,"bad \"exptime\" argument");}}if(n==5){user_flags=(uint32_t)luaL_checkinteger(L,5);}ngx_shmtx_lock(&ctx->shpool->mutex);#if 1
ngx_http_lua_shdict_expire(ctx,1);#endif
rc=ngx_http_lua_shdict_lookup(zone,hash,key.data,key.len,&sd);dd("shdict lookup returned %d",(int)rc);if(flags&NGX_HTTP_LUA_SHDICT_REPLACE){if(rc==NGX_DECLINED||rc==NGX_DONE){ngx_shmtx_unlock(&ctx->shpool->mutex);lua_pushboolean(L,0);lua_pushliteral(L,"not found");lua_pushboolean(L,forcible);return3;}/* rc == NGX_OK */gotoreplace;}if(flags&NGX_HTTP_LUA_SHDICT_ADD){if(rc==NGX_OK){ngx_shmtx_unlock(&ctx->shpool->mutex);lua_pushboolean(L,0);lua_pushliteral(L,"exists");lua_pushboolean(L,forcible);return3;}if(rc==NGX_DONE){/* exists but expired */dd("go to replace");gotoreplace;}/* rc == NGX_DECLINED */dd("go to insert");gotoinsert;}if(rc==NGX_OK||rc==NGX_DONE){if(value_type==LUA_TNIL){gotoremove;}replace:if(value.data&&value.len==(size_t)sd->value_len&&sd->value_type!=SHDICT_TLIST){ngx_log_debug0(NGX_LOG_DEBUG_HTTP,ctx->log,0,"lua shared dict set: found old entry and value ""size matched, reusing it");ngx_queue_remove(&sd->queue);ngx_queue_insert_head(&ctx->sh->lru_queue,&sd->queue);sd->key_len=(u_short)key.len;if(exptime>0){tp=ngx_timeofday();sd->expires=(uint64_t)tp->sec*1000+tp->msec+(uint64_t)(exptime*1000);}else{sd->expires=0;}sd->user_flags=user_flags;sd->value_len=(uint32_t)value.len;dd("setting value type to %d",value_type);sd->value_type=(uint8_t)value_type;p=ngx_copy(sd->data,key.data,key.len);ngx_memcpy(p,value.data,value.len);ngx_shmtx_unlock(&ctx->shpool->mutex);lua_pushboolean(L,1);lua_pushnil(L);lua_pushboolean(L,forcible);return3;}ngx_log_debug0(NGX_LOG_DEBUG_HTTP,ctx->log,0,"lua shared dict set: found old entry but value size ""NOT matched, removing it first");remove:if(sd->value_type==SHDICT_TLIST){queue=ngx_http_lua_shdict_get_list_head(sd,key.len);for(q=ngx_queue_head(queue);q!=ngx_queue_sentinel(queue);q=ngx_queue_next(q)){p=(u_char*)ngx_queue_data(q,ngx_http_lua_shdict_list_node_t,queue);ngx_slab_free_locked(ctx->shpool,p);}}ngx_queue_remove(&sd->queue);node=(ngx_rbtree_node_t*)((u_char*)sd-offsetof(ngx_rbtree_node_t,color));ngx_rbtree_delete(&ctx->sh->rbtree,node);ngx_slab_free_locked(ctx->shpool,node);}insert:/* rc == NGX_DECLINED or value size unmatch */if(value.data==NULL){ngx_shmtx_unlock(&ctx->shpool->mutex);lua_pushboolean(L,1);lua_pushnil(L);lua_pushboolean(L,0);return3;}ngx_log_debug0(NGX_LOG_DEBUG_HTTP,ctx->log,0,"lua shared dict set: creating a new entry");n=offsetof(ngx_rbtree_node_t,color)+offsetof(ngx_http_lua_shdict_node_t,data)+key.len+value.len;dd("overhead = %d",(int)(offsetof(ngx_rbtree_node_t,color)+offsetof(ngx_http_lua_shdict_node_t,data)));node=ngx_slab_alloc_locked(ctx->shpool,n);if(node==NULL){if(flags&NGX_HTTP_LUA_SHDICT_SAFE_STORE){ngx_shmtx_unlock(&ctx->shpool->mutex);lua_pushboolean(L,0);lua_pushliteral(L,"no memory");return2;}ngx_log_debug1(NGX_LOG_DEBUG_HTTP,ctx->log,0,"lua shared dict set: overriding non-expired items ""due to memory shortage for entry \"%V\"",&key);for(i=0;i<30;i++){if(ngx_http_lua_shdict_expire(ctx,0)==0){break;}forcible=1;node=ngx_slab_alloc_locked(ctx->shpool,n);if(node!=NULL){gotoallocated;}}ngx_shmtx_unlock(&ctx->shpool->mutex);lua_pushboolean(L,0);lua_pushliteral(L,"no memory");lua_pushboolean(L,forcible);return3;}allocated:sd=(ngx_http_lua_shdict_node_t*)&node->color;node->key=hash;sd->key_len=(u_short)key.len;if(exptime>0){tp=ngx_timeofday();sd->expires=(uint64_t)tp->sec*1000+tp->msec+(uint64_t)(exptime*1000);}else{sd->expires=0;}sd->user_flags=user_flags;sd->value_len=(uint32_t)value.len;dd("setting value type to %d",value_type);sd->value_type=(uint8_t)value_type;p=ngx_copy(sd->data,key.data,key.len);ngx_memcpy(p,value.data,value.len);ngx_rbtree_insert(&ctx->sh->rbtree,node);ngx_queue_insert_head(&ctx->sh->lru_queue,&sd->queue);ngx_shmtx_unlock(&ctx->shpool->mutex);lua_pushboolean(L,1);lua_pushnil(L);lua_pushboolean(L,forcible);return3;}
void*ngx_slab_alloc_locked(ngx_slab_pool_t*pool,size_tsize){size_ts;uintptr_tp,m,mask,*bitmap;ngx_uint_ti,n,slot,shift,map;ngx_slab_page_t*page,*prev,*slots;if(size>ngx_slab_max_size){ngx_log_debug1(NGX_LOG_DEBUG_ALLOC,ngx_cycle->log,0,"slab alloc: %uz",size);page=ngx_slab_alloc_pages(pool,(size>>ngx_pagesize_shift)+((size%ngx_pagesize)?1:0));if(page){p=ngx_slab_page_addr(pool,page);}else{p=0;}gotodone;}if(size>pool->min_size){shift=1;for(s=size-1;s>>=1;shift++){/* void */}slot=shift-pool->min_shift;}else{shift=pool->min_shift;slot=0;}pool->stats[slot].reqs++;ngx_log_debug2(NGX_LOG_DEBUG_ALLOC,ngx_cycle->log,0,"slab alloc: %uz slot: %ui",size,slot);slots=ngx_slab_slots(pool);page=slots[slot].next;if(page->next!=page){if(shift<ngx_slab_exact_shift){bitmap=(uintptr_t*)ngx_slab_page_addr(pool,page);map=(ngx_pagesize>>shift)/(8*sizeof(uintptr_t));for(n=0;n<map;n++){if(bitmap[n]!=NGX_SLAB_BUSY){for(m=1,i=0;m;m<<=1,i++){if(bitmap[n]&m){continue;}bitmap[n]|=m;i=(n*8*sizeof(uintptr_t)+i)<<shift;p=(uintptr_t)bitmap+i;pool->stats[slot].used++;if(bitmap[n]==NGX_SLAB_BUSY){for(n=n+1;n<map;n++){if(bitmap[n]!=NGX_SLAB_BUSY){gotodone;}}prev=ngx_slab_page_prev(page);prev->next=page->next;page->next->prev=page->prev;page->next=NULL;page->prev=NGX_SLAB_SMALL;}gotodone;}}}}elseif(shift==ngx_slab_exact_shift){for(m=1,i=0;m;m<<=1,i++){if(page->slab&m){continue;}page->slab|=m;if(page->slab==NGX_SLAB_BUSY){prev=ngx_slab_page_prev(page);prev->next=page->next;page->next->prev=page->prev;page->next=NULL;page->prev=NGX_SLAB_EXACT;}p=ngx_slab_page_addr(pool,page)+(i<<shift);pool->stats[slot].used++;gotodone;}}else{/* shift > ngx_slab_exact_shift */mask=((uintptr_t)1<<(ngx_pagesize>>shift))-1;mask<<=NGX_SLAB_MAP_SHIFT;for(m=(uintptr_t)1<<NGX_SLAB_MAP_SHIFT,i=0;m&mask;m<<=1,i++){if(page->slab&m){continue;}page->slab|=m;if((page->slab&NGX_SLAB_MAP_MASK)==mask){prev=ngx_slab_page_prev(page);prev->next=page->next;page->next->prev=page->prev;page->next=NULL;page->prev=NGX_SLAB_BIG;}p=ngx_slab_page_addr(pool,page)+(i<<shift);pool->stats[slot].used++;gotodone;}}ngx_slab_error(pool,NGX_LOG_ALERT,"ngx_slab_alloc(): page is busy");ngx_debug_point();}page=ngx_slab_alloc_pages(pool,1);if(page){if(shift<ngx_slab_exact_shift){bitmap=(uintptr_t*)ngx_slab_page_addr(pool,page);n=(ngx_pagesize>>shift)/((1<<shift)*8);if(n==0){n=1;}/* "n" elements for bitmap, plus one requested */for(i=0;i<(n+1)/(8*sizeof(uintptr_t));i++){bitmap[i]=NGX_SLAB_BUSY;}m=((uintptr_t)1<<((n+1)%(8*sizeof(uintptr_t))))-1;bitmap[i]=m;map=(ngx_pagesize>>shift)/(8*sizeof(uintptr_t));for(i=i+1;i<map;i++){bitmap[i]=0;}page->slab=shift;page->next=&slots[slot];page->prev=(uintptr_t)&slots[slot]|NGX_SLAB_SMALL;slots[slot].next=page;pool->stats[slot].total+=(ngx_pagesize>>shift)-n;p=ngx_slab_page_addr(pool,page)+(n<<shift);pool->stats[slot].used++;gotodone;}elseif(shift==ngx_slab_exact_shift){page->slab=1;page->next=&slots[slot];page->prev=(uintptr_t)&slots[slot]|NGX_SLAB_EXACT;slots[slot].next=page;pool->stats[slot].total+=8*sizeof(uintptr_t);p=ngx_slab_page_addr(pool,page);pool->stats[slot].used++;gotodone;}else{/* shift > ngx_slab_exact_shift */page->slab=((uintptr_t)1<<NGX_SLAB_MAP_SHIFT)|shift;page->next=&slots[slot];page->prev=(uintptr_t)&slots[slot]|NGX_SLAB_BIG;slots[slot].next=page;pool->stats[slot].total+=ngx_pagesize>>shift;p=ngx_slab_page_addr(pool,page);pool->stats[slot].used++;gotodone;}}p=0;pool->stats[slot].fails++;done:ngx_log_debug1(NGX_LOG_DEBUG_ALLOC,ngx_cycle->log,0,"slab alloc: %p",(void*)p);return(void*)p;}
ngx_slab_max_size は上記のように 2048 なのでそれより大きいサイズを割り当てる場合は
191行目の if の条件が true になり、193~205行目で処理されることになります。
staticngx_slab_page_t*ngx_slab_alloc_pages(ngx_slab_pool_t*pool,ngx_uint_tpages){ngx_slab_page_t*page,*p;for(page=pool->free.next;page!=&pool->free;page=page->next){if(page->slab>=pages){if(page->slab>pages){page[page->slab-1].prev=(uintptr_t)&page[pages];page[pages].slab=page->slab-pages;page[pages].next=page->next;page[pages].prev=page->prev;p=(ngx_slab_page_t*)page->prev;p->next=&page[pages];page->next->prev=(uintptr_t)&page[pages];}else{p=(ngx_slab_page_t*)page->prev;p->next=page->next;page->next->prev=page->prev;}page->slab=pages|NGX_SLAB_PAGE_START;page->next=NULL;page->prev=NGX_SLAB_PAGE;pool->pfree-=pages;if(--pages==0){returnpage;}for(p=page+1;pages;pages--){p->slab=NGX_SLAB_PAGE_BUSY;p->next=NULL;p->prev=NGX_SLAB_PAGE;p++;}returnpage;}}if(pool->log_nomem){ngx_slab_error(pool,NGX_LOG_CRIT,"ngx_slab_alloc() failed: no memory");}returnNULL;}
ngx_slab_pool_t * 型の pool の pool->free は ngx_slab_page_t 型になっています。上に書いていますが再度引用します。
voidngx_slab_init(ngx_slab_pool_t*pool){u_char*p;size_tsize;ngx_int_tm;ngx_uint_ti,n,pages;ngx_slab_page_t*slots,*page;pool->min_size=(size_t)1<<pool->min_shift;slots=ngx_slab_slots(pool);p=(u_char*)slots;size=pool->end-p;ngx_slab_junk(p,size);n=ngx_pagesize_shift-pool->min_shift;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;}p+=n*sizeof(ngx_slab_page_t);pool->stats=(ngx_slab_stat_t*)p;ngx_memzero(pool->stats,n*sizeof(ngx_slab_stat_t));p+=n*sizeof(ngx_slab_stat_t);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);m=pages-(pool->end-pool->start)/ngx_pagesize;if(m>0){pages-=m;page->slab=pages;}pool->last=pool->pages+pages;pool->pfree=pages;pool->log_nomem=1;pool->log_ctx=&pool->zero;pool->zero='\0';}