nginx学习-链表结构ngx_list_t

Content

1.链表结构

1.2 ngx_list_t的逻辑结构

2.1创建链表

3.一个例子

3.2如何编译

4.小结


0. 序

 

本文继续介绍nginx的容器——链表。

链表实现文件:文件:./src/core/ngx_list.h/.c。.表示nginx-1.0.4代码目录,本文为/usr/src/nginx-1.0.4。

1. 链表结构

 

1.1 ngx_list_t结构

 

nginx的链表(头)结构为ngx_list_t,链表节点结构为ngx_list_part_t,定义如下。

[cpp]  view plain copy
  1. typedef struct ngx_list_part_s ngx_list_part_t;  
  2.    
  3. struct ngx_list_part_s {      //链表节点结构  
  4.     void             *elts;   //指向该节点实际的数据区(该数据区中可以存放nalloc个大小为size的元素)  
  5.     ngx_uint_t        nelts;  //实际存放的元素个数  
  6.     ngx_list_part_t  *next;   //指向下一个节点  
  7. };  
  8.    
  9. typedef struct{              //链表头结构  
  10.     ngx_list_part_t  *last;   //指向链表最后一个节点(part)  
  11.     ngx_list_part_t   part;   //链表头中包含的第一个节点(part)  
  12.     size_t            size;   //每个元素大小  
  13.     ngx_uint_t        nalloc; //链表所含空间个数,即实际分配的小空间的个数  
  14.     ngx_pool_t       *pool;   //该链表节点空间在此内存池中分配  
  15. }ngx_list_t;  


其中,sizeof(ngx_list_t)=28,sizeof(ngx_list_part_t)=12。

 

由此可见,nginx的链表也要从内存池中分配。对于每一个节点(list part)将分配nalloc个大小为size的小空间,实际分配的大小为(nalloc * size)。详见下文的分析。

 

1.2 ngx_list_t的逻辑结构

 

ngx_list_t结构引用了ngx_pool_t结构,因此本文参考nginx-1.0.4源码分析—内存池结构ngx_pool_t及内存管理一文画出相关结构的逻辑图,如下。注:本文采用UML的方式画出该图。

 

2. 链表操作

 

链表操作共3个,如下。

[cpp]  view plain copy
  1. //创建链表  
  2. ngx_list_t*ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);  
  3.    
  4. //初始化链表  
  5. static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool,  
  6.     ngx_uint_tn, size_t size);  
  7.    
  8. //添加元素  
  9. void*ngx_list_push(ngx_list_t *l)  

他们的实现都很简单,本文只分析创建链表和添加元素操作。

 

2.1创建链表

 

创建链表的操作实现如下,首先分配链表头(28B),然后分配头节点(即链表头中包含的part)数据区,两次分配均在传入的内存池(pool指向的内存池)中进行。然后简单初始化链表头并返回链表头的起始位置。

[cpp]  view plain copy
  1. ngx_list_t *  
  2. ngx_list_create(ngx_pool_t*pool, ngx_uint_t n, size_t size)  
  3. {  
  4.     ngx_list_t *list;  
  5.    
  6.     list = ngx_palloc(pool,sizeof(ngx_list_t));  //从内存池中分配链表头  
  7.     if (list == NULL) {  
  8.         return NULL;  
  9.     }  
  10.    
  11.     list->part.elts =ngx_palloc(pool, n * size); //接着分配n*size大小的区域作为链表数据区  
  12.     if (list->part.elts == NULL) {  
  13.         return NULL;  
  14.     }  
  15.    
  16.     list->part.nelts = 0;     //初始化  
  17.     list->part.next = NULL;  
  18.     list->last = &list->part;  
  19.     list->size = size;  
  20.     list->nalloc = n;  
  21.     list->pool = pool;  
  22.    
  23.     return list;    //返回链表头的起始位置  
  24. }  
创建链表后内存池的物理结构图如下。


2.2添加元素

 

添加元素操作实现如下,同nginx数组实现类似,其实际的添加操作并不在该函数中完成。函数ngx_list_push返回可以在该链表数据区中放置元素(元素可以是1个或多个)的位置,而添加操作即在获得添加位置之后进行,如后文的例子。

[cpp]  view plain copy
  1. void *  
  2. ngx_list_push(ngx_list_t*l)  
  3. {  
  4.     void             *elt;  
  5.     ngx_list_part_t  *last;  
  6.    
  7.     last = l->last;  
  8.    
  9.     if (last->nelts ==l->nalloc) {  //链表数据区满  
  10.    
  11.         /* the last part is full, allocate anew list part */  
  12.    
  13.         last =ngx_palloc(l->pool, sizeof(ngx_list_part_t));  //分配节点(list part)  
  14.         if (last == NULL) {  
  15.             return NULL;  
  16.         }  
  17.    
  18.         last->elts =ngx_palloc(l->pool, l->nalloc * l->size);//分配该节点(part)的数据区  
  19.         if (last->elts == NULL) {  
  20.             return NULL;  
  21.         }  
  22.    
  23.         last->nelts = 0;  
  24.         last->next = NULL;  
  25.    
  26.         l->last->next =last;  //将分配的list part插入链表  
  27.         l->last = last;        //并修改list头的last指针  
  28.     }  
  29.    
  30.     elt = (char *)last->elts + l->size * last->nelts; //计算下一个数据在链表数据区中的位置  
  31.     last->nelts++;  //实际存放的数据个数加1  
  32.    
  33.     return elt;  //返回该位置  
  34. }  

由此可见,向链表中添加元素实际上就是从内存池中分配链表节点(part)及其该节点的实际数据区,并修改链表节点(part)信息。

 

注1:与数组的区别,数组数据区满时要扩充数据区空间;而链表每次要分配节点及其数据区。

注2:链表的每个节点(part)的数据区中可以放置1个或多个元素,这里的元素可以是一个整数,也可以是一个结构。

 

下图是一个有3个节点的链表的逻辑结构图。

 

图中的线太多,容易眼晕,下面这个图可能好一些。

 

转自:http://blog.csdn.net/livelylittlefish/article/details/6599065

你可能感兴趣的:(nginx)