当前位置:web 服务器 > Apache >>

Apache源代码分析——Apache数组[table.c]

Apache源代码分析——Apache数组[table.c]

  tingya | 18 一月, 2005 22:39

  该文件主要分析了Apache中的重要的数据结构数组和表格

  /////////////////////////////////////////////////////////////

  //Apache源代码分析——Apache数组table.c

  //张中庆于西安交通大学软件所

  //tingya$stu,xjtu,edu,cn,将$换成@,,换成.防止地址被收集

  //转载请保留出处

  //最初出自西安交通大学兵马俑Linux版

  //////////////////////////////////////////////////////////////

  数组函数

  ///////////////////////////////////////////////////////////////////////////////////////

  文件功能描述:

  该文件中定义了表格和数组的相关数据结构以及函数操作。表格用来保存应用程序中的各种数据结构,而数组则主要用来保存字符串链表。

  关于表格的最重要的数据结构有两个。

  struct apr_array_header_t {

  apr_pool_t *pool;

  int elt_size;

  int nelts;

  int nalloc;

  char *elts;

  };

  Apr_array_header_t是数组组件的核心数据结构。Pool是分配数组内存的内存池。Elt_size是数组中每个元素的大小,而nelts则是当前数组中活动的数组的个数。Nalloc则是数组中分配空间的元素。当然数组中的非活动的数组个数则就是nalloc-nelts了。

  elts则指向实际的数组元素保存空间。

  Apr_table_entry_t通常是作为apr_table_t表格的元素而存在的。Apr_table_t是apr_table_entry_t的“盛装”容易,其定义相对简单,结构如下:

  ///////////////////////////////////////////////////////////////////////////////////////

  Apache的数组操作函数中最核心的函数就是make_array_core函数,其定义如下:

  static void make_array_core(apr_array_header_t *res, apr_pool_t *p,

  int nelts, int elt_size, int clear)

  函数用来生成一个数组,申请数组的内存从内存池p中申请,数组元素个数位nelts,每个元素的大小为elt_size。clar用来通知系统在创建内存之后是否进行初始化为0

  流程描述:

  函数在确保nelts大于0之后,将从内存池p中为数组分配空间,如果clear为0,则调用apr_palloc,如果为1,则调用apr_pcalloc。两者的区别正好在于apr_palloc只管分配,不管初始化;而apr_pcalloc还需要多做一步初始化。分配的空间地址赋值给res参数。一旦获得分配的空间,函数将继续对里面的成员进行初始化,包括pool,elt_size,nelts以及nalloc。Nalloc用来记录已经分配的元素大小。

  ///////////////////////////////////////////////////////////////////////////////////////

  APR_DECLARE(void *) apr_array_pop(apr_array_header_t *arr)

  {

  //检查给定的数组是否为空

  if (apr_is_empty_array(arr)) {

  return NULL;

  }

  return arr->elts + (arr->elt_size * (--arr->nelts));

  }

  Apr_array_pop从数组重取出一个元素,该元素通过apr_array_header_t返回。Arr数组中的元素首地址始终是elts,每当在数组中增加新的元素的时候,elts所指向的内存空间大小将增加elt_size大小。因此当数组中的元素为nelts个的时候,elts的只想的总空间为elt_size*nelts大小。因此,最后一个元素的地址实际上就是(nelts-1)*elt_size。将该地址返回则将取得最后一个元素。

  ///////////////////////////////////////////////////////////////////////////////////////

  APR_DECLARE(void *) apr_array_push(apr_array_header_t *arr)

  该函数与apr_array_pop对应,用来往数组中压入新的数据。

  流程描述:

  函数在压入数组之前首先检查数组中是否有非活动的空闲元素空间,如果没有,即意味着nelts=nalloc,则必须创建新空间用来保存压入的数据,创建不是每次都创建一个元素空间,而是按照下面的原则创建:

  (1) 如果当前压入的数据是第一个数据,即压入之前nalloc为0,则只创建大小为elt_size的空间,即一个元素的空间。

  (2) 如果当前压入元素之前,系统已经分配了nalloc个单元,那么函数将直接批量一次性创建nalloc*2个元素空间,这样申请的空间实际上将达到3*nalloc*elt_size大小。

  当然这些空间都得从内存池arr->pool中申请。

  一旦分配完这些空间,第一个可用的空闲空间则是第nalloc+1或者elt_size+1个元素。此时只需要将需要压入的元素拷贝到该地址空间即可,拷贝完之后,将elt_size加一,并返回新元素的地址。这真是下面的代码所完成的事情:

  memcpy(new_data, arr->elts, arr->nalloc * arr->elt_size);

  memset(new_data + arr->nalloc * arr->elt_size, 0,

  arr->elt_size * (new_size - arr->nalloc));

  arr->elts = new_data;

  arr->nalloc = new_size;

  ///////////////////////////////////////////////////////////////////////////////////////

  static void *apr_array_push_noclear(apr_array_header_t *arr)

  该函数与apr_array_push函数功能基本类似,其唯一区别正如函数名称,在于“noclear”。Arp_array_push在产生新的空闲块,压入新元素之前调用memset对新内存块进行清零操作,而”noclear”函数则省去了这一步。

  ///////////////////////////////////////////////////////////////////////////////////////

  APR_DECLARE(apr_array_header_t *) apr_array_copy(apr_pool_t *p,

  const apr_array_header_t *arr)

  函数用来进行数组之间的拷贝,将数组arr拷贝到数组p中。

  拷贝函数内部非常简单。首先定义一个arp_array_header_t的变量res,从内存池p中为其分配足够的空间,然后调用make_array_core生成一个与arr数组大小相同的数组,逐一进行内存拷贝。然后返回该空间。

  ///////////////////////////////////////////////////////////////////////////////////////

  APR_DECLARE(void) apr_array_cat(apr_array_header_t *dst,

  const apr_array_header_t *src)

  该函数将数组dst和数组src进行合并,合并后src追加到dst的末尾。

  流程描述:

  函数需要做的第一件事情就是判断为了合并,函数是不是需要开辟新的空间。为此函数只需要检dst中的空闲元素是否足够存放src中非空闲的元素,即dst->nalloc-dst->nelts>=src->nelts,而不是dst->nalloc-dst->nelts>=src->nalloc。事实上,src中的空闲元素在拷贝的时候完全可以忽略,因为其本身不包含有效信息。如果dst足够大以至于完全可以容纳,那么函数需要做的只是将src中的非空闲元素逐一拷贝,否则增加空闲块的算法与apr_array_push类似,但是不完全相同,算法如下:

  (1) 如果dst中元素个数为零,此时,将产生一个新的空间。

  (2) 如果dst中元素个数nalloc不为零,则产生nalloc*2个空闲空间。

  (3) 尽管如此,如果src的非空闲元素实在太多,而dst本身空闲空间很小,那么即使一次产生nalloc个空闲块也不一定能够盛放src中的元素。唯一的办法就是不停的产生新的空闲块,直到空闲块总数能够容纳src中的非空闲元素为止。这真是下面的代码所做的事情:

  if (dst->nelts + src->nelts > dst->nalloc) {

  int new_size = (dst->nalloc <= 0) ? 1 : dst->nalloc * 2;

  while (dst->nelts + src->nelts > new_size) {

  new_size *= 2;

  }

  }

  一旦确定确定需要产生的空闲块的总数,函数将一次性从内存池dst->pool中申请。然后将src中的数据拷贝空间空间即可。

  ///////////////////////////////////////////////////////////////////////////////////////

  APR_DECLARE(int) apr_is_empty_array(const apr_array_header_t *a)

  该函数通过给定的数组a是否为空。判断的方法很简单,就是检查a是否为NULL ,或者a->nelts是否为NULL。

  ///////////////////////////////////////////////////////////////////////////////////////

  APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p,

  int nelts, int elt_size)

  该函数用来生成数组结构,生成的数组元素个数为nelts,每个元素空间为elt_size,函数返回生成的数组。

  函数的内部执行实际上是通过调用make_array_core来执行的。

  ///////////////////////////////////////////////////////////////////////////////////////

  ///////////////////////////////////////////////////////////////////////////////////////

  //////////////////////////////////////////////
Apache
IIS
Nginx
Tomcat
如果你遇到web 服务器难题:
访问www.zzzyk.com 试试
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,