1.基本数据结构
struct ngx_chain_s {
ngx_buf_t *buf;
ngx_chain_t *next;
};
buf: 缓冲区指针
next 下一个链表节点
注意:
- ngx_chain_t是用来管理ngx_buf_t;
- 内存池的pool->chain就是保存空闲的缓冲区链表的;
- 通过链表的方式实现buf有一个非常大的好处:如果一次需要缓冲区的内存很大,那么并不需要分配一块完整的内存,只需要将缓冲区串起来就可以
2.操作函数
释放
必须有一种结构来管理缓冲区(最好是链表),不然无法回收
内存池上的chain字段 ,被清空的ngx_chain_t结构都会放在pool->chain缓冲链上
ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool)
{
{
ngx_chain_t *cl;
cl = pool->chain;
if (cl) {
pool->chain = cl->next;
return cl;
}
cl = ngx_palloc(pool, sizeof(ngx_chain_t));
if (cl == NULL) {
return NULL;
}
return c
}
ngx_free_chain()用来从内存池里获取释放ngx_chain_t对象,声明是:
#define ngx_free_chain(pool, cl) \
cl->next = pool->chain; \
pool->chain = cl
创建多个缓冲区
typedef struct {
ngx_int_t num;
size_t size;
} ngx_bufs_t
1.节点数量
2.缓冲区的大小
// 创建多个buf
/*
typedef struct {
ngx_int_t num;
size_t size;
} ngx_bufs_t;
*/
ngx_chain_t *
ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)
{
u_char *p;
ngx_int_t i;
ngx_buf_t *b;
ngx_chain_t *chain, *cl, **ll;
// @param2 分配大小 = num * size
p = ngx_palloc(pool, bufs->num * bufs->size);
if (p == NULL) {
return NULL;
}
ll = &chain;
for (i = 0; i < bufs->num; i++) {
b = ngx_calloc_buf(pool);
if (b == NULL) {
return NULL;
}
/*
* set by ngx_calloc_buf():
*
* b->file_pos = 0;
* b->file_last = 0;
* b->file = NULL;
* b->shadow = NULL;
* b->tag = 0;
* and flags
*
*/
b->pos = p;
b->last = p;
b->temporary = 1;
b->start = p;
p += bufs->size;
b->end = p;
cl = ngx_alloc_chain_link(pool); // 创建链表结构
if (cl == NULL) {
return NULL;
}
cl->buf = b;
// 尾插法
// ll记录前一次循环的&cl->next
// 下一次循环 *ll = cl 将 &cl->next 上的值改为 cl
// 这样就将上一次循环的next指向当前循环的cl
*ll = cl;
ll = &cl->next;
}
*ll = NULL;
return chain;
}
编程技巧:尾插法(实现 cl=cl->next)
这里重点说下代码后部分的尾插法。
ll是二级指针
ll记录前一次循环的&cl->next (记录了这次循环的cl的next的地址)
下一次循环 *ll = cl 将 &cl->next 上的值改为 cl (改变了上一次循环的cl的next的地址上的值,也就是改变了上一次循环cl的next的值,就是改变了上一次循环的next,让其指向当前的cl)
这样就将上一次循环的next指向当前循环的cl
将其他缓冲区链表放到已有缓冲区链表的尾部
ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
ngx_chain_t *in);
chain->in
ngx_int_t
ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
{
ngx_chain_t *cl, **ll;
ll = chain;
for (cl = *chain; cl; cl = cl->next) {
ll = &cl->next; // 拿到*chain链表最后一个节点的地址
}
while (in) {
cl = ngx_alloc_chain_link(pool);
if (cl == NULL) {
*ll = NULL;
return NGX_ERROR;
}
cl->buf = in->buf;
*ll = cl;
ll = &cl->next;
in = in->next;
}
*ll = NULL;
return NGX_OK;
』
获取一个空闲buf
获取一个空闲buf
ngx_chain_t *
ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free)
{
ngx_chain_t *cl;
if (*free) {
cl = *free;
*free = cl->next;
cl->next = NULL;
return cl;
}
cl = ngx_alloc_chain_link(p);
if (cl == NULL) {
return NULL;
}
cl->buf = ngx_calloc_buf(p);
if (cl->buf == NULL) {
return NULL;
}
cl->next = NULL;
return cl;
释放缓冲区链表
释放掉的cl归还到 pool->chain 上
/*
#define ngx_free_chain(pool, cl) \
cl->next = pool->chain; \
pool->chain = cl
*/
// 释放缓冲区链表
void
ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
ngx_chain_t **out, ngx_buf_tag_t tag) // free 空闲的 busy 忙碌的 out 待处理的
{
ngx_chain_t *cl;
// 判断out应该放到什么位置
// 如果busy == NULL 则*busy = *out
// 否则将*out放到*busy的末尾
if (*out) {
if (*busy == NULL) {
*busy = *out;
} else {
for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
cl->next = *out;
}
*out = NULL;
}
// 检查busy
// 如果busy中的buf还存在需要处理的内存空间,则停止处理
// 否则将buf置空(处理pos last)
while (*busy) {
cl = *busy;
if (ngx_buf_size(cl->buf) != 0) {
break;
}
if (cl->buf->tag != tag) {
*busy = cl->next;
ngx_free_chain(p, cl);
continue;
}
cl->buf->pos = cl->buf->start;
cl->buf->last = cl->buf->start;
*busy = cl->next;
cl->next = *free;
*free = cl;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129629.html