1 定义
ngx_http_post_request 函数 定义在 ./nginx-1.24.0/src/http/ngx_http_request.c
ngx_int_tngx_http_post_request(ngx_http_request_t*r,ngx_http_posted_request_t*pr){ngx_http_posted_request_t**p;if(pr==NULL){pr=ngx_palloc(r->pool,sizeof(ngx_http_posted_request_t));if(pr==NULL){returnNGX_ERROR;}}pr->request=r;pr->next=NULL;for(p=&r->main->posted_requests;*p;p=&(*p)->next){/* void */}*p=pr;returnNGX_OK;}
ngx_http_post_request 函数的作用是 将一个需要延迟处理的 HTTP 请求挂载到主请求的 posted_requests 链表末尾, 以便在当前事件处理结束后再统一取出并继续执行
2 详解
1 函数签名
ngx_int_tngx_http_post_request(ngx_http_request_t*r,ngx_http_posted_request_t*pr)
返回值 NGX_OK —— 操作成功。 NGX_ERROR —— 操作失败
参数1 ngx_http_request_t *r 当前需要被“延迟处理”的 HTTP 请求对象
参数2 ngx_http_posted_request_t *pr 延迟请求链表节点 准备插入到链表中的新节点
2 逻辑流程
1 局部变量 2 分配新节点 3 初始化节点 4 遍历链表到末尾插入新节点 5 返回成功
1 局部变量
{ngx_http_posted_request_t**p;
二级指针 p, 它的类型是“指向 ngx_http_posted_request_t 指针的指针”
2 分配新节点
if(pr==NULL){pr=ngx_palloc(r->pool,sizeof(ngx_http_posted_request_t));if(pr==NULL){returnNGX_ERROR;}}
检查调用者是否提供了现成的节点 若 pr 为 NULL,表示需要由函数自己分配节点; 否则跳过分配直接使用已有节点
3 初始化节点
pr->request=r;pr->next=NULL;
将待延迟处理的请求对象 r 记录到链表节点的 request 字段中 将新节点的 next 指针初始化为 NULL
4 遍历链表到末尾插入新节点
for(p=&r->main->posted_requests;*p;p=&(*p)->next){/* void */}*p=pr;
初始化:p = &r->main->posted_requests r->main 指向主请求。无论当前 r 是主请求还是子请求, Nginx 都将延迟请求链表统一挂在主请求的 posted_requests 字段下, 这样所有相关请求的延迟调度都能由主请求的事件循环统一管理。 posted_requests 是链表头指针,指向链表的第一个节点 取 &r->main->posted_requests 得到头指针自身的地址,赋给二级指针 p。 此时 p 指向头指针变量,*p 就是头指针的值(即第一个节点或 NULL)。 条件判断:*p 检查 *p 是否为 NULL。 若 *p 非空,说明当前节点存在,循环继续; 若 *p == NULL,表示已到达链表尾部(或空链表),循环终止。 每次循环体执行前进行判断,循环体为空({ /* void */ }),所有工作都在步进中完成。 步进:p = &(*p)->next (*p) 是当前节点指针,(*p)->next 是当前节点的 next 成员。 &(*p)->next 取得该 next 成员自身的地址,然后赋给 p。 *p 从指向头节点, 一步步移动到指向下一个节点 *p 也就是 next 循环体为空,因为不需要在遍历过程中对节点本身做任何处理, 唯一目的是找到尾部的 next 循环结束时: 无论原链表是否为空,*p 总是最后一个节点的 next 此时 *p 的值为 NULL,代表链表末尾。
使用二级指针避免了区分“链表为空”和“链表非空”的特殊情况代码。 如果使用一级指针遍历,需要对空链表单独处理。 这里通过直接操作 next 域的地址, 将插入操作统一成一句 *p = pr,代码更简洁、高效。
将新节点链接到链表尾部 将新节点 pr 赋值给 *p,即链表尾部的 next 若原链表为空: p 指向 posted_requests 字段, *p = pr 使 posted_requests 字段记录 pr,链表变成只有一个节点。 若原链表非空: *p 指向原尾节点的 next ,*p = pr 使原尾节点的 next 指向 pr,完成尾插。
5 返回成功
returnNGX_OK;}