nginx源码剖析(二) —— ngx_list_t分析
2015-12-08 19:44
796 查看
前言
nginx_list_t是nginx的一个链表容器,频繁的在nginx的源码中使用,例如,HTTP的头部就是使用ngx_list_t这个数据结构来存储的。所以,今天我们一起来聊聊这个比较重要的数据结构。(这里使用的源码为nginx比较新的一个版本,nginx-1.6.2版本。)
正文
1、nginx_list_t数据结构的描述:
2、对链表操作的描述:
nginx源码中,对该链表的操作一共包含三个,函数声明如下所示:
通过上面的分析,我们不难发现:
1、nginx源码的ngx_list_t数据结构是从内存池开辟出来的。
2、若数组的空间够,则不申请新的链表节点,使用该剩余空间。
3、若数组空间已满,则在内存池申请新的链表节点。
至此,我们对nginx的链表容器的源码分析完成。
nginx_list_t是nginx的一个链表容器,频繁的在nginx的源码中使用,例如,HTTP的头部就是使用ngx_list_t这个数据结构来存储的。所以,今天我们一起来聊聊这个比较重要的数据结构。(这里使用的源码为nginx比较新的一个版本,nginx-1.6.2版本。)
正文
1、nginx_list_t数据结构的描述:
//链表节点结构 typedef struct ngx_list_part_s ngx_list_part_t; struct ngx_list_part_s { void *elts; //指向数据数组 ngx_uint_t nelts; //实际使用元素的个数 ngx_list_part_t *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;其中,要注意的是:1、void *是可以指向任意类型的地址。2、头结点结构体中nginx源码使用的不是指针而是结构体变量。
2、对链表操作的描述:
nginx源码中,对该链表的操作一共包含三个,函数声明如下所示:
//创建链表 ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size); //链表头初始化 //注:nginx源码 用ngx_int_t 来替代int // 用ngx_uint_t来替代unsigned int static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size); //尾插 void *ngx_list_push(ngx_list_t *list);由于我这次将代码的注释写的比较详细,所以就直接将代码贴下。这三个函数的具体实现如下:
//链表头初始化 //注:nginx源码 用ngx_int_t 来替代int // 用ngx_uint_t来替代unsigned int static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size) { //从内存池中申请数组,用法和malloc类似, //关于内存池这块,之后的文章咱们再好好聊聊 list->part.elts = ngx_palloc(pool, n * size); //若空间申请失败则返回错误信息。 if (list->part.elts == NULL) { return NGX_ERROR; } //已使用大小初始化为零 list->part.nelts = 0; //节点指针域初始化为空 list->part.next = NULL; //链表控制信息的尾节点使用该链表的 //第一个有效节点的地址进行初始化 list->last = &list->part; //节点大小使用传入的size_t参数初始化 list->size = size; //已申请节点大小使用传入的参数n初始化 list->nalloc = n; //指向内存池的指针使用传入的内存值进行初始化 list->pool = pool; //初始化完毕,返回初始化成功 return NGX_OK; }
//链表的创建(主要指对头节点的创建和初始化) 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)); //申请失败则退出,并返回NULL if (list == NULL) { return NULL; } //初始化头节点,若失败则返回NULL if (ngx_list_init(list, pool, n, size) != NGX_OK) { return NULL; } //否则,返回创建好的头节点的地址 return list; }
//尾部添加节点(只是将有效地址返回,不进行实际的元素插入) void * ngx_list_push(ngx_list_t *l) { void *elt; ngx_list_part_t *last; //先指向尾节点 last = l->last; //若该链表的尾节点指向的数组元素已经全部用完 if (last->nelts == l->nalloc) { //1、申请节点 last = ngx_palloc(l->pool, sizeof(ngx_list_part_t)); //申请失败,返回NULL if (last == NULL) { return NULL; } //2、申请数组空间,并让该节点的数组指针指向这个数组 last->elts = ngx_palloc(l->pool, l->nalloc * l->size); //若申请失败则返回NULL if (last->elts == NULL) { return NULL; } //3、将数组已使用元素个数初始化为0 last->nelts = 0; //4、将该节点的指针的指向先置为空 last->next = NULL; //5、将新生成的节点链接到该链表尾部 l->last->next = last; //6、将头节点的尾指针的指向改为新生成节点 l->last = last; } //记录下一个数据在该数组中的位置 elt = (char *) last->elts + l->size * last->nelts; //已使用的元素个数增加一 last->nelts++; //返回这个位置 return elt; }总结
通过上面的分析,我们不难发现:
1、nginx源码的ngx_list_t数据结构是从内存池开辟出来的。
2、若数组的空间够,则不申请新的链表节点,使用该剩余空间。
3、若数组空间已满,则在内存池申请新的链表节点。
至此,我们对nginx的链表容器的源码分析完成。
相关文章推荐
- nginx介绍,流量及并发连接数限制,访问控制及ddos预防
- CentOS 6上YUM安装Nginx和PHP-FPM
- 114 nginx 更新ubuntu14.04 localhost无法访问
- nginx的内页跳转总结
- 初探django-使用uwsgi+supervisor+nginx来部署服务
- nginx优化
- 关于nginx做负载均衡时backend server取real ip
- Nginx服务器下使用rewrite重写url以实现伪静态的示例
- Nginx应用案例分享:压力测试
- Linux下安装Nginx详细图解教程
- nginx配置详解
- nginx rewrite
- Nginx下的PHP搭载环境
- nginx配置参数
- Nginx websocket支持配置
- nginx 设置网站访问频率
- Nginx的Cache缓存
- Nginx的Cache缓存
- 【API管理系统showdoc部署】+【CentOS-5.10 YUM 方式安装NGINX+PHP】
- 安装Apache(2.4.17)、MySQL(5.5.46)、PHP7、Nginx(1.8)