ngx_process_events_and_timers
1 定义ngx_process_events_and_timers 函数 定义在 ./nginx-1.24.0/src/event/ngx_event.cvoidngx_process_events_and_timers(ngx_cycle_t*cycle){ngx_uint_tflags;ngx_msec_ttimer,delta;if(ngx_timer_resolution){timerNGX_TIMER_INFINITE;flags0;}else{timerngx_event_find_timer();flagsNGX_UPDATE_TIME;#if(NGX_WIN32)/* handle signals from master in case of network inactivity */if(timerNGX_TIMER_INFINITE||timer500){timer500;}#endif}if(ngx_use_accept_mutex){if(ngx_accept_disabled0){ngx_accept_disabled--;}else{if(ngx_trylock_accept_mutex(cycle)NGX_ERROR){return;}if(ngx_accept_mutex_held){flags|NGX_POST_EVENTS;}else{if(timerNGX_TIMER_INFINITE||timerngx_accept_mutex_delay){timerngx_accept_mutex_delay;}}}}if(!ngx_queue_empty(ngx_posted_next_events)){ngx_event_move_posted_next(cycle);timer0;}deltangx_current_msec;(void)ngx_process_events(cycle,timer,flags);deltangx_current_msec-delta;ngx_log_debug1(NGX_LOG_DEBUG_EVENT,cycle-log,0,timer delta: %M,delta);ngx_event_process_posted(cycle,ngx_posted_accept_events);if(ngx_accept_mutex_held){ngx_shmtx_unlock(ngx_accept_mutex);}ngx_event_expire_timers();ngx_event_process_posted(cycle,ngx_posted_events);}ngx_process_events_and_timers 函数 在每个 worker 进程的主循环中被反复调用。 它负责在一次迭代中协调完成 根据定时器计算下次 I/O 等待的超时时间、参与 accept 互斥锁争用、调用事件模块等待网络事件、 处理延迟的 accept 事件新连接、释放锁、触发到期的定时器最后处理其他延迟的 I/O 读写事件。 通过严格的顺序控制和延迟执行机制它在保证高并发响应的同时将 accept 锁持有时间降到最低。2 详解1 函数签名voidngx_process_events_and_timers(ngx_cycle_t*cycle)返回类型void 该函数不返回任何值。参数 ngx_cycle_t *cycle 指向当前运行周期的上下文2 逻辑流程1 局部变量 2 确定超时时间与标志位 3 Accept 互斥锁 4 处理上一轮遗留的“下轮事件” 5 调用底层事件模块收集 I/O 事件 6 处理延迟的 accept 事件 7 释放 Accept 锁 8 触发所有到期的定时器 9 处理普通延迟 I/O 事件1 局部变量{ngx_uint_tflags;ngx_msec_ttimer,delta;2 确定超时时间与标志位if(ngx_timer_resolution){timerNGX_TIMER_INFINITE;flags0;}else{timerngx_event_find_timer();flagsNGX_UPDATE_TIME;#if(NGX_WIN32)/* handle signals from master in case of network inactivity */if(timerNGX_TIMER_INFINITE||timer500){timer500;}#endif}#1 检查是否配置了 timer_resolution 指令使用系统定时信号 setitimer 周期性更新时间。 逻辑若该值非零说明时间由信号驱动更新无需事件循环自己维护时间缓存。 意义两种时间机制的切换分支。#1-1 将超时设为无限标志清零。 逻辑信号会周期性地中断事件循环更新 ngx_current_msec无需因定时器而主动唤醒。#2 进入另一种时间维护模式默认#2-1 调用 ngx_event_find_timer() 查找红黑树中最近到期的定时器返回距当前时间的毫秒数 同时设置 NGX_UPDATE_TIME 标志。 逻辑 红黑树中每个定时器对应未来某个时刻触发 函数返回最近触发点与现在的差值。 NGX_UPDATE_TIME 告诉底层事件模块 系统调用返回后要立即调用 ngx_time_update() 更新缓存时间。 意义让 epoll_wait 精确阻塞到最近定时器到期为止避免过早唤醒浪费 CPU。#2-2 Windows 平台特殊处理强制将超时限制在 500ms 以内3 Accept 互斥锁if(ngx_use_accept_mutex){if(ngx_accept_disabled0){ngx_accept_disabled--;}else{if(ngx_trylock_accept_mutex(cycle)NGX_ERROR){return;}if(ngx_accept_mutex_held){flags|NGX_POST_EVENTS;}else{if(timerNGX_TIMER_INFINITE||timerngx_accept_mutex_delay){timerngx_accept_mutex_delay;}}}}#1 处理 accept 互斥锁多 worker 负载均衡 判断是否启用了 accept_mutex 机制#2 当前 worker 被标记为“暂时停止竞争锁”则将禁止计数器减 1然后跳过本次锁竞争 ngx_accept_disabled 是一个全局变量 当本 worker 连接数达到 ngx_accept_disabled_threshold 时会被设为某个正值 逐次递减直至 0期间不再参与争锁。 意义实现简易的负载均衡让过载的 worker 逐渐让出新连接到其他 worker。#3-1 否则尝试获取 accept 锁 非阻塞地尝试获取共享内存中的互斥锁 若返回 NGX_ERROR通常标志共享内存损坏直接退出整个函数。 逻辑锁操作本身失败通常意味着严重错误应尽快返回使上层主循环检查并处理进程终止。 意义快速故障隔离避免在异常状态下继续运行。#3-2 成功持锁后将 NGX_POST_EVENTS 标志加入 flags。 逻辑 该标志指示底层事件模块 将所有到达的事件包括新连接和普通 I/O 事件先放入延迟队列 而不立即执行其回调。 意义缩短持有 accept 锁的时间避免在处理事件回调过程中长期占用锁。#3-3 若未获得锁则限制本次事件等待的超时时间。 如果 timer 为无限或大于 ngx_accept_mutex_delay通常 500ms 强制将其缩减为该值。 这样未获得锁的 worker 最多睡眠此段时间之后醒来再次尝试争锁。 意义避免长时间拿不到锁的 worker 一直阻塞导致无法及时响应新连接分发。4 处理上一轮遗留的“下轮事件”if(!ngx_queue_empty(ngx_posted_next_events)){ngx_event_move_posted_next(cycle);timer0;}处理上一轮延迟的“下轮事件” 检查队列 ngx_posted_next_events 是否非空 若有事件则将它们移动到当前待处理队列并将 timer 置 0。 意义保证高优先级延迟事件不被阻塞的 I/O 等待耽误。5 调用底层事件模块收集 I/O 事件deltangx_current_msec;记录开始等待前的时间戳(void)ngx_process_events(cycle,timer,flags);调用具体事件模块的 process_events如 ngx_epoll_process_events 传递 timer 作为最大阻塞时间毫秒。 传递 flags 控制行为如是否更新时间、是否延迟执行事件。 返回值被显式转换为 void 忽略因为所有事件已通过队列或回调函数处理。 意义这是进程阻塞、等待 I/O 事件的唯一位置是事件循环的“心脏”调用。deltangx_current_msec-delta;计算实际等待的毫秒数。 ngx_current_msec 此时已更新如果 flag 包含 NGX_UPDATE_TIME 差值即为 epoll_wait 等函数消耗的时间。ngx_log_debug1(NGX_LOG_DEBUG_EVENT,cycle-log,0,timer delta: %M,delta);在 debug 日志级别下输出本循环的等待耗时6 处理延迟的 accept 事件ngx_event_process_posted(cycle,ngx_posted_accept_events);7 释放 Accept 锁if(ngx_accept_mutex_held){ngx_shmtx_unlock(ngx_accept_mutex);}如果本轮持有了 accept 互斥锁现在解锁8 触发所有到期的定时器ngx_event_expire_timers();遍历红黑树找出所有到期的定时器事件并执行其回调。9 处理普通延迟 I/O 事件ngx_event_process_posted(cycle,ngx_posted_events);}处理所有因 NGX_POST_EVENTS 而延迟的普通读写事件。 这些事件已与 accept 锁无关因此在释放锁后处理可避免阻塞其他 worker 竞争新连接。 意义在非关键路径上完成大工作量的数据处理实现高效解锁后的并行工作。总结 该函数通过精心安排的顺序和延迟队列将一次事件循环切分为 定时器感知 → 锁竞争 → 事件等待 → 新连接处理 → 解锁 → 定时器触发 → 普通 I/O 处理 这种流水线设计保证了锁持有时间极短、高优先级事件及时响应、所有事件一次性处理 最终成就了 Nginx 的高并发低延迟特性。