apache1.3.39源码alloc.c阅读笔记
apache1.3.39源码alloc.c阅读笔记
2011年06月03日
typedef struct pool pool; 内存块管理API
malloc_block
从系统申请sizeof(block_hdr)+size大小的内存
blok->h.first_avail=(char *)(blok+1);
blok->h.endp = size + blok->h.first_avail;
free_blocks
将一条内存块链加到block_freelist链表开头,该过程会将该链表中所有的h.first_avail置为内存块开头即 (char *)(blok + 1)。
new_block
申请一块内存块,先从block_freelist中找,线性查找,找到第一个满足h.endp-h.first_avail>size+MINFREE条件的返回,并从freelist中去掉,否则调用malloc_block从系统申请,申请的时候也有最小块限制MINALLOC
bytes_in_block_list
返回某个内存块链的总长度(不是可用长度,而是总长度)
pool管理,pool分配大小对齐于align结构体的倍数
#define POOL_HDR_CLICKS (1 + ((sizeof(struct pool) - 1) / CLICK_SZ))
#define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ)
API
ap_block_alarms
ap_unblock_alarms
包装。。临界区?
pool *ap_make_sub_pool(pool *)
创建一个子pool,参数为NULL的时候无父pool,父pool.sub_pools是一个双向链表,新的子pool加入到链表头,free_first_avail指向第一个blok分配了pool结构体之后的内存。
ap_init_alloc
分配全局的父pool static pool *permanent_pool;
void ap_cleanup_alloc(void)
do nothing
ap_clear_pool && ap_destroy_pool
从最底层的子pool开始,调用
run_cleanups(a->cleanups)
free_proc_chain(a->subprocesses);
free_blocks(a->first->h.next);
destroy会把含有pool结构体的block也free掉
free_blocks(a->first);
clear会保留这个结构体所在的block,其他的free掉
总体逻辑
destroy(a)的过程,先clear(a),然后如果a有父pool,那么修改a的父pool的sub_pools链表,以及a自身的sub_pre,sub_next,将a从子pool链中移除。
clear(a)的过程,先destroy掉a的所有子pool,然后调用a的
run_cleanups(a->cleanups);
free_proc_chain(a->subprocesses);
free_blocks(a->first->h.next);
像一个双函数递归过程。
其中
enum kill_conditions {
kill_never, /* process is never sent any signals */
kill_always, /* process is sent SIGKILL on pool cleanup */
kill_after_timeout, /* SIGTERM, wait 3 seconds, SIGKILL */
just_wait, /* wait forever for the process to complete */
kill_only_once /* send SIGTERM and then wait */
};
内存分配api
API_EXPORT(void *) ap_palloc(struct pool *a, int reqsize)
先在pool的最后一个block上找,可用空间是否够,不够就申请一块新的block挂在pool的block链表之后
API_EXPORT(void *) ap_pcalloc(struct pool *a, int size)
调用上述函数之后,调用memset将内存设置为0
API_EXPORT(char *) ap_pstrdup(struct pool *a, const char *s)
在pool上分配strlen(a)+1内存后,把字符串a memcpy 过去
API_EXPORT(char *) ap_pstrndup(struct pool *a, const char *s, int n)
在pool上分配n+1大小的内存,然后从a中memcpy n个字符过去,最后补0
API_EXPORT_NONSTD(char *) ap_pstrcat(pool *a,...)
在pool上分配字符串总长度+1大小的内存,然后把各个字符串cat成一个。
apache格式化输出API
内部函数
static int psprintf_flush(ap_vformatter_buff *vbuff)
自动扩展vbuff,若空间不足则申请新的block并free掉旧的
static char *conv_10(register wide_int num, register bool_int is_unsigned,register bool_int *is_negative, char *buf_end,register int *len)
转换成十进制字符串,从右往左转换,返回开头指针
调用的时候buf_end给的是&num_buf[NUM_BUF_SIZE],没有判断越界,NUM_BUF_SIZE=512,加上精度和'\0'一共最多512个字符
static char *conv_p2(register u_wide_int num, register int nbits,char format, char *buf_end, register int *len)
转换成2的nbits次方进制字符串
register int mask = (1 >= nbits;
}
while (num);
static char *conv_fp(register char format, register double num,boolean_e add_dp, int precision, bool_int *is_negative,char *buf, int *len)
根据format为f,e,E,将num转化为字符串
static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len)
转化成IP:PORT字符串
%pI %pA
API_EXPORT(char *) ap_pvsprintf(pool *p, const char *fmt, va_list ap)
pool接口的vsprintf函数