标签:des blog http ar os 使用 sp for on
菜鸟nginx源码剖析数据结构篇(八) 缓冲区链表 ngx_chain_t
Author:Echo Chen(陈斌)
Email:chenb19870707@gmail.com
Date:Nov 6th, 2014
nginx的缓冲区链表如下图所示,ngx_chain_t为链表,ngx_buf_t为缓冲区结点:
头文件:http://trac.nginx.org/nginx/browser/nginx/src/core/ngx_buf.h
源文件:http://trac.nginx.org/nginx/browser/nginx/src/core/ngx_buf.c
ngx_buf_t为缓冲区结点,其定义如下:
   1: typedef struct ngx_buf_s    ngx_buf_t;
   2: typedef void  *ngx_buf_tag_t;
   3: struct ngx_buf_s {
   4:     /*
   5:      * pos通常是用来告诉使用者本次应该从pos这个位置开始处理内存中的数据,这样设置是因为同一个
   6:      * ngx_buf_t可能被多次反复处理。当然,pos的含义是由使用它的模板定义的
   7:      */
   8:     u_char  *pos;
   9:                                
  10:     /* last通常表示有效的内容到此为止,注意,pos与last之间的内存是希望nginx处理的内容 */
  11:     u_char  *last;
  12:                                
  13:     /*
  14:      * 处理文件时,file_pos与file_last的含义与处理内存时的pos与last相同,
  15:      * file_pos表示将要处理的文件位置,file_last表示截至的文件位置。
  16:      */
  17:     off_t   file_pos;
  18:     off_t   file_last;
  19:                                
  20:     /* 如果ngx_buf_t缓冲区用于内存,那么start指向这段内存的起始地址 */
  21:     u_char  *start;
  22:                                
  23:     /* 与start成员对应,指向缓冲区内存的末尾 */
  24:     u_char  *end;
  25:                                
  26:     /* 表示当前缓冲区的类型,例如由哪个模块使用就指向这个模块ngx_module_t变量的地址 */
  27:     ngx_buf_tag_t  tag;
  28:                                
  29:     /* 引用的文件 */
  30:     ngx_file_t  *file;
  31:                                
  32:     /*
  33:      * 当前缓冲区的影子缓冲区,该成员很少用到。当缓冲区转发上游服务器的响应时才使用了shadow成员,
  34:      * 这是因为nginx太节约内存了,分配一块内存并使用ngx_buf_t表示接收到的上游服务器响应后,
  35:      * 在向下游客户端转发时可能会把这块内存存储到文件中,也可能直接向下游发送,此时nginx绝对不会
  36:      * 重新复制一份内存用于新的目的,而是再次建立一个ngx_buf_t结构体指向原内存,这样多个ngx_buf_t
  37:      * 结构体指向了同一份内存,它们之间的关系就通过shadow成员来引用,一般不建议使用。
  38:      */
  39:     ngx_buf_t   *shadow;
  40:                                
  41:     /* 临时内存标志位,为1时表示数据在内存中且这段内存可以修改 */
  42:     unsigned    temporay:1;
  43:                                
  44:     /* 标志位,为1时表示数据在内存中且这段内存不可以修改 */
  45:     unsigned    memory:1;
  46:                                
  47:     /* 标志位,为1时表示这段内存是用nmap系统调用映射过来的,不可以修改 */
  48:     unsigned    mmap:1;
  49:                                
  50:     /* 标志位,为1时表示可回收 */
  51:     unsigned    recycled:1;
  52:                                
  53:     /* 标志位,为1时表示这段缓冲区处理的是文件而不是内存 */
  54:     unsigned    in_file:1;
  55:                                
  56:     /* 标志位,为1时表示需要执行flush操作 */
  57:     unsigned    flush:1;
  58:                                
  59:     /*
  60:      * 标志位,对于操作这块缓冲区时是否使用同步方式,需谨慎考虑,这可能会阻塞nginx进程,nginx中所有
  61:      * 操作几乎都是异步的,这是它支持高并发的关键。有些框架代码在sync为1时可能会有阻塞的方式进行I/O
  62:      * 操作,它的意义视使用它的nginx模块而定。
  63:      */
  64:     unsigned    sync:1;
  65:                                
  66:     /*
  67:      * 标志位,表示是否是最后一块缓冲区,因为ngx_buf_t可以由ngx_chain_t链表串联起来,因此为1时,
  68:      * 表示当前是最后一块待处理的缓冲区。   
  69:      */
  70:     unsigned    last_buf:1;
  71:                                
  72:     /* 标志位,表示是否是ngx_chain_t中的最后一块缓冲区 */
  73:     unsigned    last_in_chain:1;
  74:                                
  75:     /* 标志位,表示是否是最后一个影子缓冲区,与shadow域配合使用。通常不建议使用它 */
  76:     unsigned    last_shadow:1;
  77:                                
  78:     /* 标志位,表示当前缓冲区是否属于临时文件 */
  79:     unsigned    temp_file:1;
  80: }
ngx_chain_t为缓冲区链表,其结构如下:
   1: typedef struct ngx_chain_s       ngx_chain_t;
   2: struct ngx_chain_s {
   3:     ngx_buf_t    *buf;        //buf指向当前的ngx_buf_t缓冲区
   4:     ngx_chain_t  *next;       //next则用来指向下一个ngx_chain_t,如果这是最后一个ngx_chain_t,则需要把next置为NULL。
   5: };
   1: ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
   2: {
   3:     ngx_buf_t *b;
   4:  
   5:     b = ngx_calloc_buf(pool);            //分配ngx_buf_t
   6:     if (b == NULL) {
   7:         return NULL;
   8:     }
   9:  
  10:     b->start = ngx_palloc(pool, size);  //给ngx_buf_t分配buffer
  11:     if (b->start == NULL) {
  12:         return NULL;
  13:     }
  14:  
  15:     /*
  16:      * set by ngx_calloc_buf():
  17:      *
  18:      *     b->file_pos = 0;
  19:      *     b->file_last = 0;
  20:      *     b->file = NULL;
  21:      *     b->shadow = NULL;
  22:      *     b->tag = 0;
  23:      *     and flags
  24:      */
  25:  
  26:     //设置起始位置pos和结束位置last,end指向缓冲区的末尾,临时标志设置为1
  27:     b->pos = b->start;
  28:     b->last = b->start;
  29:     b->end = b->last + size;
  30:     b->temporary = 1;
  31:  
  32:     return b;
  33: }
   1: ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool)
   2: {
   3:     ngx_chain_t  *cl;
   4:  
   5:     cl = pool->chain;
   6:     
   7:     if (cl) 
   8:     {
   9:         pool->chain = cl->next;
  10:         return cl;
  11:     }
  12:  
  13:     cl = ngx_palloc(pool, sizeof(ngx_chain_t));
  14:     if (cl == NULL)
  15:     {
  16:         return NULL;
  17:     }
  18:  
  19:     return cl;
  20: }
构建如下的缓冲区链表,代码比较简单,很容易理解:
1: ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)2: {3: u_char *p;4: ngx_int_t i;5: ngx_buf_t *b;6: ngx_chain_t *chain, *cl, **ll;7:8: //分配buf内存9: p = ngx_palloc(pool, bufs->num * bufs->size);10: if (p == NULL)11: {12: return NULL;13: }14:15: ll = &chain;16:17: for (i = 0; i < bufs->num; i++)18: {19: //分配ngx_buf_t内存20: b = ngx_calloc_buf(pool);21: if (b == NULL)22: {23: return NULL;24: }25:26: /*27: * set by ngx_calloc_buf():28: *29: * b->file_pos = 0;30: * b->file_last = 0;31: * b->file = NULL;32: * b->shadow = NULL;33: * b->tag = 0;34: * and flags35: *36: */37:38: b->pos = p;39: b->last = p;40: b->temporary = 1;41:42: b->start = p;43: p += bufs->size;44: b->end = p;45:46: //分配ngx_chain_t47: cl = ngx_alloc_chain_link(pool);48: if (cl == NULL)49: {50: return NULL;51: }52:53: //54: cl->buf = b;55: *ll = cl;56: ll = &cl->next;57: }58:59: //最后一个结点指向NULL60: *ll = NULL;61:62: return chain;63: }
   1: ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
   2: {
   3:     ngx_chain_t  *cl, **ll;
   4:  
   5:     ll = chain;
   6:  
   7:     //找到缓冲区末尾,即为NULL
   8:     for (cl = *chain; cl; cl = cl->next)
   9:     {
  10:         ll = &cl->next;
  11:     }
  12:  
  13:     while (in) 
  14:     {
  15:         //遍历in,依次拷贝每一个结点
  16:         cl = ngx_alloc_chain_link(pool);
  17:         if (cl == NULL)
  18:         {
  19:             return NGX_ERROR;
  20:         }
  21:  
  22:         cl->buf = in->buf;
  23:         *ll = cl;
  24:         ll = &cl->next;
  25:         in = in->next;
  26:     }
  27:  
  28:     //缓冲区末尾赋值为NULL
  29:     *ll = NULL;
  30:  
  31:     return NGX_OK;
  32: }
ngx_chain_get_free_buf 得到链表中未使用的buf,如果没有,则分配一个。1: ngx_chain_t *ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free)2: {3: ngx_chain_t *cl;4:5: //若空闲链表中有结点,直接返回6: if (*free)7: {8: cl = *free;9: *free = cl->next;10: cl->next = NULL;11: return cl;12: }13:14: //否则分配ngx_chain_t15: cl = ngx_alloc_chain_link(p);16: if (cl == NULL) {17: return NULL;18: }19:20: //并给ngx_chain_t分配buf21: cl->buf = ngx_calloc_buf(p);22: if (cl->buf == NULL)23: {24: return NULL;25: }26:27: cl->next = NULL;28:29: return cl;30: }
   1:  
   2: void ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
   3:     ngx_chain_t **out, ngx_buf_tag_t tag)
   4: {
   5:     ngx_chain_t  *cl;
   6:  
   7:     //让busy指向out
   8:     if (*busy == NULL)
   9:     {
  10:         *busy = *out;
  11:  
  12:     } 
  13:     else
  14:     {
  15:         for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
  16:  
  17:         cl->next = *out;
  18:     }
  19:  
  20:     *out = NULL;
  21:  
  22:     while (*busy) 
  23:     {
  24:         cl = *busy;
  25:  
  26:         //这个结点内存有占用,不满足释放条件,跳出
  27:         if (ngx_buf_size(cl->buf) != 0) 
  28:         {
  29:             break;
  30:         }
  31:  
  32:         //缓冲区类型不同,直接释放
  33:         if (cl->buf->tag != tag)
  34:         {
  35:             *busy = cl->next;
  36:             ngx_free_chain(p, cl);
  37:             continue;
  38:         }
  39:  
  40:         //将该结点放入free
  41:         cl->buf->pos = cl->buf->start;
  42:         cl->buf->last = cl->buf->start;
  43:  
  44:         *busy = cl->next;
  45:         cl->next = *free;
  46:         *free = cl;
  47:     }
  48: }
菜鸟nginx源码剖析数据结构篇(八) 缓冲区链表ngx_chain_t[转]
标签:des blog http ar os 使用 sp for on
原文地址:http://www.cnblogs.com/0x2D-0x22/p/4141299.html