Nginx提供一套高效的定时器实现,除了Nginx核心能够使用定时器以外,我们在进行模块开发的时候也可以使用定时器来完成一些定时执行的任务。Nginx定时器实现的核心是使用一棵红黑树来存储各个定时事件,每次循环的时候就从这棵树里找出超时的事件,然后一一触发,完成定时任务操作。下面简单的描述一下Nginx在实现定时器时的几个关键点。本文是基于Linux的epoll来描述的定时器实现。
定时器初始化
Nginx阻塞于epoll_wait时可能被3类事件唤醒,分别是有读写事件发生、等待时间超时和信号中断。等待超时和信号中断都是与定时器实现相关的,它们的初始化发生在ngx_event_core_module模块的进程初始化阶段,代码段如下:
- if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {
- return NGX_ERROR;
- }
|
调用ngx_event_timer_init函数完成定时器红黑树的建树操作,这棵红黑树在存储定时器的同时,也为epoll_wait提供了等待时间。
- if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
- struct sigaction sa;
- struct itimerval itv;
-
- ngx_memzero(&sa, sizeof(struct sigaction));
- sa.sa_handler = ngx_timer_signal_handler;
- sigemptyset(&sa.sa_mask);
-
- if (sigaction(SIGALRM, &sa, NULL) == -1) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
- "sigaction(SIGALRM) failed");
- return NGX_ERROR;
- }
-
- itv.it_interval.tv_sec = ngx_timer_resolution / 1000;
- itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000;
- itv.it_value.tv_sec = ngx_timer_resolution / 1000;
- itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000;
-
- if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
- "setitimer() failed");
- }
- }
|