Nginx/core/ngx_list

ngx_list.h

 

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#ifndef _NGX_LIST_H_INCLUDED_
#define _NGX_LIST_H_INCLUDED_


#include <ngx_config.h>
#include <ngx_core.h>


typedef struct ngx_list_part_s  ngx_list_part_t;

// 参考:nginx源码分析—链表结构ngx_list_t http://blog.csdn.net/livelylittlefish/article/details/6599065

/*
ngx_list_t是nginx中使用的链表结构,但与我们常说的链表结构(例如`std::list`)不太一样,
它符合list类型数据结构的一些特点,比如可以添加元素,实现动态自增长,不会像数组类型的数据结构,受到初始设定的数组容量的限制,
不同点就在于它的节点,`std::list`每个节点只能存放一个元素,ngx_list_t的节点却是一个固定大小的数组,可以存放多个元素。

在初始化的时候,我们需要设定单个元素所需要占用的内存空间大小,以及每个节点数组的容量大小。
在添加元素到这个list里面的时候,会在最尾部的节点里的数组上添加元素,如果这个节点的数组存满了,就再增加一个新的节点到这个list里面去。
 */

// ngx_list_part_s是代表ngx_list_t链表的一个节点。
// 它自身包含了一个数组,用来存放最终的元素
struct ngx_list_part_s {
    void             *elts; //链表元素elts数组,数组申请的空间大小为size*nalloc
    ngx_uint_t        nelts; //当前已使用的elts个数,一定要小于等于nalloc
    ngx_list_part_t  *next; //指向ngx_list_t中的下个链表part
};

// ngx_list_t结构是一个链表,链表中每个节点是ngx_list_part_t结构。
// 而ngx_list_part_t中有个elts是一个数组,储存了任意大小固定的元素,它是由ngx_pool_t分配的连续空间
typedef struct {
    ngx_list_part_t  *last; //指向链表中最后一个元素,其作用相当于尾指针。插入新的节点时,从此开始。
    ngx_list_part_t   part; //链表中第一个元素,其作用相当于头指针。遍历时,从此开始。
    size_t            size; //链表中每个元素的大小
    ngx_uint_t        nalloc; //链表的每个ngx_list_part_t中elts数组的所能容纳的最大元素个数
    ngx_pool_t       *pool; //当前list数据存放的内存池
} ngx_list_t;

//ngx_list_create和ngx_list_init功能是一样的都是创建一个list,只是返回值不一样...
ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);

// ngx_list_init是初始化了一个已有的链表
static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    list->part.elts = ngx_palloc(pool, n * size); //从内存池申请空间后,让elts指向可用空间
    if (list->part.elts == NULL) {
        return NGX_ERROR;
    }

    list->part.nelts = 0; //刚分配下来,还没使用,所以为0
    list->part.next = NULL;
    list->last = &list->part; //last开始的时候指向首节点
    list->size = size;
    list->nalloc = n;
    list->pool = pool;

    return NGX_OK;
}


/*
 *
 *  the iteration through the list:
 *
 *  part = &list.part;
 *  data = part->elts;
 *
 *  for (i = 0 ;; i++) {
 *
 *      if (i >= part->nelts) {
 *          if (part->next == NULL) {
 *              break;
 *          }
 *
 *          part = part->next;
 *          data = part->elts;
 *          i = 0;
 *      }
 *
 *      ...  data[i] ...
 *
 *  }
 */


void *ngx_list_push(ngx_list_t *list);


#endif /* _NGX_LIST_H_INCLUDED_ */

 

 

ngx_list.c

 


/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/


#include <ngx_config.h>
#include <ngx_core.h>

//该函数创建一个ngx_list_t类型的对象,并对该list的第一个节点分配存放元素的内存空间。
//
//pool: 分配内存使用的pool。
//n: 每个节点(ngx_list_part_t)最多可以存放的元素个数
//size: 每个元素所占用的内存大小
ngx_list_t *
ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
ngx_list_t *list;

// 先创建一个ngx_list_t指针
list = ngx_palloc(pool, sizeof(ngx_list_t));
if (list == NULL) {
return NULL;
}

list->part.elts = ngx_palloc(pool, n * size);
if (list->part.elts == NULL) {
return NULL;
}

list->part.nelts = 0;
list->part.next = NULL;
list->last = &list->part;
list->size = size;
list->nalloc = n;
list->pool = pool;

return list;
}

/*
ngx_list_create的使用示例:

ngx_list_t *testlist = ngx_list_create(r->pool, 4, sizeof(ngx_str_t));
if (testlist == NULL) {
return NGX_ERROR;
}
*/


// 往链表l中添加新的元素,返回的是新分配的元素的首地址
void *
ngx_list_push(ngx_list_t *l)
{
void *elt;
ngx_list_part_t *last;

last = l->last;

if (last->nelts == l->nalloc) {
// 这里是last节点已经使用了nlloc的elts,所以必须新建一个last节点
/* the last part is full, allocate a new list part */

last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
if (last == NULL) {
return NULL;
}

last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
if (last->elts == NULL) {
return NULL;
}

last->nelts = 0;
last->next = NULL;

l->last->next = last;
l->last = last;
}

elt = (char *) last->elts + l->size * last->nelts;
last->nelts++;

return elt;
}

/*
ngx_list_push的使用实例:

ngx_str_t *str = ngx_list_push(testlist);
if (str == NULL) {
return NGX_ERROR;
}

str->len = sizeof("Hello World");
str->value = "Hello World";
*/

 

/*遍历链表的实例
//part用于指向链表中的每一个ngx_list_part_t数组
ngx_list_part_t* part = &testlist.part;
//根据链表中的数据类型,把数组里的elts转化为该类型使用
ngx_str_t* str = part->elts;
//i表示元素在链表的每个ngx_list_part_t数组里的序号
for (i = 0;;i++)
{
if (i>=part->next)
{
if (part->next == NULL)
{
//说明某个ngx_list_part_t数组的next指针为空,则说明已经遍历完链表
break;
}
//访问下一个ngx_list_part_t
part = part->next;
header = part->elts;
//将i的序号重置为0,准备重新访问下一个数组
i = 0;
}
//这里可以很方便地取到当前遍历到的链表元素、
printf("List Element:%*s\n", str[i].len, str[i].data);
}
*/

 

posted on 2016-02-22 22:56  Excavator  阅读(204)  评论(0)    收藏  举报

导航