1 定义
ngx_handle_read_event 函数 定义在 ./nginx-1.24.0/src/event/ngx_event.c
ngx_int_tngx_handle_read_event(ngx_event_t*rev,ngx_uint_tflags){if(ngx_event_flags&NGX_USE_CLEAR_EVENT){/* kqueue, epoll */if(!rev->active&&!rev->ready){if(ngx_add_event(rev,NGX_READ_EVENT,NGX_CLEAR_EVENT)==NGX_ERROR){returnNGX_ERROR;}}returnNGX_OK;}elseif(ngx_event_flags&NGX_USE_LEVEL_EVENT){/* select, poll, /dev/poll */if(!rev->active&&!rev->ready){if(ngx_add_event(rev,NGX_READ_EVENT,NGX_LEVEL_EVENT)==NGX_ERROR){returnNGX_ERROR;}returnNGX_OK;}if(rev->active&&(rev->ready||(flags&NGX_CLOSE_EVENT))){if(ngx_del_event(rev,NGX_READ_EVENT,NGX_LEVEL_EVENT|flags)==NGX_ERROR){returnNGX_ERROR;}returnNGX_OK;}}elseif(ngx_event_flags&NGX_USE_EVENTPORT_EVENT){/* event ports */if(!rev->active&&!rev->ready){if(ngx_add_event(rev,NGX_READ_EVENT,0)==NGX_ERROR){returnNGX_ERROR;}returnNGX_OK;}if(rev->oneshot&&rev->ready){if(ngx_del_event(rev,NGX_READ_EVENT,0)==NGX_ERROR){returnNGX_ERROR;}returnNGX_OK;}}/* iocp */returnNGX_OK;}
ngx_handle_read_event 函数 根据当前使用的事件驱动机制(边沿触发、水平触发、事件端口、IOCP), 统一管理读事件在内核监听中的添加与删除,确保事件既不丢失也不反复通知,同时避免忙轮询。
2 详解
1 函数签名
ngx_int_tngx_handle_read_event(ngx_event_t*rev,ngx_uint_tflags)
返回值 NGX_OK:操作成功。 NGX_ERROR:操作失败。
参数 1 ngx_event_t *rev 指向要监听的事件 参数 2 ngx_uint_t flags 传递额外的控制标志,影响函数对事件的处理策略
2 逻辑流程
1 边沿触发模式 2 水平触发模式 3 event ports 4 iocp
{if(ngx_event_flags&NGX_USE_CLEAR_EVENT){/* kqueue, epoll */if(!rev->active&&!rev->ready){if(ngx_add_event(rev,NGX_READ_EVENT,NGX_CLEAR_EVENT)==NGX_ERROR){returnNGX_ERROR;}}returnNGX_OK;}elseif(ngx_event_flags&NGX_USE_LEVEL_EVENT){/* select, poll, /dev/poll */if(!rev->active&&!rev->ready){if(ngx_add_event(rev,NGX_READ_EVENT,NGX_LEVEL_EVENT)==NGX_ERROR){returnNGX_ERROR;}returnNGX_OK;}if(rev->active&&(rev->ready||(flags&NGX_CLOSE_EVENT))){if(ngx_del_event(rev,NGX_READ_EVENT,NGX_LEVEL_EVENT|flags)==NGX_ERROR){returnNGX_ERROR;}returnNGX_OK;}}elseif(ngx_event_flags&NGX_USE_EVENTPORT_EVENT){/* event ports */if(!rev->active&&!rev->ready){if(ngx_add_event(rev,NGX_READ_EVENT,0)==NGX_ERROR){returnNGX_ERROR;}returnNGX_OK;}if(rev->oneshot&&rev->ready){if(ngx_del_event(rev,NGX_READ_EVENT,0)==NGX_ERROR){returnNGX_ERROR;}returnNGX_OK;}}
#1 判断是否为边沿触发模式: ngx_event_flags 是全局变量, 记录了当前事件模块的特性位掩码。 NGX_USE_CLEAR_EVENT 置位表示使用 边沿触发机制。 该模式只通知一次事件就绪,不会重复通知。
注释:提示该分支对应 FreeBSD 的 kqueue 和 Linux 的 epoll。
条件判断: rev->active 表示该读事件是否已被加入内核事件监听集合; rev->ready 表示内核已将该事件标识为就绪 仅当事件既没有被监听,也没有待处理的就绪状态时,才需要重新添加事件监听。
添加事件并检查结果: 调用 ngx_add_event 将读事件加入内核监听, 事件类型为 NGX_READ_EVENT, 标志为 NGX_CLEAR_EVENT(边沿触发)。 若返回值等于 NGX_ERROR, 表明添加失败 添加失败立即返回错误, 由上层调用者处理
边沿触发分支成功返回: 事件要么已处于正确监听状态, 要么刚被成功添加。
#2 判断是否为水平触发模式: 若 ngx_event_flags 中 NGX_USE_LEVEL_EVENT 置位, 表示当前使用 水平触发机制。 该模式下只要有数据可读,内核会一直通知。
与边沿触发分支相同: 当事件未被监听且未就绪时, 才需要向内核注册监听。
判断是否需要删除事件: 在水平触发模式下, 若事件仍在监听(active 为真), 且 已经就绪(ready 为真) 或 调用者要求关闭(flags 包含 NGX_CLOSE_EVENT), 则必须从内核监听集合中移除该事件。 就绪时不删除: 内核会不断通知,导致事件循环忙轮询(busy loop)。 关闭时不删除:可能触发无效事件甚至访问已释放资源。
删除读事件: 调用 ngx_del_event 移除该读事件。 标志位通过 NGX_LEVEL_EVENT | flags 组合传入, 以便底层(如 poll)可以根据 NGX_CLOSE_EVENT 跳过某些清理。
#3 判断是否为 event ports 模式: Solaris 的 event ports 机制, 行为类似边沿触发,但支持一次性事件(oneshot)。 NGX_USE_EVENTPORT_EVENT 置位时使用该分支。
4 iocp
/* iocp */returnNGX_OK;}
IOCP 下读写都由异步提交操作驱动, 无需显式添加/删除监听事件。 所有未显式返回的路径统一至此返回成功。 这包括: IOCP 模式直接执行到此处。 水平触发模式下 active 为假,或 active 为真但未就绪且无关闭标志。 event ports 模式下 oneshot 或 ready 为假。