core/ngx_buf.c源代码分析
本节我们讲述一下ngx_buf.c源文件,其主要是定义了nginx buf相关操作的实现。
1. 函数ngx_create_temp_buf()
/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */
#include <ngx_config.h>
#include <ngx_core.h>
ngx_buf_t *
ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
{
    ngx_buf_t *b;
    b = ngx_calloc_buf(pool);
    if (b == NULL) {
        return NULL;
    }
    b->start = ngx_palloc(pool, size);
    if (b->start == 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 = b->start;
    b->last = b->start;
    b->end = b->last + size;
    b->temporary = 1;
    return b;
}本函数用于创建一个temporary类型的nginx buf内存,这意味着其中的内容可以被后续filter所更改。
2. 函数ngx_alloc_chain_link
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 cl;
}如果pool池中仍有空闲的ngx_chain_t链结构,则从池中获取;否则重新分配一个(注意这里仅仅是获得一个ngx_chain_t的链接)
3. 函数ngx_create_chain_of_bufs()
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;
    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;
        ll = &cl->next;
    }
    *ll = NULL;
    return chain;
}本函数用于创建bufs->num数量的temporary buf,并且每个buf的大小为bufs->size; 然后将这些buf连接起来形成buf链。
4. 函数ngx_chain_add_copy()
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;
    }
    while (in) {
        cl = ngx_alloc_chain_link(pool);
        if (cl == NULL) {
            return NGX_ERROR;
        }
        cl->buf = in->buf;
        *ll = cl;
        ll = &cl->next;
        in = in->next;
    }
    *ll = NULL;
    return NGX_OK;
}将in链中的数据拷贝到chain链中。
5. 函数ngx_chain_get_free_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;
}从free链中获取一个空闲的ngx_chain_t链,如果没有剩余的空闲链,则分配一个。
6. 函数ngx_chain_update_chains()
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)
{
    ngx_chain_t  *cl;
    if (*busy == NULL) {
        *busy = *out;
    } else {
        for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
        cl->next = *out;
    }
    *out = NULL;
    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;
    }
}函数首先将out链中的数据复制到busy链中,然后循环处理busy链中的每一个节点:
- 
    若干当前节点仍有未处理的数据,即ngx_buf_size()不为0,则循环退出 
- 
    如果当前节点多对应的buf的tag标志不是指定的标志的话,则将该节点还回到pool中 
- 
    其他情形下,将当前节点添加到free链中 
7. 函数ngx_chain_coalesce_file()
off_t
ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit)
{
    off_t         total, size, aligned, fprev;
    ngx_fd_t      fd;
    ngx_chain_t  *cl;
    total = 0;
    cl = *in;
    fd = cl->buf->file->fd;
    do {
        size = cl->buf->file_last - cl->buf->file_pos;
        if (size > limit - total) {
            size = limit - total;
            aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
                       & ~((off_t) ngx_pagesize - 1);
            if (aligned <= cl->buf->file_last) {
                size = aligned - cl->buf->file_pos;
            }
            total += size;
            break;
        }
        total += size;
        fprev = cl->buf->file_pos + size;
        cl = cl->next;
    } while (cl
             && cl->buf->in_file
             && total < limit
             && fd == cl->buf->file->fd
             && fprev == cl->buf->file_pos);
    *in = cl;
    return total;
}合并in链中与第一个节点相邻的文件buf,并且合并长度限制在limit范围你。
说明: 其实本函数是有缺陷的,因为函数会改变参数in所指向的节点,而在函数返回后又不能确切的知道最后合并到哪一个位置。 本函数在当前ngx_linux_sendfile_chain.c文件中调用暂无问题。
8. 函数ngx_chain_update_sent()
ngx_chain_t *
ngx_chain_update_sent(ngx_chain_t *in, off_t sent)
{
    off_t  size;
    for ( /* void */ ; in; in = in->next) {
        if (ngx_buf_special(in->buf)) {
            continue;
        }
        if (sent == 0) {
            break;
        }
        size = ngx_buf_size(in->buf);
        if (sent >= size) {
            sent -= size;
            if (ngx_buf_in_memory(in->buf)) {
                in->buf->pos = in->buf->last;
            }
            if (in->buf->in_file) {
                in->buf->file_pos = in->buf->file_last;
            }
            continue;
        }
        if (ngx_buf_in_memory(in->buf)) {
            in->buf->pos += (size_t) sent;
        }
        if (in->buf->in_file) {
            in->buf->file_pos += sent;
        }
        break;
    }
    return in;
}这里根据已成功发送数据的大小sent更新in链,并返回下一次需要处理的节点。
[参看]:

