nginx代码分析-基本结构-单链表ngx_list_t

一.数据结构

单向链表, 每个链表数据节点实际是一个数组, 数组总长度一致, 数组元素大小一致.

ngx_list_t为链表头节点, 定义了链表数据节点数组中数据元素大小(size), 每个节点最大的数据个数(nalloc), 以及一个last指针指向链表的尾部数据节点方便插入数据操作.

ngx_list_part_t为链表数据节点, 记录了当前数组中已占用元素的个数, next指针指向下一节点.

struct ngx_list_part_s {
    void             *elts;   // 实际数据, n * size
    ngx_uint_t        nelts;  // 节点数组已经使用的元素个数
    ngx_list_part_t  *next;   // 链表next指针
};


typedef struct {
    ngx_list_part_t  *last;  // 指向链表中尾节点
    ngx_list_part_t   part;  // 链表头结点
    size_t            size;  // 链表中节点数组的元素大小
    ngx_uint_t        nalloc;// 链表中节点数组的元素个数
    ngx_pool_t       *pool;
} ngx_list_t;

二.链表的创建

ngx_list_t *
ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    ngx_list_t  *list;

    list = ngx_palloc(pool, sizeof(ngx_list_t)); // 分配链表头
    if (list == NULL) {
        return NULL;
    }

    if (ngx_list_init(list, pool, n, size) != NGX_OK) {
        return NULL;
    }

    return list;
}

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); // 为头结点分配n*size大小的数据空间
    if (list->part.elts == NULL) {
        return NGX_ERROR;
    }

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

    return NGX_OK;
}

如图为初始化后链表结构, 首先在内存池ngx_pool_t中分配链表头ngx_list_t的空间, 再通过ngx_list_init函数分配链表头数据节点的空间, 大小为nalloc * size.

 

nginx代码分析-基本结构-单链表ngx_list_t_第1张图片 

三.链表的使用

void *
ngx_list_push(ngx_list_t *l)
{
    void             *elt;
    ngx_list_part_t  *last;

    last = l->last;

    if (last->nelts == l->nalloc) { // 尾节点数组元素分配达到上限

        /* 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返回1个新元素的内存地址. 通过链表头的last指针找到链表尾节点, 如果elts中还有空间则分配一个元素, 否则新建一个链表数据节点ngx_list_part_t, 在新节点中分配,头结点指向该新节点

nginx代码分析-基本结构-单链表ngx_list_t_第2张图片

你可能感兴趣的:(nginx代码分析-基本结构-单链表ngx_list_t)