日期:2014-05-17  浏览次数:20789 次

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函数